Cleanup old notification formatting system

* Deprecated main entry-points
* Removed unused configuration
* Removed old formatters for Echo events (mention, edit-user-talk, etc)
* Removed unused messages

Bug: T121612
Change-Id: I639b9d9906d3ff37021cb9b5ed3cb401354b5bd9
This commit is contained in:
Stephane Bisson 2016-06-29 16:23:56 -04:00 committed by Sbisson
parent be3cca488d
commit 2f0ff9cbf6
17 changed files with 24 additions and 2632 deletions

View file

@ -374,33 +374,16 @@ $wgEchoNotifications = array(
'email' => false,
),
'presentation-model' => 'EchoWelcomePresentationModel',
'title-message' => 'notification-new-user',
'title-params' => array( 'agent' ),
'icon' => 'site',
),
'edit-user-talk' => array(
'presentation-model' => 'EchoEditUserTalkPresentationModel',
EchoAttributeManager::ATTR_LOCATORS => array(
'EchoUserLocator::locateTalkPageOwner',
),
'primary-link' => array( 'message' => 'notification-link-text-view-message', 'destination' => 'section' ),
'secondary-link' => array( 'message' => 'notification-link-text-view-changes', 'destination' => 'diff' ),
'category' => 'edit-user-talk',
'group' => 'interactive',
'section' => 'alert',
'bundle' => array( 'web' => true, 'email' => false ),
'formatter-class' => 'EchoEditUserTalkFormatter',
'title-message' => 'notification-edit-talk-page2',
'title-params' => array( 'agent', 'user', 'subject-anchor' ),
'bundle-message' => 'notification-edit-talk-page-bundle',
'bundle-params' => array( 'agent', 'user', 'agent-other-display', 'agent-other-count' ),
'email-subject-message' => 'notification-edit-talk-page-email-subject2',
'email-subject-params' => array( 'agent' ),
'email-body-batch-message' => 'notification-edit-talk-page-email-batch-body2',
'email-body-batch-params' => array( 'agent' ),
'email-body-batch-bundle-message' => 'notification-edit-user-talk-email-batch-bundle-body',
'email-body-batch-bundle-params' => array( 'agent', 'agent-other-display', 'agent-other-count' ),
'icon' => 'edit-user-talk',
'immediate' => true,
),
'reverted' => array(
@ -408,77 +391,37 @@ $wgEchoNotifications = array(
EchoAttributeManager::ATTR_LOCATORS => array(
array( 'EchoUserLocator::locateFromEventExtra', array( 'reverted-user-id' ) ),
),
'primary-link' => array( 'message' => 'notification-link-text-view-edit', 'destination' => 'diff' ),
'category' => 'reverted',
'group' => 'negative',
'section' => 'alert',
'formatter-class' => 'EchoEditFormatter',
'title-message' => 'notification-reverted2',
'title-params' => array( 'agent', 'title', 'difflink', 'number', 'userpage-contributions' ),
'email-subject-message' => 'notification-reverted-email-subject2',
'email-subject-params' => array( 'agent', 'title', 'number' ),
'email-body-batch-message' => 'notification-reverted-email-batch-body2',
'email-body-batch-params' => array( 'agent', 'title', 'number' ),
'icon' => 'revert',
),
'page-linked' => array(
'presentation-model' => 'EchoPageLinkedPresentationModel',
EchoAttributeManager::ATTR_LOCATORS => array(
'EchoUserLocator::locateArticleCreator',
),
'primary-link' => array( 'message' => 'notification-link-text-view-page', 'destination' => 'link-from-page' ),
'category' => 'article-linked',
'group' => 'neutral',
'section' => 'message',
'bundle' => array( 'web' => true, 'email' => true, 'expandable' => true ),
'formatter-class' => 'EchoPageLinkFormatter',
'title-message' => 'notification-page-linked',
'title-params' => array( 'agent', 'title', 'link-from-page' ),
'email-subject-message' => 'notification-page-linked-email-subject',
'email-subject-params' => array(),
'email-body-batch-message' => 'notification-page-linked-email-batch-body',
'email-body-batch-params' => array( 'agent', 'title', 'link-from-page' ),
'email-body-batch-bundle-message' => 'notification-page-linked-email-batch-bundle-body',
'email-body-batch-bundle-params' => array( 'agent', 'title', 'link-from-page', 'link-from-page-other-display', 'link-from-page-other-count' ),
'icon' => 'linked',
),
'mention' => array(
EchoAttributeManager::ATTR_LOCATORS => array(
array( 'EchoUserLocator::locateFromEventExtra', array( 'mentioned-users' ) ),
),
'primary-link' => array( 'message' => 'notification-link-text-view-mention', 'destination' => 'section' ),
'secondary-link' => array( 'message' => 'notification-link-text-view-changes', 'destination' => 'diff' ),
'category' => 'mention',
'group' => 'interactive',
'section' => 'alert',
'presentation-model' => 'EchoMentionPresentationModel',
'formatter-class' => 'EchoMentionFormatter',
'title-message' => 'notification-mention',
'title-params' => array( 'agent', 'subject-anchor', 'title', 'section-title', 'main-title-text', 'user' ),
'email-subject-message' => 'notification-mention-email-subject',
'email-subject-params' => array( 'agent', 'user' ),
'email-body-batch-message' => 'notification-mention-email-batch-body',
'email-body-batch-params' => array( 'agent', 'title', 'section-title', 'main-title-text', 'user' ),
'icon' => 'mention',
),
'user-rights' => array(
EchoAttributeManager::ATTR_LOCATORS => array(
array( 'EchoUserLocator::locateFromEventExtra', array( 'user' ) ),
),
'primary-link' => array( 'message' => 'echo-learn-more', 'destination' => 'user-rights-list' ),
'category' => 'user-rights',
'group' => 'neutral',
'section' => 'alert',
'presentation-model' => 'EchoUserRightsPresentationModel',
// Legacy formatting system
'formatter-class' => 'EchoUserRightsFormatter',
'title-message' => 'notification-user-rights',
'title-params' => array( 'agent', 'user-rights-list' ),
'email-subject-message' => 'notification-user-rights-email-subject',
'email-subject-params' => array(),
'email-body-batch-message' => 'notification-user-rights-email-batch-body',
'email-body-batch-params' => array( 'agent', 'user-rights-list' ),
'icon' => 'user-rights',
),
'emailuser' => array(
'presentation-model' => 'EchoEmailUserPresentationModel',
@ -488,9 +431,6 @@ $wgEchoNotifications = array(
'category' => 'emailuser',
'group' => 'neutral',
'section' => 'alert',
'title-message' => 'notification-emailuser',
'title-params' => array( 'agent' ),
'icon' => 'emailuser',
),
'foreign' => array(
'presentation-model' => 'EchoForeignPresentationModel',
@ -500,7 +440,6 @@ $wgEchoNotifications = array(
'category' => 'foreign',
'group' => 'positive',
'section' => 'alert',
'icon' => 'global',
),
'thank-you-edit' => array(
'user-locators' => array(
@ -514,7 +453,6 @@ $wgEchoNotifications = array(
'group' => 'positive',
'presentation-model' => 'EchoEditThresholdPresentationModel',
'section' => 'message',
'icon' => 'edit',
),
);

View file

@ -11,6 +11,8 @@ $wgAutoloadClasses += [
'ApiEchoNotifications' => __DIR__ . '/includes/api/ApiEchoNotifications.php',
'ApiEchoNotificationsTest' => __DIR__ . '/tests/phpunit/api/ApiEchoNotificationsTest.php',
'ApiEchoUnreadNotificationPages' => __DIR__ . '/includes/api/ApiEchoUnreadNotificationPages.php',
'BackfillReadBundles' => __DIR__ . '/maintenance/backfillReadBundles.php',
'BackfillUnreadWikis' => __DIR__ . '/maintenance/backfillUnreadWikis.php',
'Bundleable' => __DIR__ . '/includes/Bundleable.php',
'Bundler' => __DIR__ . '/includes/Bundler.php',
'BundlerTest' => __DIR__ . '/tests/phpunit/BundlerTest.php',
@ -22,11 +24,9 @@ $wgAutoloadClasses += [
'EchoArrayList' => __DIR__ . '/includes/ContainmentSet.php',
'EchoAttributeManager' => __DIR__ . '/includes/AttributeManager.php',
'EchoAttributeManagerTest' => __DIR__ . '/tests/phpunit/AttributeManagerTest.php',
'EchoBasicFormatter' => __DIR__ . '/includes/formatters/BasicFormatter.php',
'EchoCachedList' => __DIR__ . '/includes/ContainmentSet.php',
'EchoCallbackIterator' => __DIR__ . '/includes/iterator/CallbackIterator.php',
'EchoCatchableFatalErrorException' => __DIR__ . '/includes/exception/CatchableFatalErrorException.php',
'EchoCommentFormatter' => __DIR__ . '/includes/formatters/CommentFormatter.php',
'EchoContainmentList' => __DIR__ . '/includes/ContainmentSet.php',
'EchoContainmentSet' => __DIR__ . '/includes/ContainmentSet.php',
'EchoDataOutputFormatter' => __DIR__ . '/includes/DataOutputFormatter.php',
@ -36,18 +36,10 @@ $wgAutoloadClasses += [
'EchoDiffParserTest' => __DIR__ . '/tests/phpunit/DiffParserTest.php',
'EchoDiscussionParser' => __DIR__ . '/includes/DiscussionParser.php',
'EchoDiscussionParserTest' => __DIR__ . '/tests/phpunit/DiscussionParserTest.php',
'EchoEditFormatter' => __DIR__ . '/includes/formatters/EditFormatter.php',
'EchoEditThresholdPresentationModel' => __DIR__ . '/includes/formatters/EditThresholdPresentationModel.php',
'EchoEditUserTalkFormatter' => __DIR__ . '/includes/formatters/EditUserTalkFormatter.php',
'EchoEditUserTalkPresentationModel' => __DIR__ . '/includes/formatters/EditUserTalkPresentationModel.php',
'EchoEmailDecorator' => __DIR__ . '/includes/EmailFormatter.php',
'EchoEmailDigest' => __DIR__ . '/includes/EmailFormatter.php',
'EchoEmailFormat' => __DIR__ . '/includes/EmailFormat.php',
'EchoEmailFormatter' => __DIR__ . '/includes/EmailFormatter.php',
'EchoEmailFormatterTest' => __DIR__ . '/tests/phpunit/EmailFormatterTest.php',
'EchoEmailFrequency' => __DIR__ . '/includes/EmailFrequency.php',
'EchoEmailMode' => __DIR__ . '/includes/EmailFormatter.php',
'EchoEmailSingle' => __DIR__ . '/includes/EmailFormatter.php',
'EchoEmailUserPresentationModel' => __DIR__ . '/includes/formatters/EmailUserPresentationModel.php',
'EchoEvent' => __DIR__ . '/includes/model/Event.php',
'EchoEventDigestFormatter' => __DIR__ . '/includes/formatters/EchoEventDigestFormatter.php',
@ -61,13 +53,11 @@ $wgAutoloadClasses += [
'EchoForeignNotifications' => __DIR__ . '/includes/ForeignNotifications.php',
'EchoForeignPresentationModel' => __DIR__ . '/includes/formatters/EchoForeignPresentationModel.php',
'EchoForeignWikiRequest' => __DIR__ . '/includes/ForeignWikiRequest.php',
'EchoHTMLEmailDecorator' => __DIR__ . '/includes/EmailFormatter.php',
'EchoHooks' => __DIR__ . '/Hooks.php',
'EchoHtmlDigestEmailFormatter' => __DIR__ . '/includes/formatters/EchoHtmlDigestEmailFormatter.php',
'EchoHtmlEmailFormatter' => __DIR__ . '/includes/formatters/EchoHtmlEmailFormatter.php',
'EchoIteratorDecorator' => __DIR__ . '/includes/iterator/IteratorDecorator.php',
'EchoLocalCache' => __DIR__ . '/includes/cache/LocalCache.php',
'EchoMentionFormatter' => __DIR__ . '/includes/formatters/MentionFormatter.php',
'EchoMentionPresentationModel' => __DIR__ . '/includes/formatters/MentionPresentationModel.php',
'EchoModelFormatter' => __DIR__ . '/includes/formatters/EchoModelFormatter.php',
'EchoModerationController' => __DIR__ . '/includes/controller/ModerationController.php',
@ -85,7 +75,6 @@ $wgAutoloadClasses += [
'EchoNotifier' => __DIR__ . '/includes/Notifier.php',
'EchoOOUI\\LabelIconWidget' => __DIR__ . '/includes/ooui/LabelIconWidget.php',
'EchoOnWikiList' => __DIR__ . '/includes/ContainmentSet.php',
'EchoPageLinkFormatter' => __DIR__ . '/includes/formatters/PageLinkFormatter.php',
'EchoPageLinkedPresentationModel' => __DIR__ . '/includes/formatters/PageLinkedPresentationModel.php',
'EchoPlainTextDigestEmailFormatter' => __DIR__ . '/includes/formatters/EchoPlainTextDigestEmailFormatter.php',
'EchoPlainTextEmailFormatter' => __DIR__ . '/includes/formatters/EchoPlainTextEmailFormatter.php',
@ -99,8 +88,6 @@ $wgAutoloadClasses += [
'EchoTargetPageMapper' => __DIR__ . '/includes/mapper/TargetPageMapper.php',
'EchoTargetPageMapperTest' => __DIR__ . '/tests/phpunit/mapper/TargetPageMapperTest.php',
'EchoTargetPageTest' => __DIR__ . '/tests/phpunit/model/TargetPageTest.php',
'EchoTextEmailDecorator' => __DIR__ . '/includes/EmailFormatter.php',
'EchoTextEmailFormatter' => __DIR__ . '/includes/EmailFormatter.php',
'EchoTitleLocalCache' => __DIR__ . '/includes/cache/TitleLocalCache.php',
'EchoTitleLocalCacheTest' => __DIR__ . '/tests/phpunit/cache/TitleLocalCacheTest.php',
'EchoUnreadWikis' => __DIR__ . '/includes/UnreadWikis.php',
@ -108,11 +95,10 @@ $wgAutoloadClasses += [
'EchoUserLocatorTest' => __DIR__ . '/tests/phpunit/UserLocatorTest.php',
'EchoUserNotificationGateway' => __DIR__ . '/includes/gateway/UserNotificationGateway.php',
'EchoUserNotificationGatewayTest' => __DIR__ . '/tests/phpunit/gateway/UserNotificationGatewayTest.php',
'EchoUserRightsFormatter' => __DIR__ . '/includes/formatters/UserRightsFormatter.php',
'EchoUserRightsPresentationModel' => __DIR__ . '/includes/formatters/UserRightsPresentationModel.php',
'EchoWelcomePresentationModel' => __DIR__ . '/includes/formatters/WelcomePresentationModel.php',
'FilteredSequentialIteratorTest' => __DIR__ . '/tests/phpunit/iterator/FilteredSequentialIteratorTest.php',
'LegacyEchoHTMLEmailFormatter' => __DIR__ . '/includes/EmailFormatter.php',
'GenerateSampleNotifications' => __DIR__ . '/maintenance/generateSampleNotifications.php',
'MWEchoDbFactory' => __DIR__ . '/includes/EchoDbFactory.php',
'MWEchoDbFactoryTest' => __DIR__ . '/tests/phpunit/EchoDbFactoryTest.php',
'MWEchoEmailBatch' => __DIR__ . '/includes/EmailBatch.php',
@ -122,11 +108,15 @@ $wgAutoloadClasses += [
'NotificationControllerTest' => __DIR__ . '/tests/phpunit/controller/NotificationControllerTest.php',
'NotificationPager' => __DIR__ . '/includes/special/NotificationPager.php',
'NotificationsTest' => __DIR__ . '/tests/NotificationsTest.php',
'ProcessEchoEmailBatch' => __DIR__ . '/maintenance/processEchoEmailBatch.php',
'RemoveInvalidNotification' => __DIR__ . '/maintenance/removeInvalidNotification.php',
'RemoveInvalidTargetPage' => __DIR__ . '/maintenance/removeInvalidTargetPage.php',
'RemoveOrphanedEvents' => __DIR__ . '/maintenance/removeOrphanedEvents.php',
'SpecialDisplayNotificationsConfiguration' => __DIR__ . '/includes/special/SpecialDisplayNotificationsConfiguration.php',
'SpecialNotifications' => __DIR__ . '/includes/special/SpecialNotifications.php',
'SpecialNotificationsFormatter' => __DIR__ . '/includes/formatters/SpecialNotificationsFormatter.php',
'SpecialNotificationsMarkRead' => __DIR__ . '/includes/special/SpecialNotificationsMarkRead.php',
'SuppressionMaintenanceTest' => __DIR__ . '/tests/phpunit/maintenance/SupressionMaintenanceTest.php',
'TestDiscussionParser' => __DIR__ . '/maintenance/testDiscussionParser.php',
'UpdateEchoSchemaForSuppression' => __DIR__ . '/maintenance/updateEchoSchemaForSuppression.php',
];

View file

@ -74,8 +74,6 @@
"echo-pref-tooltip-mention": "Notify me when someone links to my user page.",
"echo-pref-tooltip-user-rights": "Notify me when someone changes my user rights.",
"echo-pref-tooltip-emailuser": "Notify me when someone sends me an email.",
"echo-no-agent": "[Nobody]",
"echo-no-title": "[No page]",
"echo-error-no-formatter": "No formatting defined for notification.",
"notifications": "Notifications",
"tooltip-pt-notifications-alert": "{{GENDER:|Your}} alerts",
@ -129,24 +127,14 @@
"notification-link-text-view-mention": "View mention",
"notification-link-text-view-changes": "{{GENDER:$1|View}} changes",
"notification-link-text-view-page": "View page",
"notification-link-text-view-edit": "View edit",
"notification-edit-talk-page2": "[[User:$1|$1]] {{GENDER:$1|left}} a message on your [[User talk:$2#$3|talk page]].",
"notification-edit-talk-page-with-section": "[[User:$1|$1]] {{GENDER:$1|left}} a message on your talk page in \"[[User talk:$2#$3|$4]]\".",
"notification-header-edit-user-talk": "$1 {{GENDER:$2|left}} a message on <strong>{{GENDER:$3|your}} talk page</strong>.",
"notification-header-edit-user-talk-with-section": "$1 {{GENDER:$2|left}} a message on <strong>{{GENDER:$3|your}} talk page</strong> in \"<strong>$4</strong>\".",
"notification-body-edit-user-talk-with-section": "$1",
"notification-page-linked": "[[:$2]] was {{GENDER:$1|linked}} from [[:$3]]. [[Special:WhatLinksHere/$2|See all links to this page]].",
"notification-header-page-linked": "A link was made from <strong>$4</strong> to <strong>$3</strong>.",
"notification-compact-header-page-linked": "Linked from <strong>$1</strong>.",
"notification-bundle-header-page-linked": "Links were made from {{PLURAL:$5||$5 pages|100=99+ pages}} to <strong>$3</strong>.",
"notification-link-text-what-links-here": "All links to this page",
"notification-add-comment2": "[[User:$1|$1]] {{GENDER:$1|commented}} on \"[[$3|$2]]\" on the \"$4\" talk page.",
"notification-add-talkpage-topic2": "[[User:$1|$1]] {{GENDER:$1|posted}} a new topic \"$2\" on [[$3]].",
"notification-add-talkpage-topic-yours2": "[[User:$1|$1]] {{GENDER:$1|sent}} you a message: \"[[$3#$2|$2]]\".",
"notification-add-comment-yours2": "[[User:$1|$1]] {{GENDER:$1|commented}} on \"[[$3#$2|$2]]\" on your talk page.",
"notification-body-mention": "$1",
"notification-mention": "[[User:$1|$1]] {{GENDER:$1|mentioned}} {{GENDER:$6|you}} on the $5 talk page in \"[[:$3#$2|$4]]\".",
"notification-mention-nosection": "[[User:$1|$1]] {{GENDER:$1|mentioned}} {{GENDER:$4|you}} on the [[:$3|$2 talk page]].",
"notification-header-mention-other": "$1 {{GENDER:$2|mentioned}} {{GENDER:$3|you}} on <strong>$4</strong> in \"<strong>$5</strong>\".",
"notification-header-mention-other-nosection": "$1 {{GENDER:$2|mentioned}} {{GENDER:$3|you}} on <strong>$4</strong>.",
"notification-header-mention-user-talkpage-v2": "$1 {{GENDER:$2|mentioned}} {{GENDER:$3|you}} on the <strong>user talk page {{GENDER:$5|of}} $4</strong> in \"<strong>$6</strong>\".",
@ -155,14 +143,10 @@
"notification-header-mention-agent-talkpage-nosection": "$1 {{GENDER:$2|mentioned}} {{GENDER:$3|you}} on <strong>{{GENDER:$2|his|her|their}} talk page</strong>.",
"notification-header-mention-article-talkpage": "$1 {{GENDER:$2|mentioned}} {{GENDER:$3|you}} on the <strong>$4</strong> talk page in \"<strong>$5</strong>\".",
"notification-header-mention-article-talkpage-nosection": "$1 {{GENDER:$2|mentioned}} {{GENDER:$3|you}} on the <strong>$4</strong> talk page.",
"notification-user-rights-add": "You are now a member of {{PLURAL:$2|this group|these groups}}: $1",
"notification-user-rights-remove": "You are no longer a member of {{PLURAL:$2|this group|these groups}}: $1",
"notification-user-rights": "Your user rights [[Special:Log/rights/$1|were {{GENDER:$1|changed}}]] by [[User:$1|$1]]. $2. [[Special:ListGroupRights|Learn more]]",
"notification-header-user-rights-add-only": "{{GENDER:$4|Your}} user rights were {{GENDER:$1|changed}}. You have been added to: $2.",
"notification-header-user-rights-remove-only": "{{GENDER:$4|Your}} user rights were {{GENDER:$1|changed}}. You are no longer a member of: $2.",
"notification-header-user-rights-add-and-remove": "{{GENDER:$6|Your}} user rights were {{GENDER:$1|changed}}. You have been added to: $2. You are no longer a member of: $4.",
"notification-body-user-rights": "$1",
"notification-new-user": "Welcome to {{SITENAME}}, $1! We're glad you're here.",
"notification-header-welcome": "{{GENDER:$2|Welcome}} to {{SITENAME}}, $1! We're glad {{GENDER:$2|you're}} here.",
"notification-welcome-link": "",
"notification-welcome-linktext": "Welcome",
@ -174,24 +158,17 @@
"notification-header-thank-you-100000-edit": "{{GENDER:$2|You}} just made {{GENDER:$2|your}} hundred thousandth edit; thank {{GENDER:$2|you}} for an amazing contribution!",
"notification-header-thank-you-1000000-edit": "{{GENDER:$2|You}} just made {{GENDER:$2|your}} millionth edit; thank {{GENDER:$2|you}} for an astonishing contribution!",
"notification-link-thank-you-edit": "{{GENDER:$1|Your}} edit",
"notification-reverted2": "Your {{PLURAL:$4|edit on [[:$2]] has|edits on [[:$2]] have}} been {{GENDER:$1|reverted}} by [[$5|$1]]. $3",
"notification-link-text-view-edit": "View edit",
"notification-header-reverted": "Your {{PLURAL:$4|edit on <strong>$3</strong> was|edits on <strong>$3</strong> were}} {{GENDER:$2|reverted}}",
"notification-body-reverted": "$1",
"notification-emailuser": "[[User:$1|$1]] {{GENDER:$1|sent}} you an email.",
"notification-header-emailuser": "$1 {{GENDER:$2|sent}} you an email.",
"notification-body-emailuser": "$1",
"notification-edit-talk-page-email-subject2": "$1 {{GENDER:$1|left}} you a message on {{SITENAME}}",
"notification-edit-talk-page-email-batch-body2": "$1 {{GENDER:$1|left}} a message on your talk page.",
"notification-edit-talk-page-email-batch-body-with-section": "$1 {{GENDER:$1|left}} a message on your talk page in \"$2\".",
"notification-page-linked-email-subject": "A page you created was linked on {{SITENAME}}",
"notification-page-linked-email-batch-body": "$2 was {{GENDER:$1|linked}} from $3.",
"notification-reverted-email-subject2": "Your {{PLURAL:$3|edit was|edits were}} {{GENDER:$1|reverted}} on {{SITENAME}}",
"notification-reverted-email-batch-body2": "Your {{PLURAL:$3|edit on $2 has been|edits on $2 have been}} {{GENDER:$1|reverted}} by $1.",
"notification-mention-email-subject": "$1 {{GENDER:$1|mentioned}} {{GENDER:$2|you}} on {{SITENAME}}",
"notification-mention-email-batch-body": "$1 {{GENDER:$1|mentioned}} {{GENDER:$5|you}} on the $4 talk page in \"$3\".",
"notification-mention-nosection-email-batch-body": "$1 {{GENDER:$1|mentioned}} you on the $2 talk page.",
"notification-user-rights-email-subject": "Your user rights have changed on {{SITENAME}}",
"notification-user-rights-email-batch-body": "Your user rights were {{GENDER:$1|changed}} by $1. $2.",
"notification-timestamp-ago-seconds": "{{PLURAL:$1|$1s}}",
"notification-timestamp-ago-minutes": "{{PLURAL:$1|$1m}}",
"notification-timestamp-ago-hours": "{{PLURAL:$1|$1h}}",
@ -203,9 +180,7 @@
"notification-inbox-filter-read": "Read",
"notification-inbox-filter-unread": "Unread",
"notification-inbox-filter-all": "All",
"echo-email-subject-default": "New notification at {{SITENAME}}",
"echo-email-body-default": "You have a new notification at {{SITENAME}}:\n\n$1",
"echo-email-batch-body-default": "You have a new notification.",
"echo-email-footer-default-html": "To control which emails we send you, <a href=\"$2\" style=\"text-decoration:none; color: #3868B0;\">check your preferences</a>.<br />\n$1",
"echo-email-footer-default": "$2\n\nTo control which emails we send you, check your preferences:\n{{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}\n\n$1",
"echo-email-plain-footer": "To control which emails we send you, check your preferences:",
@ -222,10 +197,7 @@
"echo-date-today": "Today",
"echo-date-yesterday": "Yesterday",
"echo-load-more-error": "An error occurred while fetching more results.",
"notification-edit-talk-page-bundle": "$1 and {{PLURAL:$3|one other|$3 others|100=99+ others}} {{GENDER:$1|left}} messages on your [[User talk:$2|talk page]].",
"notification-bundle-header-edit-user-talk-v2": "{{PLURAL:$1|One new message|$1 new messages|100=99+ new messages}} on <strong>{{GENDER:$3|your}} talk page</strong>.",
"notification-edit-user-talk-email-batch-bundle-body": "$1 and {{PLURAL:$2|one other|$2 others|100=99+ others}} {{GENDER:$1|left}} a message on your talk page.",
"notification-page-linked-email-batch-bundle-body": "$2 was {{GENDER:$1|linked}} from $3 and {{PLURAL:$4|one other page|$4 other pages|100=99+ other pages}}.",
"echo-email-batch-separator": "--",
"echo-email-batch-bullet": "•",
"echo-email-batch-subject-daily": "You have {{PLURAL:$2|a new notification|new notifications}} at {{SITENAME}}",
@ -233,7 +205,6 @@
"echo-email-batch-body-intro-daily": "Hi $1,\nHere's a summary of today's activity on {{SITENAME}} for you.",
"echo-email-batch-body-intro-weekly": "Hi $1,\nHere's a summary of this week's activity on {{SITENAME}} for you.",
"echo-email-batch-link-text-view-all-notifications": "View all notifications",
"echo-rev-deleted-text-view": "This page revision has been suppressed.",
"notification-header-foreign-alert": "More alerts from {{PLURAL:$5|another wiki|$5 other wikis}}",
"notification-header-foreign-notice": "More notices from {{PLURAL:$5|another wiki|$5 other wikis}}",
"notification-header-foreign-all": "More notifications from {{PLURAL:$5|another wiki|$5 other wikis}}",

View file

@ -65,8 +65,6 @@
"echo-pref-tooltip-mention": "This is a short description of the mention notification category.\n{{Related|Echo-pref-tooltip}}",
"echo-pref-tooltip-user-rights": "This is a short description of the user rights changes notification category\n{{Related|Echo-pref-tooltip}}",
"echo-pref-tooltip-emailuser": "This is a short description of the user email notification category\n{{Related|Echo-pref-tooltip}}",
"echo-no-agent": "Shown in place of a username in a notification\n\tif the notification has no specified user.",
"echo-no-title": "Shown in place of a page title in a notification if the notification has no specified page title.",
"echo-error-no-formatter": "Error message displayed when no formatting has been defined for a notification. In other words, the extension doesn't know how to properly display the notification.",
"notifications": "{{doc-special|Notifications}}\n{{Identical|Notification}}",
"tooltip-pt-notifications-alert": "This is used for the title (mouseover text) of the alert notifications user tool.",
@ -118,26 +116,17 @@
"notification-link-text-collapse-all": "Label for the button that collapses a bundled notification.\n{{Identical|Collapse}}",
"notification-link-text-view-message": "Label for button that links to a message on your talk page.\n{{Identical|View message}}",
"notification-link-text-view-mention": "Label for button that links to a discussion where you were mentioned.",
"notification-link-text-view-changes": "Label for button that links to a \"diff\" view showing changes made to a page. This is an alternative to the wording in {{msg-mw|notification-link-text-view-edit}}, which serves essentially the same function. Paramters:\n* $1 - name of the user viewing the notification, can be used for GENDER.\n{{Identical|View changes}}",
"notification-link-text-view-changes": "Label for button that links to a \"diff\" view showing changes made to a page. Paramters:\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-link-text-view-edit": "Label for button that links to a \"diff\" view showing an edit made to a page. This is an alternative to the wording in {{msg-mw|notification-link-text-view-changes}}, which serves essentially the same function.",
"notification-edit-talk-page2": "Format for displaying notifications of a user talk page being edited. Parameters:\n* $1 - the username of the person who edited, plain text. Can be used for GENDER.\n* $2 - the current user's name, used in the link to their talk page\n* $3 - the section title of the discussion, if any, used in the link to their talk page\nSee also:\n* {{msg-mw|Notification-edit-talk-page-flyout2}}\n* {{msg-mw|Notification-add-talkpage-topic2}}\n* left is for verb left.",
"notification-edit-talk-page-with-section": "Format for displaying notifications of a user talk page being edited with a new section or new comment.\n\nParameters:\n* $1 - the username of the person who edited, plain text. Can be used for GENDER.\n* $2 - the username of current user, used in the link to their talk page\n* $3 - the section title of the discussion, if any, used in the link to their talk page\n* $4 - the raw section title text",
"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\nSee also:\n* {{msg-mw|Notification-edit-talk-page2}}\n* {{msg-mw|Notification-add-talkpage-topic2}}",
"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\nSee also:\n* {{msg-mw|Notification-edit-talk-page2}}\n* {{msg-mw|Notification-add-talkpage-topic2}}",
"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.\n* {{msg-mw|Notification-edit-talk-page2}}\n* {{msg-mw|Notification-add-talkpage-topic2}}",
"notification-page-linked": "Format for displaying notifications of articles being linked. Parameters:\n* $1 - the username of the person who linked the page, plain text. Can be used for GENDER.\n* $2 - the page being linked\n* $3 - the page linked from\nSee also:\n* {{msg-mw|Notification-page-linked-flyout}}\n* {{msg-mw|Notification-page-linked-email-batch-body}}\n* {{msg-mw|Notification-page-linked-email-subject}}",
"notification-header-page-linked": "Notification header message for articles being linked.\n\nParameters:\n* $1 - the formatted username of the person who linked the page. \n* $2 - the username for GENDER\n* $3 - the page being linked\n* $4 - the page linked from\nSee also:\n* {{msg-mw|Notification-page-linked}}\n* {{msg-mw|Notification-page-linked-email-batch-body}}\n* {{msg-mw|Notification-page-linked-email-subject}}",
"notification-compact-header-page-linked": "Notification compact header message for articles being linked.\n\nParameters:\n* $1 - the page linked from.\nSee also:\n* {{msg-mw|Notification-page-linked}}\n* {{msg-mw|Notification-page-linked-email-batch-body}}\n* {{msg-mw|Notification-page-linked-email-subject}}",
"notification-bundle-header-page-linked": "Bundled message for page-linked notification. Parameters:\n* $1 - the formatted username of the person who linked the page. \n* $2 - the username for GENDER\n* $3 - the page title\n* $4 - the page linked from\n* $5 - The number of other pages that link to this page, except that if the count is greater than 99, this value will be 100; uses standard number formatting and used for PLURAL\n* $6 - Unused\nSee also:\n* {{msg-mw|Notification-page-linked}}\n* {{msg-mw|Notification-page-linked-flyout}}\n* {{msg-mw|Notification-page-linked-email-batch-body}}\n* {{msg-mw|Notification-page-linked-email-subject}}\n{{Related|Notification-bundle}}",
"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-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.",
"notification-header-page-linked": "Notification header message for articles being linked.\n\nParameters:\n* $1 - the formatted username of the person who linked the page. \n* $2 - the username for GENDER\n* $3 - the page being linked\n* $4 - the page linked from\nSee also:\n* {{msg-mw|Notification-page-linked-email-subject}}",
"notification-compact-header-page-linked": "Notification compact header message for articles being linked.\n\nParameters:\n* $1 - the page linked from.\nSee also:\n* {{msg-mw|Notification-page-linked-email-subject}}",
"notification-bundle-header-page-linked": "Bundled message for page-linked notification. Parameters:\n* $1 - the formatted username of the person who linked the page. \n* $2 - the username for GENDER\n* $3 - the page title\n* $4 - the page linked from\n* $5 - The number of other pages that link to this page, except that if the count is greater than 99, this value will be 100; uses standard number formatting and used for PLURAL\n* $6 - Unused\nSee also:\n* {{msg-mw|Notification-page-linked-flyout}}\n* {{msg-mw|Notification-page-linked-email-subject}}\n{{Related|Notification-bundle}}",
"notification-link-text-what-links-here": "Label for link to the WhatLinksHere special page for the page being linked in this notification.",
"notification-add-comment2": "Format for displaying notifications of a comment being added to an existing discussion.\n\nParameters:\n* $1 - the username of the person who edited, plain text. Can be used for GENDER.\n* $2 - the section title of the discussion\n* $3 - a link to a page and section\n* $4 - the page on which the discussion exists, plain text\nSee also:\n* {{msg-mw|Notification-add-comment-yours2}}",
"notification-add-talkpage-topic2": "Format for displaying notifications of a new discussion being added. Parameters:\n* $1 - the username of the person who edited, plain text. Can be used for GENDER.\n* $2 - the section title of the discussion\n* $3 - the page on which the discussion was added, plain text\nSee also:\n* {{msg-mw|Notification-edit-talk-page2}}\n* {{msg-mw|Notification-edit-talk-page-flyout2}}",
"notification-add-talkpage-topic-yours2": "Parameters:\n* $1 - a username, plain text. Can be used for GENDER.\n* $2 - a page section\n* $3 - a page title",
"notification-add-comment-yours2": "Parameters:\n* $1 - a username, plain text; can be used for GENDER\n* $2 - discussion name\n* $3 - link to user talk page\nSee also:\n* {{msg-mw|Notification-add-comment2}}",
"notification-link-text-view-edit": "Label for button that links to a \"diff\" view showing an edit made to a page. This is an alternative to the wording in {{msg-mw|notification-link-text-view-changes}}, which serves essentially the same function.",
"notification-body-mention": "{{notranslate}}",
"notification-mention": "Format for displaying notifications of a comment in a specific section including a link to another user's user page.\n\nParameters:\n* $1 - the username of the person who edited, plain text. Can be used for GENDER\n* $2 - the section title of the discussion\n* $3 - the page title of the discussion\n* $4 - the raw section title text\n* $5 - the title text without namespace (a page title in any namespace)\n* $6 - name of the user viewing the notification, can be used for GENDER",
"notification-mention-nosection": "Format for displaying notifications of a comment including a link to another user's user page. Parameters:\n* $1 - the username of the person who edited, plain text. Can be used for GENDER\n* $2 - the title text without namespace (a page title in any namespace)\n* $3 - the page title of the discussion\n* $4 - name of the user viewing the notification, can be used for GENDER",
"notification-header-mention-other": "Header text for a notification when you are mentioned by another user in a section on a page that is not an article talk page or a user talk page.\n* $1 - user's name (not suitable for GENDER).\n* $2 - user's name for use in GENDER.\n* $3 - name of the user viewing the notification, can be used for GENDER\n* $4 - name of the page they were mentioned in (with namespace).\n* $5 - name of the section they were mentioned in",
"notification-header-mention-other-nosection": "Header text for a notification when you are mentioned by another user on a page that is not an article talk page or a user talk page.\n* $1 - user's name (not suitable for GENDER).\n* $2 - user's name for use in GENDER.\n* $3 - name of the user viewing the notification, can be used for GENDER\n* $4 - name of the page they were mentioned in (with namespace)",
"notification-header-mention-user-talkpage-v2": "Header text for a notification when you are mentioned by another user in a section on a user talk page.\n* $1 - user's name (not suitable for GENDER).\n* $2 - user's name for use in GENDER.\n* $3 - name of the user viewing the notification, can be used for GENDER\n* $4 - formatted name of the user whose talk page you are mentioned in.\n* $5 - name of the user whose talk page you are mentioned in, can be used for GENDER\n* $6 - name of the section they were mentioned in",
@ -146,14 +135,10 @@
"notification-header-mention-agent-talkpage-nosection": "{{doc-singularthey}}\nHeader text for a notification when you are mentioned by another user on their talk page.\n* $1 - user's name (not suitable for GENDER).\n* $2 - user's name for use in GENDER.\n* $3 - name of the user viewing the notification, can be used for GENDER",
"notification-header-mention-article-talkpage": "Header text for a notification when you are mentioned by another user in a section on an article talk page.\n* $1 - user's name (not suitable for GENDER).\n* $2 - user's name for use in GENDER.\n* $3 - name of the user viewing the notification, can be used for GENDER\n* $4 - name of the article whose talk page you are mentioned in (without namespace).\n* $5 - name of the section they were mentioned in",
"notification-header-mention-article-talkpage-nosection": "Header text for a notification when you are mentioned by another user on an article talk page.\n* $1 - user's name (not suitable for GENDER).\n* $2 - user's name for use in GENDER.\n* $3 - name of the user viewing the notification, can be used for GENDER\n* $4 - name of the article whose talk page you are mentioned in (without namespace)",
"notification-user-rights-add": "Message indicating that a user was added to a user group. Parameters:\n* $1 - a comma separated list of user group names\n* $2 - the number of user groups, this is used for PLURAL support\nSee also:\n* {{msg-mw|Notification-user-rights-remove}}",
"notification-user-rights-remove": "Message indicating that a user was removed from a user group. Parameters:\n* $1 - a comma separated list of user group names\n* $2 - the number of user groups, this is used for PLURAL support\nSee also:\n* {{msg-mw|Notification-user-rights-add}}",
"notification-user-rights": "Format for displaying notifications of a user right change in notification page.\n\nParameters:\n* $1 - the username of the person who made the user right change. Can be used for GENDER support.\n* $2 - a semicolon separated list of {{msg-mw|Notification-user-rights-add}}, {{msg-mw|Notification-user-rights-remove}}",
"notification-header-user-rights-add-only": "Notifications header message when a user is added to groups. Parameters:\n* $1 - the raw username of the person who made the user rights change, can be used for GENDER support\n* $2 - a localized list of the groups that were added\n* $3 - the number of groups that were added, can be used for PLURAL\n* $4 - name of the user viewing the notification, can be used for GENDER",
"notification-header-user-rights-remove-only": "Notifications header message when a user is removed from groups. Parameters:\n* $1 - the raw username of the person who made the user rights change, can be used for GENDER support\n* $2 - a localized list of the groups that were removed\n* $3 - the number of groups that were removed, can be used for PLURAL\n* $4 - name of the user viewing the notification, can be used for GENDER",
"notification-header-user-rights-add-and-remove": "Notifications header message when a user is added to groups and removed from groups. Parameters:\n* $1 - the raw username of the person who made the user rights change, can be used for GENDER support\n* $2 - a localized list of the groups that were added\n* $4 - a localized list of the groups that were removed\n* $6 - name of the user viewing the notification, can be used for GENDER",
"notification-body-user-rights": "{{notranslate}}",
"notification-new-user": "Text of the welcome notification. Parameters:\n* $1 - the name of the new user\nSee also:\n* {{msg-mw|Guidedtour-tour-gettingstarted-start-title}}",
"notification-header-welcome": "Text of the welcome notification. Parameters:\n* $1 - the name of the new user.\nSee also:\n* {{msg-mw|Guidedtour-tour-gettingstarted-start-title}}",
"notification-welcome-link": "{{notranslate}}",
"notification-welcome-linktext": "Link text for link to the wiki's welcome or introduction page.\n{{Identical|Welcome}}",
@ -165,24 +150,16 @@
"notification-header-thank-you-100000-edit": "Text of the editor welcome notification for their hundred thousandth edit.\nParameters:\n* $1 - the formatted username of the new user\n* $2 - the username for gender purposes",
"notification-header-thank-you-1000000-edit": "Text of the editor welcome notification for their millionth edit.\nParameters:\n* $1 - the formatted username of the new user\n* $2 - the username for gender purposes",
"notification-link-thank-you-edit": "Label for the link to the user's edit which triggered a threshold congratulations message.\nParameters:\n* $1 - the username for gender purposes",
"notification-reverted2": "Format for displaying notifications of a user's edit being reverted. Parameters:\n* $1 - the username of the person who reverted, plain text. Can be used for GENDER.\n* $2 - the page that was reverted, formatted\n* $3 - a diff link which is labeled {{msg-mw|Showdiff}}\n* $4 - the number of edits that were reverted. NOTE: This will only be set to 1 or 2, with 2 actually meaning 'an unknown number greater than 0'.\n* $5 - Page for reverting user.\nUser page if logged in, or user's contributions page if logged out.\n{{Related|Notification-reverted}}",
"notification-header-reverted": "Notification header of a user's edit being reverted.\n\nParameters:\n* $1 - the formatted username of the person who reverted.\n* $2 - the username for GENDER\n* $3 - the page that was reverted, formatted\n* $4 - the number of edits that were reverted. NOTE: This will only be set to 1 or 2, with 2 actually meaning \"an unknown number greater than 0\".\n{{Related|Notification-reverted}}",
"notification-body-reverted": "{{notranslate}}",
"notification-emailuser": "Format for displaying notifications of a user has sent an email to another user. Parameters:\n* $1 - the username of the person the email, plain text. Can be used for GENDER.",
"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-talk-page-email-subject2": "Email subject. Parameters:\n* $1 - a username which can be used for gender support",
"notification-edit-talk-page-email-batch-body2": "First line of the email notification for a talk page edit. The following line completes it with the description of the message in question, that is its edit summary.\n\nParameters:\n* $1 - a username (which also links to the userpage of the user in question, in the HTML version)\nSee also:\n* {{msg-mw|Notification-edit-talk-page2}}\n* {{msg-mw|Notification-edit-talk-page-email-subject2}}\n* {{msg-mw|Notification-edit-talk-page-flyout2}}",
"notification-edit-talk-page-email-batch-body-with-section": "Email notification for talk page edit with new section or new comment. Parameters:\n* $1 - a username\n* $2 - the raw section title text",
"notification-page-linked-email-subject": "E-mail subject.\nSee also:\n* {{msg-mw|Notification-page-linked}}\n* {{msg-mw|Notification-page-linked-flyout}}\n* {{msg-mw|Notification-page-linked-email-batch-body}}",
"notification-page-linked-email-batch-body": "Email notification for page being linked. Parameters:\n* $1 - the username of the person who linked the page, plain text. Can be used for GENDER.\n* $2 - the page being linked\n* $3 - the page linked from\nSee also:\n* {{msg-mw|Notification-page-linked}}\n* {{msg-mw|Notification-page-linked-flyout}}\n* {{msg-mw|Notification-page-linked-email-subject}}",
"notification-page-linked-email-subject": "E-mail subject.\nSee also:\n* {{msg-mw|Notification-page-linked-flyout}}",
"notification-reverted-email-subject2": "Email subject. Parameters:\n* $1 - a username\n* $2 - (Unused) a page title\n* $3 - the number of reverts\n{{Related|Notification-reverted}}",
"notification-reverted-email-batch-body2": "Email notification for page revert. Parameters:\n* $1 - a username\n* $2 - a page title\n* $3 - the number of revert\n{{Related|Notification-reverted}}",
"notification-mention-email-subject": "Email subject. Parameters:\n* $1 - a username\n* $2 - name of the user viewing the notification, can be used for GENDER\nSee also:\n* {{msg-mw|Notification-mention}}\n* {{msg-mw|Notification-mention-flyout}}\n* {{msg-mw|Notification-mention-email-batch-body}}",
"notification-mention-email-batch-body": "E-mail notification batch body. Parameters:\n* $1 - a username, plaintext. Can be used for gender support\n* $2 - (Unused) talk page title\n* $3 - the raw section title text\n* $4 - the title text without namespace (a page title in any namespace)\n* $5 - name of the user viewing the notification, can be used for GENDER\n\nSee also:\n* {{msg-mw|Notification-mention}}\n* {{msg-mw|Notification-mention-flyout}}\n* {{msg-mw|Notification-mention-email-subject}}",
"notification-mention-nosection-email-batch-body": "E-mail notification batch body. Parameters:\n* $1 - a username, plaintext. Can be used for gender support\n* $2 - the title text without namespace (a page title in any namespace)\n* $3 - name of the user viewing the notification, can be used for GENDER\n\nSee also:\n* {{msg-mw|Notification-mention-nosection}}\n* {{msg-mw|Notification-mention-nosection-flyout}}\n* {{msg-mw|Notification-mention-email-subject}}",
"notification-user-rights-email-subject": "E-mail subject for user rights notification\n\nSee also:\n* {{msg-mw|Notification-user-rights}}\n* {{msg-mw|Notification-user-rights-email-batch-body}}",
"notification-user-rights-email-batch-body": "Email notification batch body. Parameters:\n* $1 - a user name, plaintext. Can be used for gender support.\n* $2 - a semicolon separated list of {{msg-mw|notification-user-rights-add}}, {{msg-mw|notification-user-rights-remove}}",
"notification-mention-email-subject": "Email subject. Parameters:\n* $1 - a username\n* $2 - name of the user viewing the notification, can be used for GENDER\nSee also:\n* {{msg-mw|Notification-mention-flyout}}",
"notification-user-rights-email-subject": "E-mail subject for user rights notification\n\nSee also:\n* {{msg-mw|Notification-user-rights}}",
"notification-timestamp-ago-seconds": "Label for the amount of time since a notification has arrived in the case where it is under a minute. This should be a very short string. $1 - Number of seconds",
"notification-timestamp-ago-minutes": "Label for the amount of time since a notification has arrived in the case where it is in order of minutes. This should be a very short string. $1 - Number of minutes",
"notification-timestamp-ago-hours": "Label for the amount of time since a notification has arrived in the case where it is in order of hours. This should be a very short string. $1 - Number of hours",
@ -194,9 +171,7 @@
"notification-inbox-filter-read": "Label for the button that shows only read notification.\n{{Identical|Read}}",
"notification-inbox-filter-unread": "Label for the button that shows only unread notification.",
"notification-inbox-filter-all": "Label for the button that shows all notification.\n{{Identical|All}}",
"echo-email-subject-default": "Default subject for Echo e-mail notifications",
"echo-email-body-default": "Default message content for Echo email notifications. Parameters:\n* $1 - a plain text description of the notification",
"echo-email-batch-body-default": "Default message for Echo e-mail digest notifications",
"echo-email-footer-default-html": "Default footer content for Echo html e-mail notifications. Parameters:\n* $1 - the address of the organization that sent the email\n* $2 - the URL to the notification preference page\nFor plain-text version, see {{msg-mw|Echo-email-footer-default}}.",
"echo-email-footer-default": "Default footer content for Echo text e-mail notifications. Parameters:\n* $1 - the address of the organization that sent the email\n* $2 - \"-------...\" ({{msg-mw|echo-email-batch-separator}})\n\nFor HTML version, see {{msg-mw|echo-email-footer-default-html}}.",
"echo-email-plain-footer": "Footer content for Echo text e-mail notifications.\n\nFor HTML version, see {{msg-mw|echo-email-html-footer}}.",
@ -213,10 +188,7 @@
"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}}",
"echo-load-more-error": "Error message for errors in loading more notifications",
"notification-edit-talk-page-bundle": "Bundled message for edit-user-talk notification. Parameters:\n* $1 - the name of the user who performed the action, which can be used for gender support\n* $2 - the name of the user being addressed\n* $3 - The count of other action performers, except that if the count is greater than 99, this value will be 100; uses standard number formatting and used for PLURAL\n* $4 - Unused.\nSee also:\n* {{msg-mw|Notification-edit-talk-page2}}\n* {{msg-mw|Notification-edit-talk-page-email-batch-body2}}\n* {{msg-mw|Notification-edit-talk-page-email-subject2}}",
"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}}",
"notification-edit-user-talk-email-batch-bundle-body": "Bundled message for edit-user-talk email digest notification. Parameters:\n* $1 - the username who performs the action, which can be used for gender support\n* $2 - The count of other action performers, except that if the count is greater than 99, this value will be 100; uses standard number formatting and used for PLURAL\n* $3 - Unused.\n\nSee also:\n* {{msg-mw|Notification-edit-talk-page2}}\n* {{msg-mw|Notification-edit-talk-page-flyout2}}\n* {{msg-mw|Notification-edit-talk-page-email-batch-body2}}\n* {{msg-mw|Notification-edit-talk-page-email-subject2}}",
"notification-page-linked-email-batch-bundle-body": "Bundled message for page-linked email digest notification. Parameters:\n* $1 - the username who performs the action, which can be used for gender support\n* $2 - the link-to page title\n* $3 - the link-from page title\n* $4 - The count of other pages that link to the page mentioned in the notifications, except that if the count is greater than 99, this value will be 100; uses standard number formatting and used for PLURAL\n* $5 - Unused\n\nSee also:\n* {{msg-mw|Notification-page-linked}}\n* {{msg-mw|Notification-page-linked-flyout}}\n* {{msg-mw|Notification-page-linked-email-batch-body}}\n* {{msg-mw|Notification-page-linked-email-subject}}",
"echo-email-batch-separator": "{{optional}}\nEmail batch content separator",
"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}}",
@ -224,7 +196,6 @@
"echo-email-batch-body-intro-daily": "Introduction text for daily email digest. Parameters:\n* $1 - a username\nSee also:\n* {{msg-mw|Echo-email-batch-body-intro-weekly}}",
"echo-email-batch-body-intro-weekly": "Introduction text for weekly email digest. Parameters:\n* $1 - a username\nSee also:\n* {{msg-mw|Echo-email-batch-body-intro-daily}}",
"echo-email-batch-link-text-view-all-notifications": "The link text for the primary action in daily and weekly email digest",
"echo-rev-deleted-text-view": "Short message displayed instead of edit content when revision text is suppressed.",
"notification-header-foreign-alert": "Flyout-specific format for displaying notification header of having alert notifications on foreign wikis.\n\nParameters:\n* $1 - the formatted username of the current user.\n* $2 - the username for GENDER\n* $3 (deprecated) - 1 of the foreign wikis you have notifications on\n* $4 (deprecated) - the number of remaining other wikis you have notifications on\n*$5 - the number of other wikis you have notifications on",
"notification-header-foreign-notice": "Flyout-specific format for displaying notification header of having notice notifications on foreign wikis.\n\nParameters:\n* $1 - the formatted username of the current user.\n* $2 - the username for GENDER\n* $3 (deprecated) - 1 of the foreign wikis you have notifications on\n* $4 (deprecated) - the number of remaining other wikis you have notifications on\n*$5 - the number of other wikis you have notifications on",
"notification-header-foreign-all": "Flyout-specific format for displaying notification header of having notifications (combined alerts and messages) on foreign wikis.\n\nParameters:\n* $1 - the formatted username of the current user.\n* $2 - the username for GENDER\n* $3 (deprecated) - 1 of the foreign wikis you have notifications on\n* $4 (deprecated) - the number of remaining other wikis you have notifications on\n*$5 - the number of other wikis you have notifications on",

View file

@ -1,863 +0,0 @@
<?php
/**
* Abstract class for formatting email notifications
*/
abstract class EchoEmailFormatter {
/**
* @var EchoEmailMode
*/
protected $emailMode;
/**
* @param $emailMode EchoEmailMode
*/
public function __construct( EchoEmailMode $emailMode ) {
$this->emailMode = $emailMode;
}
/**
* Abstract method for formatting email
* @return string
*/
abstract public function formatEmail();
}
/**
* Formatter class for formatting text email notification
*/
class EchoTextEmailFormatter extends EchoEmailFormatter {
/**
* @param $emailMode EchoEmailMode
*/
public function __construct( EchoEmailMode $emailMode ) {
parent::__construct( $emailMode );
$this->emailMode->attachDecorator( new EchoTextEmailDecorator() );
}
/**
* {@inheritDoc}
*/
public function formatEmail() {
$template = $this->emailMode->getTextTemplate();
foreach ( $this->emailMode->getComponent() as $val ) {
$func = 'build' . ucfirst( $val );
$template = str_replace( "%%$val%%", $this->emailMode->$func(), $template );
}
// Remove redundant newline characters
return $this->removeExtraNewLine( $template );
}
/**
* Remove extra newline from a text content
* @param $text string
* @return string
*/
protected function removeExtraNewLine( $text ) {
return preg_replace( "/\n{3,}/", "\n\n", $text );
}
}
/**
* Formatter class for formatting HTML email notification
*/
class LegacyEchoHTMLEmailFormatter extends EchoEmailFormatter {
/**
* @param $emailMode EchoEmailMode
*/
public function __construct( EchoEmailMode $emailMode ) {
parent::__construct( $emailMode );
$this->emailMode->attachDecorator( new EchoHTMLEmailDecorator() );
}
/**
* {@inheritDoc}
*/
public function formatEmail() {
$template = $this->emailMode->getHTMLTemplate();
foreach ( $this->emailMode->getComponent() as $val ) {
$func = 'build' . ucfirst( $val );
$template = str_replace( "%%$val%%", $this->emailMode->$func(), $template );
}
return $template;
}
}
/**
* Abstract entity that represents an email delivery mode
*/
abstract class EchoEmailMode {
/**
* @var array
* Email components
*/
protected $component;
/**
* @var User
* The user who receives email notifications
*/
protected $user;
/**
* @var EchoEmailDecorator
* Email decorator
*/
protected $decorator;
/**
* @var Language
* The language object for the user language
*/
protected $lang;
/**
* @param $user User
* @param $component array
*/
public function __construct( User $user, array $component ) {
$this->user = $user;
// All email delivery mode share the same footer
$this->component = array_merge( $component, array( 'footer' ) );
// Initialize with a text decorator, the decorator can be altered
// via attachDecorator() based on text/html emails
$this->decorator = new EchoTextEmailDecorator();
$this->lang = Language::factory( $user->getOption( 'language' ) );
}
/**
* Get text email template
* @return string
*/
abstract public function getTextTemplate();
/**
* Get html email template
* @return string
*/
abstract public function getHTMLTemplate();
/**
* Get the footer component
* @return string
*/
public function buildFooter() {
global $wgEchoEmailFooterAddress;
return $this->decorator->decorateFooter( $wgEchoEmailFooterAddress, $this->user );
}
/**
* Getter method for email template component
* @return array
*/
public function getComponent() {
return $this->component;
}
/**
* Get the notification icon path
* @param $icon string
* @return string
*/
public static function getNotifIcon( $icon ) {
global $wgLang;
$iconUrl = EchoNotificationFormatter::getIconUrl( $icon, $wgLang->getDir() );
return wfExpandUrl( $iconUrl, PROTO_CANONICAL );
}
/**
* Attach an email decorator to the email mode object
* @param $decorator EchoEmailDecorator
*/
public function attachDecorator( EchoEmailDecorator $decorator ) {
$this->decorator = $decorator;
}
/**
* Format the message in the user's language
* @param $message string
* @param $user User
* @return Message
*/
public static function message( $message, User $user ) {
return wfMessage( $message )->inLanguage( $user->getOption( 'language' ) );
}
}
/**
* Entity that represents a single email delivery mode
*/
class EchoEmailSingle extends EchoEmailMode {
/**
* @var EchoBasicFormatter
*/
protected $notifFormatter;
/**
* @var EchoEvent
*/
protected $event;
/**
* @param $notifFormatter EchoBasicFormatter
* @param $event EchoEvent
* @param $user User
*/
public function __construct( EchoBasicFormatter $notifFormatter, EchoEvent $event, User $user ) {
parent::__construct( $user, array( 'emailIcon', 'intro', 'summary', 'action' ) );
$this->notifFormatter = $notifFormatter;
$this->event = $event;
}
/**
* Build the intro component
* @return string
*/
public function buildIntro() {
$bundle = $this->notifFormatter->getValue( 'bundleData' );
$email = $this->notifFormatter->getValue( 'email' );
if ( $bundle['use-bundle'] && $email['batch-bundle-body']['message'] ) {
$detail = $email['batch-bundle-body'];
} else {
$detail = $email['batch-body'];
}
$message = $this->notifFormatter->formatFragment(
$detail,
$this->event,
$this->user
);
return $this->decorator->decorateIntro( $message );
}
/**
* Build the summary component
* @return string
*/
public function buildSummary() {
return $this->decorator->decorateRevisionSnippet(
$this->notifFormatter->getRevisionSnippet(
$this->event,
$this->user
)
);
}
/**
* Build the action component
* @return string
*/
public function buildAction() {
$link = array();
$ranks = array( 'primary', 'secondary' );
foreach ( $ranks as $rank ) {
$message = $this->event->getLinkMessage( $rank );
// Valid call to action should have link text
if ( !$message ) {
continue;
}
$link[] = $this->decorator->decorateSingleAction(
$this->notifFormatter,
$this->event,
$this->user,
$rank,
$message
);
}
// Add some spacing between the two action links
$spacing = $this->decorator->getActionLinkSeparator();
return implode( $spacing . $spacing, $link );
}
/**
* Build the email icon component
* @return string
*/
public function buildEmailIcon() {
return EchoEmailMode::getNotifIcon( $this->notifFormatter->getValue( 'icon' ) );
}
/**
* {@inheritDoc}
*/
public function getTextTemplate() {
return <<< EOF
%%intro%%
%%summary%%
%%action%%
%%footer%%
EOF;
}
/**
* {@inheritDoc}
*/
public function getHTMLTemplate() {
$alignStart = $this->lang->alignStart();
return <<< EOF
<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<style>
@media only screen and (max-width: 480px){
table[id="email-container"]{max-width:600px !important; width:100% !important;}
}
</style>
</head><body>
<table cellspacing="0" cellpadding="0" border="0" width="100%" align="center" lang="{$this->lang->getCode()}" dir="{$this->lang->getDir()}">
<tr>
<td bgcolor="#E6E7E8"><center>
<br /><br />
<table cellspacing="0" cellpadding="0" border="0" width="600" id="email-container">
<tr>
<td bgcolor="#FFFFFF" width="5%">&nbsp;</td>
<td bgcolor="#FFFFFF" width="10%">&nbsp;</td>
<td bgcolor="#FFFFFF" width="80%" style="line-height:40px;">&nbsp;</td>
<td bgcolor="#FFFFFF" width="5%">&nbsp;</td>
</tr><tr>
<td bgcolor="#FFFFFF" rowspan="2">&nbsp;</td>
<td bgcolor="#FFFFFF" align="center" valign="top" rowspan="2"><img src="%%emailIcon%%" alt="" height="30" width="30"></td>
<td bgcolor="#FFFFFF" align="{$alignStart}" style="font-family: Arial, Helvetica, sans-serif; font-size:13px; line-height:20px; color:#6D6E70;">%%intro%%</td>
<td bgcolor="#FFFFFF" rowspan="2">&nbsp;</td>
</tr><tr>
<td bgcolor="#FFFFFF" align="{$alignStart}" style="font-family: Arial, Helvetica, sans-serif; line-height: 20px; font-weight: 600;">
<table cellspacing="0" cellpadding="0" border="0">
<tr>
<td bgcolor="#FFFFFF" align="{$alignStart}" style="font-family: Arial, Helvetica, sans-serif; padding-top: 8px; font-size:13px; font-weight: bold; color: #58585B;">
%%summary%%
</td>
</tr>
</table>
<table cellspacing="0" cellpadding="0" border="0">
<tr>
<td bgcolor="#FFFFFF" align="{$alignStart}" style="font-family: Arial, Helvetica, sans-serif; font-size:14px; padding-top: 25px;">
%%action%%
</td>
</tr>
</table>
</td>
</tr><tr>
<td bgcolor="#FFFFFF">&nbsp;</td>
<td bgcolor="#FFFFFF">&nbsp;</td>
<td bgcolor="#FFFFFF" style="line-height:40px;">&nbsp;</td>
<td bgcolor="#FFFFFF">&nbsp;</td>
</tr><tr>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td align="{$alignStart}" style="font-family: Arial, Helvetica, sans-serif; font-size:10px; line-height:13px; color:#6D6E70; padding:10px 20px;"><br />
%%footer%%
<br /><br />
</td>
<td>&nbsp;</td>
</tr><tr>
<td colspan="4">&nbsp;</td>
</tr>
</table>
<br><br></center>
</td>
</tr>
</table>
</body></html>
EOF;
}
}
/**
* Class that represents email digest delivery mode
*/
class EchoEmailDigest extends EchoEmailMode {
/**
* @var string
* The mode of email digest, 'weekly' or 'daily'
*/
protected $digestMode;
/**
* @var array
* Raw email digest list
*/
protected $rawDigestList;
/**
* @param $user User
* @param $rawDigestList array the raw notification event list
* @param $digestMode string 'daily'/'weekly'
*/
public function __construct( User $user, array $rawDigestList, $digestMode = 'daily' ) {
parent::__construct( $user, array( 'intro', 'digestList', 'action' ) );
// Some data validation
if ( !in_array( $digestMode, array( 'daily', 'weekly' ) ) ) {
$digestMode = 'daily';
}
$this->digestMode = $digestMode;
$this->rawDigestList = $rawDigestList;
}
/**
* Build the intro component
* @return string
*/
public function buildIntro() {
// Give grep a chance to find the usages:
// echo-email-batch-body-intro-daily, echo-email-batch-body-intro-weekly
$message = EchoEmailMode::message(
'echo-email-batch-body-intro-' . $this->digestMode, $this->user
)->params( $this->user->getName() );
return $this->decorator->decorateIntro( $message );
}
/**
* Build the digestList component
* @return string
*/
public function buildDigestList() {
if ( !$this->rawDigestList ) {
return '';
}
return $this->decorator->decorateDigestList( $this->rawDigestList, $this->user );
}
/**
* Build the action component
* @return string
*/
public function buildAction() {
$title = SpecialPage::getTitleFor( 'Notifications' );
return $this->decorator->decorateDigestAction( $title, $this->user );
}
/**
* {@inheritDoc}
*/
public function getTextTemplate() {
return <<< EOF
%%intro%%
%%digestList%%
%%action%%
%%footer%%
EOF;
}
/**
* {@inheritDoc}
*/
public function getHTMLTemplate() {
$alignStart = $this->lang->alignStart();
return <<< EOF
<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<style>
@media only screen and (max-width: 480px){
table[id="email-container"]{max-width:600px !important; width:100% !important;}
}
</style>
</head><body>
<table cellspacing="0" cellpadding="0" border="0" width="100%" align="center" lang="{$this->lang->getCode()}" dir="{$this->lang->getDir()}">
<tr>
<td bgcolor="#E6E7E8"><center>
<br /><br />
<table cellspacing="0" cellpadding="0" border="0" width="600" id="email-container">
<tr>
<td bgcolor="#FFFFFF" width="5%">&nbsp;</td>
<td bgcolor="#FFFFFF" width="6%">&nbsp;</td>
<td bgcolor="#FFFFFF" width="79%" style="line-height:40px;">&nbsp;</td>
<td bgcolor="#FFFFFF" width="10%">&nbsp;</td>
</tr>
<tr>
<td bgcolor="#FFFFFF" rowspan="2">&nbsp;</td>
<td bgcolor="#FFFFFF" rowspan="2">&nbsp;</td>
<td bgcolor="#FFFFFF" align="center" style="font-family: Arial, Helvetica, sans-serif; font-size:13px; line-height:20px; color:#6D6E70; text-align: center;">%%intro%%</td>
<td bgcolor="#FFFFFF" rowspan="2">&nbsp;</td>
</tr>
<tr>
<td bgcolor="#FFFFFF" align="{$alignStart}" style="font-family: Arial, Helvetica, sans-serif; line-height: 20px; font-weight: 600;">
<table cellspacing="0" cellpadding="0" border="0" width="100%">
<tr>
<td bgcolor="#FFFFFF" align="{$alignStart}" style="font-family: Arial, Helvetica, sans-serif; font-size:13px; color: #58585B; padding-top: 25px;">
%%digestList%%
</td>
</tr>
</table>
<br /><br />
</td>
</tr>
<tr>
<td bgcolor="#FFFFFF">&nbsp;</td>
<td bgcolor="#FFFFFF">&nbsp;</td>
<td bgcolor="#FFFFFF" style="line-height:60px;" align="center">%%action%%</td>
<td bgcolor="#FFFFFF">&nbsp;</td>
</tr>
<tr>
<td bgcolor="#FFFFFF">&nbsp;</td>
<td bgcolor="#FFFFFF">&nbsp;</td>
<td bgcolor="#FFFFFF" style="line-height:40px;">&nbsp;</td>
<td bgcolor="#FFFFFF">&nbsp;</td>
</tr>
<tr>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td align="{$alignStart}" style="font-family: Arial, Helvetica, sans-serif; font-size:10px; line-height:13px; color:#6D6E70; padding: 10px 20px;"><br />
%%footer%%
<br /><br />
</td>
<td>&nbsp;</td>
</tr>
<tr>
<td colspan="4">&nbsp;</td>
</tr>
</table>
<br><br></center>
</td>
</tr>
</table>
</body></html>
EOF;
}
}
/**
* Email decorator interface
*/
interface EchoEmailDecorator {
/**
* Decorate the intro for all modes
* @param $message Message the intro message object
* @return string
*/
public function decorateIntro( $message );
/**
* Decorate the digest list for digest mode
* @param $digestList array
* @param $user User
* @return string
*/
public function decorateDigestList( $digestList, User $user );
/**
* Decorate the primary action for digest mode
* @param $title Title
* @param $user User
* @return string
*/
public function decorateDigestAction( $title, User $user );
/**
* Decorate the footer for all mode
* @param $address string
* @param $user User
* @return string
*/
public function decorateFooter( $address, User $user );
/**
* Decorate the actions for single mode
* @param $notifFormatter EchoBasicFormatter
* @param $event EchoEvent
* @param $user User
* @param $rank string
* @param $message string
* @return string
*/
public function decorateSingleAction( $notifFormatter, EchoEvent $event, User $user, $rank, $message );
/**
* Decorate a revision snippet
* @param string $snippet the raw revision snippet
* @return string
*/
public function decorateRevisionSnippet( $snippet );
/**
* Get the spacing for between action links
* @return string
*/
public function getActionLinkSeparator();
}
/**
* Text email decorator
*/
class EchoTextEmailDecorator implements EchoEmailDecorator {
/**
* {@inheritDoc}
*/
public function decorateIntro( $message ) {
return $message->text();
}
/**
* {@inheritDoc}
*/
public function decorateDigestList( $digestList, User $user ) {
$result = array();
// build the text section for each category
foreach ( $digestList as $category => $notifs ) {
$output = EchoEmailMode::message( 'echo-category-title-' . $category, $user )->numParams( count( $notifs ) )->text()
. EchoEmailMode::message( 'colon-separator', $user )->text() . "\n";
foreach ( $notifs as $notif ) {
$output .= "\n " . EchoEmailMode::message( 'echo-email-batch-bullet', $user )->text() . ' ' . $notif['batch-body'];
}
$result[] = $output;
}
// for prepending and appending 'echo-email-batch-separator'
$result = array_merge( array( '' ), $result, array( '' ) );
return trim(
implode(
"\n\n" . EchoEmailMode::message( 'echo-email-batch-separator', $user )->text() . "\n\n",
$result
)
);
}
/**
* {@inheritDoc}
*/
public function decorateDigestAction( $title, User $user ) {
return EchoEmailMode::message( 'echo-email-batch-link-text-view-all-notifications', $user )->text() .
EchoEmailMode::message( 'colon-separator', $user )->text() .
'<' .
$title->getFullURL( '', false, PROTO_CANONICAL ) .
'>';
}
/**
* {@inheritDoc}
*/
public function decorateFooter( $address, User $user ) {
return EchoEmailMode::message( 'echo-email-footer-default', $user )
->params(
$address,
EchoEmailMode::message( 'echo-email-batch-separator', $user )->text()
)
->text();
}
/**
* {@inheritDoc}
*/
public function decorateSingleAction( $notifFormatter, EchoEvent $event, User $user, $rank, $message ) {
$url = $notifFormatter->getLink( $event, $user, $rank, false, true );
return EchoEmailMode::message( $message, $user )->text() .
EchoEmailMode::message( 'colon-separator', $user )->text() .
'<' .
$notifFormatter->sanitizeEmailLink( $url ) .
'>';
}
/**
* {@inheritDoc}
*/
public function decorateRevisionSnippet( $snippet ) {
// Doing nothing now, but there is a potential to wrap the text
// around snippet with quote in plain text email
return $snippet;
}
/**
* {@inheritDoc}
*/
public function getActionLinkSeparator() {
return "\n";
}
}
/**
* HTML email decorator
*/
class EchoHTMLEmailDecorator implements EchoEmailDecorator {
/**
* {@inheritDoc}
*/
public function decorateIntro( $message ) {
return nl2br( $message->parse() );
}
/**
* {@inheritDoc}
*/
public function decorateDigestList( $digestList, User $user ) {
$result = array();
// build the html section for each category
foreach ( $digestList as $category => $notifs ) {
$output = $this->applyStyleToCategory(
EchoEmailMode::message( 'echo-category-title-' . $category, $user )
->numParams( count( $notifs ) )
->escaped()
);
foreach ( $notifs as $notif ) {
$output .= "\n" . $this->applyStyleToEvent( $notif );
}
$result[] = '<table border="0" width="100%">' . $output . '</table>';
}
return trim( implode( "\n", $result ) );
}
/**
* {@inheritDoc}
*/
public function decorateDigestAction( $title, User $user ) {
/*
* Linker::link() will try to figure out if $title already exists
* (Title::isKnown) and alter the link depending on the outcome
* (&action=edit&redlink=1)
* Notifications are usually triggered by new content, so we better
* make damn sure that slave lag doesn't mess that up. Especially
* in emails, which we can't rerender once they've been sent.
* I'll force the status for this $title to be read from master, so
* Linker::link is guaranteed to get the correct exists() result.
*/
$title->exists( wfGetLB()->hasOrMadeRecentMasterChanges() ? Title::GAID_FOR_UPDATE : 0 );
return Linker::link(
$title,
EchoEmailMode::message( 'echo-email-batch-link-text-view-all-notifications', $user )->escaped(),
array( 'style' => $this->getPrimaryLinkCSS() ),
array(),
array( 'https' )
);
}
/**
* {@inheritDoc}
*/
public function decorateFooter( $address, User $user ) {
$title = SpecialPage::getTitleFor( 'Preferences' );
$title->setFragment( "#mw-prefsection-echo" );
return EchoEmailMode::message( 'echo-email-footer-default-html', $user )
->params( $address )
->rawParams( $title->getFullURL( '', false, PROTO_HTTPS ) )
->text();
}
/**
* {@inheritDoc}
*/
public function decorateSingleAction( $notifFormatter, EchoEvent $event, User $user, $rank, $message ) {
if ( $rank === 'primary' ) {
$style = $this->getPrimaryLinkCSS();
} else {
$style = $this->getSecondaryLinkCSS();
}
return $notifFormatter->getLink( $event, $user, $rank, false, false, $style );
}
/**
* {@inheritDoc}
*/
public function decorateRevisionSnippet( $snippet ) {
return htmlspecialchars( $snippet );
}
/**
* {@inheritDoc}
*/
public function getActionLinkSeparator() {
return "&nbsp;";
}
/**
* The style for primary link
* @return string
*/
protected function getPrimaryLinkCSS() {
return 'cursor:pointer; text-align:center; text-decoration:none; padding:.45em 1.2em .45em;
color:#D9EEF7; background:#3366BB; font-family: Arial, Helvetica, sans-serif;font-size: 13px;';
}
/**
* The style for secondary link
* @return string
*/
protected function getSecondaryLinkCSS() {
return 'text-decoration: none;font-size: 10px;font-family: Arial, Helvetica, sans-serif; color: #808184';
}
/**
* Apply style to notification category header
* @param $category string
* @return string
*/
protected function applyStyleToCategory( $category ) {
return <<< EOF
<tr>
<td colspan="2" style="color: #A87B4F; font-weight: normal; font-size: 13px; padding-top: 15px;">
$category <br />
<hr style="background-color:#FFFFFF; color:#FFFFFF; border: 1px solid #F2F2F2;" />
</td>
</tr>
EOF;
}
/**
* Apply style to individual notification event
* @param $notif array an array containts keys: icon, batch-body, batch-body-html
* @return string
*/
protected function applyStyletoEvent( $notif ) {
// notification icon
$icon = EchoEmailMode::getNotifIcon( $notif['icon'] );
// notification text
$text = $notif['batch-body-html'];
return <<< EOF
<tr>
<td width="30">
<img src="$icon" width="30" height="30" style="vertical-align:middle;">
</td>
<td style="font-family: Arial, Helvetica, sans-serif; font-size:13px; color: #58585B;">
$text
</td>
</tr>
EOF;
}
}

View file

@ -392,8 +392,10 @@ class EchoNotificationController {
* @param string $type The type of notification being distributed (e.g. email, web)
* @return string|array The formatted notification, or an array of subject
* and body (for emails), or an error message
* @deprecated
*/
public static function formatNotification( EchoEvent $event, User $user, $format = 'text', $type = 'web' ) {
wfDeprecated( 'EchoNotificationController::formatNotification', '1.28', 'Echo' );
$eventType = $event->getType();
$res = '';

View file

@ -1,903 +0,0 @@
<?php
/**
* @Todo - Consider having $event/$user as class properties since the formatter is
* always tied to these two entities, in this case, we won't have to pass it around
* in all the internal method
* @Todo - Instance variable $distributionType has been added, the local distribution
* type variable $type passed along all the protected/private method should be removed
* from all formatters
*/
class EchoBasicFormatter extends EchoNotificationFormatter {
/**
* Notification title data for archive page
* @var array
*/
protected $title;
/**
* Notification title data for bundling ( archive page )
*/
protected $bundleTitle;
/**
* Notification email data
* @var array
*/
protected $email;
/**
* Notification icon for each type
* @var string
*/
protected $icon;
/**
* @todo make this private
* The language to format a message, default language
* is the current language
* @var mixed Language code or Language object
*/
protected $language;
/**
* Data for constructing bundle message, data in this array
* should be used in function processParams()
* @var array
*/
protected $bundleData = array(
'use-bundle' => false,
'raw-data-count' => 1
);
/**
* Max number of raw bundle data to query for each bundle event
*/
protected static $maxRawBundleData = 250;
/**
* @param array
*/
public function __construct( $params ) {
parent::__construct( $params );
if ( !isset( $params['title-message'] ) ) {
// Required, no default value set
throw new InvalidArgumentException( "'title-message' parameter not set" );
}
// Set up default params if any are missing
$params = $this->setDefaultParams( $params );
// Title for archive page
$this->title = array(
'message' => $params['title-message'],
'params' => $params['title-params']
);
// Bundle title for both archive page
$this->bundleTitle = array(
'message' => $params['bundle-message'],
'params' => $params['bundle-params']
);
// Notification payload data, eg, summary
$this->payload = $params['payload'];
// Notification email subject and body
$this->email = array(
'subject' => array(
'message' => $params['email-subject-message'],
'params' => $params['email-subject-params']
),
'batch-body' => array(
'message' => $params['email-body-batch-message'],
'params' => $params['email-body-batch-params']
),
'batch-bundle-body' => array(
'message' => $params['email-body-batch-bundle-message'],
'params' => $params['email-body-batch-bundle-params']
)
);
// Notification icon for the event type
$this->icon = $params['icon'];
}
/**
* Internal function for setting notification default params
* @param $params array
* @return array
*/
protected function setDefaultParams( $params ) {
$params += array(
'title-params' => array(),
'bundle-message' => '',
'bundle-params' => array(),
'payload' => array(),
'email-subject-message' => 'echo-email-subject-default',
'email-subject-params' => array(),
'email-body-batch-message' => 'echo-email-batch-body-default',
'email-body-batch-params' => array(),
'email-body-batch-bundle-message' => '',
'email-body-batch-bundle-params' => array(),
'icon' => 'placeholder'
);
return $params;
}
/**
* Apply some custom change before formatting, child class overwriting this method
* should always invoke a call to the parent method unless child class wants to overwrite
* the default completely
*
* @param $event EchoEvent that the notification is for.
* @param $user User to format the notification for.
* @param $type string deprecated
*/
protected function applyChangeBeforeFormatting( EchoEvent $event, User $user, $type ) {
// Use the bundle message if use-bundle is true and there is a bundle message
$this->generateBundleData( $event, $user, $type );
if ( $this->bundleData['use-bundle'] && $this->bundleTitle['message'] ) {
$this->title = $this->bundleTitle;
}
}
/**
* Formats a notification
*
* @param $event EchoEvent that the notification is for.
* @param $user User to format the notification for.
* @param $type string The type of notification being distributed (e.g. email, web)
* @return array|string
*/
public function format( $event, $user, $type ) {
$this->setDistributionType( $type );
$this->applyChangeBeforeFormatting( $event, $user, $type );
if ( $this->outputFormat === 'email' ) {
return $this->formatEmail( $event, $user, $type );
}
if ( $this->outputFormat === 'text' ) {
return $this->formatNotificationTitle( $event, $user )->text();
}
$iconUrl = $this->getIconUrl( $this->icon, $this->getLanguage()->getDir() );
// Assume html as the format for the notification
$output = Html::element(
'img',
array(
'class' => "mw-echo-icon",
'src' => $iconUrl,
)
);
// Build the notification title
$content = Xml::tags(
'div',
array( 'class' => 'mw-echo-title' ),
$this->formatNotificationTitle( $event, $user )->parse()
) . "\n";
// Build the notification payload
$payload = '';
foreach ( $this->payload as $payloadComponent ) {
$payload .= $this->formatPayload( $payloadComponent, $event, $user );
}
if ( $payload !== '' ) {
$content .= Xml::tags( 'div', array( 'class' => 'mw-echo-payload' ), $payload ) . "\n";
}
// Add footer (timestamp and secondary link)
$content .= $this->formatFooter( $event, $user );
$output .= Xml::tags( 'div', array( 'class' => 'mw-echo-content' ), $content ) . "\n";
// The state div is used to visually indicate read or unread status. This is
// handled in a separate element than the notification element so that things
// like the close box won't inherit the greyed out opacity (which can't be reset).
$output = Xml::tags( 'div', array( 'class' => 'mw-echo-state' ), $output ) . "\n";
return $output;
}
/**
* @param $event EchoEvent
* @param $user User
* @return string
*/
protected function formatNotificationTitle( $event, $user ) {
return $this->formatFragment( $this->title, $event, $user );
}
/**
* Create text version and/or html version for email notification
*
* @param $event EchoEvent
* @param $user User
* @param $type string deprecated
* @return array
*/
protected function formatEmail( $event, $user, $type ) {
// Email should be always sent in user language
$this->language = $user->getOption( 'language' );
// Email digest
if ( $this->distributionType === 'emaildigest' ) {
return $this->formatEmailDigest( $event, $user );
}
// Echo single email
$emailSingle = new EchoEmailSingle( $this, $event, $user );
$textEmailFormatter = new EchoTextEmailFormatter( $emailSingle );
// Update the distribution type to emailsubject when formatting
// email subject
// @FIXME - Find a better way to do this
$distributionType = $this->distributionType;
$this->setDistributionType( 'emailsubject' );
$subject = $this->formatFragment( $this->email['subject'], $event, $user )->text();
$this->setDistributionType( $distributionType );
$content = array(
// Single email subject, there is no need to to escape it for either html
// or text email since it's always treated as plain text by mail client
'subject' => $subject,
// Single email text body
'body' => $textEmailFormatter->formatEmail(),
);
$format = MWEchoNotifUser::newFromUser( $user )->getEmailFormat();
if ( $format == EchoEmailFormat::HTML ) {
$htmlEmailFormatter = new LegacyEchoHTMLEmailFormatter( $emailSingle );
$outputFormat = $this->outputFormat;
$this->setOutputFormat( 'htmlemail' );
// Add single email html body if user prefers html format
$content['body'] = array(
'text' => $content['body'],
'html' => $htmlEmailFormatter->formatEmail()
);
$this->setOutputFormat( $outputFormat );
}
return $content;
}
/**
* Format text and/or html verion of email digest fragment for this event
* @param $event EchoEvent
* @param $user User
* @return array
*/
protected function formatEmailDigest( $event, $user ) {
if ( $this->bundleData['use-bundle'] && $this->email['batch-bundle-body'] ) {
$key = $this->email['batch-bundle-body'];
} else {
$key = $this->email['batch-body'];
}
// Email digest text body
$content = array( 'batch-body' => $this->formatFragment( $key, $event, $user )->text() );
$format = MWEchoNotifUser::newFromUser( $user )->getEmailFormat();
if ( $format == EchoEmailFormat::HTML ) {
$outputFormat = $this->outputFormat;
$this->setOutputFormat( 'htmlemail' );
$content['batch-body-html'] = $this->formatFragment( $key, $event, $user )->parse();
$content['icon'] = $this->icon;
$this->setOutputFormat( $outputFormat );
}
return $content;
}
/**
* Get Message object in the desired language, use this method instead
* of wfMessage() if a message would be used in either web or email
* @param $msgStr string message string
* @return Message
*/
public function getMessage( $msgStr ) {
return wfMessage( $msgStr )->inLanguage( $this->getLanguage() );
}
/**
* @return Language
*/
public function getLanguage() {
global $wgLang;
// @todo we should always set this
if ( $this->language ) {
return wfGetLangObj( $this->language );
}
// Make sure we unstub first
StubObject::unstub( $wgLang );
return $wgLang;
}
/**
* Creates a notification fragment based on a message and parameters
*
* @param $details array An i18n message and parameters to pass to the message
* @param $event EchoEvent that the notification is for.
* @param $user User to format the notification for.
* @return Message
*/
public function formatFragment( $details, $event, $user ) {
$message = $this->getMessage( $details['message'] );
$this->processParams( $details['params'], $event, $message, $user );
return $message;
}
/**
* Formats the payload of a notification, child method overwriting this method should
* always call this method in default case so they can use the payload defined in this
* function as well
* @param $payload string
* @param $event EchoEvent
* @param $user User
* @return string
*/
protected function formatPayload( $payload, $event, $user ) {
switch ( $payload ) {
case 'summary':
$revisionSnippet = $this->getRevisionSnippet( $event, $user );
if ( $revisionSnippet ) {
return Xml::tags(
'div',
array( 'class' => 'mw-echo-edit-summary' ),
Xml::tags(
'span', array( 'class' => 'comment' ),
htmlspecialchars( $revisionSnippet )
)
);
} else {
return '';
}
break;
case 'comment-text':
return $this->formatCommentText( $event, $user );
break;
default:
return '';
}
}
/**
* Extract the comment left by a user on a talk page from the event.
* @param $event EchoEvent The event to format the comment of
* @param $user User The user to format content for
* @return string Up to the first 200 characters of the comment
*/
protected function formatCommentText( EchoEvent $event, $user ) {
if ( !$event->userCan( Revision::DELETED_TEXT, $user ) ) {
return $this->getMessage( 'echo-rev-deleted-text-view' )->text();
}
$extra = $event->getExtra();
if ( !isset( $extra['content'] ) ) {
return '';
}
$content = EchoDiscussionParser::stripHeader( $extra['content'] );
$content = EchoDiscussionParser::stripSignature( $content );
$content = EchoDiscussionParser::stripIndents( $content );
return EchoDiscussionParser::getTextSnippet( $content, $this->getLanguage(), 200 );
}
/**
* Extract the subject anchor (linkable portion of the edited page) from
* the event.
*
* @param $event EchoEvent The event to format the subject anchor of
* @return string The anchor on page, or an empty string
*/
protected function formatSubjectAnchor( EchoEvent $event ) {
global $wgParser, $wgUser;
if ( !$event->userCan( Revision::DELETED_TEXT, $wgUser ) ) {
return $this->getMessage( 'echo-rev-deleted-text-view' )->text();
}
$extra = $event->getExtra();
if ( empty( $extra['section-title'] ) ) {
return '';
}
// Strip out #, keeping # in the i18n message makes it look more clear
return substr( $wgParser->guessLegacySectionNameFromWikiText( $extra['section-title'] ), 1 );
}
/**
* Build the footer for the notification (timestamp and secondary link)
* @param EchoEvent $event
* @param User $user The user to format the notification for.
* @return String HTML
*/
protected function formatFooter( $event, $user ) {
// Default footer is timestamp
$footer = $this->formatTimestamp( $event->getTimestamp() );
$secondaryLink = $this->getLink( $event, $user, 'secondary' );
if ( $secondaryLink ) {
$footer = $this->getLanguage()->pipeList( array( $footer, $secondaryLink ) );
}
return Xml::tags( 'div', array( 'class' => 'mw-echo-notification-footer' ), $footer ) . "\n";
}
/**
* Generate links based on output format and passed properties
* $event EchoEvent
* $message Message
* $props array
*/
protected function setTitleLink( $event, $message, $props = array() ) {
$title = $event->getTitle();
if ( !$title ) {
$message->params( $this->getMessage( 'echo-no-title' )->text() );
return;
}
if ( !isset( $props['fragment'] ) ) {
$props['fragment'] = $this->formatSubjectAnchor( $event );
}
$link = $this->buildLinkParam( $title, $props );
$message->params( $link );
}
/**
* Build a link, to be used as message parameter, based on output format and
* passed properties. Return value of this function can be used as parameter
* for Message::params()
* $title Title
* $props array
*/
protected function buildLinkParam( $title, $props = array() ) {
$param = array();
if ( isset( $props['param'] ) ) {
$param = (array)$props['param'];
}
if ( isset( $props['fragment'] ) ) {
$fragment = $props['fragment'];
$title->setFragment( "#$fragment" );
}
if ( in_array( $this->outputFormat, array( 'htmlemail' ) ) ) {
$attribs = array();
if ( isset( $props['attribs'] ) ) {
$attribs = (array)$props['attribs'];
}
if ( isset( $props['linkText'] ) ) {
$linkText = $props['linkText'];
} else {
$linkText = htmlspecialchars( $title->getPrefixedText() );
}
$options = array();
if ( $this->outputFormat === 'htmlemail' ) {
$options = array( 'https' );
}
return array( Message::rawParam( Linker::link( $title, $linkText, $attribs, $param, $options ) ) );
} elseif ( $this->outputFormat === 'email' ) {
$url = $title->getFullURL( $param, false, PROTO_HTTPS );
return $this->sanitizeEmailLink( $url );
} else {
return $title->getFullURL( $param );
}
}
/**
* Plain text email in some mail client is misinterpreting the ending
* punctuation, this function would encode the last character
*
* @param $url string
*
* @return string
*/
public function sanitizeEmailLink( $url ) {
// $url should contain all ascii characters now, it's safe to use substr()
$lastChar = substr( $url, -1 );
if ( $lastChar && !ctype_alnum( $lastChar ) ) {
$lastChar = str_replace(
array( '.', '-', '(', ';', '!', ':', ',' ),
array( '%2E', '%2D', '%28', '%3B', '%21', '%3A', '%2C' ),
$lastChar
);
$url = substr( $url, 0, -1 ) . $lastChar;
}
return $url;
}
/**
* Get raw bundle data for an event so it can be manipulated
* @param EchoEvent
* @param User
* @param string deprecated
* @return EchoEvent[]|bool
*/
protected function getRawBundleData( $event, $user, $type ) {
// We should keep bundling for events as long as it has bundle hash
// even for events with bundling switched to off, this is mainly for
// historical data
if ( !$event->getBundleHash() ) {
return false;
}
$eventMapper = new EchoEventMapper();
$events = $eventMapper->fetchByUserBundleHash(
$user, $event->getBundleHash(), $this->distributionType, 'DESC', self::$maxRawBundleData
);
if ( $events ) {
$this->bundleData['raw-data-count'] += count( $events );
// Distribution types other than web include the base event
// in the result already, decrement it by one
if ( $this->distributionType !== 'web' ) {
$this->bundleData['raw-data-count']--;
}
}
return $events;
}
/**
* Construct the bundle data for an event, by default, the group iterator
* is agent, eg, by user A and x others. custom formatter can overwrite
* this function to use a differnt group iterator such as title, namespace
*
* @param EchoEvent
* @param User
* @param string deprecated
* @throws MWException
*/
protected function generateBundleData( $event, $user, $type ) {
$data = $this->getRawBundleData( $event, $user, $type );
// Default the last raw data to false, which means there is no
// bundle data other than the base
$this->bundleData['last-raw-data'] = false;
if ( !$data ) {
return;
}
$agents = array();
$agent = $event->getAgent();
if ( $agent ) {
if ( $agent->isAnon() ) {
$agents[$agent->getName()] = $agent->getName();
} else {
$agents[$agent->getId()] = $agent->getId();
}
} else {
throw new MWException( "Agent is required for bundling notification!" );
}
// Initialize with 1 for the agent of current event
$count = 1;
foreach ( $data as $evt ) {
if ( $evt->getAgent() ) {
if ( $evt->getAgent()->isAnon() ) {
$key = $evt->getAgent()->getName();
} else {
$key = $evt->getAgent()->getId();
}
if ( !isset( $agents[$key] ) ) {
$agents[$key] = $key;
$count++;
}
}
$this->bundleData['last-raw-data'] = $evt;
}
$this->bundleData['agent-other-count'] = $count - 1;
if ( $count > 1 ) {
$this->bundleData['use-bundle'] = true;
}
// If there is more raw data than we requested, that means we have not
// retrieved the very last raw record, set the key back to null
if ( count( $data ) >= self::$maxRawBundleData ) {
$this->bundleData['last-raw-data'] = null;
}
}
/**
* @return array
*/
public function getBundleData() {
return $this->bundleData;
}
/**
* Convert the parameters into real values and pass them into the message
*
* @param $params array
* @param $event EchoEvent
* @param $message Message
* @param $user User
*/
protected function processParams( $params, $event, $message, $user ) {
foreach ( $params as $param ) {
$this->processParam( $event, $param, $message, $user );
}
}
/**
* Process a parameter that should be escaped for display except for use
* cases like plain text email and email subject
*
* @param $message Message
* @param $paramContent string
*/
protected function processParamEscaped( $message, $paramContent ) {
// Plain text email and email subject do not need to be escaped
if ( $this->outputFormat !== 'email' && $this->distributionType !== 'emailsubject' ) {
$paramContent = htmlspecialchars( $paramContent );
}
$message->rawParams( $paramContent );
}
/**
* Get the URL for the primary or secondary link for an event
*
* @param EchoEvent $event
* @param User $user The user receiving the notification
* @param String $rank 'primary' or 'secondary' (default is 'primary')
* @param boolean $local True to return a local (relative) URL, false to
* return a full URL (for email for example) (default is true)
* @param boolean $urlOnly True to return only the URL without the <a> tag,
* false to return a full anchor link (default is false)
* @param String $style A style attribute to apply to the anchor, e.g.
* 'border: 1px solid green; text-decoration: none;' (optional)
* @return String URL for link, or HTML for anchor tag, or empty string
*/
public function getLink( $event, $user, $rank = 'primary', $local = true, $urlOnly = false, $style = '' ) {
$destination = $event->getLinkDestination( $rank );
if ( !$destination ) {
return '';
}
// Get link parameters based on the destination
list( $target, $query ) = $this->getLinkParams( $event, $user, $destination );
// Note that $target can be a Title object or a raw url
if ( !$target ) {
return '';
}
if ( $urlOnly ) {
if ( is_string( $target ) ) {
// A raw url was passed back
return $target;
}
if ( $local ) {
return $target->getLinkURL( $query );
} else {
return $target->getFullURL( $query, false, PROTO_HTTPS );
}
} else {
$message = $this->getMessage( $event->getLinkMessage( $rank ) )->text();
$attribs = array( 'class' => "mw-echo-notification-{$rank}-link" );
if ( $style ) {
$attribs['style'] = $style;
}
$options = array();
// If local is false, return an absolute url using HTTP protocol
if ( !$local ) {
$options[] = 'https';
}
if ( is_string( $target ) ) {
$attribs['href'] = wfAppendQuery( $target, $query );
return Html::element( 'a', $attribs, $message );
} else {
return Linker::link( $target, $message, $attribs, $query, $options );
}
}
}
/**
* Helper function for getLink()
*
* @param EchoEvent $event
* @param User $user The user receiving the notification
* @param String $destination The destination type for the link, e.g. 'agent'
* @return Array including target and query parameters. Note that target can
* be either a Title or a full url
*/
protected function getLinkParams( $event, $user, $destination ) {
$target = null;
$query = array();
$title = $event->getTitle();
// Set up link parameters based on the destination
switch ( $destination ) {
case 'agent':
if ( $event->getAgent() ) {
$target = $event->getAgent()->getUserPage();
}
break;
case 'title':
$target = $title;
break;
case 'section':
$target = $title;
if ( $target ) {
$fragment = $this->formatSubjectAnchor( $event );
if ( $fragment ) {
$target->setFragment( "#$fragment" );
}
}
break;
case 'diff':
$eventData = $event->getExtra();
if ( isset( $eventData['revid'] ) && $title ) {
$target = $title;
// Explicitly set fragment to empty string for diff links, $title is
// passed around by reference, it may end up using fragment set from
// other parameters
$target->setFragment( '#' );
$query = array(
'oldid' => 'prev',
'diff' => $eventData['revid'],
);
$data = $this->getBundleLastRawData( $event, $user );
if ( $data ) {
$extra = $data->getExtra();
if ( isset( $extra['revid'] ) ) {
$oldId = $target->getPreviousRevisionID( $extra['revid'] );
// The diff engine doesn't provide a way to diff against a null revision.
// In this case, just fall back old id to the first revision
if ( !$oldId ) {
$oldId = $extra['revid'];
}
if ( $oldId < $eventData['revid'] ) {
$query['oldid'] = $oldId;
}
}
}
}
break;
}
return array( $target, $query );
}
/**
* Get the last echo event in a set of bundling data. When bundling notifications,
* we mostly only need the very first notification, which is the bundle base.
* In some cases, like talk notification diff, Flow notificaiton first unread post,
* we need data from the very last notification.
*
* @param EchoEvent
* @param User
* @return EchoEvent|boolean false for none
*/
protected function getBundleLastRawData( EchoEvent $event, User $user ) {
if ( $event->getBundleHash() ) {
// First try cache data from preivous query
if ( isset( $this->bundleData['last-raw-data'] ) ) {
$data = $this->bundleData['last-raw-data'];
// Then try to query the storage
} else {
$eventMapper = new EchoEventMapper();
$data = $eventMapper->fetchByUserBundleHash(
$user, $event->getBundleHash(), $this->distributionType, 'ASC', 1
);
if ( $data ) {
$data = reset( $data );
}
}
if ( $data ) {
return $data;
}
}
return false;
}
/**
* Get the style for standard links in html email
* @return string
*/
public function getHTMLLinkStyle() {
return 'text-decoration: none; color: #3A68B0;';
}
/**
* Helper function for processParams()
*
* @param $event EchoEvent
* @param $param string
* @param $message Message
* @param $user User
* @throws MWException
*/
protected function processParam( $event, $param, $message, $user ) {
if ( $param === 'agent' ) {
$agent = $event->getAgent();
if ( !$agent ) {
$message->params( $this->getMessage( 'echo-no-agent' )->text() );
} elseif ( !$event->userCan( Revision::DELETED_USER, $user ) ) {
$message->params( $this->getMessage( 'rev-deleted-user' )->text() );
} else {
if ( $this->outputFormat === 'htmlemail' ) {
$message->rawParams(
Linker::link(
$agent->getUserPage(),
$agent->getName(),
array( 'style' => $this->getHTMLLinkStyle() ),
array(),
array( 'https' )
)
);
} else {
$message->params( $agent->getName() );
}
}
// example: {7} others, {99+} others
// agent-other-display is no longer needed for new messags, but kept for
// backwards compatibility.
} elseif ( $param === 'agent-other-count' || $param === 'agent-other-display' ) {
$message->numParams(
EchoNotificationController::getCappedNotificationCount( $this->bundleData['agent-other-count'] )
);
} elseif ( $param === 'user' ) {
$message->params( $user->getName() );
} elseif ( $param === 'title' ) {
$title = $event->getTitle();
if ( !$title ) {
$message->params( $this->getMessage( 'echo-no-title' )->text() );
} else {
if ( $this->outputFormat === 'htmlemail' ) {
$props = array(
'attribs' => array( 'style' => $this->getHTMLLinkStyle() )
);
$this->setTitleLink( $event, $message, $props );
} else {
$message->params( $this->formatTitle( $title ) );
}
}
} elseif ( $param === 'titlelink' ) {
$this->setTitleLink( $event, $message );
} elseif ( $param === 'text-notification' ) {
$oldOutputFormat = $this->outputFormat;
$this->setOutputFormat( 'text' );
// $type is ignored in this class
$textNotification = $this->format( $event, $user, '' );
$this->setOutputFormat( $oldOutputFormat );
$message->params( $textNotification );
} else {
throw new MWException( "Unrecognised parameter $param" );
}
}
/**
* Getter method
*
* @param $key string
*
* @throws MWException
* @return mixed
*/
public function getValue( $key ) {
if ( !property_exists( $this, $key ) ) {
throw new MWException( "Call to non-existing property $key in " . get_class( $this ) );
}
return $this->$key;
}
}

View file

@ -1,34 +0,0 @@
<?php
class EchoCommentFormatter extends EchoEditFormatter {
public function __construct( $params ) {
parent::__construct( $params );
}
/**
* @param EchoEvent $event
* @param $param
* @param Message $message
* @param User $user
*/
protected function processParam( $event, $param, $message, $user ) {
if ( $param === 'content-page' ) {
if ( $event->getTitle() ) {
$message->params( $event->getTitle()->getSubjectPage()->getPrefixedText() );
} else {
$message->params( '' );
}
} elseif ( $param === 'subject-link' ) {
$this->setTitleLink( $event, $message );
// The title text without namespace
} elseif ( $param === 'main-title-text' ) {
if ( !$event->getTitle() ) {
$message->params( $this->getMessage( 'echo-no-title' )->text() );
} else {
$message->params( $event->getTitle()->getText() );
}
} else {
parent::processParam( $event, $param, $message, $user );
}
}
}

View file

@ -1,88 +0,0 @@
<?php
class EchoEditFormatter extends EchoBasicFormatter {
/**
* @param EchoEvent $event
* @param $param
* @param $message Message
* @param $user User
*/
protected function processParam( $event, $param, $message, $user ) {
if ( $param === 'subject-anchor' ) {
$message->params( $this->formatSubjectAnchor( $event ) );
} elseif ( $param === 'section-title' ) {
$message->params( $this->getSectionTitle( $event, $user ) );
} elseif ( $param === 'difflink' ) {
$revid = $event->getExtraParam( 'revid' );
if ( !$revid ) {
$message->params( '' );
return;
}
$diff = $event->getExtraParam( 'diffid', 'prev' );
$props = array(
'attribs' => array( 'class' => 'mw-echo-diff' ),
'linkText' => $this->getMessage( 'parentheses' )
->params(
$this->getMessage( 'showdiff' )->text()
)->escaped(),
'param' => array(
'oldid' => $revid,
'diff' => $diff,
),
// Set fragment to empty string for diff links
'fragment' => ''
);
$this->setTitleLink( $event, $message, $props );
} elseif ( $param === 'summary' ) {
$message->params( $this->getRevisionSnippet( $event, $user ) );
} elseif ( $param === 'number' ) {
$eventData = $event->getExtra();
// The folliwing is a bit of a hack...
// If the edit is a rollback, we want to say 'your edits' in the
// notification. If the edit is an undo, we want to say 'your edit'
// in the notification. To accomplish this, we pass a 'number' param
// to the message which is set to 1 or 2 and formatted with {{PLURAL}}.
if ( isset( $eventData['method'] ) && $eventData['method'] === 'rollback' ) {
$message->params( 2 );
} else {
$message->params( 1 );
}
} elseif ( $param === 'userpage-contributions' ) {
$user = $event->getAgent();
$name = $user->getName();
if ( $user->isAnon() ) {
$message->params( "Special:Contributions/$name" );
} else {
$message->params( "User:$name" );
}
} else {
parent::processParam( $event, $param, $message, $user );
}
}
/**
* Get the section title for a talk page post
* @param $event EchoEvent
* @param $user User
* @return string
*/
protected function getSectionTitle( $event, $user ) {
$extra = $event->getExtra();
if ( !empty( $extra['section-title'] ) ) {
if ( $event->userCan( Revision::DELETED_TEXT, $user ) ) {
return EchoDiscussionParser::getTextSnippet(
$extra['section-title'],
$this->getLanguage(),
30
);
} else {
return $this->getMessage( 'echo-rev-deleted-text-view' )->text();
}
}
return '';
}
}

View file

@ -1,37 +0,0 @@
<?php
/**
* Custom formatter for 'edit-user-talk' notifications
*/
class EchoEditUserTalkFormatter extends EchoEditFormatter {
/**
* {@inheritDoc}
*/
protected function applyChangeBeforeFormatting( EchoEvent $event, User $user, $type ) {
parent::applyChangeBeforeFormatting( $event, $user, $type );
// Replace default generic notification message with 'Someone left a message
// on your talk page in "xxxx"' if
// * the message is not bundled and
// * there is a section title
// We could go with the approach of creating a new notification type, but
// * this is variant is too small to introduce a new type
// * may not fall back to default for talk page post with oversighted content
// * message bundling is supposed to bundle the same notfication type, creating
// a new type will not be able to bundle them together
if ( !$this->bundleData['use-bundle'] && $this->getSectionTitle( $event, $user ) ) {
$this->title = array(
'message' => 'notification-edit-talk-page-with-section',
'params' => array( 'agent', 'user', 'subject-anchor', 'section-title' )
);
$this->email['batch-body'] = array(
'message' => 'notification-edit-talk-page-email-batch-body-with-section',
'params' => array( 'agent', 'section-title' )
);
// Display the summary if there is a section title
$this->payload = array( 'summary' );
}
}
}

View file

@ -1,23 +0,0 @@
<?php
class EchoMentionFormatter extends EchoCommentFormatter {
/**
* {@inheritDoc}
*/
protected function applyChangeBeforeFormatting( EchoEvent $event, User $user, $type ) {
parent::applyChangeBeforeFormatting( $event, $user, $type );
// If we can't find a section title for the mention,
// fall back to `notification-mention-nosection`.
if ( !$this->getSectionTitle( $event, $user ) ) {
$this->title = array(
'message' => 'notification-mention-nosection',
'params' => array( 'agent', 'main-title-text', 'title', 'user' )
);
$this->email['batch-body'] = array(
'message' => 'notification-mention-nosection-email-batch-body',
'params' => array( 'agent', 'main-title-text', 'user' )
);
}
}
}

View file

@ -5,6 +5,7 @@
* only the most generic formatting functionality as it may be extended by
* notification formatters for other extensions with unique content or
* requirements.
* @deprecated
*/
abstract class EchoNotificationFormatter {
@ -43,6 +44,7 @@ abstract class EchoNotificationFormatter {
* @throws MWException
*/
public function __construct( array $parameters ) {
wfDeprecated( __CLASS__, '1.28', 'Echo' );
$this->parameters = $parameters;
}

View file

@ -1,187 +0,0 @@
<?php
/**
* Custom formatter for 'page-link' notifications
*/
class EchoPageLinkFormatter extends EchoBasicFormatter {
/**
* This is a workaround for backwards compatibility.
* In https://gerrit.wikimedia.org/r/#/c/63076 we changed
* the schema to save link-from-page-id instead of
* link-from-namespace & link-from-title
*/
protected function extractExtra( $extra ) {
if ( isset( $extra['link-from-namespace'], $extra['link-from-title'] )
&& !isset( $extra['link-from-page-id'] )
) {
$title = Title::makeTitleSafe(
$extra['link-from-namespace'],
$extra['link-from-title']
);
if ( $title ) {
$extra['link-from-page-id'] = $title->getArticleId();
unset(
$extra['link-from-namespace'],
$extra['link-from-title']
);
}
}
return $extra;
}
/**
* This method overwrite parent method and construct the bundle iterator
* based on link from, it will be used in a message like this: Page A was
* link from Page B and X other pages
*
* @param $event EchoEvent
* @param $user User
* @param $type string deprecated
*/
protected function generateBundleData( $event, $user, $type ) {
$data = $this->getRawBundleData( $event, $user, $type );
if ( !$data ) {
return;
}
$extra = self::extractExtra( $event->getExtra() );
if ( !$this->isTitleSet( $extra ) ) {
// Link from title is required for bundling notification
return;
}
$count = 1;
$linkFrom = array(
$extra['link-from-page-id'] => true
);
foreach ( $data as $bundledEvent ) {
$extra = $bundledEvent->getExtra();
if ( !$extra ) {
continue;
}
if ( $this->isTitleSet( $extra ) ) {
$pageId = $extra['link-from-page-id'];
if ( !isset( $linkFrom[$pageId] ) ) {
$linkFrom[$pageId] = true;
$count++;
}
}
if ( $count > MWEchoNotifUser::MAX_BADGE_COUNT + 1 ) {
break;
}
}
$this->bundleData['link-from-page-other-count'] = $count - 1;
if ( $count > 1 ) {
$this->bundleData['use-bundle'] = true;
}
}
/**
* Internal function to check if link from page id key is set
* @param $extra array
* @return bool
*/
private function isTitleSet( $extra ) {
return isset( $extra['link-from-page-id'] ) && $extra['link-from-page-id'];
}
/**
* @param $event EchoEvent
* @param $param string
* @param $message Message
* @param $user User
*/
protected function processParam( $event, $param, $message, $user ) {
$extra = self::extractExtra( $event->getExtra() );
switch ( $param ) {
// 'A' part in this message: link from page A and X others
case 'link-from-page':
$title = null;
if ( $this->isTitleSet( $extra ) ) {
$title = Title::newFromId( $extra['link-from-page-id'] );
// Link-from page could be a brand new page and page_id would not be replicated
// to slave db yet. If job queue is enabled to process web and email notification,
// the check against master database is not necessary since there is already a
// delay in the job queue
if ( !$title ) {
global $wgEchoUseJobQueue;
$diff = wfTimestamp() - wfTimestamp( TS_UNIX, $event->getTimestamp() );
if ( !$wgEchoUseJobQueue && $diff < 5 ) {
$title = Title::newFromID( $extra['link-from-page-id'], Title::GAID_FOR_UPDATE );
}
}
if ( $title ) {
if ( $this->outputFormat === 'htmlemail' ) {
$message->rawParams(
Linker::link(
$title,
$this->formatTitle( $title ),
array( 'style' => $this->getHTMLLinkStyle() ),
array(),
array( 'https' )
)
);
} else {
$message->params( $this->formatTitle( $title ) );
}
}
}
if ( !$title ) {
$message->params( $this->getMessage( 'echo-no-title' ) );
}
break;
// example: {7} other pages, {99+} other pages
// link-from-page-other-display is no longer needed for new messages, but kept for backwards-compatibility
case 'link-from-page-other-display':
case 'link-from-page-other-count':
$message->numParams(
EchoNotificationController::getCappedNotificationCount( $this->bundleData['link-from-page-other-count'] )
);
break;
default:
parent::processParam( $event, $param, $message, $user );
break;
}
}
/**
* Helper function for getLink()
*
* @param EchoEvent $event
* @param User $user The user receiving the notification
* @param String $destination The destination type for the link
* @return Array including target and query parameters
*/
protected function getLinkParams( $event, $user, $destination ) {
$target = null;
$query = array();
// Set up link parameters based on the destination (or pass to parent)
switch ( $destination ) {
case 'link-from-page':
if ( $this->bundleData['use-bundle'] ) {
if ( $event->getTitle() ) {
$target = SpecialPage::getTitleFor( 'WhatLinksHere', $event->getTitle()->getPrefixedText() );
}
} else {
$extra = self::extractExtra( $event->getExtra() );
if ( $this->isTitleSet( $extra ) ) {
$target = Title::newFromId( $extra['link-from-page-id'] );
}
}
break;
default:
return parent::getLinkParams( $event, $user, $destination );
}
return array( $target, $query );
}
}

View file

@ -1,73 +0,0 @@
<?php
/**
* Formatter for 'user-rights' notifications
*/
class EchoUserRightsFormatter extends EchoBasicFormatter {
/**
* @param $event EchoEvent
* @param $param string
* @param $message Message
* @param $user User
*/
protected function processParam( $event, $param, $message, $user ) {
$extra = $event->getExtra();
switch ( $param ) {
// List of user rights that are granted or revoked
case 'user-rights-list':
$lang = $this->getLanguage();
$list = array();
foreach ( array( 'add', 'remove' ) as $action ) {
if ( isset( $extra[$action] ) && $extra[$action] ) {
// Get the localized group names, bug 55338
$groups = array();
foreach ( $extra[$action] as $group ) {
$msg = $this->getMessage( 'group-' . $group );
$groups[] = $msg->isBlank() ? $group : $msg->escaped();
}
// Messages that can be used here:
// * notification-user-rights-add
// * notification-user-rights-remove
$list[] = $this->getMessage( 'notification-user-rights-' . $action )
->params( $lang->commaList( $groups ), count( $groups ) )
->escaped();
}
}
$message->params( $lang->semicolonList( $list ) );
break;
default:
parent::processParam( $event, $param, $message, $user );
break;
}
}
/**
* Helper function for getLink()
*
* @param EchoEvent $event
* @param User $user The user receiving the notification
* @param String $destination The destination type for the link
* @return Array including target and query parameters
*/
protected function getLinkParams( $event, $user, $destination ) {
$target = null;
$query = array();
// Set up link parameters based on the destination (or pass to parent)
switch ( $destination ) {
case 'user-rights-list':
$target = SpecialPage::getTitleFor( 'Listgrouprights' );
break;
default:
return parent::getLinkParams( $event, $user, $destination );
}
return array( $target, $query );
}
}

View file

@ -10,6 +10,7 @@ function main() {
$dirs = array(
'includes',
'tests',
'maintenance',
);
foreach ( $dirs as $dir ) {
$generator->readDir( $base . '/' . $dir );

View file

@ -1,93 +0,0 @@
<?php
/**
* @group Echo
*/
class EchoEmailFormatterTest extends MediaWikiTestCase {
private $emailSingle;
private $emailDigest;
protected function setUp() {
parent::setUp();
$this->setMwGlobals( 'wgAllowHTMLEmail', true );
$event = $this->mockEvent( 'edit-user-talk' );
$event->expects( $this->any() )
->method( 'getTitle' )
->will( $this->returnValue( Title::newMainPage() ) );
$formatter = EchoNotificationFormatter::factory( $event->getType() );
$formatter->setOutputFormat( 'email' );
$user = User::newFromId( 1 );
$user->setName( 'Test' );
$user->setOption( 'echo-email-format', EchoEmailFormat::HTML );
$this->emailSingle = new EchoEmailSingle( $formatter, $event, $user );
$content[$event->getCategory()][] = EchoNotificationController::formatNotification( $event, $user, 'email', 'emaildigest' );
$this->emailDigest = new EchoEmailDigest( User::newFromId( 2 ), $content );
}
public function testEmailFormatter() {
$pattern = '/%%(.*?)%%/is';
// Single email mode
$textFormatter = new EchoTextEmailFormatter( $this->emailSingle );
$this->assertRegExp( $pattern, $this->emailSingle->getTextTemplate() );
$this->assertEquals( 0, preg_match( $pattern, $textFormatter->formatEmail() ) );
$htmlFormatter = new LegacyEchoHTMLEmailFormatter( $this->emailSingle );
$this->assertRegExp( $pattern, $this->emailSingle->getHTMLTemplate() );
$this->assertEquals( 0, preg_match( $pattern, $htmlFormatter->formatEmail() ) );
// Digest email mode
$textFormatter = new EchoTextEmailFormatter( $this->emailDigest );
$this->assertRegExp( $pattern, $this->emailSingle->getTextTemplate() );
$this->assertEquals( 0, preg_match( $pattern, $textFormatter->formatEmail() ) );
$htmlFormatter = new LegacyEchoHTMLEmailFormatter( $this->emailDigest );
$this->assertRegExp( $pattern, $this->emailSingle->getHTMLTemplate() );
$this->assertEquals( 0, preg_match( $pattern, $htmlFormatter->formatEmail() ) );
}
public function testBuildAction() {
$this->emailSingle->attachDecorator( new EchoTextEmailDecorator() );
$this->assertEquals( 0, preg_match( '/<a /i', $this->emailSingle->buildAction() ) );
$this->emailSingle->attachDecorator( new EchoHTMLEmailDecorator() );
$this->assertRegExp( '/<a /i', $this->emailSingle->buildAction() );
$this->emailDigest->attachDecorator( new EchoTextEmailDecorator() );
$this->assertEquals( 0, preg_match( '/<a /i', $this->emailDigest->buildAction() ) );
$this->emailDigest->attachDecorator( new EchoHTMLEmailDecorator() );
$this->assertRegExp( '/<a /i', $this->emailDigest->buildAction() );
}
/**
* @param string $type
* @return PHPUnit_Framework_MockObject_MockObject|EchoEvent
*/
protected function mockEvent( $type ) {
$methods = get_class_methods( 'EchoEvent' );
$methods = array_diff( $methods, array( 'userCan', 'getLinkMessage', 'getLinkDestination' ) );
$attribManager = EchoAttributeManager::newFromGlobalVars();
$event = $this->getMockBuilder( 'EchoEvent' )
->disableOriginalConstructor()
->setMethods( $methods )
->getMock();
$event->expects( $this->any() )
->method( 'getType' )
->will( $this->returnValue( $type ) );
$event->expects( $this->any() )
->method( 'getCategory' )
->will( $this->returnValue( $attribManager->getNotificationCategory( $type ) ) );
return $event;
}
}

View file

@ -13,188 +13,6 @@ class EchoNotificationFormatterTest extends MediaWikiTestCase {
$this->setMwGlobals( 'wgUser', $user );
}
public static function provider_editUserTalkEmail() {
return array(
array( '/Main_Page[^#]/', null ),
array( '/Main_Page#Section_8/', 'Section 8' ),
);
}
/**
* @dataProvider provider_editUserTalkEmail
*/
public function testEditUserTalkEmailNotificationLink( $pattern, $sectionTitle ) {
$event = $this->mockEvent( 'edit-user-talk', array(
'section-title' => $sectionTitle,
) );
$event->expects( $this->any() )
->method( 'getTitle' )
->will( $this->returnValue( Title::newMainPage() ) );
$formatted = $this->format( $event, 'email' );
if ( is_array( $formatted['body'] ) ) {
$this->assertRegExp( $pattern, $formatted['body']['text'] );
$this->assertRegExp( $pattern, $formatted['body']['html'] );
} else {
$this->assertRegExp( $pattern, $formatted['body'] );
}
# Reset the Title cache
$mainPage = Title::newMainPage();
$mainPage->setFragment( '' );
# And assert it has been cleaned up
$mainPageCached = Title::newMainPage();
$this->assertEquals( '', $mainPageCached->getFragment() );
}
public function provider_formatterDoesntFail() {
// Remove events from this array once they have specific tests for their formatting
$untested = array(
'welcome' => array(),
'reverted' => array(
'revid' => 42,
'reverted-user-id' => 77,
'reverted-revision-id' => 13,
'method' => 'undo',
),
'page-linked' => array(
'link-from-page-id' => 42,
),
'mention' => array(
'content' => 'lorem ipsum dolar sit amet',
'section-title' => 'Zombies',
'revid' => 42,
'mentionedusers' => array( 101 => 101 ),
),
'user-rights' => array(
'user' => 187,
'add' => array( 'aaa', 'bbb' ),
'remove' => array( 'other' ),
),
);
$formats = array( 'email', 'text' );
$tests = array();
$loggedUser = User::newFromName( 'Notification-formatter-test' );
$anonUser = new User();
foreach ( $untested as $type => $extra ) {
foreach ( $formats as $format ) {
// Run tests with blank extra data and with the provided extra data
$tests[] = array( $format, $type, $extra, $loggedUser );
$tests[] = array( $format, $type, array(), $anonUser );
}
}
return $tests;
}
public static function provider_revisionSummary() {
$sectionText = '(dummy comment)';
// Test the 4 different events that reference the summary, although they should follow mostly
// the same code they may use different classes extended from the EchoNotificationFormatter
$tests = array();
$events = array( 'edit-user-talk' );
foreach ( $events as $eventType ) {
$tests[] = array( $eventType, $sectionText, 0 );
$tests[] = array( $eventType, $sectionText, Revision::DELETED_TEXT );
}
return $tests;
}
/**
* @dataProvider provider_revisionSummary
*/
public function testRevisionSummarySuppression( $eventType, $text, $deleted ) {
// Revision needs a comment to attempt to format
$event = $this->mockEvent(
$eventType,
array( 'section-title' => 'Test Title', 'section-text' => $text ),
new Revision( compact( 'deleted' ) )
);
if ( $deleted === Revision::DELETED_TEXT ) {
$this->assertNotContains( $text, $this->format( $event, 'htmlemail' ) );
} else {
$this->assertContains( $text, $this->format( $event, 'htmlemail' ) );
}
}
public static function provider_revisionAgent() {
$userText = '10.2.3.4';
$suppressed = wfMessage( 'rev-deleted-user' )->text();
$tests = array();
$events = array( 'edit-user-talk', 'reverted', 'mention' );
foreach ( $events as $eventType ) {
$tests[] = array( $eventType, $userText, $userText, 0 );
$tests[] = array( $eventType, $suppressed, $userText, Revision::DELETED_USER );
}
return $tests;
}
/**
* @dataProvider provider_revisionAgent
*/
public function testAgentSuppression( $eventType, $expect, $user_text, $deleted ) {
$event = $this->mockEvent(
$eventType,
array(),
new Revision( compact( 'user_text', 'deleted' ) )
);
$user = new User;
$user->setName( $user_text );
$event->expects( $this->any() )
->method( 'getAgent' )
->will( $this->returnValue( $user ) );
$this->assertContains( $expect, $this->format( $event, 'text' ) );
}
public static function provider_sectionTitle() {
$message = "some_section_title"; // underscores simplifies the test, since it will transform ' ' to '_'
$suppressed = wfMessage( 'echo-rev-deleted-text-view' )->text();
$tests = array();
$events = array( 'mention' ); // currently only mention uses sectionTitle, but likely edit-user-talk will soon as well
foreach ( $events as $eventType ) {
$tests[] = array( $eventType, $message, $message, 0 );
$tests[] = array( $eventType, $suppressed, $message, Revision::DELETED_TEXT );
}
return $tests;
}
/**
* @dataProvider provider_formatterDoesntFail
*/
public function testFormatterDoesntFail( $format, $type, array $extra, User $agent ) {
$result = $this->format( $this->mockEvent( $type, $extra, null, $agent ), $format );
// generic assertion, could do better
if ( $format === 'email' ) {
$this->assertInternalType( 'array', $result );
$this->assertCount( 2, $result );
} else {
$this->assertInternalType( 'string', $result );
$this->assertGreaterThan( 0, strlen( $result ) );
}
}
/**
* @dataProvider provider_sectionTitle
*/
public function testMentionSubjectSectionTitleSuppression( $eventType, $expect, $sectionTitle, $deleted ) {
$event = $this->mockEvent(
$eventType,
array( 'section-title' => $sectionTitle ),
new Revision( compact( 'deleted' ) )
);
$this->assertContains( $expect, $this->format( $event, 'text' ) );
}
protected function format( EchoEvent $event, $format, $user = false, $type = 'web' ) {
if ( $user === false ) {
$user = User::newFromName( 'Notification-formatter-test' );