mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/Echo
synced 2024-09-23 10:22:05 +00:00
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:
parent
be3cca488d
commit
2f0ff9cbf6
62
Echo.php
62
Echo.php
|
@ -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',
|
||||
),
|
||||
);
|
||||
|
||||
|
|
24
autoload.php
24
autoload.php
|
@ -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',
|
||||
];
|
||||
|
|
31
i18n/en.json
31
i18n/en.json
|
@ -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}}",
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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%"> </td>
|
||||
<td bgcolor="#FFFFFF" width="10%"> </td>
|
||||
<td bgcolor="#FFFFFF" width="80%" style="line-height:40px;"> </td>
|
||||
<td bgcolor="#FFFFFF" width="5%"> </td>
|
||||
</tr><tr>
|
||||
<td bgcolor="#FFFFFF" rowspan="2"> </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"> </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"> </td>
|
||||
<td bgcolor="#FFFFFF"> </td>
|
||||
<td bgcolor="#FFFFFF" style="line-height:40px;"> </td>
|
||||
<td bgcolor="#FFFFFF"> </td>
|
||||
</tr><tr>
|
||||
<td> </td>
|
||||
<td> </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> </td>
|
||||
</tr><tr>
|
||||
<td colspan="4"> </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%"> </td>
|
||||
<td bgcolor="#FFFFFF" width="6%"> </td>
|
||||
<td bgcolor="#FFFFFF" width="79%" style="line-height:40px;"> </td>
|
||||
<td bgcolor="#FFFFFF" width="10%"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td bgcolor="#FFFFFF" rowspan="2"> </td>
|
||||
<td bgcolor="#FFFFFF" rowspan="2"> </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"> </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"> </td>
|
||||
<td bgcolor="#FFFFFF"> </td>
|
||||
<td bgcolor="#FFFFFF" style="line-height:60px;" align="center">%%action%%</td>
|
||||
<td bgcolor="#FFFFFF"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td bgcolor="#FFFFFF"> </td>
|
||||
<td bgcolor="#FFFFFF"> </td>
|
||||
<td bgcolor="#FFFFFF" style="line-height:40px;"> </td>
|
||||
<td bgcolor="#FFFFFF"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td> </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> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="4"> </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 " ";
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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 = '';
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 '';
|
||||
}
|
||||
}
|
|
@ -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' );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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' )
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
|
@ -10,6 +10,7 @@ function main() {
|
|||
$dirs = array(
|
||||
'includes',
|
||||
'tests',
|
||||
'maintenance',
|
||||
);
|
||||
foreach ( $dirs as $dir ) {
|
||||
$generator->readDir( $base . '/' . $dir );
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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' );
|
||||
|
|
Loading…
Reference in a new issue