Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
65.96% covered (warning)
65.96%
31 / 47
41.67% covered (danger)
41.67%
5 / 12
CRAP
0.00% covered (danger)
0.00%
0 / 1
RevisionSourceHandler
65.96% covered (warning)
65.96%
31 / 47
41.67% covered (danger)
41.67%
5 / 12
38.40
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 postValidationSetup
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 constructHtmlUrl
85.71% covered (warning)
85.71%
6 / 7
0.00% covered (danger)
0.00%
0 / 1
2.01
 run
85.71% covered (warning)
85.71%
18 / 21
0.00% covered (danger)
0.00%
0 / 1
5.07
 getTargetFormat
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getResponseBodySchemaFileName
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
20
 getETag
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getLastModified
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getOutputMode
66.67% covered (warning)
66.67%
2 / 3
0.00% covered (danger)
0.00%
0 / 1
2.15
 needsWriteAccess
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getParamSettings
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 hasRepresentation
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3namespace MediaWiki\Rest\Handler;
4
5use LogicException;
6use MediaWiki\Rest\Handler\Helper\PageRestHelperFactory;
7use MediaWiki\Rest\Handler\Helper\RevisionContentHelper;
8use MediaWiki\Rest\LocalizedHttpException;
9use MediaWiki\Rest\Response;
10use MediaWiki\Rest\SimpleHandler;
11use MediaWiki\Revision\RevisionRecord;
12use Wikimedia\Message\MessageValue;
13
14/**
15 * A handler that returns page source and metadata for the following routes:
16 * - /revision/{revision}
17 * - /revision/{revision}/bare
18 */
19class RevisionSourceHandler extends SimpleHandler {
20
21    private RevisionContentHelper $contentHelper;
22
23    public function __construct( PageRestHelperFactory $helperFactory ) {
24        $this->contentHelper = $helperFactory->newRevisionContentHelper();
25    }
26
27    protected function postValidationSetup() {
28        $this->contentHelper->init( $this->getAuthority(), $this->getValidatedParams() );
29    }
30
31    private function constructHtmlUrl( RevisionRecord $rev ): string {
32        // TODO: once legacy "v1" routes are removed, just use the path prefix from the module.
33        $pathPrefix = $this->getModule()->getPathPrefix();
34        if ( $pathPrefix === '' ) {
35            $pathPrefix = 'v1';
36        }
37
38        return $this->getRouter()->getRouteUrl(
39            '/' . $pathPrefix . '/revision/{id}/html',
40            [ 'id' => $rev->getId() ]
41        );
42    }
43
44    /**
45     * @return Response
46     * @throws LocalizedHttpException
47     */
48    public function run() {
49        $this->contentHelper->checkAccess();
50
51        $outputMode = $this->getOutputMode();
52        switch ( $outputMode ) {
53            case 'restbase': // compatibility for restbase migration
54                $body = [ 'items' => [ $this->contentHelper->constructRestbaseCompatibleMetadata() ] ];
55                break;
56            case 'bare':
57                $revisionRecord = $this->contentHelper->getTargetRevision();
58                $body = $this->contentHelper->constructMetadata();
59                // @phan-suppress-next-line PhanTypeMismatchArgumentNullable revisionRecord is set when used
60                $body['html_url'] = $this->constructHtmlUrl( $revisionRecord );
61                $response = $this->getResponseFactory()->createJson( $body );
62                $this->contentHelper->setCacheControl( $response );
63                break;
64            case 'source':
65                $content = $this->contentHelper->getContent();
66                $body = $this->contentHelper->constructMetadata();
67                $body['source'] = $content->getText();
68                break;
69            default:
70                throw new LogicException( "Unknown output mode $outputMode" );
71        }
72
73        $response = $this->getResponseFactory()->createJson( $body );
74        $this->contentHelper->setCacheControl( $response );
75
76        return $response;
77    }
78
79    private function getTargetFormat(): string {
80        return $this->getConfig()['format'];
81    }
82
83    protected function getResponseBodySchemaFileName( string $method ): ?string {
84        switch ( $this->getTargetFormat() ) {
85            case 'bare':
86                return __DIR__ . '/Schema/RevisionMetaDataBare.json';
87
88            case 'source':
89                return __DIR__ . '/Schema/RevisionMetaDataWithSource.json';
90
91            default:
92                throw new LocalizedHttpException(
93                    new MessageValue( "rest-unsupported-target-format" ), 500
94                );
95        }
96    }
97
98    protected function getETag(): ?string {
99        return $this->contentHelper->getETag();
100    }
101
102    protected function getLastModified(): ?string {
103        return $this->contentHelper->getLastModified();
104    }
105
106    private function getOutputMode(): string {
107        if ( $this->getRouter()->isRestbaseCompatEnabled( $this->getRequest() ) ) {
108            return 'restbase';
109        }
110        return $this->getConfig()['format'];
111    }
112
113    public function needsWriteAccess(): bool {
114        return false;
115    }
116
117    public function getParamSettings(): array {
118        return $this->contentHelper->getParamSettings();
119    }
120
121    /**
122     * @return bool
123     */
124    protected function hasRepresentation() {
125        return $this->contentHelper->hasContent();
126    }
127}