From ffaea5ed7ea197d165d9effdd05adae5979e3405 Mon Sep 17 00:00:00 2001 From: Sohom Date: Wed, 23 Aug 2023 22:18:50 +0530 Subject: [PATCH] Don't expose usernames if user is hidden - Remove user_name and user info from 'pagetriagelist' API - Add user_hidden field to 'pagetriagelist' API - Modify pagetriage toolbar to handle cases where no username is provided - Modify Special:NewPagesFeed to gracefully handle cases where the username is hidden - Add a special case in the Special:NewPagesFeed vue version for hidden usernames (where other information is availiable) Bug: T344359 Change-Id: I5714f69a70909e3c3e7322e5f3be62d837e4d1cc --- extension.json | 13 ++++++- i18n/en.json | 1 + i18n/qqq.json | 1 + includes/Api/ApiPageTriageList.php | 37 +++++++++++++++---- includes/SpecialNewPagesFeed.php | 2 + .../components/ListContent.vue | 1 + .../components/ListItem.vue | 9 ++++- .../models/ext.pageTriage.article.js | 3 +- .../ext.pageTriage.listItem.css | 5 +++ .../ext.pageTriage.listItem.underscore | 8 +++- .../ext.pageTriage.views.toolbar/ToolView.js | 1 + .../articleInfo.js | 10 ++++- .../articleInfo.underscore | 6 ++- modules/ext.pageTriage.views.toolbar/mark.js | 3 +- modules/ext.pageTriage.views.toolbar/tags.js | 2 +- .../ext.pageTriage.views.toolbar/wikiLove.js | 7 +++- 16 files changed, 92 insertions(+), 17 deletions(-) diff --git a/extension.json b/extension.json index 3895ce32..30c9fae2 100644 --- a/extension.json +++ b/extension.json @@ -15,7 +15,12 @@ "MediaWiki": ">= 1.41" }, "APIModules": { - "pagetriagelist": "MediaWiki\\Extension\\PageTriage\\Api\\ApiPageTriageList", + "pagetriagelist": { + "class": "MediaWiki\\Extension\\PageTriage\\Api\\ApiPageTriageList", + "services": [ + "UserFactory" + ] + }, "pagetriagestats": "MediaWiki\\Extension\\PageTriage\\Api\\ApiPageTriageStats", "pagetriageaction": { "class": "MediaWiki\\Extension\\PageTriage\\Api\\ApiPageTriageAction", @@ -239,8 +244,10 @@ "pagetriage-mark-as-unreviewed", "pagetriage-info-title", "pagetriage-byline", + "rev-deleted-user", "pagetriage-byline-new-editor", "pagetriage-articleinfo-byline", + "pagetriage-articleinfo-byline-hidden-username", "pagetriage-articleinfo-byline-new-editor", "pipe-separator", "pagetriage-edits", @@ -390,6 +397,8 @@ "pagetriage-recreated", "pagetriage-no-author", "pagetriage-byline", + "pagetriage-byline-hidden-username", + "rev-deleted-user", "pagetriage-byline-new-editor", "pagetriage-editcount", "pagetriage-author-not-autoconfirmed", @@ -587,6 +596,7 @@ "pagetriage-no-author", "pagetriage-no-pages", "pagetriage-byline", + "pagetriage-byline-hidden-username", "pagetriage-byline-heading", "pagetriage-byline-new-editor", "pagetriage-byline-new-editor-heading", @@ -602,6 +612,7 @@ "pagetriage-unreviewed-article-count", "pagetriage-reviewed-article-count-past-week", "pagetriage-unreviewed-draft-count", + "rev-deleted-user", "pagetriage-sort-by", "pagetriage-newest", "pagetriage-oldest", diff --git a/i18n/en.json b/i18n/en.json index edfd73f8..263238f2 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -37,6 +37,7 @@ "pagetriage-byline-new-editor": "Created by new editor $1 ($2$3$4)", "pagetriage-byline-new-editor-heading": "Created by a {{GENDER:$1|new editor}}", "pagetriage-articleinfo-byline": "This page was created on $1 by $2 ($3$4$5)", + "pagetriage-articleinfo-byline-hidden-username": "This page was created on $1", "pagetriage-articleinfo-byline-new-editor": "This page was created on $1 by new editor $2 ($3$4$5)", "pagetriage-editcount": "$1 {{PLURAL:$1|edit|edits}} since $2", "pagetriage-author-not-autoconfirmed": "New editor", diff --git a/i18n/qqq.json b/i18n/qqq.json index 7e4b3415..2e02d690 100644 --- a/i18n/qqq.json +++ b/i18n/qqq.json @@ -57,6 +57,7 @@ "pagetriage-byline-new-editor": "Text indicating the page author (for when the author is a new editor). $1 is a link to the author's user page, $2 is a link to the author's talk page, $3 is a separator character, $4 is a link to the author's contributions.", "pagetriage-byline-new-editor-heading": "Text indicating the page author (for when the author is a new editor). Parameters:\n* $1 - the 'author's username, used for GENDER support.", "pagetriage-articleinfo-byline": "Text indicating the page author. $1 is the article creation date, $2 is a link to the author's user page, $3 is a link to the author's talk page, $4 is a separator character. $5 is a link to the author's contributions.", + "pagetriage-articleinfo-byline-hidden-username": "Text indicating that a article was created by a author whoes name has been removed in the article info section of the pagetriage toolbar. $1 is the article creation date", "pagetriage-articleinfo-byline-new-editor": "Text indicating the page author (for when the author is a new editor). Parameters:\n* $1 is the article creation date.\n* $2 is a link to the author's user page.\n* $3 is a link to the author's talk page.\n* $4 is a separator character\n* $5 is a link to the author's contributions.", "pagetriage-editcount": "Display of page author's editing experience. $1 is total edit count, $2 is author's join date", "pagetriage-author-not-autoconfirmed": "String indicating that the author was not yet autoconfirmed when the page was last edited", diff --git a/includes/Api/ApiPageTriageList.php b/includes/Api/ApiPageTriageList.php index a1e25ada..f6382cd1 100644 --- a/includes/Api/ApiPageTriageList.php +++ b/includes/Api/ApiPageTriageList.php @@ -3,12 +3,14 @@ namespace MediaWiki\Extension\PageTriage\Api; use ApiBase; +use ApiMain; use ApiResult; use MediaWiki\Extension\PageTriage\ArticleMetadata; use MediaWiki\Extension\PageTriage\OresMetadata; use MediaWiki\Extension\PageTriage\PageTriageUtil; use MediaWiki\Logger\LoggerFactory; use MediaWiki\Title\Title; +use MediaWiki\User\UserFactory; use ORES\Services\ORESServices; use SpecialPage; use Wikimedia\ParamValidator\ParamValidator; @@ -22,6 +24,18 @@ use Wikimedia\ParamValidator\TypeDef\IntegerDef; */ class ApiPageTriageList extends ApiBase { + /** @var UserFactory */ + private UserFactory $userFactory; + + /** + * @param ApiMain $query + * @param string $moduleName + */ + public function __construct( ApiMain $query, string $moduleName, UserFactory $userFactory ) { + $this->userFactory = $userFactory; + parent::__construct( $query, $moduleName ); + } + public function execute() { // Get the API parameters and store them $opts = $this->extractRequestParams(); @@ -72,12 +86,20 @@ class ApiPageTriageList extends ApiBase { $metaData[$page]['creation_date'] ); - // Page creator - $metaData[$page] += $this->createUserInfo( - $metaData[$page]['user_name'], - $userPageStatus, - 'creator' - ); + if ( $metaData[$page]['user_name'] ) { + // Page creator + $user = $this->userFactory->newFromName( $metaData[$page]['user_name'] ); + if ( $user && $user->isHidden() ) { + $metaData[$page]['user_name'] = null; + $metaData[$page]['creator_hidden'] = true; + } else { + $metaData[$page] += $this->createUserInfo( + $metaData[$page]['user_name'], + $userPageStatus, + 'creator' + ); + } + } // Page reviewer if ( $metaData[$page]['reviewer'] ) { @@ -103,7 +125,7 @@ class ApiPageTriageList extends ApiBase { } $metaData[$page][ApiResult::META_BC_BOOLS] = [ - 'creator_user_page_exist', 'creator_user_talk_page_exist', + 'creator_hidden', 'creator_user_page_exist', 'creator_user_talk_page_exist', 'reviewer_user_page_exist', 'reviewer_user_talk_page_exist', ]; @@ -219,6 +241,7 @@ class ApiPageTriageList extends ApiBase { $prefix . '_user_talk_page_exist' => isset( $userPageStatus[$userTalkPage->getPrefixedDBkey()] ), $prefix . '_contribution_page' => $userContribsPage->getPrefixedText(), $prefix . '_contribution_page_url' => $userContribsPage->getFullURL(), + $prefix . '_hidden' => false, ]; } diff --git a/includes/SpecialNewPagesFeed.php b/includes/SpecialNewPagesFeed.php index 33dcdcda..2684208f 100644 --- a/includes/SpecialNewPagesFeed.php +++ b/includes/SpecialNewPagesFeed.php @@ -56,6 +56,8 @@ class SpecialNewPagesFeed extends SpecialPage { // Output the title of the page $out->setPageTitle( $this->msg( 'newpagesfeed' ) ); + // Load common interface css ++ $out->addModuleStyles( [ 'mediawiki.interface.helpers.styles' ] ); // Allow infinite scrolling override from query string parameter // We don't use getBool() here since the param is optional diff --git a/modules/ext.pageTriage.list/components/ListContent.vue b/modules/ext.pageTriage.list/components/ListContent.vue index 7385fff3..d79d2ae7 100644 --- a/modules/ext.pageTriage.list/components/ListContent.vue +++ b/modules/ext.pageTriage.list/components/ListContent.vue @@ -58,6 +58,7 @@ const listItemPropFormatter = ( pageInfo ) => { listItemProps.revCount = parseInt( pageInfo.rev_count ); listItemProps.creationDateUTC = pageInfo.creation_date_utc; listItemProps.creatorName = pageInfo.user_name; + listItemProps.creatorHidden = pageInfo.creator_hidden; listItemProps.creatorAutoConfirmed = pageInfo.user_autoconfirmed === '1'; listItemProps.creatorRegistrationUTC = pageInfo.user_creation_date; listItemProps.creatorUserId = parseInt( pageInfo.user_id ); diff --git a/modules/ext.pageTriage.list/components/ListItem.vue b/modules/ext.pageTriage.list/components/ListItem.vue index 2a42cd54..df895f1b 100644 --- a/modules/ext.pageTriage.list/components/ListItem.vue +++ b/modules/ext.pageTriage.list/components/ListItem.vue @@ -58,9 +58,15 @@
- + + + {{ $i18n( 'rev-deleted-user' ).text() }} + +
<% if ( typeof( user_name ) !== "undefined" ) { %> - <%= author_byline_html %> + <% if ( !creator_hidden ) { %> + <%= author_byline_html %> + <% } else { %> + + <%= author_byline_html %> + + <% } %> <% if ( typeof ( user_id ) != 'undefined' && Number( user_id ) !== 0 ) { %> · diff --git a/modules/ext.pageTriage.views.toolbar/ToolView.js b/modules/ext.pageTriage.views.toolbar/ToolView.js index 74a96746..f2544fec 100644 --- a/modules/ext.pageTriage.views.toolbar/ToolView.js +++ b/modules/ext.pageTriage.views.toolbar/ToolView.js @@ -267,6 +267,7 @@ module.exports = Backbone.View.extend( { pageid: mw.config.get( 'wgArticleId' ), title: mw.config.get( 'wgPageName' ), creator: this.model.get( 'user_name' ), + creatorHidden: this.model.get( 'creator_hidden' ), reviewed: reviewed }, data ); }, diff --git a/modules/ext.pageTriage.views.toolbar/articleInfo.js b/modules/ext.pageTriage.views.toolbar/articleInfo.js index 9b9ef2af..28eef292 100644 --- a/modules/ext.pageTriage.views.toolbar/articleInfo.js +++ b/modules/ext.pageTriage.views.toolbar/articleInfo.js @@ -109,6 +109,8 @@ module.exports = ToolView.extend( { url.toString() ); + const offset = parseInt( mw.user.options.get( 'timecorrection' ).split( '|' )[ 1 ] ); + // creator information if ( this.model.get( 'user_name' ) ) { // show new editor message only if the user is not anonymous and not autoconfirmed @@ -119,7 +121,6 @@ module.exports = ToolView.extend( { bylineMessage = 'pagetriage-articleinfo-byline'; } - const offset = parseInt( mw.user.options.get( 'timecorrection' ).split( '|' )[ 1 ] ); // put it all together in the byline // The following messages are used here: // * pagetriage-articleinfo-byline-new-editor @@ -150,6 +151,13 @@ module.exports = ToolView.extend( { ) ).parse(); this.model.set( 'articleByline_html', articleByline ); + } else if ( this.model.get( 'creator_hidden' ) ) { + this.model.set( 'articleByline_html', mw.msg( 'pagetriage-articleinfo-byline-hidden-username', moment.utc( + this.model.get( 'creation_date_utc' ), + 'YYYYMMDDHHmmss' + ).utcOffset( offset ).format( + mw.msg( 'pagetriage-info-timestamp-date-format' ) + ), mw.msg( 'rev-deleted-user' ) ) ); } const stats = [ diff --git a/modules/ext.pageTriage.views.toolbar/articleInfo.underscore b/modules/ext.pageTriage.views.toolbar/articleInfo.underscore index 9a7ce587..4d9a00ec 100644 --- a/modules/ext.pageTriage.views.toolbar/articleInfo.underscore +++ b/modules/ext.pageTriage.views.toolbar/articleInfo.underscore @@ -23,7 +23,11 @@ <% if( typeof( user_name ) != 'undefined' ) { %> - <%= articleByline_html %> + <% if ( !creator_hidden ) { %> + <%= articleByline_html %> + <% } else { %> + <%= articleByline_html %> + <% } %>
<% if( typeof user_id != 'undefined' && Number( user_id ) !== 0 ) { %> diff --git a/modules/ext.pageTriage.views.toolbar/mark.js b/modules/ext.pageTriage.views.toolbar/mark.js index 4d347924..ea221f07 100644 --- a/modules/ext.pageTriage.views.toolbar/mark.js +++ b/modules/ext.pageTriage.views.toolbar/mark.js @@ -221,6 +221,7 @@ module.exports = ToolView.extend( { status = this.model.get( 'patrol_status' ) === '0' ? 'reviewed' : 'unreviewed', hasPreviousReviewer = this.model.get( 'ptrp_last_reviewed_by' ) > 0, articleCreator = this.model.get( 'user_name' ), + articleCreatorHidden = this.model.get( 'creator_hidden' ), previousReviewer = hasPreviousReviewer ? this.model.get( 'reviewer' ) : ''; let noteTarget = articleCreator, notePlaceholder = 'pagetriage-message-for-creator-default-note', @@ -239,7 +240,7 @@ module.exports = ToolView.extend( { notePlaceholder = 'pagetriage-message-for-creator-default-note'; } - if ( mw.config.get( 'wgUserName' ) === articleCreator ) { + if ( mw.config.get( 'wgUserName' ) === articleCreator || articleCreatorHidden ) { numRecipients--; noteTarget = previousReviewer; noteRecipientRole = 'reviewer'; diff --git a/modules/ext.pageTriage.views.toolbar/tags.js b/modules/ext.pageTriage.views.toolbar/tags.js index 45ebfc61..b1d9a896 100644 --- a/modules/ext.pageTriage.views.toolbar/tags.js +++ b/modules/ext.pageTriage.views.toolbar/tags.js @@ -308,7 +308,7 @@ module.exports = ToolView.extend( { if ( this.selectedTagCount > 0 ) { $( '#mwe-pt-tag-submit-button' ).button( 'enable' ); $( '#mwe-pt-checkbox-mark-reviewed-wrapper' ).show(); - if ( mw.config.get( 'wgUserName' ) !== this.model.get( 'user_name' ) ) { + if ( mw.config.get( 'wgUserName' ) !== this.model.get( 'user_name' ) && !this.model.get( 'creator_hidden' ) ) { $( '#mwe-pt-tag-note' ).show(); } } else { diff --git a/modules/ext.pageTriage.views.toolbar/wikiLove.js b/modules/ext.pageTriage.views.toolbar/wikiLove.js index f493b069..22fe7d0a 100644 --- a/modules/ext.pageTriage.views.toolbar/wikiLove.js +++ b/modules/ext.pageTriage.views.toolbar/wikiLove.js @@ -26,11 +26,14 @@ module.exports = ToolView.extend( { render: function () { // get the article's creator const creator = this.model.get( 'user_name' ); + const creatorHidden = this.model.get( 'creator_hidden' ); // get the last 20 editors of the article const contributorArray = []; this.model.revisions.each( function ( revision ) { - contributorArray.push( revision.get( 'user' ) ); + if ( typeof ( revision.get( 'userhidden' ) ) === 'undefined' ) { + contributorArray.push( revision.get( 'user' ) ); + } } ); // count how many times each editor edited the article @@ -54,7 +57,7 @@ module.exports = ToolView.extend( { // set the Learn More link URL $( '#mwe-pt-wikilove .mwe-pt-flyout-help-link' ).attr( 'href', this.moduleConfig.helplink ); - if ( mw.user.getName() !== creator ) { + if ( mw.user.getName() !== creator && !creatorHidden ) { // add the creator info to the top of the list $( '#mwe-pt-article-contributor-list' ).append( '' + -- 2.42.0