jenkins-bot has submitted this change and it was merged. Change subject: (Bug 61715) Make history entries look at most recent revision ......................................................................
(Bug 61715) Make history entries look at most recent revision The problem with history thingies is that "restore" should not show up for users that can not view the permissions for what is restored. isAllowed will check the most recent revision to get some sort of "global allowed state" for a revision. Combined with the above, this would make any revision of a just-restored post be invisible. For that reason, I had made history (and RC) permission checks only do isRevisionAllowed. That's incorrect; they should also check last revision (but in a way that is actually correct - where the restore-aspect is ignored for the "global" moderation state) Bug: 61715 Change-Id: Ia27c94176bb8f40f2fe683a54ab9ddafb4f98fc0 --- M FlowActions.php M includes/Block/Header.php M includes/Block/Topic.php M includes/Formatter/CheckUser.php M includes/Formatter/Contributions.php M includes/Formatter/RecentChanges.php M includes/Log/Formatter.php M includes/RevisionActionPermissions.php M includes/Templating.php M tests/RevisionCollectionPermissionsTest.php 10 files changed, 78 insertions(+), 59 deletions(-) Approvals: EBernhardson: Looks good to me, approved jenkins-bot: Verified diff --git a/FlowActions.php b/FlowActions.php index a799372..b0731c2 100644 --- a/FlowActions.php +++ b/FlowActions.php @@ -371,14 +371,47 @@ 'log_type' => false, 'permissions' => array( PostRevision::MODERATED_NONE => function( AbstractRevision $revision, RevisionActionPermissions $permissions ) { - // if a revision was the result of a restore-action, we have - // to look at the previous revision what the original moderation - // status was; permissions for the restore-actions visibility - // is the same as the moderation (e.g. if user can't see - // suppress actions, he can't see restores from suppress + static $previousCollectionId; + + /* + * To check permissions, both the current revision (revision- + * specific moderation state)& the last revision (global + * collection moderation state) will always be checked. + * This one has special checks to make sure "restore" actions + * are hidden when the user has no permissions to see the + * moderation state they were restored from. + * We don't want that test to happen; otherwise, when a post + * has just been restored in the most recent revisions, that + * would result in none of the previous revisions being + * available (because a user would need permissions for the the + * state the last revision was restored from) + */ + $collection = $revision->getCollection(); + if ( $previousCollectionId && $collection->getId()->equals( $previousCollectionId ) ) { + // doublecheck that this run is indeed against the most + // recent revision, to get the global collection state + try { + $lastRevision = $collection->getLastRevision(); + if ( $revision->getRevisionId()->equals( $lastRevision->getRevisionId() ) ) { + $previousCollectionId = null; + return ''; + } + } catch ( Exception $e ) { + // nothing to do here; if fetching last revision failed, + // we're just not testing any stored revision; that's ok + } + } + $previousCollectionId = $collection->getId(); + + /* + * If a revision was the result of a restore-action, we have + * to look at the previous revision what the original moderation + * status was; permissions for the restore-actions visibility + * is the same as the moderation (e.g. if user can't see + * suppress actions, he can't see restores from suppress. + */ if ( $revision->getChangeType() == 'restore-post' ) { - $revisionable = $revision->getCollection(); - $previous = $revisionable->getPrevRevision( $revision ); + $previous = $collection->getPrevRevision( $revision ); if ( $previous->getModerationState() === AbstractRevision::MODERATED_NONE ) { return ''; diff --git a/includes/Block/Header.php b/includes/Block/Header.php index f7aac7f..785a109 100644 --- a/includes/Block/Header.php +++ b/includes/Block/Header.php @@ -206,8 +206,10 @@ // get rid of history entries user doesn't have sufficient permissions for foreach ( $history as $i => $revision ) { + /** @var PostRevision|Header $revision */ + // only check against the specific revision, ignoring the most recent - if ( !$this->permissions->isRevisionAllowed( $revision, 'post-history' ) ) { + if ( !$this->permissions->isAllowed( $revision, 'post-history' ) ) { unset( $history[$i] ); } } diff --git a/includes/Block/Topic.php b/includes/Block/Topic.php index 40534ab..2bee4eb 100644 --- a/includes/Block/Topic.php +++ b/includes/Block/Topic.php @@ -755,8 +755,10 @@ if ( $history ) { // get rid of history entries user doesn't have sufficient permissions for foreach ( $history as $i => $revision ) { + /** @var PostRevision $revision */ + // only check against the specific revision, ignoring the most recent - if ( !$this->permissions->isRevisionAllowed( $revision, 'post-history' ) ) { + if ( !$this->permissions->isAllowed( $revision, 'post-history' ) ) { unset( $history[$i] ); } } @@ -869,8 +871,10 @@ if ( $history ) { // get rid of history entries user doesn't have sufficient permissions for foreach ( $history as $i => $revision ) { + /** @var PostRevision $revision */ + // only check against the specific revision, ignoring the most recent - if ( !$this->permissions->isRevisionAllowed( $revision, 'topic-history' ) ) { + if ( !$this->permissions->isAllowed( $revision, 'topic-history' ) ) { unset( $history[$i] ); } } diff --git a/includes/Formatter/CheckUser.php b/includes/Formatter/CheckUser.php index 8010e12..d359f9e 100644 --- a/includes/Formatter/CheckUser.php +++ b/includes/Formatter/CheckUser.php @@ -22,7 +22,7 @@ // @todo: this currently only implements CU links // we'll probably want to add a hook to CheckUser that lets us blank out - // the entire line for entries that !isRevisionAllowed( <this-revision>, 'checkuser' ) + // the entire line for entries that !isAllowed( <this-revision>, 'checkuser' ) $data = explode( ',', $row->cuc_comment ); $post = null; diff --git a/includes/Formatter/Contributions.php b/includes/Formatter/Contributions.php index 13f70e8..e96dc23 100644 --- a/includes/Formatter/Contributions.php +++ b/includes/Formatter/Contributions.php @@ -30,7 +30,7 @@ $user = $pager->getUser(); $title = $workflow->getArticleTitle(); - if ( !$this->getPermissions( $user )->isRevisionAllowed( $revision, 'contributions' ) ) { + if ( !$this->getPermissions( $user )->isAllowed( $revision, 'contributions' ) ) { return false; } diff --git a/includes/Formatter/RecentChanges.php b/includes/Formatter/RecentChanges.php index 2081c31..99a1137 100644 --- a/includes/Formatter/RecentChanges.php +++ b/includes/Formatter/RecentChanges.php @@ -68,7 +68,7 @@ return false; } - if ( !$this->getPermissions( $user )->isRevisionAllowed( $revision, 'recentchanges' ) ) { + if ( !$this->getPermissions( $user )->isAllowed( $revision, 'recentchanges' ) ) { return false; } diff --git a/includes/Log/Formatter.php b/includes/Log/Formatter.php index 5de483c..ca3450c 100644 --- a/includes/Log/Formatter.php +++ b/includes/Log/Formatter.php @@ -20,11 +20,11 @@ $skin = $this->plaintext ? null : $this->context->getSkin(); $params = $this->entry->getParameters(); - // @todo: we should probably check if user isRevisionAllowed( <this-revision>, 'log' ) + // @todo: we should probably check if user isAllowed( <this-revision>, 'log' ) // unlike RC, Contributions, ... this one does not batch-load all Flow // revisions & does not use the same Formatter, i18n message text, etc // I assume this will change with https://trello.com/c/S10KfqBm/62-8-history-watchlist-rc-and-contribs-changes - // Then, we should also add in the isRevisionAllowed check! + // Then, we should also add in the isAllowed check! // FIXME this is ugly. Why were we treating log parameters as // URL GET parameters in the first place? diff --git a/includes/RevisionActionPermissions.php b/includes/RevisionActionPermissions.php index 2d59074..bb3eb56 100644 --- a/includes/RevisionActionPermissions.php +++ b/includes/RevisionActionPermissions.php @@ -63,17 +63,13 @@ try { // Also check if the user would be allowed to perform this against - // against the most recent revision (unless it's already the most recent - // revision) - the last revision is the current state of a revision, so - // checking against a revision at one point in time alone isn't enough. + // against the most recent revision - the last revision is the + // current state of an object, so checking against a revision at one + // point in time alone isn't enough. $last = $revision->getCollection()->getLastRevision(); + return $allowed && $this->isRevisionAllowed( $last, $action ); - // check if $revision is not already the most recent, to prevent - // infinite recursion in this method - $isLastRevision = $last->getRevisionId()->equals( $revision->getRevisionId() ); - return $allowed && ( $isLastRevision || $this->isAllowed( $last, $action ) ); - - // If data is not in storage, just return that revision's status + // If data is not in storage, just return that revision's status } catch ( InvalidDataException $e ) { return $allowed; } @@ -113,7 +109,7 @@ * @param string $action * @return bool */ - public function isRevisionAllowed( AbstractRevision $revision = null, $action ) { + protected function isRevisionAllowed( AbstractRevision $revision = null, $action ) { // Users must have the core 'edit' permission to perform any write action in flow $performsWrites = $this->actions->getValue( $action, 'performs-writes' ); if ( $performsWrites && ( !$this->user->isAllowed( 'edit' ) || $this->user->isBlocked() ) ) { @@ -133,33 +129,6 @@ array( $this->user, 'isAllowedAny' ), (array) $permission ); - } - - /** - * Check if a user is allowed to perform certain actions, only against 1 - * specific revision (whereas the default isAllowed() will check if the - * given $action is allowed for both given and the most current revision) - * - * @param AbstractRevision|null $revision - * @param string $action... Multiple parameters to check if either of the provided actions are allowed - * @return bool - */ - public function isRevisionAllowedAny( AbstractRevision $revision = null, $action /* [, $action2 [, ... ]] */ ) { - $actions = func_get_args(); - // Pull $revision out of the actions list - array_shift( $actions ); - $allowed = false; - - foreach ( $actions as $action ) { - $allowed |= $this->isRevisionAllowed( $revision, $action ); - - // as soon as we've found one that is allowed, break - if ( $allowed ) { - break; - } - } - - return $allowed; } /** diff --git a/includes/Templating.php b/includes/Templating.php index 1cd5966..ef26b16 100644 --- a/includes/Templating.php +++ b/includes/Templating.php @@ -307,7 +307,7 @@ * @return string */ public function getUserText( AbstractRevision $revision ) { - if ( $this->permissions->isRevisionAllowed( $revision, 'view' ) ) { + if ( $this->permissions->isAllowed( $revision, 'view' ) ) { return $this->usernames->get( wfWikiId(), $revision->getUserId(), $revision->getUserIp() ); } else { $username = $this->usernames->get( @@ -337,7 +337,7 @@ * @return string HTML */ public function getUserLinks( AbstractRevision $revision ) { - if ( $this->permissions->isRevisionAllowed( $revision, 'view' ) ) { + if ( $this->permissions->isAllowed( $revision, 'view' ) ) { $userid = $revision->getUserId(); $username = $this->usernames->get( wfWikiId(), $revision->getUserId(), $revision->getUserIp() ); return Linker::userLink( $userid, $username ) . Linker::userToolLinks( $userid, $username ); @@ -374,7 +374,7 @@ * @return string */ public function getCreatorText( PostRevision $revision ) { - if ( $this->permissions->isRevisionAllowed( $revision, 'view' ) ) { + if ( $this->permissions->isAllowed( $revision, 'view' ) ) { return $this->usernames->get( wfWikiId(), $revision->getCreatorId(), @@ -414,7 +414,7 @@ * @return string HTML */ public function getContent( AbstractRevision $revision, $format = 'html' ) { - if ( $this->permissions->isRevisionAllowed( $revision, 'view' ) ) { + if ( $this->permissions->isAllowed( $revision, 'view' ) ) { $content = $revision->getContent( $format ); if ( $format === 'html' ) { diff --git a/tests/RevisionCollectionPermissionsTest.php b/tests/RevisionCollectionPermissionsTest.php index 62637af..604f423 100644 --- a/tests/RevisionCollectionPermissionsTest.php +++ b/tests/RevisionCollectionPermissionsTest.php @@ -147,13 +147,24 @@ array( 'restore-post' => true ), array( 'suppress-post' => true ), ) ), + + // bug 61715 + array( $this->confirmedUser(), 'topic-history', array( + array( 'new-post' => false ), + array( 'suppress-post' => false ), + ) ), + array( $this->confirmedUser(), 'topic-history', array( + array( 'new-post' => true ), + array( 'suppress-post' => false ), + array( 'restore-post' => false ), + ) ), ); } /** * @dataProvider permissionsProvider */ - public function testPermissions( User $user, $action, $actions ) { + public function testPermissions( User $user, $permisisonAction, $actions ) { $permissions = new RevisionActionPermissions( $this->actions, $user ); // we'll have to process this in 2 steps: first do all of the actions, @@ -171,8 +182,8 @@ $revision = array_shift( $revisions ); $this->assertEquals( $expected, - $permissions->isAllowed( $revision, 'view' ), - 'User ' . $user->getName() . ' should ' . ( $expected ? '' : 'not' ) . ' be allowed to view revision ' . key( $action ) + $permissions->isAllowed( $revision, $permisisonAction ), + 'User ' . $user->getName() . ' should ' . ( $expected ? '' : 'not ' ) . 'be allowed action ' . $permisisonAction . ' on revision ' . key( $action ) ); } } -- To view, visit https://gerrit.wikimedia.org/r/114679 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: Ia27c94176bb8f40f2fe683a54ab9ddafb4f98fc0 Gerrit-PatchSet: 2 Gerrit-Project: mediawiki/extensions/Flow Gerrit-Branch: master Gerrit-Owner: Matthias Mullie <mmul...@wikimedia.org> Gerrit-Reviewer: EBernhardson <ebernhard...@wikimedia.org> Gerrit-Reviewer: jenkins-bot <> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits