2021-01-22 00:20:44 +00:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
namespace MediaWiki\Tests\Unit\Permissions;
|
|
|
|
|
|
2021-03-10 19:40:33 +00:00
|
|
|
use MediaWiki\Block\Block;
|
2021-01-22 00:20:44 +00:00
|
|
|
use MediaWiki\Permissions\Authority;
|
|
|
|
|
use MediaWiki\Permissions\SimpleAuthority;
|
|
|
|
|
use MediaWiki\Permissions\UltimateAuthority;
|
|
|
|
|
use MediaWiki\User\UserIdentity;
|
|
|
|
|
use MediaWiki\User\UserIdentityValue;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Various useful Authority mocks.
|
2021-06-06 04:08:04 +00:00
|
|
|
* @stable to use (since 1.37)
|
2021-01-22 00:20:44 +00:00
|
|
|
*/
|
|
|
|
|
trait MockAuthorityTrait {
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Create mock ultimate Authority for anon user.
|
|
|
|
|
*
|
|
|
|
|
* @return Authority
|
|
|
|
|
*/
|
|
|
|
|
private function mockAnonUltimateAuthority(): Authority {
|
2021-02-15 18:58:09 +00:00
|
|
|
return new UltimateAuthority( new UserIdentityValue( 0, '127.0.0.1' ) );
|
2021-01-22 00:20:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Create mock ultimate Authority for registered user.
|
|
|
|
|
*
|
|
|
|
|
* @return Authority
|
|
|
|
|
*/
|
|
|
|
|
private function mockRegisteredUltimateAuthority(): Authority {
|
2021-06-01 23:06:18 +00:00
|
|
|
return new UltimateAuthority( new UserIdentityValue( 9999, 'Petr' ) );
|
2021-01-22 00:20:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Create mock Authority for anon user with no permissions.
|
|
|
|
|
*
|
|
|
|
|
* @return Authority
|
|
|
|
|
*/
|
|
|
|
|
private function mockAnonNullAuthority(): Authority {
|
2021-02-15 18:58:09 +00:00
|
|
|
return new SimpleAuthority( new UserIdentityValue( 0, '127.0.0.1' ), [] );
|
2021-01-22 00:20:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Create mock Authority for a registered user with no permissions.
|
|
|
|
|
*
|
|
|
|
|
* @return Authority
|
|
|
|
|
*/
|
|
|
|
|
private function mockRegisteredNullAuthority(): Authority {
|
2021-06-01 23:06:18 +00:00
|
|
|
return new SimpleAuthority( new UserIdentityValue( 9999, 'Petr' ), [] );
|
2021-01-22 04:06:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Create a mock Authority for anon user with $permissions.
|
|
|
|
|
*
|
|
|
|
|
* @param array $permissions
|
|
|
|
|
* @return Authority
|
|
|
|
|
*/
|
|
|
|
|
private function mockAnonAuthorityWithPermissions( array $permissions ): Authority {
|
2021-02-15 18:58:09 +00:00
|
|
|
return new SimpleAuthority( new UserIdentityValue( 0, '127.0.0.1' ), $permissions );
|
2021-01-22 04:06:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Create a mock Authority for a registered user with $permissions.
|
|
|
|
|
*
|
|
|
|
|
* @param array $permissions
|
|
|
|
|
* @return Authority
|
|
|
|
|
*/
|
|
|
|
|
private function mockRegisteredAuthorityWithPermissions( array $permissions ): Authority {
|
2021-06-01 23:06:18 +00:00
|
|
|
return new SimpleAuthority( new UserIdentityValue( 9999, 'Petr' ), $permissions );
|
2021-01-22 00:20:44 +00:00
|
|
|
}
|
|
|
|
|
|
2021-03-04 03:23:56 +00:00
|
|
|
/**
|
2021-03-04 19:45:28 +00:00
|
|
|
* Create a mock Authority for a $user with $permissions.
|
2021-03-04 03:23:56 +00:00
|
|
|
*
|
2021-03-04 19:45:28 +00:00
|
|
|
* @param UserIdentity $user
|
2021-03-04 03:23:56 +00:00
|
|
|
* @param array $permissions
|
|
|
|
|
* @return Authority
|
|
|
|
|
*/
|
|
|
|
|
private function mockUserAuthorityWithPermissions(
|
2021-03-04 19:45:28 +00:00
|
|
|
UserIdentity $user,
|
2021-03-04 03:23:56 +00:00
|
|
|
array $permissions
|
|
|
|
|
): Authority {
|
2021-03-04 19:45:28 +00:00
|
|
|
return new SimpleAuthority( $user, $permissions );
|
2021-03-04 03:23:56 +00:00
|
|
|
}
|
|
|
|
|
|
2021-03-10 19:40:33 +00:00
|
|
|
/**
|
|
|
|
|
* Create a mock Authority for $user with $block and $permissions.
|
|
|
|
|
*
|
|
|
|
|
* @param UserIdentity $user
|
|
|
|
|
* @param Block $block
|
|
|
|
|
* @param array $permissions
|
|
|
|
|
*
|
|
|
|
|
* @return Authority
|
|
|
|
|
*/
|
|
|
|
|
private function mockUserAuthorityWithBlock(
|
|
|
|
|
UserIdentity $user,
|
|
|
|
|
Block $block,
|
|
|
|
|
array $permissions = []
|
|
|
|
|
): Authority {
|
|
|
|
|
return $this->mockAuthority(
|
|
|
|
|
$user,
|
|
|
|
|
static function ( $permission ) use ( $permissions ) {
|
|
|
|
|
return in_array( $permission, $permissions );
|
|
|
|
|
},
|
|
|
|
|
$block
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-02 22:28:04 +00:00
|
|
|
/**
|
|
|
|
|
* Create a mock Authority for an anon user with all but $permissions
|
|
|
|
|
* @param array $permissions
|
|
|
|
|
* @return Authority
|
|
|
|
|
*/
|
|
|
|
|
private function mockAnonAuthorityWithoutPermissions( array $permissions ): Authority {
|
2021-03-04 03:23:56 +00:00
|
|
|
return $this->mockUserAuthorityWithoutPermissions(
|
2021-02-15 18:58:09 +00:00
|
|
|
new UserIdentityValue( 0, '127.0.0.1' ),
|
2021-03-04 03:23:56 +00:00
|
|
|
$permissions
|
|
|
|
|
);
|
2021-03-02 22:28:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Create a mock Authority for a registered user with all but $permissions
|
|
|
|
|
* @param array $permissions
|
|
|
|
|
* @return Authority
|
|
|
|
|
*/
|
|
|
|
|
private function mockRegisteredAuthorityWithoutPermissions( array $permissions ): Authority {
|
2021-03-04 03:23:56 +00:00
|
|
|
return $this->mockUserAuthorityWithoutPermissions(
|
2021-06-01 23:06:18 +00:00
|
|
|
new UserIdentityValue( 9999, 'Petr' ),
|
2021-03-04 03:23:56 +00:00
|
|
|
$permissions
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Create a mock Authority for a $user with all but $permissions
|
2021-03-04 19:45:28 +00:00
|
|
|
* @param UserIdentity $user
|
2021-03-04 03:23:56 +00:00
|
|
|
* @param array $permissions
|
|
|
|
|
* @return Authority
|
|
|
|
|
*/
|
|
|
|
|
private function mockUserAuthorityWithoutPermissions(
|
2021-03-04 19:45:28 +00:00
|
|
|
UserIdentity $user,
|
2021-03-04 03:23:56 +00:00
|
|
|
array $permissions
|
|
|
|
|
): Authority {
|
|
|
|
|
return $this->mockAuthority(
|
2021-03-04 19:45:28 +00:00
|
|
|
$user,
|
2021-04-29 16:24:12 +00:00
|
|
|
static function ( $permission ) use ( $permissions ) {
|
2021-03-04 03:23:56 +00:00
|
|
|
return !in_array( $permission, $permissions );
|
|
|
|
|
}
|
|
|
|
|
);
|
2021-03-02 22:28:04 +00:00
|
|
|
}
|
|
|
|
|
|
2021-01-22 00:20:44 +00:00
|
|
|
/**
|
|
|
|
|
* Create mock Authority for anon user where permissions are determined by $callback.
|
|
|
|
|
*
|
|
|
|
|
* @param callable $permissionCallback
|
|
|
|
|
* @return Authority
|
|
|
|
|
*/
|
|
|
|
|
private function mockAnonAuthority( callable $permissionCallback ): Authority {
|
|
|
|
|
return $this->mockAuthority(
|
2021-02-15 18:58:09 +00:00
|
|
|
new UserIdentityValue( 0, '127.0.0.1' ),
|
2021-01-22 00:20:44 +00:00
|
|
|
$permissionCallback
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Create mock Authority for registered user where permissions are determined by $callback.
|
|
|
|
|
*
|
|
|
|
|
* @param callable $permissionCallback
|
|
|
|
|
* @return Authority
|
|
|
|
|
*/
|
|
|
|
|
private function mockRegisteredAuthority( callable $permissionCallback ): Authority {
|
|
|
|
|
return $this->mockAuthority(
|
2021-06-01 23:06:18 +00:00
|
|
|
new UserIdentityValue( 9999, 'Petr' ),
|
2021-01-22 00:20:44 +00:00
|
|
|
$permissionCallback
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2021-03-04 19:45:28 +00:00
|
|
|
* Create mock Authority for $user where permissions are determined by $callback.
|
2021-01-22 00:20:44 +00:00
|
|
|
*
|
2021-03-04 19:45:28 +00:00
|
|
|
* @param UserIdentity $user
|
DeletePage: add option to delete the associated talk page
Currently this is implemented internally as a second method call. In the
future, it might be possible to optimize the implementation, e.g. to
reduce the amount of DB queries/jobs etc. without changing anything for
callers.
Since the implementation of e.g. the result getters is generic, a future
commit may add an option to delete subpages with relatively low effort.
The revision limit for big deletions is now using the total number of
revisions (base page + talk page). This is because both deletions would
happen in the same main transaction, and we presumably want to optimize
the deletion as a whole, not as two separated steps. This would become
even more important if the aforementioned improvements are ever
implemented. Note, the whole concept of "big deletion" might have been
superseded by batched deletions in the author's opinion, but as long as
such a limit exists, it should serve its purpose.
The current interpretation of the associated talk option is that the
request is validated, and an exception is raised if we cannot delete the
associated talk, as opposed to silently ignoring the parameter if the
talk cannot be deleted. The only exception to this is that it will not
fail hard if the talk page turns out not to exist by the time the
deletion is attempted, as that's hard to foresee due to race conditions.
Note that the summary for the talk deletion is prefixed with the
delete-talk-summary-prefix message. The main reason behind this is that
the delete UI can sometimes offer an auto-generated summary like "the
only contributor was XXX" or "the content was YYY", and since this may
not apply to the talk page as well, the log entry might look confusing.
Bug: T263209
Bug: T27471
Change-Id: Ife1f4e8258a69528dd1ce8fef8ae809761aa6f1d
2021-09-01 12:56:43 +00:00
|
|
|
* @param callable $permissionCallback ( string $permission, PageIdentity $page = null )
|
2021-03-10 19:40:33 +00:00
|
|
|
* @param Block|null $block
|
|
|
|
|
*
|
2021-01-22 00:20:44 +00:00
|
|
|
* @return Authority
|
|
|
|
|
*/
|
2021-03-10 19:40:33 +00:00
|
|
|
private function mockAuthority(
|
|
|
|
|
UserIdentity $user,
|
|
|
|
|
callable $permissionCallback,
|
|
|
|
|
Block $block = null
|
|
|
|
|
): Authority {
|
2021-01-22 00:20:44 +00:00
|
|
|
$mock = $this->createMock( Authority::class );
|
2021-03-04 19:45:28 +00:00
|
|
|
$mock->method( 'getUser' )->willReturn( $user );
|
2021-01-22 00:20:44 +00:00
|
|
|
$methods = [ 'isAllowed', 'probablyCan', 'definitelyCan', 'authorizeRead', 'authorizeWrite' ];
|
|
|
|
|
foreach ( $methods as $method ) {
|
|
|
|
|
$mock->method( $method )->willReturnCallback( $permissionCallback );
|
|
|
|
|
}
|
|
|
|
|
$mock->method( 'isAllowedAny' )
|
2021-02-07 13:10:36 +00:00
|
|
|
->willReturnCallback( static function ( ...$permissions ) use ( $permissionCallback ) {
|
2021-01-22 00:20:44 +00:00
|
|
|
foreach ( $permissions as $permission ) {
|
|
|
|
|
if ( $permissionCallback( $permission ) ) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
} );
|
|
|
|
|
$mock->method( 'isAllowedAll' )
|
2021-02-07 13:10:36 +00:00
|
|
|
->willReturnCallback( static function ( ...$permissions ) use ( $permissionCallback ) {
|
2021-01-22 00:20:44 +00:00
|
|
|
foreach ( $permissions as $permission ) {
|
2021-04-07 16:20:09 +00:00
|
|
|
if ( !$permissionCallback( $permission ) ) {
|
2021-01-22 00:20:44 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
} );
|
2021-03-10 19:40:33 +00:00
|
|
|
$mock->method( 'getBlock' )->willReturn( $block );
|
2021-01-22 00:20:44 +00:00
|
|
|
return $mock;
|
|
|
|
|
}
|
|
|
|
|
}
|