From 91869f5708fde9ce490f6bd3db60bff5bed0533a Mon Sep 17 00:00:00 2001 From: Ed Sanders Date: Thu, 9 Mar 2023 14:18:07 +0000 Subject: [PATCH] Add notification type for user page edits Creates a notification type to notify users when their user page is edited. Co-authored-by: Kunal Mehta Co-authored-by: Ed Sanders Bug: T3876 Change-Id: Ibe0092a96d96f6fa9d93991418b723f3e70e1b75 --- extension.json | 22 +++++ i18n/en.json | 6 ++ i18n/qqq.json | 6 ++ includes/DiscussionParser.php | 14 +++ .../EchoEditUserPagePresentationModel.php | 97 +++++++++++++++++++ includes/Hooks.php | 16 ++- includes/UserLocator.php | 21 ++++ modules/icons/edit-user-page.svg | 8 ++ 8 files changed, 186 insertions(+), 4 deletions(-) create mode 100644 includes/Formatters/EchoEditUserPagePresentationModel.php create mode 100644 modules/icons/edit-user-page.svg diff --git a/extension.json b/extension.json index 406345c93..3a813e448 100644 --- a/extension.json +++ b/extension.json @@ -652,6 +652,10 @@ "all" ] }, + "edit-user-page": { + "priority": 4, + "tooltip": "echo-pref-tooltip-edit-user-page" + }, "edit-user-talk": { "priority": 1, "no-dismiss": [ @@ -722,6 +726,9 @@ "edit": { "path": "Echo/modules/icons/edit-progressive.svg" }, + "edit-user-page": { + "path": "Echo/modules/icons/edit-user-page.svg" + }, "edit-user-talk": { "path": "Echo/modules/icons/edit-user-talk-progressive.svg" }, @@ -805,6 +812,21 @@ "section": "message", "presentation-model": "MediaWiki\\Extension\\Notifications\\Formatters\\EchoWelcomePresentationModel" }, + "edit-user-page": { + "presentation-model": "MediaWiki\\Extension\\Notifications\\Formatters\\EchoEditUserPagePresentationModel", + "user-locators": [ + "EchoUserLocator::locateUserPageOwner" + ], + "category": "edit-user-page", + "group": "interactive", + "section": "alert", + "bundle": { + "web": true, + "email": false, + "expandable": true + }, + "immediate": true + }, "edit-user-talk": { "presentation-model": "MediaWiki\\Extension\\Notifications\\Formatters\\EchoEditUserTalkPresentationModel", "user-locators": [ diff --git a/i18n/en.json b/i18n/en.json index 3b1861b76..f71962cda 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -67,6 +67,7 @@ "echo-log": "Public log", "echo-new-messages": "You have a new Talk page message", "echo-category-title-edit-user-talk": "{{PLURAL:$1|Edit|Edits}} to my user talk page", + "echo-category-title-edit-user-page": "{{PLURAL:$1|Edit|Edits}} to my user page", "echo-category-title-article-linked": "Page {{PLURAL:$1|link|links}}", "echo-category-title-reverted": "Edit {{PLURAL:$1|revert|reverts}}", "echo-category-title-mention": "{{PLURAL:$1|Mention|Mentions}}", @@ -83,6 +84,7 @@ "echo-category-title-watchlist": "Edit to watched page", "echo-category-title-minor-watchlist": "Minor edit to watched page", "echo-pref-tooltip-edit-user-talk": "Notify me when someone edits my user talk page.", + "echo-pref-tooltip-edit-user-page": "Notify me when someone edits my user page.", "echo-pref-tooltip-article-linked": "Notify me when someone links to a page I created from another page.", "echo-pref-tooltip-reverted": "Notify me when someone reverts an edit I made, by using the undo or rollback tool.", "echo-pref-tooltip-mention": "Notify me when someone links to my user page.", @@ -153,8 +155,10 @@ "notification-link-text-view-mention-failure": "{{PLURAL:$1|View mention|View mentions}}", "notification-link-text-view-changes": "{{GENDER:$1|View}} changes", "notification-link-text-view-page": "View page", + "notification-header-edit-user-page": "$1 {{GENDER:$2|edited}} {{GENDER:$3|your}} user page.", "notification-header-edit-user-talk": "$1 {{GENDER:$2|left}} a message on {{GENDER:$3|your}} talk page.", "notification-header-edit-user-talk-with-section": "$1 {{GENDER:$2|left}} a message on {{GENDER:$3|your}} talk page in \"$4\".", + "notification-compact-header-edit-user-page": "$1 {{GENDER:$2|edited}} {{GENDER:$3|your}} user page.", "notification-compact-header-edit-user-talk": "$1 {{GENDER:$2|left}} {{GENDER:$3|you}} a message.", "notification-compact-header-edit-user-talk-with-section": "$1 {{GENDER:$2|left}} {{GENDER:$3|you}} a message in \"$4\".", "notification-body-edit-user-talk-with-section": "$1", @@ -216,6 +220,7 @@ "notification-body-reverted": "$1", "notification-header-emailuser": "$1 {{GENDER:$2|sent}} you an email.", "notification-body-emailuser": "$1", + "notification-edit-user-page-email-subject": "$1 {{GENDER:$2|edited}} {{GENDER:$3|your}} user page on {{SITENAME}}", "notification-edit-talk-page-email-subject2": "$1 {{GENDER:$2|left}} {{GENDER:$3|you}} a message on {{SITENAME}}", "notification-page-linked-email-subject": "A page {{GENDER:$3|you}} created was linked on {{SITENAME}}", "notification-reverted-email-subject2": "{{GENDER:$3|Your}} {{PLURAL:$4|edit was|edits were}} {{GENDER:$2|reverted}} on {{SITENAME}}", @@ -248,6 +253,7 @@ "echo-displaysnippet-title": "New notification", "echo-date-today": "Today", "echo-date-yesterday": "Yesterday", + "notification-bundle-header-edit-user-page": "{{PLURAL:$1|One new edit|$1 new edits|100=99+ new edits}} to {{GENDER:$2|your}} user page.", "notification-bundle-header-edit-user-talk-v2": "{{PLURAL:$1|One new message|$1 new messages|100=99+ new messages}} on {{GENDER:$3|your}} talk page.", "echo-email-batch-bullet": "•", "echo-email-batch-subject-daily": "You have {{PLURAL:$2|a new notification|new notifications}} at {{SITENAME}}", diff --git a/i18n/qqq.json b/i18n/qqq.json index 7756b334f..75d65e25a 100644 --- a/i18n/qqq.json +++ b/i18n/qqq.json @@ -71,6 +71,7 @@ "echo-log": "Text for link to go to Special:Log", "echo-new-messages": "Message to let the user know that they have new talk page messages, displayed in the personal menu (top-right corner on Vector and Monobook).\n\nKeep this message short. It '''should not''' end in a full stop.", "echo-category-title-edit-user-talk": "'''When translating, please emphasize the distinction between “my user talk page” and “other talk pages”, to avoid confusion with {{msg-mw|echo-category-title-dt-subscription}}.'''\n\n{{doc-echo-category-title|tooltip=Echo-pref-tooltip-edit-user-talk}}", + "echo-category-title-edit-user-page": "{{doc-echo-category-title|tooltip=Echo-pref-tooltip-edit-user-page}}", "echo-category-title-article-linked": "{{doc-echo-category-title|tooltip=Echo-pref-tooltip-article-linked}}", "echo-category-title-reverted": "{{doc-echo-category-title|tooltip=Echo-pref-tooltip-reverted}}", "echo-category-title-mention": "{{doc-echo-category-title|tooltip=Echo-pref-tooltip-mention}}\n{{Identical|Mention}}", @@ -87,6 +88,7 @@ "echo-category-title-watchlist": "{{doc-echo-category-title|tooltip=Echo-pref-tooltip-watchlist}}", "echo-category-title-minor-watchlist": "{{doc-echo-category-title|tooltip=Echo-pref-tooltip-minor-watchlist}}", "echo-pref-tooltip-edit-user-talk": "{{doc-echo-pref-tooltip|title=Echo-category-title-edit-user-talk}}", + "echo-pref-tooltip-edit-user-page": "{{doc-echo-pref-tooltip|title=Echo-category-title-edit-user-page}}", "echo-pref-tooltip-article-linked": "{{doc-echo-pref-tooltip|title=Echo-category-title-article-linked}}", "echo-pref-tooltip-reverted": "{{doc-echo-pref-tooltip|title=Echo-category-title-reverted}}", "echo-pref-tooltip-mention": "{{doc-echo-pref-tooltip|title=Echo-category-title-mention}}", @@ -157,8 +159,10 @@ "notification-link-text-view-mention-failure": "Label for button that links to a discussion where your mentions failed.\n* $1 - The number of failed mentions; uses standard number formatting and used for PLURAL", "notification-link-text-view-changes": "Label for button that links to a \"diff\" view showing changes made to a page. Parameters:\n* $1 - name of the user viewing the notification, can be used for GENDER.\n{{Identical|View changes}}", "notification-link-text-view-page": "Label for button that links to a page.\n{{Identical|View page}}", + "notification-header-edit-user-page": "Notification header of a user page being edited.\n\nParameters:\n* $1 - the formatted username of the person who edited.\n* $2 - the username for GENDER\n* $3 - username of the current user, can be used for GENDER", "notification-header-edit-user-talk": "Flyout-specific format for displaying notification header of a user talk page being edited.\n\nParameters:\n* $1 - the formatted username of the person who edited.\n* $2 - the username for GENDER\n* $3 - username of the current user, can be used for GENDER", "notification-header-edit-user-talk-with-section": "Flyout-specific format for displaying notification header of a user talk page being edited with a new section or new comment.\n\nParameters:\n* $1 - the formatted username of the person who edited.\n* $2 - the username for GENDER\n* $3 - username of the current user, can be used for GENDER\n* $4 - the raw section title text", + "notification-compact-header-edit-user-page": "Flyout-specific format for displaying compact notification header of a user page being edited.\n\nParameters:\n* $1 - the formatted username of the person who edited.\n* $2 - the username for GENDER\n* $3 - username of the current user, can be used for GENDER", "notification-compact-header-edit-user-talk": "Flyout-specific format for displaying compact notification header of a user talk page being edited.\n\nParameters:\n* $1 - the formatted username of the person who edited.\n* $2 - the username for GENDER\n* $3 - username of the current user, can be used for GENDER", "notification-compact-header-edit-user-talk-with-section": "Flyout-specific format for displaying compact notification header of a user talk page being edited with a new section or new comment.\n\nParameters:\n* $1 - the formatted username of the person who edited.\n* $2 - the username for GENDER\n* $3 - username of the current user, can be used for GENDER\n* $4 - the raw section title text", "notification-body-edit-user-talk-with-section": "{{optional}}\nFlyout-specific format for displaying notification body of a user talk page being edited with a new section or new comment.\n\nParameters:\n* $1 - comment left on the user talk page.", @@ -220,6 +224,7 @@ "notification-body-reverted": "{{notranslate}}", "notification-header-emailuser": "Flyout-specific format for displaying notifications of user has sent an email to another user.\n\nParameters:\n* $1 - the formatted username of the person who sent the email.\n* $2 - the username for GENDER.", "notification-body-emailuser": "{{notranslate}}", + "notification-edit-user-page-email-subject": "Email subject. Parameters:\n* $1 - the formatted username of the person who edited (not suitable for GENDER).\n* $2 - the username for GENDER.\n* $3 - username of the current user, can be used for GENDER.", "notification-edit-talk-page-email-subject2": "Email subject. Parameters:\n* $1 - the formatted username of the person who edited (not suitable for GENDER).\n* $2 - the username for GENDER.\n* $3 - username of the current user, can be used for GENDER.", "notification-page-linked-email-subject": "E-mail subject Parameters:\n* $1 - the formatted username of the person who edited (not suitable for GENDER).\n* $2 - the username for GENDER.\n* $3 - username of the current user, can be used for GENDER.", "notification-reverted-email-subject2": "Email subject. Parameters:\n* $1 - the formatted username of the person who reverted the edit (not suitable for GENDER).\n* $2 - the username for GENDER.\n* $3 - username of the current user, can be used for GENDER.\n* $4 - the number of reverts\n{{Related|Notification-reverted}}", @@ -252,6 +257,7 @@ "echo-displaysnippet-title": "The header text for notification snippets displayed in a corner of the screen when the user receives a new notification", "echo-date-today": "The header text for today's notification section.\n{{Identical|Today}}", "echo-date-yesterday": "The header text for yesterday's notification section.\n{{Identical|Yesterday}}", + "notification-bundle-header-edit-user-page": "Bundled header message for edit-user-page notification. Parameters:\n* $1 - the number of new messages, except that if the count is greater than 99, this value will be 100; uses standard number formatting and used for PLURAL\n* $2 - Unused\n* $3 - the name of the user being addressed, can be used for GENDER\n{{Related|Notification-bundle}}", "notification-bundle-header-edit-user-talk-v2": "Bundled header message for edit-user-talk notification. Parameters:\n* $1 - the number of new messages, except that if the count is greater than 99, this value will be 100; uses standard number formatting and used for PLURAL\n* $2 - Unused\n* $3 - the name of the user being addressed, can be used for GENDER\n{{Related|Notification-bundle}}", "echo-email-batch-bullet": "{{optional}}", "echo-email-batch-subject-daily": "Daily email batch subject.\n* $1 - (Unused, Compatibility) Same as $2. \n* $2 - a numeric count, this is used for plural support\nSee also:\n* {{msg-mw|Echo-email-batch-subject-weekly}}", diff --git a/includes/DiscussionParser.php b/includes/DiscussionParser.php index 4418f1d17..7ba218651 100644 --- a/includes/DiscussionParser.php +++ b/includes/DiscussionParser.php @@ -122,6 +122,20 @@ abstract class EchoDiscussionParser { ]; } } + } elseif ( $title->inNamespace( NS_USER ) ) { + $notifyUser = User::newFromName( $title->getText() ); + // If the recipient is a valid non-anonymous user and hasn't turned + // off their notifications, generate a talk page post Echo notification. + if ( $notifyUser && $notifyUser->getId() ) { + $events[] = [ + 'type' => 'edit-user-page', + 'title' => $title, + 'extra' => [ + 'revid' => $revision->getId(), + ], + 'agent' => $user, + ]; + } } // Notify users mentioned in edit summary diff --git a/includes/Formatters/EchoEditUserPagePresentationModel.php b/includes/Formatters/EchoEditUserPagePresentationModel.php new file mode 100644 index 000000000..ddffd602d --- /dev/null +++ b/includes/Formatters/EchoEditUserPagePresentationModel.php @@ -0,0 +1,97 @@ +event->getTitle(); + } + + public function getIconType() { + return 'edit-user-page'; + } + + public function getPrimaryLink() { + return [ + 'url' => $this->getDiffLinkUrl(), + 'label' => $this->msg( 'notification-link-text-view-edit' )->text() + ]; + } + + public function getSecondaryLinks() { + if ( $this->isBundled() ) { + return []; + } else { + return [ $this->getAgentLink() ]; + } + } + + public function getHeaderMessage() { + if ( $this->isBundled() ) { + $msg = $this->msg( 'notification-bundle-header-edit-user-page' ); + $count = $this->getNotificationCountForOutput(); + + $msg->numParams( $count ); + $msg->params( $this->getViewingUserForGender() ); + return $msg; + } else { + $msg = parent::getHeaderMessage(); + $msg->params( $this->getViewingUserForGender() ); + return $msg; + } + } + + public function getCompactHeaderMessage() { + $msg = $this->getMessageWithAgent( 'notification-compact-header-edit-user-page' ); + $msg->params( $this->getViewingUserForGender() ); + return $msg; + } + + public function getBodyMessage() { + $revision = $this->event->getRevision(); + if ( $revision && $revision->getComment() && $this->userCan( RevisionRecord::DELETED_COMMENT ) ) { + $summary = $revision->getComment()->text; + $summary = Linker::formatComment( $summary ); + $summary = Sanitizer::stripAllTags( $summary ); + } else { + $summary = false; + } + if ( !$this->isBundled() ) { + return new RawMessage( '$1', [ Message::plaintextParam( $summary ) ] ); + } + return false; + } + + private function getDiffLinkUrl() { + $revId = $this->event->getExtraParam( 'revid' ); + $oldId = $this->isBundled() ? $this->getRevBeforeFirstNotification() : 'prev'; + $query = [ + 'oldid' => $oldId, + 'diff' => $revId, + ]; + return $this->event->getTitle()->getFullURL( $query ); + } + + private function getRevBeforeFirstNotification() { + $events = $this->getBundledEvents(); + $firstNotificationRevId = end( $events )->getExtraParam( 'revid' ); + $revisionLookup = MediaWikiServices::getInstance()->getRevisionLookup(); + $revisionRecord = $revisionLookup->getRevisionById( $firstNotificationRevId ); + $previousRevision = $revisionRecord ? $revisionLookup->getPreviousRevision( $revisionRecord ) : null; + $oldRevisionID = $previousRevision ? $previousRevision->getId() : 0; + + return $oldRevisionID; + } + + protected function getSubjectMessageKey() { + return 'notification-edit-user-page-email-subject'; + } +} diff --git a/includes/Hooks.php b/includes/Hooks.php index 011a0d0e0..53234b694 100644 --- a/includes/Hooks.php +++ b/includes/Hooks.php @@ -367,6 +367,7 @@ class Hooks implements */ public static function onEchoGetBundleRules( $event, &$bundleString ) { switch ( $event->getType() ) { + case 'edit-user-page': case 'edit-user-talk': case 'page-linked': $bundleString = $event->getType(); @@ -1294,12 +1295,19 @@ class Hooks implements // Let echo handle watchlist notifications entirely return false; } - // If a user is watching his/her own talk page, do not send talk page watchlist - // email notification if the user is receiving Echo talk page notification - if ( $title->isTalkPage() && $targetUser->getTalkPage()->equals( $title ) ) { + $eventName = false; + // The edit-user-talk and edit-user-page events effectively duplicate watchlist notifications. + // If we are sending Echo notification emails, suppress the watchlist notifications. + if ( $title->inNamespace( NS_USER_TALK ) && $targetUser->getTalkPage()->equals( $title ) ) { + $eventName = 'edit-user-talk'; + } elseif ( $title->inNamespace( NS_USER ) && $targetUser->getUserPage()->equals( $title ) ) { + $eventName = 'edit-user-page'; + } + + if ( $eventName !== false ) { $attributeManager = EchoServices::getInstance()->getAttributeManager(); $events = $attributeManager->getUserEnabledEvents( $targetUser, 'email' ); - if ( in_array( 'edit-user-talk', $events ) ) { + if ( in_array( $eventName, $events ) ) { // Do not send watchlist email notification, the user will receive an Echo notification return false; } diff --git a/includes/UserLocator.php b/includes/UserLocator.php index 9f39b75b6..4a3be8029 100644 --- a/includes/UserLocator.php +++ b/includes/UserLocator.php @@ -65,6 +65,27 @@ class EchoUserLocator { return []; } + /** + * If the event occurred on the user page of a registered + * user return that user. + * + * @param EchoEvent $event + * @return User[] + */ + public static function locateUserPageOwner( EchoEvent $event ) { + $title = $event->getTitle(); + if ( !$title || !$title->inNamespace( NS_USER ) ) { + return []; + } + + $user = User::newFromName( $title->getDBkey() ); + if ( $user && $user->isRegistered() ) { + return [ $user->getId() => $user ]; + } + + return []; + } + /** * Return the event agent * diff --git a/modules/icons/edit-user-page.svg b/modules/icons/edit-user-page.svg new file mode 100644 index 000000000..216ebf539 --- /dev/null +++ b/modules/icons/edit-user-page.svg @@ -0,0 +1,8 @@ + + + + edit user page + + + +