From 5db52c791b42a5dda97ae9b938ae89ea93b4b978 Mon Sep 17 00:00:00 2001
From: Sohom <sohomdatta1+git@gmail.com>
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                                |  7 ++++++
 i18n/en.json                                  |  2 ++
 i18n/qqq.json                                 |  2 ++
 includes/Api/ApiPageTriageList.php            | 25 +++++++++++++------
 .../components/ListContent.vue                |  1 +
 .../components/ListItem.vue                   | 15 ++++++++++-
 .../models/ext.pageTriage.article.js          | 12 ++++++++-
 .../ext.pageTriage.listItem.css               |  5 ++++
 .../articleInfo.js                            | 15 ++++++++++-
 9 files changed, 74 insertions(+), 10 deletions(-)

diff --git a/extension.json b/extension.json
index 477d637a..a21bbe28 100644
--- a/extension.json
+++ b/extension.json
@@ -240,8 +240,11 @@
 				"pagetriage-mark-as-unreviewed",
 				"pagetriage-info-title",
 				"pagetriage-byline",
+				"rev-deleted-user",
+				"pagetriage-byline-hidden-username",
 				"pagetriage-byline-new-editor",
 				"pagetriage-articleinfo-byline",
+				"pagetriage-articleinfo-byline-hidden-username",
 				"pagetriage-articleinfo-byline-new-editor",
 				"pipe-separator",
 				"pagetriage-edits",
@@ -391,6 +394,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 +592,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 +608,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..0c0e44d3 100644
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -34,9 +34,11 @@
 	"pagetriage-no-author": "No author information present",
 	"pagetriage-byline": "Created by $1 ($2$3$4)",
 	"pagetriage-byline-heading": "Created by {{GENDER:$1}}",
+	"pagetriage-byline-hidden-username": "Created by ",
 	"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 by ",
 	"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 f8902fec..f64e32d3 100644
--- a/i18n/qqq.json
+++ b/i18n/qqq.json
@@ -53,10 +53,12 @@
 	"pagetriage-recreated": "Label indicating a page was previously deleted.",
 	"pagetriage-no-author": "Error message for missing page author information",
 	"pagetriage-byline": "Text indicating the page author.\n*$1 is a link to the author's user page.\n*$2 is a link to the author's talk page.\n*$3 is a separator character.\n*$4 is a link to the author's contributions.",
+	"pagetriage-byline-hidden-username": "Text indicating that a article was created by a author whoes name has been removed. This message is immediately followed by rev-deleted-user.",
 	"pagetriage-byline-heading": "Text indicating the page author. Parameters:\n* $1 - the author's username, used for GENDER support.",
 	"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. This message is immediately followed by rev-deleted-user.",
 	"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..8cd66547 100644
--- a/includes/Api/ApiPageTriageList.php
+++ b/includes/Api/ApiPageTriageList.php
@@ -7,6 +7,7 @@ use ApiResult;
 use MediaWiki\Extension\PageTriage\ArticleMetadata;
 use MediaWiki\Extension\PageTriage\OresMetadata;
 use MediaWiki\Extension\PageTriage\PageTriageUtil;
+use MediaWiki\MediaWikiServices;
 use MediaWiki\Logger\LoggerFactory;
 use MediaWiki\Title\Title;
 use ORES\Services\ORESServices;
@@ -27,6 +28,8 @@ class ApiPageTriageList extends ApiBase {
 		$opts = $this->extractRequestParams();
 		$pages = null;
 
+		$userFactory = MediaWikiServices::getInstance()->getUserFactory();
+
 		if ( $opts['page_id'] ) {
 			// page id was specified
 			$pages = [ $opts['page_id'] ];
@@ -72,12 +75,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 = $userFactory->newFromName( $metaData[$page]['user_name'] );
+					if ( $user && !$user->isHidden() ) {
+						$metaData[$page] += $this->createUserInfo(
+							$metaData[$page]['user_name'],
+							$userPageStatus,
+							'creator'
+						);
+					} else {
+						$metaData[$page]['user_name'] = null;
+						$metaData[$page]['user_hidden'] = true;
+					}
+				}
 
 				// Page reviewer
 				if ( $metaData[$page]['reviewer'] ) {
@@ -103,7 +114,7 @@ class ApiPageTriageList extends ApiBase {
 				}
 
 				$metaData[$page][ApiResult::META_BC_BOOLS] = [
-					'creator_user_page_exist', 'creator_user_talk_page_exist',
+					'user_hidden', 'creator_user_page_exist', 'creator_user_talk_page_exist',
 					'reviewer_user_page_exist', 'reviewer_user_talk_page_exist',
 				];
 
diff --git a/modules/ext.pageTriage.list/components/ListContent.vue b/modules/ext.pageTriage.list/components/ListContent.vue
index c20b7f13..b97a0192 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.user_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 50e317e1..048f61ce 100644
--- a/modules/ext.pageTriage.list/components/ListItem.vue
+++ b/modules/ext.pageTriage.list/components/ListItem.vue
@@ -58,14 +58,22 @@
 			</div>
 			<div class="mwe-vue-pt-info-row">
 				<div>
-					<span v-if="creatorName">
+					<span v-if="creatorName || creatorHidden">
 						<creator-byline
+							v-if="creatorName"
 							:creator-name="creatorName"
+							:creator-hidden="creatorHidden"
 							:creator-user-id="creatorUserId"
 							:creator-auto-confirmed="creatorAutoConfirmed"
 							:creator-user-page-exists="creatorUserPageExists"
 							:creator-talk-page-exists="creatorTalkPageExists"
 						></creator-byline>
+						<template v-else>
+							{{ $i18n( 'pagetriage-byline-hidden-username' ) }}
+							<span class="mwe-pt-history-suppressed">
+								{{ $i18n( 'rev-deleted-user' ) }}
+							</span>
+						</template>
 						<span v-if="creatorUserId > 0">
 							{{ $i18n( 'pagetriage-dot-separator' ).text() }}
 							{{ $i18n( 'pagetriage-editcount', creatorEditCount, creatorRegistrationPretty ).text() }}
@@ -185,6 +193,7 @@ module.exports = {
          */
 		// Creator information tags
 		creatorUserId: { type: Number, required: true },
+		creatorHidden: { type: Boolean, required: true },
 		creatorName: { type: String, required: true },
 		creatorEditCount: { type: Number, required: true },
 		creatorRegistrationUTC: {
@@ -433,4 +442,8 @@ module.exports = {
 .ores-pt-issues {
 	height: 0.55em;
 }
+.mwe-pt-history-suppressed {
+	text-decoration-line: line-through;
+	text-decoration-style: double;
+}
 </style>
diff --git a/modules/ext.pageTriage.util/models/ext.pageTriage.article.js b/modules/ext.pageTriage.util/models/ext.pageTriage.article.js
index 4bb28dfc..67172b2f 100644
--- a/modules/ext.pageTriage.util/models/ext.pageTriage.article.js
+++ b/modules/ext.pageTriage.util/models/ext.pageTriage.article.js
@@ -106,7 +106,17 @@ const Article = Backbone.Model.extend( {
 					article.get( 'creator_user_page_exist' )
 				)
 			);
-			article.set( 'user_contribs_title', article.get( 'creator_contribution_page' ) );
+		} else if ( article.get( 'user_hidden' ) ) {
+			const usernameRemoved = $( '<span>' )
+				.addClass( 'mwe-pt-history-suppressed' )
+				.text( mw.msg( 'rev-deleted-user' ) )
+				.prop( 'outerHTML' );
+
+			article.set( 'author_byline_html', mw.msg( 'pagetriage-byline-hidden-username' ) + usernameRemoved );
+			article.set(
+				'user_title_url',
+				mw.msg( 'rev-deleted-user' )
+			);
 		}
 
 		// Are there any PageTriage messages on the talk page?
diff --git a/modules/ext.pageTriage.views.list/ext.pageTriage.listItem.css b/modules/ext.pageTriage.views.list/ext.pageTriage.listItem.css
index 4d8f89e5..5016727f 100644
--- a/modules/ext.pageTriage.views.list/ext.pageTriage.listItem.css
+++ b/modules/ext.pageTriage.views.list/ext.pageTriage.listItem.css
@@ -123,6 +123,11 @@
 	display: table-cell;
 }
 
+.mwe-pt-history-suppressed {
+	text-decoration-line: line-through;
+	text-decoration-style: double;
+}
+
 .mwe-pt-potential-issues {
 	display: table-cell;
 	text-align: right;
diff --git a/modules/ext.pageTriage.views.toolbar/articleInfo.js b/modules/ext.pageTriage.views.toolbar/articleInfo.js
index bc1c2c7a..60c1f8ac 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,18 @@ module.exports = ToolView.extend( {
 				)
 			).parse();
 			this.model.set( 'articleByline_html', articleByline );
+		} else if ( this.model.get( 'user_hidden' ) ) {
+			const usernameRemoved = $( '<span>' )
+				.addClass( 'mwe-pt-history-suppressed' )
+				.text( mw.msg( 'rev-deleted-user' ) )
+				.prop( 'outerHTML' );
+
+			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' )
+			) ) + usernameRemoved );
 		}
 
 		const stats = [
-- 
2.41.0

