EBernhardson (WMF) has submitted this change and it was merged.
Change subject: Flow: Implement initial notifications for
edit/rename/reply/newtopic
......................................................................
Flow: Implement initial notifications for edit/rename/reply/newtopic
Change-Id: I4da232cd162f85aac71c4f39fc84af66d3c16ae7
---
M Flow.i18n.php
M Flow.php
M Hooks.php
M includes/Block/Topic.php
M includes/Block/TopicList.php
M includes/Container.php
M includes/Model/PostRevision.php
A includes/NotificationFormatter.php
M includes/UrlGenerator.php
M includes/api/ApiFlow.php
M includes/api/ApiQueryFlow.php
M special/SpecialFlow.php
12 files changed, 313 insertions(+), 7 deletions(-)
Approvals:
EBernhardson (WMF): Verified; Looks good to me, approved
diff --git a/Flow.i18n.php b/Flow.i18n.php
index eccadd3..ca1d226 100644
--- a/Flow.i18n.php
+++ b/Flow.i18n.php
@@ -83,6 +83,11 @@
'flow-days-ago' => '$1 {{PLURAL:$1|day|days}} ago',
'flow-months-ago' => '$1 {{PLURAL:$1|month|months}} ago',
'flow-years-ago' => '$1 {{PLURAL:$1|year|years}} ago',
+
+ 'flow-notification-reply' => '$1 replied to your [$5 post] in $2 on
[[$3|$4]].',
+ 'flow-notification-edit' => '$1 edited your [$5 post] in $2 on
[[$3|$4]].',
+ 'flow-notification-newtopic' => '$1 created a [$5 new topic] on
[[$2|$3]]: $4.',
+ 'flow-notification-rename' => '$1 changed the title of [$2 $3] to "$4"
on [[$5|$6]]'
);
/** Message documentation (Message documentation)
@@ -189,6 +194,33 @@
'flow-comment-hidden' => 'Used as comment when the comment has been
hidden.',
'flow-paging-rev' => 'Label for paging link that shows more recently
modified topics',
'flow-paging-fwd' => 'Label for paging link that shows less recently
modified topics',
+
+ 'flow-notification-reply' => 'Notification text for when a user
receives a reply. Parameters:
+* $1: Username of the person who replied.
+* $2: Title of the topic.
+* $3: Title for the Flow board.
+* $4: Title for the page that the Flow board is attached to.
+* $5: Permanent URL for the post.',
+ 'flow-notification-edit' => 'Notification text for when a user\'s post
is edited. Parameters:
+* $1: Username of the person who edited the post.
+* $2: Title of the topic.
+* $3: Title for the Flow board.
+* $4: Title for the page that the Flow board is attached to.
+* $5: Permanent URL for the post.',
+ 'flow-notification-newtopic' => 'Notification text for when a new topic
is created. Parameters:
+* $1: Username of the person who created the topic.
+* $2: Title for the Flow board.
+* $3: Title for the page that the Flow board is attached to.
+* $4: Title of the topic.
+* $5: Permanent URL for the topic.',
+ 'flow-notification-rename' => 'Notification text for when the subject
of a topic is changed. Parameters:
+* $1: Username of the person who edited the title.
+* $2: Permalink to the topic.
+* $3: Old topic subject.
+* $4: New topic subject.
+* $5: Title for the Flow board.
+* $6: Title for the page that the Flow board is attached to.
+',
);
/** Asturian (asturianu)
diff --git a/Flow.php b/Flow.php
index 4f90656..e94ba4d 100755
--- a/Flow.php
+++ b/Flow.php
@@ -58,6 +58,7 @@
$wgAutoloadClasses['Flow\UrlGenerator'] = $dir . 'includes/UrlGenerator.php';
$wgAutoloadClasses['Flow\WorkflowLoader'] = $dir .
'includes/WorkflowLoader.php';
$wgAutoloadClasses['Flow\WorkflowLoaderFactory'] = $dir .
'includes/WorkflowLoader.php';
+$wgAutoloadClasses['FlowCommentFormatter'] = $dir .
'includes/NotificationFormatter.php';
// Classes that model our data
$wgAutoloadClasses['Flow\Model\Definition'] = $dir .
'includes/Model/Definition.php';
diff --git a/Hooks.php b/Hooks.php
index ded1608..426e384 100644
--- a/Hooks.php
+++ b/Hooks.php
@@ -1,11 +1,61 @@
<?php
+use Flow\Model\UUID;
+
class FlowHooks {
/**
* Initialize Flow extension with necessary data, this function is
invoked
* from $wgExtensionFunctions
*/
public static function initFlowExtension() {
+ global $wgEchoNotifications, $wgHooks, $wgEchoNotificationIcons;
+
+ if ( isset( $wgEchoNotifications ) ) {
+ $wgHooks['EchoGetDefaultNotifiedUsers'][] =
'FlowHooks::getDefaultNotifiedUsers';
+
+ $notificationTemplate = array(
+ 'category' => 'flow-discussion',
+ 'group' => 'other',
+ 'formatter-class' => 'FlowCommentFormatter',
+ 'icon' => 'flow-discussion',
+ );
+
+ $wgEchoNotifications['flow-new-topic'] = array(
+ 'title-message' => 'flow-notification-newtopic',
+ 'title-params' => array( 'user', 'flow-title',
'title', 'subject', 'topic-permalink' ),
+ 'payload' => array( 'comment-text' ),
+ ) + $notificationTemplate;
+
+ $wgEchoNotifications['flow-post-reply'] = array(
+ 'title-message' => 'flow-notification-reply',
+ 'title-params' => array( 'user', 'subject',
'flow-title', 'title', 'post-permalink' ),
+ 'payload' => array( 'comment-text' ),
+ ) + $notificationTemplate;
+
+ $wgEchoNotifications['flow-post-edited'] = array(
+ 'title-message' => 'flow-notification-edit',
+ 'title-params' => array( 'user', 'subject',
'flow-title', 'title', 'post-permalink' ),
+ ) + $notificationTemplate;
+
+ // Saving for a rainy day
+ // $wgEchoNotifications['flow-post-moderated'] = array(
+ // 'title-message' =>
'flow-notification-moderated',
+ // 'title-params' => array( 'user', 'subject',
'flow-title', 'title', 'post-permalink' ),
+ // ) + $notificationTemplate;
+
+ $wgEchoNotifications['flow-topic-renamed'] = array(
+ 'title-message' => 'flow-notification-rename',
+ 'title-params' => array( 'user',
'topic-permalink', 'old-subject', 'new-subject', 'flow-title', 'title' ),
+ ) + $notificationTemplate;
+
+ $wgEchoNotificationIcons['flow-discussion'] = array(
+ 'path' =>
'Flow/modules/discussion/images/Talk.png',
+ );
+
+ $wgEchoNotificationCategories['flow-discussion'] =
array(
+ // 'echo-pref'
+ );
+ }
}
/**
@@ -31,4 +81,62 @@
//$files[] = "$dir/DiscussionParserTest.php";
return true;
}
+
+ /**
+ * Handler for EchoGetDefaultNotifiedUsers hook
+ * Returns a list of User objects in the second param
+ *
+ * @param $event EchoEvent being triggered
+ * @param &$users Array of User objects.
+ * @return true
+ */
+ public static function getDefaultNotifiedUsers( EchoEvent $event,
&$users ) {
+ $container = Flow\Container::getContainer();
+ $storage = $container['storage'];
+ $extra = $event->getExtra();
+ switch ( $event->getType() ) {
+ case 'flow-new-topic':
+ $title = $event->getTitle();
+ if ( $title->getNamespace() == NS_USER_TALK ) {
+ $users[] = User::newFromName( $title->getText()
);
+ }
+ break;
+ case 'flow-topic-renamed':
+ $postId = $extra['topic-workflow'];
+ case 'flow-post-reply':
+ case 'flow-post-edited':
+ case 'flow-post-moderated':
+ if ( isset( $extra['reply-to'] ) ) {
+ $postId = $extra['reply-to'];
+ } elseif ( ! $postId ) {
+ $postId = $extra['post-id'];
+ }
+
+ $post = $storage->find(
+ 'PostRevision',
+ array(
+ 'tree_rev_descendant_id' =>
UUID::create( $postId )
+ ),
+ array(
+ 'sort' => 'rev_id',
+ 'order' => 'DESC',
+ 'limit' => 1
+ )
+ );
+
+ $post = reset( $post );
+
+ if ( $post ) {
+ $user = User::newFromName(
$post->getCreatorName() );
+
+ if ( ! $user->isAnon() ) {
+ $users[$user->getId()] = $user;
+ }
+ }
+ break;
+ default:
+ // Do nothing
+ }
+ return true;
+ }
}
diff --git a/includes/Block/Topic.php b/includes/Block/Topic.php
index dce20f0..a8abc80 100644
--- a/includes/Block/Topic.php
+++ b/includes/Block/Topic.php
@@ -11,6 +11,7 @@
use Flow\DbFactory;
use Flow\ParsoidUtils;
use Flow\Templating;
+use EchoEvent;
use User;
class TopicBlock extends AbstractBlock {
@@ -19,6 +20,7 @@
protected $topicTitle;
protected $rootLoader;
protected $newRevision;
+ protected $notification;
protected $requestedPost;
// POST actions, GET do not need to be listed
@@ -97,6 +99,14 @@
}
$this->newRevision = $topicTitle->newNextRevision(
$this->user, $this->submitted['content'], 'flow-edit-title' );
+
+ $this->setNotification(
+ 'flow-topic-renamed',
+ array(
+ 'old-subject' =>
$topicTitle->getContent(),
+ 'new-subject' =>
$this->newRevision->getContent(),
+ )
+ );
}
}
@@ -121,6 +131,15 @@
// TODO: assert post belongs to this tree?
Does it realy matter?
// answer: might not belong, and probably does
matter due to inter-wiki interaction
$this->newRevision = $post->reply( $this->user,
$this->parsedContent, 'flow-comment-added' );
+
+ $this->setNotification(
+ 'flow-post-reply',
+ array(
+ 'reply-to' =>
$post->getPostId(),
+ 'content' =>
$this->submitted['content'],
+ 'topic-title' =>
$this->getTitleText(),
+ )
+ );
}
}
}
@@ -183,6 +202,13 @@
$post = $this->loadRequestedPost( $this->submitted['postId'] );
if ( $post ) {
$this->newRevision = $post->newNextRevision(
$this->user, $this->parsedContent, 'flow-edit-post' );
+ $this->setNotification(
+ 'flow-post-edited',
+ array(
+ 'content' =>
$this->submitted['content'],
+ 'topic-title' =>
$this->getTitleText(),
+ )
+ );
} else {
$this->errors['edit-post'] = wfMessage(
'flow-post-not-found' );
}
@@ -219,6 +245,13 @@
$renderFunction = function( $templating ) use (
$self, $newRevision, $rootPost ) {
return $templating->renderPost(
$newRevision, $self, $rootPost );
};
+ }
+
+ if ( class_exists( 'EchoEvent' ) && is_array(
$this->notification ) ) {
+ $this->notification['extra']['revision-id'] =
$this->newRevision->getRevisionId();
+ $this->notification['extra']['post-id'] =
$this->newRevision->getPostId();
+
+ EchoEvent::create( $this->notification );
}
return array(
@@ -481,6 +514,10 @@
return $this->topicTitle;
}
+ public function getTitleText() {
+ return $this->loadTopicTitle()->getContent();
+ }
+
protected function loadTopicHistory() {
$found = $this->storage->find(
'PostRevision',
@@ -527,4 +564,15 @@
return 'topic';
}
+ protected function setNotification( $notificationType, array $extraVars
) {
+ $this->notification = array(
+ 'type' => $notificationType,
+ 'agent' => $this->user,
+ 'title' => $this->workflow->getArticleTitle(),
+ 'extra' => $extraVars + array(
+ 'topic-workflow' =>
$this->workflow->getId(),
+ )
+ );
+ }
+
}
diff --git a/includes/Block/TopicList.php b/includes/Block/TopicList.php
index aa2c563..b07da2a 100644
--- a/includes/Block/TopicList.php
+++ b/includes/Block/TopicList.php
@@ -12,6 +12,7 @@
use Flow\Data\RootPostLoader;
use Flow\DbFactory;
use Flow\Templating;
+use EchoEvent;
use User;
class TopicListBlock extends AbstractBlock {
@@ -63,6 +64,21 @@
$user = $this->user;
+ if ( class_exists( 'EchoEvent' ) ) {
+ EchoEvent::create( array(
+ 'type' => 'flow-new-topic',
+ 'agent' => $user,
+ 'title' => $this->workflow->getArticleTitle(),
+ 'extra' => array(
+ 'board-workflow' =>
$this->workflow->getId(),
+ 'topic-workflow' =>
$topicWorkflow->getId(),
+ 'post-id' =>
$firstPost->getRevisionId(),
+ 'topic-title' =>
$this->submitted['topic'],
+ 'content' =>
$this->submitted['content'],
+ ),
+ ) );
+ }
+
$output = array(
'created-topic-id' => $topicWorkflow->getId(),
'created-post-id' => $firstPost->getRevisionId(),
diff --git a/includes/Container.php b/includes/Container.php
index a89eb49..6dba03f 100644
--- a/includes/Container.php
+++ b/includes/Container.php
@@ -3,4 +3,24 @@
namespace Flow;
class Container extends \Pimple {
+ /**
+ * Get a Flow Container
+ * IMPORTANT: If you are using this function, consider if you can
achieve
+ * your objectives by passing values from an existing, accessible
+ * container object instead.
+ * If you use this function outside a Flow entry point (such as a hook,
+ * special page or API module), there is a good chance that your code
+ * requires refactoring
+ *
+ * @return FLow\Container
+ */
+ static function getContainer() {
+ static $container = false;
+
+ if ( $container == false ) {
+ $container = include __DIR__ . '/../container.php';
+ }
+
+ return $container;
+ }
}
diff --git a/includes/Model/PostRevision.php b/includes/Model/PostRevision.php
index 1f9b2ae..bd06b87 100644
--- a/includes/Model/PostRevision.php
+++ b/includes/Model/PostRevision.php
@@ -79,6 +79,14 @@
return $this->postId;
}
+ public function getCreatorId() {
+ return $this->origUserId;
+ }
+
+ public function getCreatorName() {
+ return $this->origUserText;
+ }
+
public function isTopicTitle() {
return $this->replyToId === null;
}
diff --git a/includes/NotificationFormatter.php
b/includes/NotificationFormatter.php
new file mode 100644
index 0000000..7053a9f
--- /dev/null
+++ b/includes/NotificationFormatter.php
@@ -0,0 +1,67 @@
+<?php
+
+use Flow\UrlGenerator;
+
+class FlowCommentFormatter extends EchoBasicFormatter {
+ protected function processParam( $event, $param, $message, $user ) {
+ $extra = $event->getExtra();
+ if ( $param === 'flow-board' ) {
+ $title = $event->getTitle();
+ $boardTitle = Special::getTitleFor( 'Flow',
$title->getPrefixedText() );
+ $output = $this->formatTitle( $boardTitle );
+ $message->params( $output );
+ } elseif ( $param === 'subject' ) {
+ if ( isset( $extra['topic-title'] ) &&
$extra['topic-title'] ) {
+ $message->params( $extra['topic-title'] );
+ } else {
+ $message->params( '' );
+ }
+ } elseif ( $param === 'commentText' ) {
+ /**
+ * @var $wgLang Language
+ */
+ global $wgLang; // Message::language is protected :(
+
+ if ( isset( $extra['content'] ) && $extra['content'] ) {
+ $content = $extra['content'];
+ $content = trim( $content );
+ $content = $wgLang->truncate( $content, 200 );
+
+ $message->params( $content );
+ } else {
+ $message->params( '' );
+ }
+ } elseif ( $param === 'post-permalink' ) {
+ $postId = $extra['post-id'];
+ $url = UrlGenerator::buildUrl(
+ $event->getTitle(),
+ 'view',
+ array(
+ 'topic[postId]' => $postId->getHex(),
+ 'workflow' =>
$extra['topic-workflow']->getHex(),
+ )
+ );
+
+ $message->params( $url );
+ } elseif ( $param === 'topic-permalink' ) {
+ $url = UrlGenerator::buildUrl(
+ $event->getTitle(),
+ 'view',
+ array(
+ 'workflow' =>
$extra['topic-workflow']->getHex(),
+ )
+ );
+
+ $message->params( $url );
+ } elseif ( $param == 'flow-title' ) {
+ $title = $this->formatTitle( SpecialPage::getTitleFor(
'Flow', $event->getTitle() ) );
+ $message->params( $title );
+ } elseif ( $param == 'old-subject' ) {
+ $message->params( $extra['old-subject'] );
+ } elseif ( $param == 'new-subject' ) {
+ $message->params( $extra['new-subject'] );
+ } else {
+ parent::processParam( $event, $param, $message, $user );
+ }
+ }
+}
\ No newline at end of file
diff --git a/includes/UrlGenerator.php b/includes/UrlGenerator.php
index c476797..8f54e67 100644
--- a/includes/UrlGenerator.php
+++ b/includes/UrlGenerator.php
@@ -2,13 +2,20 @@
namespace Flow;
-use Flow\Model\Workflow;
use Flow\Data\ObjectManager;
+use Flow\Model\Workflow;
+use SpecialPage;
use Title;
class UrlGenerator {
public function __construct( ObjectManager $workflowStorage ) {
$this->storage = $workflowStorage;
+ }
+
+ public static function buildUrl( $title, $action, $query ) {
+ $query['action'] = $action;
+ return SpecialPage::getTitleFor( 'Flow',
$title->getPrefixedText() )
+ ->getFullUrl( $query );
}
public function generateUrl( $workflow, $action = 'view', array $query
= array() ) {
@@ -20,14 +27,13 @@
throw new \MWException( "Unknown flow object:
$workflowId" );
}
}
- $query['action'] = $action;
+
if ( $workflow->isNew() ) {
$query['definition'] =
$workflow->getDefinitionId()->getHex();
} else {
$query['workflow'] = $workflow->getId()->getHex();
}
- return Title::newFromText( 'Flow/' .
$workflow->getTitleFullText(), NS_SPECIAL )
- ->getLinkURL( $query );
+ return self::buildUrl( $workflow->getTitle(), $action, $query );
}
}
diff --git a/includes/api/ApiFlow.php b/includes/api/ApiFlow.php
index 0cf4418..46f0379 100644
--- a/includes/api/ApiFlow.php
+++ b/includes/api/ApiFlow.php
@@ -4,7 +4,7 @@
class ApiFlow extends ApiBase {
public function execute() {
- $this->container = include __DIR__ . "/../../container.php";
+ $this->container = Flow\Container::getContainer();
$params = $this->extractRequestParams();
$output = array();
diff --git a/includes/api/ApiQueryFlow.php b/includes/api/ApiQueryFlow.php
index e34779f..a802012 100644
--- a/includes/api/ApiQueryFlow.php
+++ b/includes/api/ApiQueryFlow.php
@@ -11,7 +11,7 @@
}
public function execute() {
- $this->container = include __DIR__ . "/../../container.php";
+ $this->container = Flow\Container::getContainer();
// Get the parameters
$params = $this->extractRequestParams();
$passedParams = json_decode( $params['params'], true );
diff --git a/special/SpecialFlow.php b/special/SpecialFlow.php
index cd14148..07cec02 100644
--- a/special/SpecialFlow.php
+++ b/special/SpecialFlow.php
@@ -92,7 +92,7 @@
}
protected function loadContainer() {
- $container = include __DIR__ . '/../container.php';
+ $container = Flow\Container::getContainer();
$container['request'] = $this->getRequest();
$container['output'] = $this->getOutput();
--
To view, visit https://gerrit.wikimedia.org/r/80514
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: I4da232cd162f85aac71c4f39fc84af66d3c16ae7
Gerrit-PatchSet: 3
Gerrit-Project: mediawiki/extensions/Flow
Gerrit-Branch: master
Gerrit-Owner: Werdna <[email protected]>
Gerrit-Reviewer: EBernhardson (WMF) <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits