Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 65 |
|
0.00% |
0 / 4 |
CRAP | |
0.00% |
0 / 1 |
ApiJsonSchema | |
0.00% |
0 / 65 |
|
0.00% |
0 / 4 |
420 | |
0.00% |
0 / 1 |
getAllowedParams | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
2 | |||
getExamplesMessages | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
2 | |||
markCacheable | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
2 | |||
execute | |
0.00% |
0 / 46 |
|
0.00% |
0 / 1 |
306 |
1 | <?php |
2 | /** |
3 | * API module for retrieving JSON Schema. |
4 | * |
5 | * @file |
6 | * @ingroup EventLogging |
7 | * @ingroup Extensions |
8 | * |
9 | * @author Ori Livneh <ori@wikimedia.org> |
10 | */ |
11 | |
12 | namespace MediaWiki\Extension\EventLogging; |
13 | |
14 | use ApiBase; |
15 | use ApiResult; |
16 | use MediaWiki\MediaWikiServices; |
17 | use MediaWiki\Revision\RevisionRecord; |
18 | use MediaWiki\Revision\SlotRecord; |
19 | use MediaWiki\Title\Title; |
20 | use Wikimedia\ParamValidator\ParamValidator; |
21 | |
22 | /** |
23 | * API module for retrieving JSON Schema. |
24 | * This avoids API result paths and returns HTTP error codes in order to |
25 | * act like a request for the raw page content. |
26 | * @ingroup API |
27 | */ |
28 | class ApiJsonSchema extends ApiBase { |
29 | |
30 | public function getAllowedParams() { |
31 | return [ |
32 | 'revid' => [ |
33 | ParamValidator::PARAM_TYPE => 'integer', |
34 | ], |
35 | 'title' => [ |
36 | ParamValidator::PARAM_TYPE => 'string', |
37 | ], |
38 | ]; |
39 | } |
40 | |
41 | /** |
42 | * @see ApiBase::getExamplesMessages() |
43 | * @return array |
44 | */ |
45 | protected function getExamplesMessages() { |
46 | return [ |
47 | 'action=jsonschema&revid=1234' |
48 | => 'apihelp-jsonschema-example-1', |
49 | 'action=jsonschema&title=Test' |
50 | => 'apihelp-jsonschema-example-2', |
51 | ]; |
52 | } |
53 | |
54 | /** |
55 | * Set headers on the pending HTTP response. |
56 | * @param RevisionRecord $revRecord |
57 | */ |
58 | private function markCacheable( RevisionRecord $revRecord ) { |
59 | $main = $this->getMain(); |
60 | $main->setCacheMode( 'public' ); |
61 | $main->setCacheMaxAge( 300 ); |
62 | |
63 | $lastModified = wfTimestamp( TS_RFC2822, $revRecord->getTimestamp() ); |
64 | $main->getRequest()->response()->header( "Last-Modified: $lastModified" ); |
65 | } |
66 | |
67 | public function execute() { |
68 | $params = $this->extractRequestParams(); |
69 | |
70 | if ( !isset( $params['revid'] ) && !isset( $params['title'] ) ) { |
71 | $this->dieWithError( |
72 | [ 'apierror-missingparam-at-least-one-of', 'revid', 'title' ], |
73 | null, null, 400 |
74 | ); |
75 | } |
76 | |
77 | $revLookup = MediaWikiServices::getInstance()->getRevisionLookup(); |
78 | // If we are given revid, then look up Revision and |
79 | // verify that $params['title'] (if given) matches. |
80 | if ( isset( $params['revid'] ) ) { |
81 | $revRecord = $revLookup->getRevisionById( $params['revid'] ); |
82 | if ( !$revRecord ) { |
83 | $this->dieWithError( |
84 | [ 'apierror-nosuchrevid', $params['revid'] ], null, null, 400 |
85 | ); |
86 | } |
87 | $title = Title::newFromLinkTarget( $revRecord->getPageAsLinkTarget() ); |
88 | if ( !$title || !$title->inNamespace( NS_SCHEMA ) ) { |
89 | $this->dieWithError( |
90 | [ 'apierror-invalidtitle', wfEscapeWikiText( $title ?: '' ) ], null, null, 400 |
91 | ); |
92 | } |
93 | |
94 | // If we use the revid param for lookup; the 'title' parameter is |
95 | // optional. If present, it is used to assert that the specified |
96 | // revision ID is indeed a revision of a page with the specified |
97 | // title. (Bug 46174) |
98 | if ( |
99 | $params['title'] && |
100 | !$title->equals( Title::newFromText( $params['title'], NS_SCHEMA ) ) |
101 | ) { |
102 | $this->dieWithError( |
103 | [ 'apierror-revwrongpage', $params['revid'], wfEscapeWikiText( $params['title'] ) ], |
104 | null, null, 400 |
105 | ); |
106 | } |
107 | |
108 | // Else use $params['title'] and get the latest revision |
109 | } else { |
110 | $title = Title::newFromText( $params['title'], NS_SCHEMA ); |
111 | if ( !$title || !$title->exists() || !$title->inNamespace( NS_SCHEMA ) ) { |
112 | $this->dieWithError( |
113 | [ 'apierror-invalidtitle', wfEscapeWikiText( $params['title'] ) ], null, null, 400 |
114 | ); |
115 | } |
116 | |
117 | $revRecord = $revLookup->getRevisionById( $title->getLatestRevID() ); |
118 | } |
119 | |
120 | /** @var JsonSchemaContent $content */ |
121 | $content = $revRecord->getContent( SlotRecord::MAIN ); |
122 | if ( !$content ) { |
123 | $this->dieWithError( |
124 | [ 'apierror-nosuchrevid', $revRecord->getId() ], |
125 | null, null, 400 |
126 | ); |
127 | } |
128 | |
129 | // @phan-suppress-next-line PhanTypeMismatchArgumentNullable T240141 |
130 | $this->markCacheable( $revRecord ); |
131 | '@phan-var JsonSchemaContent $content'; |
132 | $schema = $content->getJsonData(); |
133 | |
134 | $result = $this->getResult(); |
135 | $result->addValue( null, 'title', $title->getText() ); |
136 | foreach ( $schema as $k => &$v ) { |
137 | if ( $k === 'properties' ) { |
138 | foreach ( $v as &$properties ) { |
139 | $properties[ApiResult::META_BC_BOOLS] = [ 'required' ]; |
140 | } |
141 | } |
142 | $result->addValue( null, $k, $v ); |
143 | } |
144 | } |
145 | } |