wiki.techinc.nl/includes/Rest/Handler/EditHandler.php

161 lines
4.5 KiB
PHP

<?php
namespace MediaWiki\Rest\Handler;
use MediaWiki\Api\IApiMessage;
use MediaWiki\Config\Config;
use MediaWiki\Content\IContentHandlerFactory;
use MediaWiki\MainConfigNames;
use MediaWiki\Request\WebResponse;
use MediaWiki\Rest\LocalizedHttpException;
use MediaWiki\Rest\Response;
use MediaWiki\Rest\TokenAwareHandlerTrait;
use MediaWiki\Rest\Validator\Validator;
use MediaWiki\Revision\RevisionLookup;
use MediaWiki\Revision\SlotRecord;
use MediaWiki\Title\TitleFormatter;
use MediaWiki\Title\TitleParser;
use RuntimeException;
use Wikimedia\Message\MessageValue;
/**
* Base class for REST API handlers that perform page edits (main slot only).
*/
abstract class EditHandler extends ActionModuleBasedHandler {
use TokenAwareHandlerTrait;
protected Config $config;
protected IContentHandlerFactory $contentHandlerFactory;
protected TitleParser $titleParser;
protected TitleFormatter $titleFormatter;
protected RevisionLookup $revisionLookup;
public function __construct(
Config $config,
IContentHandlerFactory $contentHandlerFactory,
TitleParser $titleParser,
TitleFormatter $titleFormatter,
RevisionLookup $revisionLookup
) {
$this->config = $config;
$this->contentHandlerFactory = $contentHandlerFactory;
$this->titleParser = $titleParser;
$this->titleFormatter = $titleFormatter;
$this->revisionLookup = $revisionLookup;
}
public function needsWriteAccess() {
return true;
}
/**
* Returns the requested title.
*
* @return string
*/
abstract protected function getTitleParameter();
/**
* @inheritDoc
*/
public function validate( Validator $restValidator ) {
parent::validate( $restValidator );
$this->validateToken( true );
}
/**
* @inheritDoc
*/
protected function mapActionModuleResult( array $data ) {
if ( isset( $data['error'] ) ) {
throw new LocalizedHttpException( new MessageValue( 'apierror-' . $data['error'] ), 400 );
}
if ( !isset( $data['edit'] ) || !$data['edit']['result'] ) {
throw new RuntimeException( 'Bad result structure received from ApiEditPage' );
}
if ( $data['edit']['result'] !== 'Success' ) {
// Probably an edit conflict
// TODO: which code for null edits?
throw new LocalizedHttpException(
new MessageValue( "rest-edit-conflict", [ $data['edit']['result'] ] ),
409
);
}
$title = $this->titleParser->parseTitle( $data['edit']['title'] );
// This seems wasteful. This is the downside of delegating to the action API module:
// if we need additional data in the response, we have to load it.
$revision = $this->revisionLookup->getRevisionById( (int)$data['edit']['newrevid'] );
$content = $revision->getContent( SlotRecord::MAIN );
return [
'id' => $data['edit']['pageid'],
'title' => $this->titleFormatter->getPrefixedText( $title ),
'key' => $this->titleFormatter->getPrefixedDBkey( $title ),
'latest' => [
'id' => $data['edit']['newrevid'],
'timestamp' => $data['edit']['newtimestamp'],
],
'license' => [
'url' => $this->config->get( MainConfigNames::RightsUrl ),
'title' => $this->config->get( MainConfigNames::RightsText )
],
'content_model' => $data['edit']['contentmodel'],
'source' => $content->serialize(),
];
}
/**
* @inheritDoc
*/
protected function throwHttpExceptionForActionModuleError( IApiMessage $msg, $statusCode = 400 ) {
$code = $msg->getApiCode();
if ( $code === 'protectedpage' ) {
throw new LocalizedHttpException( $this->makeMessageValue( $msg ), 403 );
}
if ( $code === 'badtoken' ) {
throw new LocalizedHttpException( $this->makeMessageValue( $msg ), 403 );
}
if ( $code === 'missingtitle' ) {
throw new LocalizedHttpException( $this->makeMessageValue( $msg ), 404 );
}
if ( $code === 'articleexists' ) {
throw new LocalizedHttpException( $this->makeMessageValue( $msg ), 409 );
}
if ( $code === 'editconflict' ) {
throw new LocalizedHttpException( $this->makeMessageValue( $msg ), 409 );
}
if ( $code === 'ratelimited' ) {
throw new LocalizedHttpException( $this->makeMessageValue( $msg ), 429 );
}
// Fall through to generic handling of the error (status 400).
parent::throwHttpExceptionForActionModuleError( $msg, $statusCode );
}
protected function mapActionModuleResponse(
WebResponse $actionModuleResponse,
array $actionModuleResult,
Response $response
) {
parent::mapActionModuleResponse(
$actionModuleResponse,
$actionModuleResult,
$response
);
if ( $actionModuleResult['edit']['new'] ?? false ) {
$response->setStatus( 201 );
}
}
}