Fix #3546: Notify all uploaders when nominating file for deletion#6729
Fix #3546: Notify all uploaders when nominating file for deletion#6729kushwaha-Khushi-0612 wants to merge 3 commits intocommons-app:mainfrom
Conversation
8deb704 to
fb7848a
Compare
|
|
||
| deleteHelper.makeDeletion(context, media, "Test reason")?.blockingGet() | ||
| } | ||
|
|
There was a problem hiding this comment.
This is the test which i added for furture also for testing this notification thing.
|
✅ Generated APK variants! |
There was a problem hiding this comment.
Pull request overview
This PR updates the deletion nomination flow to notify all uploaders of a file (instead of only a single creator), by fetching uploader info from file revision history via the MediaWiki imageinfo API.
Changes:
- Add an API endpoint and client helper to fetch a file’s
imageinforevision list (uploaders/timestamps). - Update
DeleteHelperto notify each distinct uploader’s talk page after a successful nomination flow. - Extend
DeleteHelperTestwith mocks and a new test covering multiple uploader notifications.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| app/src/main/java/fr/free/nrw/commons/delete/DeleteHelper.kt | Injects MediaClient and changes nomination flow to notify all uploaders’ talk pages. |
| app/src/main/java/fr/free/nrw/commons/media/MediaInterface.kt | Adds a MediaWiki API endpoint intended to fetch all file revisions (imageinfo). |
| app/src/main/java/fr/free/nrw/commons/media/MediaClient.kt | Adds getImageInfoList() wrapper to extract ImageInfo entries from the API response. |
| app/src/main/java/fr/free/nrw/commons/wikidata/mwapi/MwQueryPage.kt | Adds imageInfoList() accessor returning all imageinfo items from the page. |
| app/src/test/kotlin/fr/free/nrw/commons/delete/DeleteHelperTest.kt | Updates tests for new DeleteHelper dependency and adds multi-uploader notification test. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| mediaClient.getImageInfoList(media.filename!!) | ||
| .toObservable() | ||
| .flatMap { imageInfos -> | ||
|
|
||
| val uploaders = imageInfos | ||
| .map { it.getUser() } | ||
| .filter { it.isNotEmpty() } | ||
| .toSet() | ||
|
|
||
| if (uploaders.isEmpty()) { | ||
| // No uploaders found, still return success | ||
| return@flatMap Observable.just(true) | ||
| } |
There was a problem hiding this comment.
delete() now fetches uploaders via mediaClient.getImageInfoList(...), but any network/API error from that call will fail the whole deletion flow (even though the nomination edits already succeeded). Consider handling errors from getImageInfoList (e.g., fallback to notifying creator or treating uploader-fetch failure as non-fatal) so users don’t see a failed deletion due only to uploader lookup issues.
|
|
||
| if (uploaders.isEmpty()) { | ||
| // No uploaders found, still return success |
There was a problem hiding this comment.
creator is still computed earlier in delete() (and can throw if null), but the new uploader-notification logic no longer uses it. This is now dead code and also unnecessarily blocks nominations when getAuthorOrUser() is missing. Either remove the creator lookup/exception, or use it as a fallback uploader when the imageinfo list is empty/unavailable.
| if (uploaders.isEmpty()) { | |
| // No uploaders found, still return success | |
| .ifEmpty { | |
| // Fallback to creator when no uploader is available from image info | |
| creator?.takeIf { it.isNotEmpty() }?.let { setOf(it) } ?: emptySet() | |
| } | |
| if (uploaders.isEmpty()) { | |
| // No uploaders (including creator) found, still return success |
|
|
||
| val uploaders = imageInfos | ||
| .map { it.getUser() } | ||
| .filter { it.isNotEmpty() } |
There was a problem hiding this comment.
When building uploaders, the filter uses isNotEmpty(), which will still keep usernames that are only whitespace. Using isNotBlank() (and/or trimming) would avoid attempting to write to invalid talk page titles.
| .filter { it.isNotEmpty() } | |
| .filter { it.isNotBlank() } |
| /** | ||
| * Fetches all file revisions (for getting all uploaders) | ||
| * Uses iilimit=max to get all imageInfo versions | ||
| * | ||
| * @param title the file name to get all revisions for | ||
| * @return | ||
| */ | ||
| @GET("w/api.php?action=query&format=json&formatversion=2&prop=imageinfo&iiprop=user|timestamp&iilimit=max") | ||
| fun getAllFileRevisions( | ||
| @Query("titles") title: String?, | ||
| ): Single<MwQueryResponse> |
There was a problem hiding this comment.
getAllFileRevisions is documented as fetching “all file revisions”, but iilimit=max only returns the maximum per request and MediaWiki will still paginate via continue/iicontinue for files with many revisions. Either implement continuation support (loop until no continue) or rename/reword the API/docs to avoid implying it always returns all revisions.
| fun getImageInfoList(titles: String?): Single<List<ImageInfo>> = | ||
| mediaInterface.getAllFileRevisions(titles) | ||
| .map { response -> | ||
| response.query()?.pages()?.flatMap { page -> | ||
| page.imageInfoList() | ||
| } ?: emptyList() | ||
| } |
There was a problem hiding this comment.
getImageInfoList() currently makes a single getAllFileRevisions call and ignores any continue values in the MwQueryResponse, so it will silently return a partial revision list for files with lots of history. If the goal is “notify all uploaders”, this should either page through continuation tokens or make it explicit that the list may be truncated.
| * Get all imageInfo objects (all file revisions) | ||
| * Used for finding all uploaders when nominating for deletion |
There was a problem hiding this comment.
imageInfoList() is described as returning “all file revisions”, but it only returns whatever imageinfo entries were included in the API response (which may be paginated/truncated). Consider adjusting the KDoc to avoid implying completeness unless continuation is handled elsewhere.
| * Get all imageInfo objects (all file revisions) | |
| * Used for finding all uploaders when nominating for deletion | |
| * Get the imageInfo objects (file revisions) included in this API response. | |
| * Used for finding uploaders when nominating for deletion. | |
| * Note: this may not include all file revisions if the API results are paginated. |
|
|
||
| val userPageString = "\n{{subst:idw|${media.filename}}} ~~~~" | ||
|
|
||
| val creator = media.getAuthorOrUser() |
There was a problem hiding this comment.
How about getting the list here itself and simplifying the logic? L169 in the diff seems to get the same value.
|
@sivaraam could you please help test this PR or share the exact steps to reproduce this (or maybe an example image on Commons having multiple uploaders)? I'm not sure if cross-account revisions are common 🤔 |
|
@RitikaPahwa4444 it is likely better to test this in the beta cluster as there you could freely create multiple accounts and test by uploading multiple versions of a file and nominating the same. Anyways, an example version of the file that has multiple uploaders (see "File history" section): https://commons.wikimedia.org/wiki/File:%E4%B8%AD%E8%8B%8F%E5%8F%8B%E8%B0%8A%E7%BA%AA%E5%BF%B5%E5%A1%94_2020.jpg When you nominate that file, nomination request should go to both User:Finavon and User:MintCandy user pages. In Commons, cross-account revisions are not rare given the wiki's nature. So, it should be possible to find the same |
|
Alternatively, if prod is the only way to test this. You could also feel free to upload a new version to one of the following uploads of mine and nominate it for deletion (test deletion of course). In prod, some more images with multiple author uploads can be found via this Quarry query: https://quarry.wmcloud.org/query/103353 |
Fix for Issue #3546
Problem
When a file with multiple revisions is nominated for deletion, only the first uploader is notified on their talk page.
This happens because:
Solution
This PR ensures that all uploaders of a file revision receive a deletion notification.
Changes:
iilimit=maxto fetch all file revisionsMwQueryPage.imageInfoList()MediaClient.getImageInfoList()to return all revisionsTesting
Added unit test
makeDeletionNotifiesAllUploadersto ensure notifications are sent to all uploaders.Result
All users who uploaded a revision of a file now receive deletion notifications.