Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
Total | |
0.00% |
0 / 1 |
|
33.33% |
2 / 6 |
CRAP | |
41.07% |
23 / 56 |
RemoteApiActionExecutor | |
0.00% |
0 / 1 |
|
33.33% |
2 / 6 |
35.76 | |
41.07% |
23 / 56 |
__construct | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
executeTestEditActionQuery | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 12 |
|||
executeEditAction | |
100.00% |
1 / 1 |
2 | |
100.00% |
13 / 13 |
|||
executeUserRightsQuery | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 7 |
|||
executeDeleteAction | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 12 |
|||
statusFromApiResponse | |
0.00% |
0 / 1 |
4.13 | |
80.00% |
8 / 10 |
<?php | |
namespace FileImporter\Remote\MediaWiki; | |
use FileImporter\Data\SourceUrl; | |
use StatusValue; | |
use User; | |
/** | |
* @license GPL-2.0-or-later | |
*/ | |
class RemoteApiActionExecutor { | |
public const CHANGE_TAG = 'fileimporter-remote'; | |
/** | |
* @var RemoteApiRequestExecutor | |
*/ | |
private $remoteApiRequestExecutor; | |
/** | |
* @param RemoteApiRequestExecutor $remoteApiRequestExecutor | |
*/ | |
public function __construct( RemoteApiRequestExecutor $remoteApiRequestExecutor ) { | |
$this->remoteApiRequestExecutor = $remoteApiRequestExecutor; | |
} | |
/** | |
* @param SourceUrl $sourceUrl | |
* @param User $user | |
* @param string $title | |
* | |
* @return StatusValue ok if the user can edit the page | |
*/ | |
public function executeTestEditActionQuery( SourceUrl $sourceUrl, User $user, string $title ): StatusValue { | |
// Expected return values: | |
// { "query": { "pages": [ { "actions": { "edit": true }, … | |
// { "query": { "pages": [ { "actions": { "edit": false }, … | |
$result = $this->remoteApiRequestExecutor->execute( | |
$sourceUrl, | |
$user, | |
[ | |
'action' => 'query', | |
'format' => 'json', | |
'formatversion' => 2, | |
'prop' => 'info', | |
'titles' => $title, | |
'intestactions' => 'edit', | |
], | |
true | |
); | |
$status = $this->statusFromApiResponse( $result ); | |
$canEdit = $result['query']['pages'][0]['actions']['edit'] ?? false; | |
$status->setOK( $canEdit ); | |
return $status; | |
} | |
/** | |
* @param SourceUrl $sourceUrl | |
* @param User $user | |
* @param string $title | |
* @param array $params At least one of the parameters "text", "appendtext", "prependtext" and | |
* "undo" is required. | |
* @param string $editSummary | |
* | |
* @return StatusValue | |
*/ | |
public function executeEditAction( | |
SourceUrl $sourceUrl, | |
User $user, | |
string $title, | |
array $params, | |
string $editSummary | |
): StatusValue { | |
$token = $this->remoteApiRequestExecutor->getCsrfToken( $sourceUrl, $user ); | |
if ( $token === null ) { | |
return $this->statusFromApiResponse(); | |
} | |
$result = $this->remoteApiRequestExecutor->execute( | |
$sourceUrl, | |
$user, | |
array_merge( | |
[ | |
'action' => 'edit', | |
'token' => $token, | |
'format' => 'json', | |
'title' => $title, | |
'summary' => $editSummary, | |
'tags' => self::CHANGE_TAG, | |
], | |
$params | |
), | |
true | |
); | |
return $this->statusFromApiResponse( $result ); | |
} | |
/** | |
* @param SourceUrl $sourceUrl | |
* @param User $user | |
* | |
* @return StatusValue ok if the user is allowed to delete pages | |
*/ | |
public function executeUserRightsQuery( SourceUrl $sourceUrl, User $user ): StatusValue { | |
// Expected return values: | |
// { "query": { "userinfo": { "rights": [ "delete", … | |
// Same with formatversion=2 | |
$result = $this->remoteApiRequestExecutor->execute( | |
$sourceUrl, | |
$user, | |
[ | |
'action' => 'query', | |
'format' => 'json', | |
'meta' => 'userinfo', | |
'uiprop' => 'rights', | |
] | |
); | |
$status = $this->statusFromApiResponse( $result ); | |
$rights = $result['query']['userinfo']['rights'] ?? []; | |
$canDelete = in_array( 'delete', $rights ); | |
$status->setOK( $canDelete ); | |
return $status; | |
} | |
/** | |
* @param SourceUrl $sourceUrl | |
* @param User $user | |
* @param string $title | |
* @param string $deletionReason | |
* | |
* @return StatusValue | |
*/ | |
public function executeDeleteAction( | |
SourceUrl $sourceUrl, | |
User $user, | |
string $title, | |
string $deletionReason | |
): StatusValue { | |
$token = $this->remoteApiRequestExecutor->getCsrfToken( $sourceUrl, $user ); | |
if ( $token === null ) { | |
return $this->statusFromApiResponse(); | |
} | |
$result = $this->remoteApiRequestExecutor->execute( | |
$sourceUrl, | |
$user, | |
[ | |
'action' => 'delete', | |
'format' => 'json', | |
'title' => $title, | |
'reason' => $deletionReason, | |
'tags' => self::CHANGE_TAG, | |
'token' => $token, | |
], | |
true | |
); | |
return $this->statusFromApiResponse( $result ); | |
} | |
private function statusFromApiResponse( array $apiResponse = null ): StatusValue { | |
$status = StatusValue::newGood(); | |
if ( !$apiResponse ) { | |
$status->setOK( false ); | |
return $status; | |
} | |
// It's an array of "errors" with errorformat=plaintext, but a single "error" without. | |
$errors = $apiResponse['errors'] ?? []; | |
if ( isset( $apiResponse['error'] ) ) { | |
$errors[] = $apiResponse['error']; | |
} | |
foreach ( $errors as $error ) { | |
// Errors contain "code" and "info" with formatversion=2, but "code" and "*" without. | |
$status->error( $error['code'] ); | |
} | |
return $status; | |
} | |
} |