EBernhardson has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/91135


Change subject: [WIP] Moderate a post or topic
......................................................................

[WIP] Moderate a post or topic

Adds actions to moderate topics and attempts to fix prior issues
with application of delete and censor.  Still needs some work in
regards to historical posts.

Change-Id: I10cae63c2491c9f467968d6f8d604ea7f743ea96
---
M Flow.i18n.php
M includes/Block/Topic.php
M includes/Model/AbstractRevision.php
M includes/Model/PostRevision.php
M includes/Templating.php
M includes/View/PostActionMenu.php
M modules/discussion/styles/topic.less
A templates/bak
M templates/topic.html.php
9 files changed, 556 insertions(+), 124 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/Flow 
refs/changes/35/91135/1

diff --git a/Flow.i18n.php b/Flow.i18n.php
index c68f915..6059643 100644
--- a/Flow.i18n.php
+++ b/Flow.i18n.php
@@ -27,6 +27,9 @@
        'flow-post-censored-by' => '{{GENDER:$1|Censored}} by $1 $2',
        'flow-post-actions' => 'actions',
        'flow-topic-actions' => 'actions',
+       'flow-topic-hidden-by' => 'This topic was hidden by $1',
+       'flow-topic-deleted-by' => 'This topic was deleted by $1',
+       'flow-topic-censored-by' => 'This topic was suppressed by $1',
        'flow-cancel' => 'Cancel',
 
        'flow-newtopic-title-placeholder' => 'Message subject',
@@ -59,6 +62,10 @@
        'flow-topic-action-watchlist' => 'Watchlist',
        'flow-topic-action-edit-title' => 'Edit title',
        'flow-topic-action-history' => 'Topic history',
+       'flow-topic-action-hide-topic' => 'Hide topic',
+       'flow-topic-action-delete-topic' => 'Delete topic',
+       'flow-topic-action-censor-topic' => 'Suppress topic',
+       'flow-topic-action-restore-topic' => 'Restore topic',
 
        'flow-error-http' => 'An error occurred while contacting the server. 
Your post was not saved.', // Needs real copy
        'flow-error-other' => 'An unexpected error occurred. Your post was not 
saved.',
@@ -197,6 +204,12 @@
 {{Identical|Action}}',
        'flow-topic-actions' => 'Used as link text.
 {{Identical|Action}}',
+       'flow-topic-hidden-by' => 'Used as replacement topic title when hidden. 
Parameters:
+* $1 - username of the user that hid the topic',
+       'flow-topic-deleted-by' => 'Used as replacement topic title when 
deleted. Parameters:
+* $1 - username of the user that deleted the topic',
+       'flow-topic-censored-by' => 'Used as replacement topic title when 
suppressed. Parameters:
+* $1 - username of the user that suppressed the topic',
        'flow-cancel' => 'Used as action link text.
 {{Identical|Cancel}}',
        'flow-newtopic-title-placeholder' => 'Used as placeholder for the 
"Subject/Title for topic" textarea.',
@@ -252,6 +265,10 @@
        'flow-topic-action-edit-title' => 'Used as title for the link which is 
used to edit the title.',
        'flow-topic-action-history' => 'Used as text for the link which is used 
to view topic-history.
 {{Identical|Topic history}}',
+       'flow-topic-action-hide-topic' => 'Used as a link in a dropdown menu to 
hide a topic.',
+       'flow-topic-action-delete-topic' => 'Used as a link in a dropdown menu 
to delete a topic.',
+       'flow-topic-action-censor-topic' => 'Used as a link in a dropdown menu 
to suppress a topic.',
+       'flow-topic-action-restore-topic' => 'Used as a link in a dropdown menu 
to clear existing moderation.',
        'flow-error-http' => 'Used as error message on HTTP error.',
        'flow-error-other' => 'Used as generic error message.',
        'flow-error-external' => 'Uses as error message. Parameters:
diff --git a/includes/Block/Topic.php b/includes/Block/Topic.php
index 6cec6dc..516b8dc 100644
--- a/includes/Block/Topic.php
+++ b/includes/Block/Topic.php
@@ -20,6 +20,7 @@
        protected $topicTitle;
        protected $rootLoader;
        protected $newRevision;
+       protected $relatedRevisions = array();
        protected $notification;
        protected $requestedPost;
 
@@ -28,10 +29,12 @@
        protected $supportedActions = array(
                // Standard editing
                'edit-post', 'reply',
-               // Moderation
+               // Topic Moderation
+               'hide-topic', 'delete-topic', 'censor-topic', 'restore-topic',
+               // Post Moderation
                'hide-post', 'delete-post', 'censor-post', 'restore-post',
                // Other stuff
-               'hide-topic', 'edit-title',
+               'edit-title',
        );
 
        public function __construct( Workflow $workflow, ManagerGroup $storage, 
NotificationController $notificationController, $root ) {
@@ -58,8 +61,19 @@
                        break;
 
                case 'hide-topic':
-                       // this should be a workflow level action, not 
implemented per-block
-                       $this->validateHideTopic();
+                       $this->validateModerateTopic( 
AbstractRevision::MODERATED_HIDDEN );
+                       break;
+
+               case 'delete-topic':
+                       $this->validateModerateTopic( 
AbstractRevision::MODERATED_DELETED );
+                       break;
+
+               case 'censor-topic':
+                       $this->validateModerateTopic( 
AbstractRevision::MODERATED_CENSORED );
+                       break;
+
+               case 'restore-topic':
+                       $this->validateRestorePost();
                        break;
 
                case 'hide-post':
@@ -139,9 +153,27 @@
                }
        }
 
-       protected function validateHideTopic() {
-               if ( !$this->workflow->lock( $this->user ) ) {
-                       $this->errors['hide-topic'] = wfMessage( 
'flow-error-hide-failure' );
+       protected function validateModerateTopic( $moderationState ) {
+               $topic = $this->loadTopicTitle();
+               $this->newRevision = $topic->moderate( $this->user, 
$moderationState );
+               // The application of moderation to historical revisions is 
pushed out of the
+               // model because the moderation is in AbstractRevision, but not 
all revisions
+               // (ex: header) will want moderation to apply to historical 
revisions.
+               if ( $this->newRevision && 
$this->newRevision->needsModerateHistorical() ) {
+                       $this->relatedRevisions = $this->loadHistorical( $topic 
);
+                       foreach ( $this->relatedRevisions as $revision ) {
+                               $revision->moderate( $this->user, 
$moderationState, null, /* $createRevision = */ false );
+                       }
+               } elseif ( !$this->newRevision ) {
+                       $this->errors['moderate'] = wfMessage( 
'flow-error-not-allowed' );
+               }
+       }
+
+       protected function validateRestoreTopic() {
+               $topic = $this->loadTopicTitle();
+               $this->newRevision = $topic->restore( $this->user );
+               if ( !$this->newRevision ) {
+                       $this->errors['restore-topic'] = wfMessage( 
'flow-error-not-allowed' );
                }
        }
 
@@ -213,6 +245,10 @@
 
                switch( $this->action ) {
                case 'reply':
+               case 'hide-topic':
+               case 'delete-topic':
+               case 'censor-topic':
+               case 'restore-topic':
                case 'hide-post':
                case 'delete-post':
                case 'censor-post':
@@ -224,6 +260,10 @@
                        }
                        $this->storage->put( $this->newRevision );
                        $this->storage->put( $this->workflow );
+                       // These are moderated historical revisions of 
$this->newRevision
+                       foreach ( $this->relatedRevisions as $revision ) {
+                               $this->storage->put( $revision );
+                       }
                        $self = $this;
                        $newRevision = $this->newRevision;
                        $rootPost = $this->loadRootPost();
@@ -557,6 +597,33 @@
                return $this->requestedPost[$postId] ?: null;
        }
 
+       protected function loadHistorical( PostRevision $post ) {
+               if ( $post->isFirstRevision() ) {
+                       throw new \Exception( 'first?' );
+                       return array();
+               }
+
+               $found = $this->storage->find(
+                       'PostRevision',
+                       array( 'tree_rev_descendant_id' => $post->getPostId() ),
+                       // TODO: should we really be reverting moderation state 
for more than
+                       // 50 revisions?
+                       array( 'limit' => 50 )
+               );
+               if ( !$found ) {
+                       throw new \Exception( 'should have found revisions' );
+               }
+               // We need to filter out $post
+               $revId = $post->getRevisionId();
+               foreach ( $found as $idx => $revision ) {
+                       if ( $revId->equals( $revision->getRevisionId() ) ) {
+                               unset( $found[$idx] );
+                               break;
+                       }
+               }
+               return $found;
+       }
+
        // Somehow the template has to know which post the errors go with
        public function getRepliedTo() {
                return isset( $this->submitted['replyTo'] ) ? 
$this->submitted['replyTo'] : null;
diff --git a/includes/Model/AbstractRevision.php 
b/includes/Model/AbstractRevision.php
index 89776a5..c7ef83f 100644
--- a/includes/Model/AbstractRevision.php
+++ b/includes/Model/AbstractRevision.php
@@ -22,6 +22,8 @@
                        'perm' => null,
                        // i18n key to replace content with when state is 
active(unused with perm === null )
                        'content' => null,
+                       // This is the bit of text rendered instead of the 
content when isTopicTitle returns true
+                       'topic' => null,
                        // This is the bit of text rendered instead of the post 
creator
                        'usertext' => null,
                        // Whether or not to create a new revision when setting 
this state
@@ -35,6 +37,8 @@
                        // i18n key to replace content with when state is active
                        // NOTE: special case self::getHiddenContent still 
retrieves content in this case only
                        'content' => 'flow-post-hidden-by',
+                       // This is the bit of text rendered instead of the 
content when isTopicTitle returns true
+                       'topic' => 'flow-topic-hidden-by',
                        // This is the bit of text rendered instead of the post 
creator
                        'usertext' => 'flow-rev-message-hid-post',
                        // Whether or not to create a new revision when setting 
this state
@@ -47,6 +51,8 @@
                        'perm' => 'flow-delete',
                        // i18n key to replace content with when state is active
                        'content' => 'flow-post-deleted-by',
+                       // This is the bit of text rendered instead of the 
content when isTopicTitle returns true
+                       'topic' => 'flow-topic-deleted-by',
                        // This is the bit of text rendered instead of the post 
creator
                        'usertext' => 'flow-rev-message-deleted-post',
                        // Whether or not to create a new revision when setting 
this state
@@ -59,6 +65,8 @@
                        'perm' => 'flow-censor',
                        // i18n key to replace content with when state is active
                        'content' => 'flow-post-censored-by',
+                       // This is the bit of text rendered instead of the 
content when isTopicTitle returns true
+                       'topic' => 'flow-topic-censored-by',
                        // This is the bit of text rendered instead of the post 
creator
                        'usertext' => 'flow-rev-message-censored-post',
                        // Whether or not to create a new revision when setting 
this state
@@ -198,7 +206,11 @@
                return $keys[max( $aPos, $bPos )];
        }
 
-       public function moderate( User $user, $state, $changeType = null ) {
+       /**
+        * $createRevision = false should only be used to apply a moderation 
action
+        * to historical revisions, not general moderation.
+        */
+       public function moderate( User $user, $state, $changeType = null, 
$createRevision = true ) {
                if ( !isset( self::$perms[$state] ) ) {
                        wfDebugLog( __CLASS__, __FUNCTION__ . ': Provided 
moderation state does not exist : ' . $state );
                        return null;
@@ -208,11 +220,14 @@
                if ( !$this->isAllowed( $user, $mostRestrictive ) ) {
                        return null;
                }
-               // Censoring is special,  other moderation types just create
-               // a new revision but censoring adjusts the existing revision.
-               // Yes this mucks with the history just being a revision list.
-               if ( self::$perms[$state]['new-revision'] ) {
+
+               if ( $createRevision ) {
                        $obj = $this->newNullRevision( $user );
+                       if ( $changeType === null && isset( 
self::$perms[$state]['change-type'] ) ) {
+                               $obj->changeType = 
self::$perms[$state]['change-type'];
+                       } else {
+                               $obj->changeType = $changeType;
+                       }
                } else {
                        $obj = $this;
                }
@@ -227,12 +242,17 @@
                        $obj->moderatedByUserText = $user->getName();
                        $obj->moderationTimestamp = wfTimestampNow();
                }
-               if ( $changeType === null && isset( 
self::$perms[$state]['change-type'] ) ) {
-                       $obj->changeType = self::$perms[$state]['change-type'];
-               } else {
-                       $obj->changeType = $changeType;
-               }
+
                return $obj;
+       }
+
+       public function needsModerateHistorical() {
+               $state = $this->moderationState;
+               if ( !isset( self::$perms[$state]['new-revision'] ) ) {
+                       wfWarn( __CLASS__, __FUNCTION__ . ": Moderation state 
does not exist : $state" );
+                       return false;
+               }
+               return self::$perms[$state]['new-revision'];
        }
 
        public function restore( User $user ) {
@@ -277,17 +297,21 @@
                if ( $this->isAllowed( $user ) ) {
                        return $this->getConvertedContent( $format );
                } else {
-                       $moderatedAt = new MWTimestamp( 
$this->moderationTimestamp );
-
-                       // Messages: flow-post-hidden-by, flow-post-deleted-by, 
flow-post-censored-by
-                       return wfMessage(
-                               self::$perms[$this->moderationState]['content'],
-                               $this->moderatedByUserText,
-                               $moderatedAt->getHumanTimestamp()
-                       );
+                       return $this->getModeratedContent();
                }
        }
 
+       protected function getModeratedContent() {
+               $moderatedAt = new MWTimestamp( $this->moderationTimestamp );
+
+               // Messages: flow-post-hidden-by, flow-post-deleted-by, 
flow-post-censored-by
+               return wfMessage(
+                       self::$perms[$this->moderationState]['content'],
+                       $this->moderatedByUserText,
+                       $moderatedAt->getHumanTimestamp()
+               );
+       }
+
        public function getContentRaw() {
                if ( $this->decompressedContent === null ) {
                        $this->decompressedContent = 
\Revision::decompressRevisionText( $this->content, $this->flags );
diff --git a/includes/Model/PostRevision.php b/includes/Model/PostRevision.php
index 9f878c5..0ceec7a 100644
--- a/includes/Model/PostRevision.php
+++ b/includes/Model/PostRevision.php
@@ -88,7 +88,7 @@
 
        /**
         * Get the user ID of the user who created this post.
-        * Checks permissions and returns false 
+        * Checks permissions and returns false
         *
         * @param $user User The user to check permissions for.
         * @return int|bool The user ID, or false
@@ -389,4 +389,15 @@
                }
                return $user->getId() == $this->getCreatorId() || 
$user->isAllowed( 'flow-edit-post' );
        }
+
+       protected function getModeratedContent() {
+               if ( $this->isTopicTitle() ) {
+                       return wfMessage(
+                               self::$perms[$this->moderationState]['topic'],
+                               $this->moderatedByUserText
+                       );
+               } else {
+                       return parent::getModeratedContent();
+               }
+       }
 }
diff --git a/includes/Templating.php b/includes/Templating.php
index 250404c..76c1b5e 100644
--- a/includes/Templating.php
+++ b/includes/Templating.php
@@ -94,15 +94,7 @@
                        array(
                                'block' => $block,
                                'post' => $post,
-                               // An ideal world may pull this from the 
container, but for now this is fine.  This templating
-                               // class has too many responsibilities to keep 
receiving all required objects in the constructor.
-                               'postActionMenu' => new PostActionMenu(
-                                       $this->urlGenerator,
-                                       $wgUser,
-                                       $block,
-                                       $post,
-                                       $wgUser->getEditToken( $wgFlowTokenSalt 
)
-                               ),
+                               'postActionMenu' => $this->createActionMenu( 
$post, $block ),
                        ),
                        $return
                );
@@ -113,7 +105,22 @@
                        'block' => $block,
                        'topic' => $block->getWorkflow(),
                        'root' => $root,
+                       'postActionMenu' => $this->createActionMenu( $root, 
$block ),
                ), $return );
+       }
+
+       // An ideal world may pull this from the container, but for now this is 
fine.  This templating
+       // class has too many responsibilities to keep receiving all required 
objects in the constructor.
+       protected function createActionMenu( PostRevision $post, Block $block ) 
{
+               global $wgUser, $wgFlowTokenSalt;
+
+               return new PostActionMenu(
+                       $this->urlGenerator,
+                       $wgUser,
+                       $block,
+                       $post,
+                       $wgUser->getEditToken( $wgFlowTokenSalt )
+               );
        }
 
        public function getPagingLink( $block, $direction, $offset, $limit ) {
@@ -220,7 +227,7 @@
         * Gets a Flow-formatted plaintext human-readable identifier for a user.
         * Usually the user's name, but it can also return "an anonymous user",
         * or information about an item's moderation state.
-        * 
+        *
         * @param  User             $user    The User object to get a 
description for.
         * @param  AbstractRevision $rev     An AbstractRevision object to 
retrieve moderation state from.
         * @param  bool             $showIPs Whether or not to show IP 
addresses for anonymous users
diff --git a/includes/View/PostActionMenu.php b/includes/View/PostActionMenu.php
index 43d1ea9..9386f65 100644
--- a/includes/View/PostActionMenu.php
+++ b/includes/View/PostActionMenu.php
@@ -32,6 +32,37 @@
         */
        protected function getActionDetails( $action ) {
                $actions = array(
+                       // Not sure about mixing topic's and post's, although 
they are handled
+                       // the same currently.
+                       'hide-topic' => array(
+                               'method' => 'POST',
+                               'permissions' => array(
+                                       PostRevision::MODERATED_NONE => 
'flow-hide',
+                                       PostRevision::MODERATED_HIDDEN => 
'flow-hide',
+                               ),
+                       ),
+                       'delete-topic' => array(
+                               'method' => 'POST',
+                               'permissions' => array(
+                                       PostRevision::MODERATED_NONE => 
'flow-delete',
+                                       PostRevision::MODERATED_HIDDEN => 
'flow-delete',
+                               ),
+                       ),
+                       'censor-topic' => array(
+                               'method' => 'POST',
+                               'permissions' => array(
+                                       PostRevision::MODERATED_NONE => 
'flow-censor',
+                                       PostRevision::MODERATED_HIDDEN => 
'flow-censor',
+                               ),
+                       ),
+                       'restore-topic' => array(
+                               'method' => 'POST',
+                               'permissions' => array(
+                                       PostRevision::MODERATED_HIDDEN => 
'flow-hide',
+                                       PostRevision::MODERATED_DELETED => 
array( 'flow-delete', 'flow-censor' ),
+                                       PostRevision::MODERATED_CENSORED => 
'flow-censor',
+                               ),
+                       ),
                        'hide-post' => array(
                                'method' => 'POST',
                                'permissions' => array(
diff --git a/modules/discussion/styles/topic.less 
b/modules/discussion/styles/topic.less
index f307318..6fe85a5 100644
--- a/modules/discussion/styles/topic.less
+++ b/modules/discussion/styles/topic.less
@@ -4,6 +4,38 @@
 .flow-topic-container {
        padding-bottom: 54px;
 
+       &.flow-topic-moderated {
+               > .flow-post-container {
+                       display: none
+               }
+               .flow-topic-posts-meta {
+                       display: none
+               }
+       }
+
+       .flow-topic-moderated-hide,
+       .flow-topic-moderated-deleted,
+       .flow-topic-moderated-suppressed {
+               padding-left: 22px !important;
+
+               background-position: left;
+               background-size: 14px auto;
+               background-repeat: no-repeat;
+       }
+
+       .flow-topic-moderated-hide {
+               
.background-image-svg('../../base/images/moderate_menu_hidden_normal.svg', 
'../../base/images/moderate_menu_hidden_normal.png');
+       }
+
+       .flow-topic-moderated-deleted {
+               .background-image-svg('../../base/images/moderated_normal.svg', 
'../../base/images/moderated_normal.png');
+       }
+
+       .flow-topic-moderated-censored {
+               
.background-image-svg('../../base/images/suppressed_normal.svg', 
'../../base/images/suppressed_normal.png');
+       }
+
+
        .flow-titlebar {
                position: relative;
 
@@ -22,6 +54,16 @@
                &:hover,
                &.mw-ui-hover {
                        background: @topic-titlebar-background-color;
+
+                       .flow-topic-moderated-censored {
+                               
.background-image-svg('../../base/images/suppressed_hover.svg', 
'../../base/images/suppressed_hover.png');
+                       }
+                       .flow-topic-moderated-deleted {
+                               
.background-image-svg('../../base/images/moderated_hover.svg', 
'../../base/images/moderated_hover.png');
+                       }
+                       .flow-topic-moderated-hide {
+                               
.background-image-svg('../../base/images/moderate_menu_hidden_hover.svg', 
'../../base/images/moderate_menu_hidden_hover.png');
+                       }
                }
 
                .flow-topic-title {
diff --git a/templates/bak b/templates/bak
new file mode 100644
index 0000000..8a8089a
--- /dev/null
+++ b/templates/bak
@@ -0,0 +1,198 @@
+<?php
+
+// treat title like unparsed (wiki)text
+$title = $root->getContent( $user, 'wikitext' );
+
+// pre-register recursive callbacks; will then be fetched all at once when the
+// first one's result is requested
+$indexDescendantCount = $root->registerDescendantCount();
+$indexParticipants = $root->registerParticipants();
+
+echo Html::openElement( 'div', array(
+       'class' => 'flow-topic-container flow-topic-full' . 
$root->isModerated() ? ' flow-topic-moderated' : '',
+       'id' => 'flow-topic-' . $topic->getId()->getHex(),
+       'data-topic-id' => $topic->getId()->getHex(),
+       'data-title' => $root->isModerated() ? '' : $title,
+) );
+?>
+<div class="flow-element-container">
+       <div class="flow-titlebar mw-ui-button">
+               <?php
+               echo Html::rawElement(
+                       'a',
+                       array(
+                               'href' => $this->generateUrl( 
$root->getPostId(), 'edit-title' ),
+                               'class' => 'flow-edit-topic-link flow-icon 
flow-icon-top-aligned',
+                       ),
+                       wfMessage( 'flow-topic-action-edit-title' )
+               );
+               ?>
+
+               <div class="flow-topic-title">
+                       <?php if ( $root->isModerated() ): ?>
+                               <h2 class='flow-topic-moderated 
flow-topic-moderated-<?php echo $root->getModerationState() ?>'>
+                                       <?php // passing null as user 
(unprivileged) gets the hidden/deleted/suppressed text
+                                       echo htmlspecialchars( 
$root->getContent( null ) ) ?>
+                               </h2>
+                       <?php else: ?>
+                               <h2 class="flow-realtitle">
+                                       <?php echo htmlspecialchars( $title ); 
?>
+                               </h2>
+                       <?php endif ?>
+               </div>
+
+               <div class="flow-actions">
+                       <a class="flow-actions-link" href="#"><?php echo 
wfMessage( 'flow-topic-actions' )->escaped(); ?></a>
+                       <div class="flow-actions-flyout">
+                               <ul>
+                                       <?php if ( $postActionMenu->isAllowed( 
'hide-topic' ) ) {
+                                               echo '<li 
class="flow-action-hide">', $postActionMenu->getButton(
+                                                       'hide-topic',
+                                                       wfMessage( 
'flow-topic-action-hide-topic' )->plain(),
+                                                       'mw-ui-button'
+                                               ), '</li>';
+                                       } ?>
+                                       <?php if ( $postActionMenu->isAllowed( 
'delete-topic' ) ) {
+                                               echo '<li 
class="flow-action-delete">', $postActionMenu->getButton(
+                                                       'delete-topic',
+                                                       wfMessage( 
'flow-topic-action-delete-topic' )->plain(),
+                                                       'mw-ui-button'
+                                               ), '</li>';
+                                       } ?>
+                                       <?php if ( $postActionMenu->isAllowed( 
'censor-topic' ) ) {
+                                               echo '<li 
class="flow-action-censor">', $postActionMenu->getButton(
+                                                       'censor-topic',
+                                                       wfMessage( 
'flow-topic-action-censor-topic' )->plain(),
+                                                       'mw-ui-button'
+                                               ), '</li>';
+                                       } ?>
+                                       <?php if ( $postActionMenu->isAllowed( 
'restore-topic' ) ) {
+                                               echo '<li 
class="flow-action-restore">', $postActionMenu->getButton(
+                                                       'restore-topic',
+                                                       wfMessage( 
'flow-topic-action-restore-topic' )->plain(),
+                                                       'mw-ui-button'
+                                               ), '</li>';
+                                       } ?>
+                                       <li class="flow-action-close">
+                                               <a href="#" 
class="mw-ui-button">@todo: Close topic</a>
+                                       </li>
+                               </ul>
+                       </div>
+               </div>
+
+               <p class="flow-datestamp">
+                       <?php
+                               // timestamp html
+                               $content = '
+                                       <span class="flow-agotime" 
style="display: inline">'. $topic->getLastModifiedObj()->getHumanTimestamp() 
.'</span>
+                                       <span class="flow-utctime" 
style="display: none">'. $topic->getLastModifiedObj()->getTimestamp( TS_RFC2822 
) .'</span>';
+
+                               // build history button with timestamp html as 
content
+                               echo Html::rawElement( 'a',
+                                       array(
+                                               'class' => 
'flow-action-history-link',
+                                               'href' => $this->generateUrl( 
$root->getPostId(), 'topic-history' ),
+                                       ),
+                                       $content
+                               );
+                       ?>
+               </p>
+
+               <?php if ( $root->isAllowed( $user ) ):
+                       echo Html::element(
+                               'a',
+                               array(
+                                       'class' => 'flow-icon-permalink 
flow-icon flow-icon-top-aligned',
+                                       'title' => wfMessage( 
'flow-topic-action-view' )->text(),
+                                       'href' => $this->generateUrl( $topic ),
+                               ),
+                               wfMessage( 'flow-topic-action-view' )->text()
+                       );
+                       ?>
+
+                       <ul class="flow-topic-posts-meta">
+                               <li class="flow-topic-participants">
+                                       <?php echo $this->printParticipants( 
$root, $indexParticipants ); ?>
+                               </li>
+                               <li class="flow-topic-comments">
+                                       <a href="#" class="flow-reply-link" 
data-topic-id="<?php echo $topic->getId()->getHex() ?>">
+                                               <?php
+                                                       // get total number of 
posts in topic
+                                                       $comments = 
$root->getRecursiveResult( $indexDescendantCount );
+                                                       echo wfMessage( 
'flow-topic-comments', $comments )->text();
+                                               ?>
+                                       </a>
+                               </li>
+                       </ul>
+
+                       <?php
+                               // @todo: afaik, there's no watchlist 
functionality yet; this blurb is just to position it correctly already
+
+                               $watchlistActive = false; // @todo: true if 
already watchlisted, false if not
+                               echo Html::element(
+                                       'a',
+                                       array(
+                                               'class' => 'flow-icon-watchlist 
flow-icon flow-icon-bottom-aligned'
+                                                       . ( $watchlistActive ? 
' flow-icon-watchlist-active' : '' ),
+                                               'title' => wfMessage( 
'flow-topic-action-watchlist' )->text(),
+                                               'href' => '#',
+                                               'onclick' => "alert( '@todo: 
Not yet implemented!' ); return false;"
+                                       ),
+                                       wfMessage( 
'flow-topic-action-watchlist' )->text()
+                               );
+                       ?>
+               <?php endif; /* !$root->isModerated() */ ?>
+       </div>
+</div>
+<?php if ( $root->isAllowed( $user ) ):
+       foreach( $root->getChildren() as $child ) {
+               echo $this->renderPost( $child, $block, $root );
+       }
+
+       // Topic reply box
+       echo Html::openElement( 'div', array(
+               'class' => 'flow-topic-reply-container flow-post-container 
flow-element-container',
+               'data-post-id' => $root->getRevisionId()->getHex(),
+               'id' => 'flow-topic-reply-' . $topic->getId()->getHex()
+       ) );
+       ?>
+               <span class="flow-creator">
+                       <span class="flow-creator-simple" style="display: 
inline">
+                               <?php echo $this->getUserText( $user ); ?>
+                       </span>
+                       <span class="flow-creator-full" style="display: none">
+                               <?php echo $this->userToolLinks( 
$user->getId(), $user->getName() ); ?>
+                       </span>
+               </span>
+       <?php
+               echo Html::openElement( 'form', array(
+                       'method' => 'POST',
+                       'action' => $this->generateUrl( $block->getWorkflow(), 
'reply' ),
+                       'class' => 'flow-topic-reply-form',
+               ) ),
+               Html::element( 'input', array(
+                       'type' => 'hidden',
+                       'name' => $block->getName() . '[replyTo]',
+                       'value' => $topic->getId()->getHex(),
+               ) ),
+               Html::element( 'input', array(
+                       'type' => 'hidden',
+                       'name' => 'wpEditToken',
+                       'value' => $editToken,
+               ) ),
+               Html::textarea( $block->getName() . '[topic-reply-content]', 
'', array(
+                       'placeholder' => wfMessage( 
'flow-reply-topic-placeholder', $user->getName(), $title )->text(),
+                       'class' => 'flow-input mw-ui-input 
flow-topic-reply-content',
+               ) ),
+               Html::openElement( 'div', array( 'class' => 
'flow-post-form-controls' ) ),
+               Html::element( 'input', array(
+                       'type' => 'submit',
+                       'value' => wfMessage( 'flow-reply-submit', 
$this->getUserText( $root->getCreator( $user ), $root ) )->text(),
+                       'class' => 'mw-ui-button mw-ui-constructive 
flow-topic-reply-submit',
+               ) ),
+               Html::closeElement( 'div' ),
+               Html::closeElement( 'form' ),
+               Html::closeElement( 'div' );
+       ?>
+       </div>
+<?php endif /* !$root->isModerated() */ ?>
diff --git a/templates/topic.html.php b/templates/topic.html.php
index 0adade3..67bbc84 100644
--- a/templates/topic.html.php
+++ b/templates/topic.html.php
@@ -9,10 +9,10 @@
 $indexParticipants = $root->registerParticipants();
 
 echo Html::openElement( 'div', array(
-       'class' => 'flow-topic-container flow-topic-full',
+       'class' => 'flow-topic-container flow-topic-full' . ( 
$root->isModerated() ? ' flow-topic-moderated' : '' ),
        'id' => 'flow-topic-' . $topic->getId()->getHex(),
        'data-topic-id' => $topic->getId()->getHex(),
-       'data-title' => $title,
+       'data-title' => $root->isModerated() ? '' : $title,
 ) );
 ?>
 <div class="flow-element-container">
@@ -29,17 +29,50 @@
                ?>
 
                <div class="flow-topic-title">
-                       <h2 class="flow-realtitle">
-                               <?php echo htmlspecialchars( $title ); ?>
-                       </h2>
+                       <?php if ( $root->isModerated() ): ?>
+                               <h2 class='flow-topic-moderated 
flow-topic-moderated-<?php echo $root->getModerationState() ?>'>
+                                       <?php // passing null as user 
(unprivileged) gets the hidden/deleted/suppressed text
+                                       echo htmlspecialchars( 
$root->getContent( null ) ) ?>
+                               </h2>
+                       <?php else: ?>
+                               <h2 class="flow-realtitle">
+                                       <?php echo htmlspecialchars( $title ); 
?>
+                               </h2>
+                       <?php endif ?>
                </div>
+
                <div class="flow-actions">
                        <a class="flow-actions-link" href="#"><?php echo 
wfMessage( 'flow-topic-actions' )->escaped(); ?></a>
                        <div class="flow-actions-flyout">
                                <ul>
-                                       <li class="flow-action-hide">
-                                               <a href="#" class="mw-ui-button 
mw-ui-destructive">@todo: Hide topic</a>
-                                       </li>
+                                       <?php if ( $postActionMenu->isAllowed( 
'hide-topic' ) ) {
+                                               echo '<li 
class="flow-action-hide">', $postActionMenu->getButton(
+                                                       'hide-topic',
+                                                       wfMessage( 
'flow-topic-action-hide-topic' )->plain(),
+                                                       'mw-ui-button'
+                                               ), '</li>';
+                                       } ?>
+                                       <?php if ( $postActionMenu->isAllowed( 
'delete-topic' ) ) {
+                                               echo '<li 
class="flow-action-delete">', $postActionMenu->getButton(
+                                                       'delete-topic',
+                                                       wfMessage( 
'flow-topic-action-delete-topic' )->plain(),
+                                                       'mw-ui-button'
+                                               ), '</li>';
+                                       } ?>
+                                       <?php if ( $postActionMenu->isAllowed( 
'censor-topic' ) ) {
+                                               echo '<li 
class="flow-action-censor">', $postActionMenu->getButton(
+                                                       'censor-topic',
+                                                       wfMessage( 
'flow-topic-action-censor-topic' )->plain(),
+                                                       'mw-ui-button'
+                                               ), '</li>';
+                                       } ?>
+                                       <?php if ( $postActionMenu->isAllowed( 
'restore-topic' ) ) {
+                                               echo '<li 
class="flow-action-restore">', $postActionMenu->getButton(
+                                                       'restore-topic',
+                                                       wfMessage( 
'flow-topic-action-restore-topic' )->plain(),
+                                                       'mw-ui-button'
+                                               ), '</li>';
+                                       } ?>
                                        <li class="flow-action-close">
                                                <a href="#" 
class="mw-ui-button">@todo: Close topic</a>
                                        </li>
@@ -65,7 +98,7 @@
                        ?>
                </p>
 
-               <?php
+               <?php if ( $root->isAllowed( $user ) ):
                        echo Html::element(
                                'a',
                                array(
@@ -75,89 +108,91 @@
                                ),
                                wfMessage( 'flow-topic-action-view' )->text()
                        );
-               ?>
+                       ?>
 
-               <ul class="flow-topic-posts-meta">
-                       <li class="flow-topic-participants">
-                               <?php echo $this->printParticipants( $root, 
$indexParticipants ); ?>
-                       </li>
-                       <li class="flow-topic-comments">
-                               <a href="#" class="flow-reply-link" 
data-topic-id="<?php echo $topic->getId()->getHex() ?>">
-                                       <?php
-                                               // get total number of posts in 
topic
-                                               $comments = 
$root->getRecursiveResult( $indexDescendantCount );
-                                               echo wfMessage( 
'flow-topic-comments', $comments )->text();
-                                       ?>
-                               </a>
-                       </li>
-               </ul>
+                       <ul class="flow-topic-posts-meta">
+                               <li class="flow-topic-participants">
+                                       <?php echo $this->printParticipants( 
$root, $indexParticipants ); ?>
+                               </li>
+                               <li class="flow-topic-comments">
+                                       <a href="#" class="flow-reply-link" 
data-topic-id="<?php echo $topic->getId()->getHex() ?>">
+                                               <?php
+                                                       // get total number of 
posts in topic
+                                                       $comments = 
$root->getRecursiveResult( $indexDescendantCount );
+                                                       echo wfMessage( 
'flow-topic-comments', $comments )->text();
+                                               ?>
+                                       </a>
+                               </li>
+                       </ul>
 
-               <?php
-                       // @todo: afaik, there's no watchlist functionality 
yet; this blurb is just to position it correctly already
+                       <?php
+                               // @todo: afaik, there's no watchlist 
functionality yet; this blurb is just to position it correctly already
 
-                       $watchlistActive = false; // @todo: true if already 
watchlisted, false if not
-                       echo Html::element(
-                               'a',
-                               array(
-                                       'class' => 'flow-icon-watchlist 
flow-icon flow-icon-bottom-aligned'
-                                               . ( $watchlistActive ? ' 
flow-icon-watchlist-active' : '' ),
-                                       'title' => wfMessage( 
'flow-topic-action-watchlist' )->text(),
-                                       'href' => '#',
-                                       'onclick' => "alert( '@todo: Not yet 
implemented!' ); return false;"
-                               ),
-                               wfMessage( 'flow-topic-action-watchlist' 
)->text()
-                       );
-               ?>
+                               $watchlistActive = false; // @todo: true if 
already watchlisted, false if not
+                               echo Html::element(
+                                       'a',
+                                       array(
+                                               'class' => 'flow-icon-watchlist 
flow-icon flow-icon-bottom-aligned'
+                                                       . ( $watchlistActive ? 
' flow-icon-watchlist-active' : '' ),
+                                               'title' => wfMessage( 
'flow-topic-action-watchlist' )->text(),
+                                               'href' => '#',
+                                               'onclick' => "alert( '@todo: 
Not yet implemented!' ); return false;"
+                                       ),
+                                       wfMessage( 
'flow-topic-action-watchlist' )->text()
+                               );
+                       ?>
+               <?php endif; /* !$root->isModerated() */ ?>
        </div>
 </div>
-<?php
-foreach( $root->getChildren() as $child ) {
-       echo $this->renderPost( $child, $block, $root );
-}
+<?php if ( $root->isAllowed( $user ) ):
+       foreach( $root->getChildren() as $child ) {
+               echo $this->renderPost( $child, $block, $root );
+       }
 
-// Topic reply box
-echo Html::openElement( 'div', array(
-       'class' => 'flow-topic-reply-container flow-post-container 
flow-element-container',
-       'data-post-id' => $root->getRevisionId()->getHex(),
-       'id' => 'flow-topic-reply-' . $topic->getId()->getHex()
-) );
-?>
-       <span class="flow-creator">
-               <span class="flow-creator-simple" style="display: inline">
-                       <?php echo $this->getUserText( $user ); ?>
+       // Topic reply box
+       echo Html::openElement( 'div', array(
+               'class' => 'flow-topic-reply-container flow-post-container 
flow-element-container',
+               'data-post-id' => $root->getRevisionId()->getHex(),
+               'id' => 'flow-topic-reply-' . $topic->getId()->getHex()
+       ) );
+       ?>
+               <span class="flow-creator">
+                       <span class="flow-creator-simple" style="display: 
inline">
+                               <?php echo $this->getUserText( $user ); ?>
+                       </span>
+                       <span class="flow-creator-full" style="display: none">
+                               <?php echo $this->userToolLinks( 
$user->getId(), $user->getName() ); ?>
+                       </span>
                </span>
-               <span class="flow-creator-full" style="display: none">
-                       <?php echo $this->userToolLinks( $user->getId(), 
$user->getName() ); ?>
-               </span>
-       </span>
-<?php
-       echo Html::openElement( 'form', array(
-               'method' => 'POST',
-               'action' => $this->generateUrl( $block->getWorkflow(), 'reply' 
),
-               'class' => 'flow-topic-reply-form',
-       ) ),
-       Html::element( 'input', array(
-               'type' => 'hidden',
-               'name' => $block->getName() . '[replyTo]',
-               'value' => $topic->getId()->getHex(),
-       ) ),
-       Html::element( 'input', array(
-               'type' => 'hidden',
-               'name' => 'wpEditToken',
-               'value' => $editToken,
-       ) ),
-       Html::textarea( $block->getName() . '[topic-reply-content]', '', array(
-               'placeholder' => wfMessage( 'flow-reply-topic-placeholder', 
$user->getName(), $title )->text(),
-               'class' => 'flow-input mw-ui-input flow-topic-reply-content',
-       ) ),
-       Html::openElement( 'div', array( 'class' => 'flow-post-form-controls' ) 
),
-       Html::element( 'input', array(
-               'type' => 'submit',
-               'value' => wfMessage( 'flow-reply-submit', $this->getUserText( 
$root->getCreator( $user ), $root ) )->text(),
-               'class' => 'mw-ui-button mw-ui-constructive 
flow-topic-reply-submit',
-       ) ),
-       Html::closeElement( 'div' ),
-       Html::closeElement( 'form' ),
-       Html::closeElement( 'div' );
-?>
-</div>
+       <?php
+               echo Html::openElement( 'form', array(
+                       'method' => 'POST',
+                       'action' => $this->generateUrl( $block->getWorkflow(), 
'reply' ),
+                       'class' => 'flow-topic-reply-form',
+               ) ),
+               Html::element( 'input', array(
+                       'type' => 'hidden',
+                       'name' => $block->getName() . '[replyTo]',
+                       'value' => $topic->getId()->getHex(),
+               ) ),
+               Html::element( 'input', array(
+                       'type' => 'hidden',
+                       'name' => 'wpEditToken',
+                       'value' => $editToken,
+               ) ),
+               Html::textarea( $block->getName() . '[topic-reply-content]', 
'', array(
+                       'placeholder' => wfMessage( 
'flow-reply-topic-placeholder', $user->getName(), $title )->text(),
+                       'class' => 'flow-input mw-ui-input 
flow-topic-reply-content',
+               ) ),
+               Html::openElement( 'div', array( 'class' => 
'flow-post-form-controls' ) ),
+               Html::element( 'input', array(
+                       'type' => 'submit',
+                       'value' => wfMessage( 'flow-reply-submit', 
$this->getUserText( $root->getCreator( $user ), $root ) )->text(),
+                       'class' => 'mw-ui-button mw-ui-constructive 
flow-topic-reply-submit',
+               ) ),
+               Html::closeElement( 'div' ),
+               Html::closeElement( 'form' ),
+               Html::closeElement( 'div' );
+       ?>
+       </div>
+<?php endif /* !$root->isModerated() */ ?>

-- 
To view, visit https://gerrit.wikimedia.org/r/91135
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I10cae63c2491c9f467968d6f8d604ea7f743ea96
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/Flow
Gerrit-Branch: master
Gerrit-Owner: EBernhardson <ebernhard...@wikimedia.org>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to