2019-05-24 00:07:27 +00:00
|
|
|
<?php
|
|
|
|
|
2022-05-03 18:11:54 +00:00
|
|
|
namespace MediaWiki\Minerva;
|
2019-05-24 00:07:27 +00:00
|
|
|
|
2024-10-20 07:28:03 +00:00
|
|
|
use MediaWiki\Content\ContentHandler;
|
2021-05-28 20:15:31 +00:00
|
|
|
use MediaWiki\Content\IContentHandlerFactory;
|
2024-05-19 12:45:56 +00:00
|
|
|
use MediaWiki\Context\RequestContext;
|
2024-03-03 13:31:09 +00:00
|
|
|
use MediaWiki\HookContainer\HookContainer;
|
2024-02-25 19:26:11 +00:00
|
|
|
use MediaWiki\MainConfigNames;
|
2019-05-24 00:07:27 +00:00
|
|
|
use MediaWiki\Minerva\Permissions\IMinervaPagePermissions;
|
|
|
|
use MediaWiki\Minerva\Permissions\MinervaPagePermissions;
|
2024-03-24 10:49:33 +00:00
|
|
|
use MediaWiki\Minerva\Skins\SkinUserPageHelper;
|
2023-07-17 17:31:07 +00:00
|
|
|
use MediaWiki\Permissions\Authority;
|
|
|
|
use MediaWiki\Tests\Unit\Permissions\MockAuthorityTrait;
|
2023-08-19 04:23:00 +00:00
|
|
|
use MediaWiki\Title\Title;
|
2023-07-17 17:31:07 +00:00
|
|
|
use MediaWiki\User\UserFactory;
|
2021-04-29 17:20:44 +00:00
|
|
|
use MediaWiki\Watchlist\WatchlistManager;
|
2021-10-11 22:53:10 +00:00
|
|
|
use MediaWikiIntegrationTestCase;
|
2019-05-24 00:07:27 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @group MinervaNeue
|
|
|
|
* @coversDefaultClass \MediaWiki\Minerva\Permissions\MinervaPagePermissions
|
|
|
|
*/
|
2021-10-11 22:53:10 +00:00
|
|
|
class MinervaPagePermissionsTest extends MediaWikiIntegrationTestCase {
|
2023-07-17 17:31:07 +00:00
|
|
|
use MockAuthorityTrait;
|
2019-05-24 00:07:27 +00:00
|
|
|
|
2024-02-25 19:26:11 +00:00
|
|
|
protected function setUp(): void {
|
|
|
|
$this->overrideConfigValues( [
|
|
|
|
MainConfigNames::HideInterlanguageLinks => false
|
|
|
|
] );
|
|
|
|
}
|
|
|
|
|
2019-05-24 00:07:27 +00:00
|
|
|
private function buildPermissionsObject(
|
|
|
|
Title $title,
|
|
|
|
array $options = [],
|
|
|
|
ContentHandler $contentHandler = null,
|
2023-07-17 17:31:07 +00:00
|
|
|
Authority $user = null,
|
2024-02-25 19:26:11 +00:00
|
|
|
$hasOtherLanguagesOrVariants = false
|
2024-10-21 18:39:39 +00:00
|
|
|
): MinervaPagePermissions {
|
2019-10-22 17:13:55 +00:00
|
|
|
$languageHelper = $this->createMock( LanguagesHelper::class );
|
2021-12-17 10:29:48 +00:00
|
|
|
$languageHelper->method( 'doesTitleHasLanguagesOrVariants' )
|
2019-07-09 16:10:31 +00:00
|
|
|
->willReturn( $hasOtherLanguagesOrVariants );
|
2019-05-24 00:07:27 +00:00
|
|
|
|
2023-07-17 17:31:07 +00:00
|
|
|
$user ??= $this->mockRegisteredNullAuthority();
|
2019-05-24 00:07:27 +00:00
|
|
|
$contentHandler = $contentHandler ??
|
|
|
|
$this->getMockForAbstractClass( ContentHandler::class, [], '', false );
|
2024-03-03 13:31:09 +00:00
|
|
|
$skinOptions = new SkinOptions(
|
2024-03-24 10:49:33 +00:00
|
|
|
$this->createMock( HookContainer::class ),
|
|
|
|
$this->createMock( SkinUserPageHelper::class )
|
2024-03-03 13:31:09 +00:00
|
|
|
);
|
2019-05-24 00:07:27 +00:00
|
|
|
if ( $options ) {
|
|
|
|
$skinOptions->setMultiple( $options );
|
|
|
|
}
|
|
|
|
|
2019-10-08 17:22:31 +00:00
|
|
|
$context = new RequestContext();
|
2023-08-01 18:04:24 +00:00
|
|
|
// Force a content model to avoid DB queries.
|
|
|
|
$title->setContentModel( CONTENT_MODEL_WIKITEXT );
|
2019-10-08 17:22:31 +00:00
|
|
|
$context->setTitle( $title );
|
2023-07-17 17:31:07 +00:00
|
|
|
$context->setAuthority( $user );
|
2019-10-08 17:22:31 +00:00
|
|
|
|
2023-07-17 17:31:07 +00:00
|
|
|
$permissionManager = $this->getServiceContainer()->getPermissionManager();
|
2021-03-09 19:43:14 +00:00
|
|
|
|
2021-05-28 20:15:31 +00:00
|
|
|
$contentHandlerFactory = $this->createMock( IContentHandlerFactory::class );
|
|
|
|
|
2024-03-09 21:21:25 +00:00
|
|
|
$contentHandlerFactory->expects( $this->once() )
|
2021-05-28 20:15:31 +00:00
|
|
|
->method( 'getContentHandler' )
|
|
|
|
->willReturn( $contentHandler );
|
|
|
|
|
2019-10-08 17:22:31 +00:00
|
|
|
return ( new MinervaPagePermissions(
|
2019-05-24 00:07:27 +00:00
|
|
|
$skinOptions,
|
2019-08-27 20:27:57 +00:00
|
|
|
$languageHelper,
|
2021-05-28 20:15:31 +00:00
|
|
|
$permissionManager,
|
2023-07-17 17:31:07 +00:00
|
|
|
$contentHandlerFactory,
|
2024-02-26 07:35:55 +00:00
|
|
|
$this->createMock( UserFactory::class ),
|
|
|
|
$this->getServiceContainer()->getWatchlistManager()
|
2021-05-28 20:15:31 +00:00
|
|
|
) )->setContext( $context );
|
2019-05-24 00:07:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @covers ::isAllowed
|
|
|
|
*/
|
|
|
|
public function testWatchAndEditNotAllowedOnMainPage() {
|
2023-07-17 17:31:07 +00:00
|
|
|
$user = $this->mockAnonNullAuthority();
|
2024-02-28 08:01:32 +00:00
|
|
|
$permsAnon = $this->buildPermissionsObject( Title::newMainPage(), [], null, $user );
|
2019-05-24 00:07:27 +00:00
|
|
|
$perms = $this->buildPermissionsObject( Title::newMainPage() );
|
|
|
|
|
|
|
|
$this->assertFalse( $perms->isAllowed( IMinervaPagePermissions::WATCH ) );
|
2019-08-29 14:16:10 +00:00
|
|
|
$this->assertFalse( $perms->isAllowed( IMinervaPagePermissions::CONTENT_EDIT ) );
|
2021-10-18 21:04:03 +00:00
|
|
|
$this->assertFalse( $permsAnon->isAllowed( IMinervaPagePermissions::TALK ) );
|
2019-05-24 00:07:27 +00:00
|
|
|
|
|
|
|
// Check to make sure 'talk' and 'switch-language' are enabled on the Main page.
|
|
|
|
$this->assertTrue( $perms->isAllowed( IMinervaPagePermissions::TALK ) );
|
|
|
|
$this->assertTrue( $perms->isAllowed( IMinervaPagePermissions::SWITCH_LANGUAGE ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @covers ::isAllowed
|
|
|
|
*/
|
|
|
|
public function testInvalidPageActionsArentAllowed() {
|
2024-02-28 08:01:32 +00:00
|
|
|
$perms = $this->buildPermissionsObject( Title::makeTitle( NS_MAIN, 'Test' ) );
|
2019-05-24 00:07:27 +00:00
|
|
|
|
2021-10-18 21:04:03 +00:00
|
|
|
$this->assertFalse( $perms->isAllowed( 'blah' ) );
|
|
|
|
$this->assertFalse( $perms->isAllowed( 'wah' ) );
|
2019-05-24 00:07:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @covers ::isAllowed
|
|
|
|
*/
|
|
|
|
public function testValidPageActionsAreAllowed() {
|
2023-07-17 17:31:07 +00:00
|
|
|
$perms = $this->buildPermissionsObject(
|
|
|
|
Title::makeTitle( NS_MAIN, 'Test' ),
|
|
|
|
[],
|
|
|
|
null,
|
|
|
|
$this->mockRegisteredUltimateAuthority()
|
|
|
|
);
|
2019-05-24 00:07:27 +00:00
|
|
|
$this->assertTrue( $perms->isAllowed( IMinervaPagePermissions::TALK ) );
|
|
|
|
$this->assertTrue( $perms->isAllowed( IMinervaPagePermissions::WATCH ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
public static function editPageActionProvider() {
|
|
|
|
return [
|
|
|
|
[ false, false, false ],
|
|
|
|
[ true, false, false ],
|
|
|
|
[ true, true, true ]
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The "edit" page action is allowed when the page doesn't support direct editing via the API.
|
|
|
|
*
|
|
|
|
* @dataProvider editPageActionProvider
|
|
|
|
* @covers ::isAllowed
|
|
|
|
*/
|
|
|
|
public function testEditPageAction(
|
|
|
|
$supportsDirectEditing,
|
|
|
|
$supportsDirectApiEditing,
|
|
|
|
$expected
|
|
|
|
) {
|
2021-04-08 18:58:17 +00:00
|
|
|
$contentHandler = $this->getMockBuilder( ContentHandler::class )
|
2019-05-24 00:07:27 +00:00
|
|
|
->disableOriginalConstructor()
|
|
|
|
->getMock();
|
|
|
|
|
|
|
|
$contentHandler->method( 'supportsDirectEditing' )
|
2021-12-17 10:29:48 +00:00
|
|
|
->willReturn( $supportsDirectEditing );
|
2019-05-24 00:07:27 +00:00
|
|
|
|
|
|
|
$contentHandler->method( 'supportsDirectApiEditing' )
|
2021-12-17 10:29:48 +00:00
|
|
|
->willReturn( $supportsDirectApiEditing );
|
2019-05-24 00:07:27 +00:00
|
|
|
|
2024-02-28 08:01:32 +00:00
|
|
|
$perms = $this->buildPermissionsObject( Title::makeTitle( NS_MAIN, 'Test' ), [],
|
2019-05-24 00:07:27 +00:00
|
|
|
$contentHandler );
|
|
|
|
|
2019-08-29 14:16:10 +00:00
|
|
|
$this->assertEquals( $expected, $perms->isAllowed( IMinervaPagePermissions::CONTENT_EDIT ) );
|
2019-05-24 00:07:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @covers ::isAllowed
|
|
|
|
*/
|
|
|
|
public function testPageActionsWhenOnUserPage() {
|
2022-03-10 21:39:37 +00:00
|
|
|
$perms = $this->buildPermissionsObject( Title::makeTitle( NS_USER, 'Admin' ) );
|
2019-05-24 00:07:27 +00:00
|
|
|
$this->assertTrue( $perms->isAllowed( IMinervaPagePermissions::TALK ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @covers ::isAllowed
|
|
|
|
*/
|
|
|
|
public function testPageActionsWhenOnAnonUserPage() {
|
2022-03-10 21:39:37 +00:00
|
|
|
$perms = $this->buildPermissionsObject( Title::makeTitle( NS_USER, '1.1.1.1' ) );
|
2019-05-24 00:07:27 +00:00
|
|
|
$this->assertTrue( $perms->isAllowed( IMinervaPagePermissions::TALK ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
public static function switchLanguagePageActionProvider() {
|
|
|
|
return [
|
2024-03-10 23:28:35 +00:00
|
|
|
[ true, false, true ],
|
|
|
|
[ false, true, true ],
|
2019-07-09 16:10:31 +00:00
|
|
|
[ false, false, false ],
|
2019-05-24 00:07:27 +00:00
|
|
|
];
|
|
|
|
}
|
|
|
|
|
2019-06-21 15:46:44 +00:00
|
|
|
/**
|
|
|
|
* MediaWiki defines wgHideInterlanguageLinks which is default set to false, but some wikis
|
|
|
|
* can set this config to true. Minerva page permissions must respect that
|
|
|
|
* @covers ::isAllowed
|
|
|
|
*/
|
|
|
|
public function testGlobalHideLanguageLinksTakesPrecedenceOnMainPage() {
|
2024-02-25 19:26:11 +00:00
|
|
|
$this->overrideConfigValues( [ MainConfigNames::HideInterlanguageLinks => true ] );
|
2019-06-21 15:46:44 +00:00
|
|
|
$perms = $this->buildPermissionsObject( Title::newMainPage() );
|
|
|
|
$this->assertFalse( $perms->isAllowed( IMinervaPagePermissions::SWITCH_LANGUAGE ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* MediaWiki defines wgHideInterlanguageLinks which is default set to false, but some wikis
|
|
|
|
* can set this config to true. Minerva page permissions must respect that
|
|
|
|
* @covers ::isAllowed
|
|
|
|
*/
|
|
|
|
public function testGlobalHideLanguageLinksTakesPrecedence() {
|
2024-02-25 19:26:11 +00:00
|
|
|
$this->overrideConfigValues( [ MainConfigNames::HideInterlanguageLinks => true ] );
|
2022-03-10 21:39:37 +00:00
|
|
|
$perms = $this->buildPermissionsObject( Title::makeTitle( NS_MAIN, 'Test' ) );
|
2019-06-21 15:46:44 +00:00
|
|
|
$this->assertFalse( $perms->isAllowed( IMinervaPagePermissions::SWITCH_LANGUAGE ) );
|
|
|
|
}
|
|
|
|
|
2019-05-24 00:07:27 +00:00
|
|
|
/**
|
|
|
|
* The "switch-language" page action is allowed when: v2 of the page action bar is enabled and
|
|
|
|
* if the page has interlanguage links or if the <code>$wgMinervaAlwaysShowLanguageButton</code>
|
|
|
|
* configuration variable is set to truthy.
|
|
|
|
*
|
|
|
|
* @dataProvider switchLanguagePageActionProvider
|
|
|
|
* @covers ::isAllowed
|
|
|
|
*/
|
|
|
|
public function testSwitchLanguagePageAction(
|
2019-07-09 16:10:31 +00:00
|
|
|
$hasLanguagesOrVariants,
|
2019-05-24 00:07:27 +00:00
|
|
|
$minervaAlwaysShowLanguageButton,
|
|
|
|
$expected
|
|
|
|
) {
|
2019-10-22 17:13:55 +00:00
|
|
|
$title = $this->createMock( Title::class );
|
2019-05-24 00:07:27 +00:00
|
|
|
$title->expects( $this->once() )
|
|
|
|
->method( 'isMainPage' )
|
|
|
|
->willReturn( false );
|
2024-03-09 21:21:25 +00:00
|
|
|
$title->expects( $this->once() )
|
2021-05-28 20:15:31 +00:00
|
|
|
->method( 'getContentModel' )
|
|
|
|
->willReturn( CONTENT_MODEL_WIKITEXT );
|
2019-05-24 00:07:27 +00:00
|
|
|
|
2024-02-25 19:26:11 +00:00
|
|
|
$this->overrideConfigValues( [
|
|
|
|
'MinervaAlwaysShowLanguageButton' => $minervaAlwaysShowLanguageButton
|
|
|
|
] );
|
2019-05-24 00:07:27 +00:00
|
|
|
$permissions = $this->buildPermissionsObject(
|
|
|
|
$title,
|
|
|
|
[],
|
|
|
|
null,
|
|
|
|
null,
|
2024-02-25 19:26:11 +00:00
|
|
|
$hasLanguagesOrVariants
|
2019-05-24 00:07:27 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
$actual = $permissions->isAllowed( IMinervaPagePermissions::SWITCH_LANGUAGE );
|
|
|
|
$this->assertEquals( $expected, $actual );
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Watch action requires 'viewmywatchlist' and 'editmywatchlist' permissions
|
|
|
|
* to be grated. Verify that isAllowedAction('watch') returns false when user
|
|
|
|
* do not have those permissions granted
|
|
|
|
* @covers ::isAllowed
|
|
|
|
*/
|
|
|
|
public function testWatchIsAllowedOnlyWhenWatchlistPermissionsAreGranted() {
|
2022-03-10 21:39:37 +00:00
|
|
|
$title = Title::makeTitle( NS_MAIN, 'Test_watchstar_permissions' );
|
2023-07-17 17:31:07 +00:00
|
|
|
$perms = $this->buildPermissionsObject( $title );
|
2019-05-24 00:07:27 +00:00
|
|
|
$this->assertTrue( $perms->isAllowed( IMinervaPagePermissions::TALK ) );
|
|
|
|
$this->assertFalse( $perms->isAllowed( IMinervaPagePermissions::WATCH ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* If Title is not watchable, it cannot be watched
|
|
|
|
* @covers ::isAllowed
|
|
|
|
*/
|
|
|
|
public function testCannotWatchNotWatchableTitle() {
|
2019-10-22 17:13:55 +00:00
|
|
|
$title = $this->createMock( Title::class );
|
2019-05-24 00:07:27 +00:00
|
|
|
$title->expects( $this->once() )
|
|
|
|
->method( 'isMainPage' )
|
|
|
|
->willReturn( false );
|
2024-03-09 21:21:25 +00:00
|
|
|
$title->expects( $this->once() )
|
2021-05-28 20:15:31 +00:00
|
|
|
->method( 'getContentModel' )
|
|
|
|
->willReturn( CONTENT_MODEL_UNKNOWN );
|
2021-04-29 17:20:44 +00:00
|
|
|
|
|
|
|
$watchlistManager = $this->createMock( WatchlistManager::class );
|
|
|
|
$watchlistManager->expects( $this->once() )
|
2019-05-24 00:07:27 +00:00
|
|
|
->method( 'isWatchable' )
|
|
|
|
->willReturn( false );
|
2021-04-29 17:20:44 +00:00
|
|
|
$this->setService( 'WatchlistManager', $watchlistManager );
|
2019-05-24 00:07:27 +00:00
|
|
|
|
|
|
|
$permissions = $this->buildPermissionsObject( $title );
|
2020-01-26 19:26:31 +00:00
|
|
|
$this->assertFalse( $permissions->isAllowed( IMinervaPagePermissions::WATCH ) );
|
2019-05-24 00:07:27 +00:00
|
|
|
}
|
|
|
|
|
2021-03-09 19:43:14 +00:00
|
|
|
/**
|
|
|
|
* @covers ::isAllowed
|
|
|
|
*/
|
|
|
|
public function testMoveAndDeleteAndProtectNotAllowedByDefault() {
|
2024-02-28 08:01:32 +00:00
|
|
|
$perms = $this->buildPermissionsObject( Title::makeTitle( NS_MAIN, 'Test' ) );
|
2021-03-09 19:43:14 +00:00
|
|
|
$this->assertFalse( $perms->isAllowed( IMinervaPagePermissions::MOVE ) );
|
|
|
|
$this->assertFalse( $perms->isAllowed( IMinervaPagePermissions::DELETE ) );
|
|
|
|
$this->assertFalse( $perms->isAllowed( IMinervaPagePermissions::PROTECT ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @covers ::isAllowed
|
|
|
|
*/
|
|
|
|
public function testMoveAndDeleteAndProtectAllowedForUserWithPermissions() {
|
|
|
|
$title = $this->createMock( Title::class );
|
2024-03-09 21:21:25 +00:00
|
|
|
$title
|
2021-03-09 19:43:14 +00:00
|
|
|
->method( 'exists' )
|
|
|
|
->willReturn( true );
|
2024-03-09 21:21:25 +00:00
|
|
|
$title->expects( $this->once() )
|
2021-05-28 20:15:31 +00:00
|
|
|
->method( 'getContentModel' )
|
|
|
|
->willReturn( CONTENT_MODEL_WIKITEXT );
|
|
|
|
|
2021-03-09 19:43:14 +00:00
|
|
|
$perms = $this->buildPermissionsObject(
|
|
|
|
$title,
|
|
|
|
[],
|
|
|
|
null,
|
2023-07-17 17:31:07 +00:00
|
|
|
$this->mockRegisteredUltimateAuthority()
|
2021-03-09 19:43:14 +00:00
|
|
|
);
|
|
|
|
$this->assertTrue( $perms->isAllowed( IMinervaPagePermissions::MOVE ) );
|
|
|
|
$this->assertTrue( $perms->isAllowed( IMinervaPagePermissions::DELETE ) );
|
|
|
|
$this->assertTrue( $perms->isAllowed( IMinervaPagePermissions::PROTECT ) );
|
|
|
|
}
|
2019-05-24 00:07:27 +00:00
|
|
|
}
|