wiki.techinc.nl/includes/Rest/Handler/RevisionHTMLHandler.php
daniel 2ec1791d40 Introduce PageRestHelperFactory
This allows extensions like VisualEditor to safely instantiate REST
helper objects. It also reduces the number of services that need to be
injected into REST handlers from route definitions.

Change-Id: I10af85b2da96568cfffd03867d1cb299645fb371
2022-11-21 07:23:26 +00:00

149 lines
4.5 KiB
PHP

<?php
namespace MediaWiki\Rest\Handler;
use LogicException;
use MediaWiki\MediaWikiServices;
use MediaWiki\Rest\LocalizedHttpException;
use MediaWiki\Rest\Response;
use MediaWiki\Rest\SimpleHandler;
use MediaWiki\Rest\StringStream;
use Wikimedia\Assert\Assert;
/**
* A handler that returns Parsoid HTML for the following routes:
* - /revision/{revision}/html,
* - /revision/{revision}/with_html
*
* Class RevisionHTMLHandler
* @package MediaWiki\Rest\Handler
*/
class RevisionHTMLHandler extends SimpleHandler {
/** @var HtmlOutputRendererHelper */
private $htmlHelper;
/** @var RevisionContentHelper */
private $contentHelper;
public function __construct( PageRestHelperFactory $helperFactory ) {
$this->contentHelper = $helperFactory->newRevisionContentHelper();
$this->htmlHelper = $helperFactory->newHtmlOutputRendererHelper();
}
protected function postValidationSetup() {
// TODO: Once Authority supports rate limit (T310476), just inject the Authority.
$user = MediaWikiServices::getInstance()->getUserFactory()
->newFromUserIdentity( $this->getAuthority()->getUser() );
$this->contentHelper->init( $user, $this->getValidatedParams() );
$page = $this->contentHelper->getPage();
$revision = $this->contentHelper->getTargetRevision();
if ( $page && $revision ) {
$this->htmlHelper->init( $page, $this->getValidatedParams(), $user );
$this->htmlHelper->setRevision( $revision );
$request = $this->getRequest();
$acceptLanguage = $request->getHeaderLine( 'Accept-Language' ) ?: null;
if ( $acceptLanguage ) {
$this->htmlHelper->setVariantConversionLanguage( $acceptLanguage );
}
}
}
/**
* @return Response
* @throws LocalizedHttpException
*/
public function run(): Response {
$this->contentHelper->checkAccess();
$page = $this->contentHelper->getPage();
$revisionRecord = $this->contentHelper->getTargetRevision();
// The call to $this->contentHelper->getPage() should not return null if
// $this->contentHelper->checkAccess() did not throw.
Assert::invariant( $page !== null, 'Page should be known' );
// The call to $this->contentHelper->getTargetRevision() should not return null if
// $this->contentHelper->checkAccess() did not throw.
Assert::invariant( $revisionRecord !== null, 'Revision should be known' );
$outputMode = $this->getOutputMode();
$setContentLanguageHeader = true;
switch ( $outputMode ) {
case 'html':
$parserOutput = $this->htmlHelper->getHtml();
$response = $this->getResponseFactory()->create();
// TODO: need to respect content-type returned by Parsoid.
$response->setHeader( 'Content-Type', 'text/html' );
$this->htmlHelper->putHeaders( $response, $setContentLanguageHeader );
$this->contentHelper->setCacheControl( $response, $parserOutput->getCacheExpiry() );
$response->setBody( new StringStream( $parserOutput->getText() ) );
break;
case 'with_html':
$parserOutput = $this->htmlHelper->getHtml();
$body = $this->contentHelper->constructMetadata();
$body['html'] = $parserOutput->getText();
$response = $this->getResponseFactory()->createJson( $body );
// For JSON content, it doesn't make sense to set content language header
$this->htmlHelper->putHeaders( $response, !$setContentLanguageHeader );
$this->contentHelper->setCacheControl( $response, $parserOutput->getCacheExpiry() );
break;
default:
throw new LogicException( "Unknown HTML type $outputMode" );
}
return $response;
}
/**
* Returns an ETag representing a page's source. The ETag assumes a page's source has changed
* if the latest revision of a page has been made private, un-readable for another reason,
* or a newer revision exists.
* @return string|null
*/
protected function getETag(): ?string {
if ( !$this->contentHelper->isAccessible() ) {
return null;
}
// Vary eTag based on output mode
return $this->htmlHelper->getETag( $this->getOutputMode() );
}
/**
* @return string|null
*/
protected function getLastModified(): ?string {
if ( !$this->contentHelper->isAccessible() ) {
return null;
}
return $this->htmlHelper->getLastModified();
}
private function getOutputMode(): string {
return $this->getConfig()['format'];
}
public function needsWriteAccess(): bool {
return false;
}
public function getParamSettings(): array {
return array_merge(
$this->contentHelper->getParamSettings(),
$this->htmlHelper->getParamSettings()
);
}
/**
* @return bool
*/
protected function hasRepresentation() {
return $this->contentHelper->hasContent();
}
}