From ba6de424771aeae64390780982974d01858b097e Mon Sep 17 00:00:00 2001 From: Aditya Kumar Date: Thu, 11 Jun 2026 00:07:49 +0530 Subject: [PATCH] fix: update get_mediawiki_user_edit_count to retrieve global edit count and handle CentralAuth fallback --- backend/app/utils/__init__.py | 54 ++++++++++++++++++++++++++--------- frontend/package-lock.json | 8 ++++++ 2 files changed, 49 insertions(+), 13 deletions(-) diff --git a/backend/app/utils/__init__.py b/backend/app/utils/__init__.py index 15eb3012..bf671fc3 100644 --- a/backend/app/utils/__init__.py +++ b/backend/app/utils/__init__.py @@ -1208,9 +1208,13 @@ def get_mediawiki_user_edit_count( username: str, mw_uri: str = "https://meta.wikimedia.org/w/index.php" ) -> Optional[int]: """ - Get the edit count for a MediaWiki user. + Get the global edit count for a MediaWiki user. + + Queries the CentralAuth globaluserinfo API to get the user's combined + edit count across all Wikimedia projects (the same source XTools uses). + Falls back to the wiki-local edit count if CentralAuth is not available + on the target wiki. - Fetches user information from MediaWiki API and returns their edit count. This is used to check if a user meets the minimum edit count requirement for automatic trusted member status (>= 300 edits). @@ -1225,26 +1229,53 @@ def get_mediawiki_user_edit_count( # Build API URL from MediaWiki URI # Convert from index.php format to api.php format if mw_uri.endswith('/index.php'): - api_url = mw_uri.replace('/index.php', '/w/api.php') + api_url = mw_uri[: -len('/index.php')] + '/api.php' elif mw_uri.endswith('/'): api_url = f"{mw_uri}w/api.php" else: api_url = f"{mw_uri}/w/api.php" - # Build API parameters to get user info - # Use users query to get edit count + headers = get_mediawiki_headers() + + # Global edit count across all Wikimedia projects (CentralAuth) + api_params = { + 'action': 'query', + 'meta': 'globaluserinfo', + 'guiuser': username, + 'guiprop': 'editcount', + 'format': 'json', + 'formatversion': '2' + } + + response = requests.get( + api_url, + params=api_params, + headers=headers, + timeout=MEDIAWIKI_API_TIMEOUT + ) + + if response.status_code != 200: + return None + + data = response.json() + + global_info = data.get('query', {}).get('globaluserinfo', {}) + if not global_info.get('missing'): + edit_count = global_info.get('editcount') + if edit_count is not None: + return int(edit_count) + + # CentralAuth unavailable or user has no global account: + # fall back to the wiki-local edit count api_params = { 'action': 'query', 'list': 'users', 'ususers': username, - 'usprop': 'editcount', # Get edit count + 'usprop': 'editcount', 'format': 'json', 'formatversion': '2' } - headers = get_mediawiki_headers() - - # Make request to MediaWiki API response = requests.get( api_url, params=api_params, @@ -1257,13 +1288,11 @@ def get_mediawiki_user_edit_count( data = response.json() - # Check for API errors if 'error' in data: return None - # Extract edit count from response users = data.get('query', {}).get('users', []) - if not users or len(users) == 0: + if not users: return None user_data = users[0] @@ -1272,7 +1301,6 @@ def get_mediawiki_user_edit_count( if user_data.get('missing'): return None - # Get edit count edit_count = user_data.get('editcount') if edit_count is None: return None diff --git a/frontend/package-lock.json b/frontend/package-lock.json index e38d06e7..f603902f 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1084,6 +1084,7 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -1880,6 +1881,7 @@ "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -2076,6 +2078,7 @@ "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.9", @@ -2133,6 +2136,7 @@ "integrity": "sha512-jDex9s7D/Qial8AGVIHq4W7NswpUD5DPDL2RH8Lzd9EloWUuvUkHfv4FRLMipH5q2UtyurorBkPeNi1wVWNh3Q==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "builtins": "^5.0.1", "eslint-plugin-es": "^4.1.0", @@ -2172,6 +2176,7 @@ "integrity": "sha512-57Zzfw8G6+Gq7axm2Pdo3gW/Rx3h9Yywgn61uE/3elTCOePEHVrn2i5CdfBwA1BLK0Q0WqctICIUSqXZW/VprQ==", "dev": true, "license": "ISC", + "peer": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -2188,6 +2193,7 @@ "integrity": "sha512-174lJKuNsuDIlLpjeXc5E2Tss8P44uIimAfGD0b90k0NoirJqpG7stLuU9Vp/9ioTOrQdWVREc4mRd1BD+CvGw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "globals": "^13.24.0", @@ -4515,6 +4521,7 @@ "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", @@ -4574,6 +4581,7 @@ "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.25.tgz", "integrity": "sha512-YLVdgv2K13WJ6n+kD5owehKtEXwdwXuj2TTyJMsO7pSeKw2bfRNZGjhB7YzrpbMYj5b5QsUebHpOqR3R3ziy/g==", "license": "MIT", + "peer": true, "dependencies": { "@vue/compiler-dom": "3.5.25", "@vue/compiler-sfc": "3.5.25",