Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
48.33% |
29 / 60 |
|
0.00% |
0 / 4 |
CRAP | |
0.00% |
0 / 1 |
TransformHandler | |
48.33% |
29 / 60 |
|
0.00% |
0 / 4 |
68.79 | |
0.00% |
0 / 1 |
getParamSettings | |
0.00% |
0 / 13 |
|
0.00% |
0 / 1 |
2 | |||
checkPreconditions | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getRequestAttributes | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
6 | |||
execute | |
72.50% |
29 / 40 |
|
0.00% |
0 / 1 |
19.68 |
1 | <?php |
2 | |
3 | /** |
4 | * Copyright (C) 2011-2020 Wikimedia Foundation and others. |
5 | * |
6 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by |
8 | * the Free Software Foundation; either version 2 of the License, or |
9 | * (at your option) any later version. |
10 | * |
11 | * This program is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | * GNU General Public License for more details. |
15 | * |
16 | * You should have received a copy of the GNU General Public License along |
17 | * with this program; if not, write to the Free Software Foundation, Inc., |
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
19 | */ |
20 | |
21 | namespace MediaWiki\Rest\Handler; |
22 | |
23 | use MediaWiki\Rest\Handler\Helper\ParsoidFormatHelper; |
24 | use MediaWiki\Rest\HttpException; |
25 | use MediaWiki\Rest\LocalizedHttpException; |
26 | use MediaWiki\Rest\Response; |
27 | use Wikimedia\Message\MessageValue; |
28 | use Wikimedia\ParamValidator\ParamValidator; |
29 | |
30 | /** |
31 | * Handler for transforming content given in the request. |
32 | * - /v1/transform/{from}/to/{format} |
33 | * - /v1/transform/{from}/to/{format}/{title} |
34 | * - /v1/transform/{from}/to/{format}/{title}/{revision} |
35 | * |
36 | * @see https://www.mediawiki.org/wiki/Parsoid/API#POST |
37 | */ |
38 | class TransformHandler extends ParsoidHandler { |
39 | |
40 | /** @inheritDoc */ |
41 | public function getParamSettings() { |
42 | return [ |
43 | 'from' => [ self::PARAM_SOURCE => 'path', |
44 | ParamValidator::PARAM_TYPE => 'string', |
45 | ParamValidator::PARAM_REQUIRED => true, ], |
46 | 'format' => [ self::PARAM_SOURCE => 'path', |
47 | ParamValidator::PARAM_TYPE => 'string', |
48 | ParamValidator::PARAM_REQUIRED => true, ], |
49 | 'title' => [ self::PARAM_SOURCE => 'path', |
50 | ParamValidator::PARAM_TYPE => 'string', |
51 | ParamValidator::PARAM_REQUIRED => false, ], |
52 | 'revision' => [ self::PARAM_SOURCE => 'path', |
53 | ParamValidator::PARAM_TYPE => 'string', |
54 | ParamValidator::PARAM_REQUIRED => false, ], ]; |
55 | } |
56 | |
57 | public function checkPreconditions() { |
58 | // NOTE: disable all precondition checks. |
59 | // If-(not)-Modified-Since is not supported by the /transform/ handler. |
60 | // If-None-Match is not supported by the /transform/ handler. |
61 | // If-Match for wt2html is handled in getRequestAttributes. |
62 | } |
63 | |
64 | protected function &getRequestAttributes(): array { |
65 | $attribs =& parent::getRequestAttributes(); |
66 | |
67 | $request = $this->getRequest(); |
68 | |
69 | // NOTE: If there is more than one ETag, this will break. |
70 | // We don't have a good way to test multiple ETag to see if one of them is a working stash key. |
71 | $ifMatch = $request->getHeaderLine( 'If-Match' ); |
72 | |
73 | if ( $ifMatch ) { |
74 | $attribs['opts']['original']['etag'] = $ifMatch; |
75 | } |
76 | |
77 | return $attribs; |
78 | } |
79 | |
80 | /** |
81 | * Transform content given in the request from or to wikitext. |
82 | * |
83 | * @return Response |
84 | * @throws HttpException |
85 | */ |
86 | public function execute(): Response { |
87 | $request = $this->getRequest(); |
88 | $from = $request->getPathParam( 'from' ); |
89 | $format = $request->getPathParam( 'format' ); |
90 | |
91 | // XXX: Fallback to the default valid transforms in case the request is |
92 | // coming from a legacy client (restbase) that supports everything |
93 | // in the default valid transforms. |
94 | $validTransformations = $this->getConfig()['transformations'] ?? ParsoidFormatHelper::VALID_TRANSFORM; |
95 | |
96 | if ( !isset( $validTransformations[$from] ) || !in_array( $format, |
97 | $validTransformations[$from], |
98 | true ) ) { |
99 | throw new LocalizedHttpException( new MessageValue( "rest-invalid-transform", [ $from, $format ] ), 404 ); |
100 | } |
101 | $attribs = &$this->getRequestAttributes(); |
102 | if ( !$this->acceptable( $attribs ) ) { // mutates $attribs |
103 | throw new LocalizedHttpException( new MessageValue( "rest-unsupported-target-format" ), 406 ); |
104 | } |
105 | if ( $from === ParsoidFormatHelper::FORMAT_WIKITEXT ) { |
106 | // Accept wikitext as a string or object{body,headers} |
107 | $wikitext = $attribs['opts']['wikitext'] ?? null; |
108 | if ( is_array( $wikitext ) ) { |
109 | $wikitext = $wikitext['body']; |
110 | // We've been given a pagelanguage for this page. |
111 | if ( isset( $attribs['opts']['wikitext']['headers']['content-language'] ) ) { |
112 | $attribs['pagelanguage'] = $attribs['opts']['wikitext']['headers']['content-language']; |
113 | } |
114 | } |
115 | // We've been given source for this page |
116 | if ( $wikitext === null && isset( $attribs['opts']['original']['wikitext'] ) ) { |
117 | $wikitext = $attribs['opts']['original']['wikitext']['body']; |
118 | // We've been given a pagelanguage for this page. |
119 | if ( isset( $attribs['opts']['original']['wikitext']['headers']['content-language'] ) ) { |
120 | $attribs['pagelanguage'] = $attribs['opts']['original']['wikitext']['headers']['content-language']; |
121 | } |
122 | } |
123 | // Abort if no wikitext or title. |
124 | if ( $wikitext === null && empty( $attribs['pageName'] ) ) { |
125 | throw new LocalizedHttpException( new MessageValue( "rest-transform-missing-title" ), 400 ); |
126 | } |
127 | $pageConfig = $this->tryToCreatePageConfig( $attribs, $wikitext ); |
128 | |
129 | return $this->wt2html( $pageConfig, |
130 | $attribs, |
131 | $wikitext ); |
132 | } elseif ( $format === ParsoidFormatHelper::FORMAT_WIKITEXT ) { |
133 | $html = $attribs['opts']['html'] ?? null; |
134 | // Accept html as a string or object{body,headers} |
135 | if ( is_array( $html ) ) { |
136 | $html = $html['body']; |
137 | } |
138 | if ( $html === null ) { |
139 | throw new LocalizedHttpException( new MessageValue( "rest-transform-missing-html" ), 400 ); |
140 | } |
141 | |
142 | // TODO: use ETag from If-Match header, for compat! |
143 | |
144 | $page = $this->tryToCreatePageIdentity( $attribs ); |
145 | |
146 | return $this->html2wt( |
147 | $page, |
148 | $attribs, |
149 | $html |
150 | ); |
151 | } else { |
152 | return $this->pb2pb( $attribs ); |
153 | } |
154 | } |
155 | } |