| Current File : /home/jvzmxxx/wiki1/extensions/Flow/tests/phpunit/Collection/RevisionCollectionPermissionsTest.php |
<?php
namespace Flow\Tests\Collection;
use Flow\Container;
use Flow\FlowActions;
use Flow\Model\PostRevision;
use Flow\Model\AbstractRevision;
use Flow\RevisionActionPermissions;
use Flow\Tests\PostRevisionTestCase;
use Block;
use User;
/**
* @group Database
* @group Flow
*/
class RevisionCollectionPermissionsTest extends PostRevisionTestCase {
/**
* @var FlowActions
*/
protected $actions;
/**
* Map of action name to moderation status, as helper for
* $this->generateRevision()
*
* @var array
*/
protected $moderation = array(
'restore-post' => AbstractRevision::MODERATED_NONE,
'hide-post' => AbstractRevision::MODERATED_HIDDEN,
'delete-post' => AbstractRevision::MODERATED_DELETED,
'suppress-post' => AbstractRevision::MODERATED_SUPPRESSED,
);
/**
* @var User
*/
protected
$blockedUser,
$anonUser,
$unconfirmedUser,
$confirmedUser,
$sysopUser,
$oversightUser;
/**
* @var Block
*/
protected $block;
protected function setUp() {
parent::setUp();
$this->clearExtraLifecycleHandlers();
// We don't want local config getting in the way of testing whether or
// not our permissions implementation works well.
// This will load default $wgGroupPermissions + Flow settings, so we can
// test if permissions work well, regardless of any custom config.
global $IP, $wgFlowGroupPermissions;
$wgGroupPermissions = array();
require "$IP/includes/DefaultSettings.php";
$wgGroupPermissions = array_merge_recursive( $wgGroupPermissions, $wgFlowGroupPermissions );
$this->setMwGlobals( 'wgGroupPermissions', $wgGroupPermissions );
// When external store is used, data is written to "blobs" table, which
// by default doesn't exist - let's just not use externalstorage in test
$this->setMwGlobals( 'wgFlowExternalStore', false );
// load actions object
$this->actions = Container::get( 'flow_actions' );
// block a user
$blockedUser = $this->blockedUser();
$this->block = new Block( array(
'address' => $blockedUser->getName(),
'user' => $blockedUser->getID()
) );
$this->block->insert();
// ensure that block made it into the database
wfGetDB( DB_MASTER )->commit( __METHOD__, 'flush' );
}
/**
* Provides User, permissions test action, and revision actions (with
* expected permission results for test action).
*
* Basically: a new post is created and the actions in $actions are
* performed. After that, we'll check if $action is allowed on all of those
* revisions, with the expected true/false value from $actions as result.
*
* @return array
*/
public function permissionsProvider() {
return array(
// irregardless of current status, if a user has no permissions for
// a specific revision, he can't see it
array( $this->confirmedUser(), 'view', array(
// Key is the moderation action; value is the 'view' permission
// for that corresponding revision after all moderation is done.
// In this case, a post will be created with 3 revisions:
// [1] create post, [2] suppress, [3] restore
// After creating all revisions, all of these will be tested for
// 'view' permissions against that specific revision. Here:
// [1] should be visible (this + last rev not suppressed)
// [2] should not (was suppressed)
// [3] should be visible again (undid suppression)
array( 'new-post' => true ),
array( 'suppress-post' => false ),
array( 'restore-post' => true ),
) ),
array( $this->oversightUser(), 'view', array(
array( 'new-post' => true ),
array( 'suppress-post' => true ),
array( 'restore-post' => true ),
) ),
// last moderation status should always bubble down to previous revs
array( $this->confirmedUser(), 'view', array(
array( 'new-post' => false ),
array( 'suppress-post' => false ),
array( 'restore-post' => false ),
array( 'suppress-post' => false ),
) ),
array( $this->oversightUser(), 'view', array(
array( 'new-post' => true ),
array( 'suppress-post' => true ),
array( 'restore-post' => true ),
array( 'suppress-post' => true ),
) ),
// bug 61715
array( $this->confirmedUser(), 'history', array(
array( 'new-post' => false ),
array( 'suppress-post' => false ),
) ),
array( $this->confirmedUser(), 'history', array(
array( 'new-post' => true ),
array( 'suppress-post' => false ),
array( 'restore-post' => false ),
) ),
);
}
/**
* @dataProvider permissionsProvider
*/
public function testPermissions( User $user, $permissionAction, $actions ) {
$permissions = new RevisionActionPermissions( $this->actions, $user );
// we'll have to process this in 2 steps: first do all of the actions,
// so we have a full tree of moderated revisions
$revision = null;
$revisions = array();
$debug = array();
foreach ( $actions as $action ) {
$expect = current( $action );
$action = key( $action );
$debug[] = $action . ':' . ( $expect ? 'true' : 'false' );
$revisions[] = $revision = $this->generateRevision( $action, $revision );
}
// commit pending db transaction
Container::get( 'db.factory' )->getDB( DB_MASTER )->commit( __METHOD__, 'flush' );
$debug = implode( ' ', $debug );
// secondly, iterate all revisions & see if expected permissions line up
foreach ( $actions as $action ) {
$expected = current( $action );
$revision = array_shift( $revisions );
$this->assertEquals(
$expected,
$permissions->isAllowed( $revision, $permissionAction ),
'User ' . $user->getName() . ' should ' . ( $expected ? '' : 'not ' ) . 'be allowed action ' . $permissionAction . ' on revision ' . key( $action ) . ' : ' . $debug . ' : ' . json_encode( $revision::toStorageRow( $revision ) )
);
}
}
protected function blockedUser() {
if ( !$this->blockedUser ) {
$this->blockedUser = User::newFromName( 'UTFlowBlockee' );
$this->blockedUser->addToDatabase();
// note: the block will be added in setUp & deleted in tearDown;
// otherwise this is just any regular user
}
return $this->blockedUser;
}
protected function anonUser() {
if ( !$this->anonUser ) {
$this->anonUser = new User;
}
return $this->anonUser;
}
protected function unconfirmedUser() {
if ( !$this->unconfirmedUser ) {
$this->unconfirmedUser = User::newFromName( 'UTFlowUnconfirmed' );
$this->unconfirmedUser->addToDatabase();
$this->unconfirmedUser->addGroup( 'user' );
}
return $this->unconfirmedUser;
}
protected function confirmedUser() {
if ( !$this->confirmedUser ) {
$this->confirmedUser = User::newFromName( 'UTFlowConfirmed' );
$this->confirmedUser->addToDatabase();
$this->confirmedUser->addGroup( 'autoconfirmed' );
}
return $this->confirmedUser;
}
protected function sysopUser() {
if ( !$this->sysopUser ) {
$this->sysopUser = User::newFromName( 'UTFlowSysop' );
$this->sysopUser->addToDatabase();
$this->sysopUser->addGroup( 'sysop' );
}
return $this->sysopUser;
}
protected function oversightUser() {
if ( !$this->oversightUser ) {
$this->oversightUser = User::newFromName( 'UTFlowOversight' );
$this->oversightUser->addToDatabase();
$this->oversightUser->addGroup( 'oversight' );
}
return $this->oversightUser;
}
/**
* @param string $action
* @param AbstractRevision|null $parent
* @param array $overrides
* @return PostRevision
*/
public function generateRevision( $action, AbstractRevision $parent = null, array $overrides = array() ) {
$overrides['rev_change_type'] = $action;
if ( $parent ) {
$overrides['rev_parent_id'] = $parent->getRevisionId()->getBinary();
$overrides['tree_rev_descendant_id'] = $parent->getPostId()->getBinary();
$overrides['rev_type_id'] = $parent->getPostId()->getBinary();
}
switch ( $action ) {
case 'restore-post':
$overrides += array(
'rev_mod_state' => $this->moderation[$action], // AbstractRevision::MODERATED_NONE
'rev_mod_user_id' => null,
'rev_mod_user_ip' => null,
'rev_mod_timestamp' => null,
'rev_mod_reason' => 'unit test',
);
break;
case 'hide-post':
case 'delete-post':
case 'suppress-post':
$overrides += array(
'rev_mod_state' => $this->moderation[$action], // AbstractRevision::MODERATED_(HIDDEN|DELETED|SUPPRESSED)
'rev_mod_user_id' => 1,
'rev_mod_user_ip' => null,
'rev_mod_timestamp' => wfTimestampNow(),
'rev_mod_reason' => 'unit test',
);
break;
default:
// nothing special
break;
}
$revision = $this->generateObject( $overrides );
$this->store( $revision );
return $revision;
}
}