wiki.techinc.nl/tests/phpunit/includes/api/query/ApiQueryBlocksTest.php
Thalia c67f181dd4 Introduce infrastructure for partial blocks for actions
This adds a new type of block restriction for actions, which extends
AbstractRestriction. Like page and namespace restrictions, action
restrictions are stored in the ipblocks_restrictions table.

Blockable actions are defined in a BlockActionInfo service, with a
method for getting all the blockable actions, getAllBlockActions.

Action blocks are checked for in PermissionManager::checkUserBlock
using DatabaseBlock::appliesToRight. To make this work, this patch
also removes the 'edit' case from AbstractBlock::appliesToRight,
which always returned true. This was incorrect, as blocks do not
always apply to edit, so cases that called appliesToRight('edit')
were fixed before this commit. appliesToRight('edit') now returns
null (i.e. unsure), which is correct because it is not possible to
determine whether a block applies to editing a particular page
without knowing what that page is, and appliesToRight doesn't know
that page.

There are some flags on sitewide blocks that predate partial blocks,
which block particular actions: 'createaccount' and 'sendemail'.
These are still handled in AbstractBlock::appliesToRight, and are
still checked for separately in the peripheral components.

The feature flag $wgEnablePartialActionBlocks must set to true to
enable partial action blocks.

Bug: T279556
Bug: T6995
Change-Id: I17962bb7c4247a12c722e7bc6bcaf8c36efd8600
2021-04-27 21:53:13 +01:00

175 lines
4.8 KiB
PHP

<?php
use MediaWiki\Block\DatabaseBlock;
use MediaWiki\Block\Restriction\NamespaceRestriction;
use MediaWiki\Block\Restriction\PageRestriction;
use MediaWiki\MediaWikiServices;
/**
* @group API
* @group Database
* @group medium
*
* @covers ApiQueryBlocks
*/
class ApiQueryBlocksTest extends ApiTestCase {
protected $tablesUsed = [
'ipblocks',
'ipblocks_restrictions',
];
public function testExecute() {
list( $data ) = $this->doApiRequest( [
'action' => 'query',
'list' => 'blocks',
] );
$this->assertEquals( [ 'batchcomplete' => true, 'query' => [ 'blocks' => [] ] ], $data );
}
public function testExecuteBlock() {
$badActor = $this->getTestUser()->getUser();
$sysop = $this->getTestSysop()->getUser();
$block = new DatabaseBlock( [
'address' => $badActor->getName(),
'user' => $badActor->getId(),
'by' => $sysop->getId(),
'expiry' => 'infinity',
] );
MediaWikiServices::getInstance()->getDatabaseBlockStore()->insertBlock( $block );
list( $data ) = $this->doApiRequest( [
'action' => 'query',
'list' => 'blocks',
] );
$this->assertArrayHasKey( 'query', $data );
$this->assertArrayHasKey( 'blocks', $data['query'] );
$this->assertCount( 1, $data['query']['blocks'] );
$subset = [
'id' => $block->getId(),
'user' => $badActor->getName(),
'expiry' => $block->getExpiry(),
];
$this->assertArraySubmapSame( $subset, $data['query']['blocks'][0] );
}
public function testExecuteSitewide() {
$badActor = $this->getTestUser()->getUser();
$sysop = $this->getTestSysop()->getUser();
$block = new DatabaseBlock( [
'address' => $badActor->getName(),
'user' => $badActor->getId(),
'by' => $sysop->getId(),
'ipb_expiry' => 'infinity',
'ipb_sitewide' => 1,
] );
MediaWikiServices::getInstance()->getDatabaseBlockStore()->insertBlock( $block );
list( $data ) = $this->doApiRequest( [
'action' => 'query',
'list' => 'blocks',
] );
$this->assertArrayHasKey( 'query', $data );
$this->assertArrayHasKey( 'blocks', $data['query'] );
$this->assertCount( 1, $data['query']['blocks'] );
$subset = [
'id' => $block->getId(),
'user' => $badActor->getName(),
'expiry' => $block->getExpiry(),
'partial' => !$block->isSitewide(),
];
$this->assertArraySubmapSame( $subset, $data['query']['blocks'][0] );
}
public function testExecuteRestrictions() {
$badActor = $this->getTestUser()->getUser();
$sysop = $this->getTestSysop()->getUser();
$block = new DatabaseBlock( [
'address' => $badActor->getName(),
'user' => $badActor->getId(),
'by' => $sysop->getId(),
'expiry' => 'infinity',
'sitewide' => 0,
] );
MediaWikiServices::getInstance()->getDatabaseBlockStore()->insertBlock( $block );
$subset = [
'id' => $block->getId(),
'user' => $badActor->getName(),
'expiry' => $block->getExpiry(),
];
$title = 'Lady Macbeth';
$pageData = $this->insertPage( $title );
$pageId = $pageData['id'];
$this->db->insert( 'ipblocks_restrictions', [
'ir_ipb_id' => $block->getId(),
'ir_type' => PageRestriction::TYPE_ID,
'ir_value' => $pageId,
] );
// Page that has been deleted.
$this->db->insert( 'ipblocks_restrictions', [
'ir_ipb_id' => $block->getId(),
'ir_type' => PageRestriction::TYPE_ID,
'ir_value' => 999999,
] );
$this->db->insert( 'ipblocks_restrictions', [
'ir_ipb_id' => $block->getId(),
'ir_type' => NamespaceRestriction::TYPE_ID,
'ir_value' => NS_USER_TALK,
] );
// Invalid type
$this->db->insert( 'ipblocks_restrictions', [
'ir_ipb_id' => $block->getId(),
'ir_type' => 127,
'ir_value' => 4,
] );
// Test without requesting restrictions.
list( $data ) = $this->doApiRequest( [
'action' => 'query',
'list' => 'blocks',
] );
$this->assertArrayHasKey( 'query', $data );
$this->assertArrayHasKey( 'blocks', $data['query'] );
$this->assertCount( 1, $data['query']['blocks'] );
$flagSubset = array_merge( $subset, [
'partial' => !$block->isSitewide(),
] );
$this->assertArraySubmapSame( $flagSubset, $data['query']['blocks'][0] );
$this->assertArrayNotHasKey( 'restrictions', $data['query']['blocks'][0] );
// Test requesting the restrictions.
list( $data ) = $this->doApiRequest( [
'action' => 'query',
'list' => 'blocks',
'bkprop' => 'id|user|expiry|restrictions'
] );
$this->assertArrayHasKey( 'query', $data );
$this->assertArrayHasKey( 'blocks', $data['query'] );
$this->assertCount( 1, $data['query']['blocks'] );
$restrictionsSubset = array_merge( $subset, [
'restrictions' => [
'pages' => [
[
'id' => $pageId,
'ns' => 0,
'title' => $title,
],
],
'namespaces' => [
NS_USER_TALK,
],
],
] );
$this->assertArraySubmapSame( $restrictionsSubset, $data['query']['blocks'][0] );
$this->assertArrayNotHasKey( 'partial', $data['query']['blocks'][0] );
}
}