Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
41.46% |
34 / 82 |
|
30.77% |
4 / 13 |
CRAP | |
0.00% |
0 / 1 |
CollaborationListContentHandler | |
41.46% |
34 / 82 |
|
30.77% |
4 / 13 |
82.99 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
canBeUsedOn | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
unserializeContent | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
6 | |||
serializeContent | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
makeEmptyContent | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
makeMemberList | |
100.00% |
20 / 20 |
|
100.00% |
1 / 1 |
1 | |||
getContentClass | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
isParserCacheSupported | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
supportsDirectApiEditing | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
supportsRedirects | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
makeRedirectContent | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
preSaveTransform | |
100.00% |
12 / 12 |
|
100.00% |
1 / 1 |
2 | |||
postMemberList | |
0.00% |
0 / 28 |
|
0.00% |
0 / 1 |
6 |
1 | <?php |
2 | |
3 | use MediaWiki\Content\Transform\PreSaveTransformParams; |
4 | use MediaWiki\MediaWikiServices; |
5 | |
6 | /** |
7 | * Content handler for CollaborationListContent. |
8 | * |
9 | * We extend TextContentHandler instead of JsonContentHandler since |
10 | * we do not display this as JSON code except upon request. |
11 | * |
12 | * @file |
13 | */ |
14 | class CollaborationListContentHandler extends TextContentHandler { |
15 | const FORMAT_WIKI = 'text/x-collabkit'; |
16 | |
17 | /** |
18 | * @param string $modelId |
19 | * @param string[] $formats |
20 | */ |
21 | public function __construct( |
22 | $modelId = 'CollaborationListContent', |
23 | $formats = [ CONTENT_FORMAT_JSON, CONTENT_FORMAT_TEXT, self::FORMAT_WIKI ] |
24 | ) { |
25 | // text/x-collabkit is a format for lists similar to <gallery>. |
26 | // CONTENT_FORMAT_TEXT is for back-compat with old revs. Could be removed. |
27 | // @todo Ideally, we'd have the preferred format for editing be |
28 | // self::FORMAT_WIKI and the preferred format for db be |
29 | // CONTENT_FORMAT_JSON. Unclear if that's possible. |
30 | parent::__construct( $modelId, $formats ); |
31 | } |
32 | |
33 | /** |
34 | * Can this content handler be used on a given page? |
35 | * |
36 | * @param Title $title Page to check |
37 | * @return bool |
38 | */ |
39 | public function canBeUsedOn( Title $title ) { |
40 | global $wgCollaborationListAllowedNamespaces; |
41 | |
42 | $namespace = $title->getNamespace(); |
43 | return isset( $wgCollaborationListAllowedNamespaces[$namespace] ) && |
44 | $wgCollaborationListAllowedNamespaces[$namespace]; |
45 | } |
46 | |
47 | /** |
48 | * Takes JSON string and creates a new CollaborationListContent object. |
49 | * |
50 | * Validation is intentionally not done at this step, as it is done later. |
51 | * |
52 | * @param string $text |
53 | * @param string|null $format |
54 | * @return CollaborationListContent |
55 | * @throws MWContentSerializationException |
56 | */ |
57 | public function unserializeContent( $text, $format = null ) { |
58 | $this->checkFormat( $format ); |
59 | if ( $format === self::FORMAT_WIKI ) { |
60 | $data = CollaborationListContent::convertFromHumanEditable( $text ); |
61 | $text = FormatJson::encode( $data ); |
62 | } |
63 | $content = new CollaborationListContent( $text ); |
64 | return $content; |
65 | } |
66 | |
67 | /** |
68 | * Serializes the CollaborationListContent object. |
69 | * |
70 | * @param Content|CollaborationListContent $content |
71 | * @param string|null $format |
72 | * @return string |
73 | */ |
74 | public function serializeContent( Content $content, $format = null ) { |
75 | if ( $format === self::FORMAT_WIKI ) { |
76 | return $content->convertToHumanEditable(); |
77 | } |
78 | return parent::serializeContent( $content, $format ); |
79 | } |
80 | |
81 | /** |
82 | * @return CollaborationListContent |
83 | */ |
84 | public function makeEmptyContent() { |
85 | $empty = <<<JSON |
86 | { |
87 | "displaymode": "normal", |
88 | "columns": [ |
89 | { "items": [] } |
90 | ], |
91 | "options": {}, |
92 | "description": "" |
93 | } |
94 | JSON; |
95 | return new CollaborationListContent( $empty ); |
96 | } |
97 | |
98 | /** |
99 | * Spawns a new "members" list, using the project creator as initial member. |
100 | * |
101 | * @param string $username Username without "User:" prefix |
102 | * @param string $initialDescription The initial description of the list |
103 | * @return CollaborationListContent |
104 | */ |
105 | public static function makeMemberList( $username, $initialDescription ) { |
106 | $linkToUserpage = Title::makeTitleSafe( NS_USER, $username ) |
107 | ->getPrefixedText(); |
108 | $newMemberList = [ |
109 | 'displaymode' => 'members', |
110 | 'columns' => [ [ |
111 | 'items' => [ [ |
112 | 'title' => $linkToUserpage |
113 | ] ] |
114 | ] ], |
115 | 'options' => [ |
116 | 'mode' => 'normal' |
117 | ], |
118 | 'description' => $initialDescription |
119 | ]; |
120 | $newMemberListJson = FormatJson::encode( |
121 | $newMemberList, |
122 | "\t", |
123 | FormatJson::ALL_OK |
124 | ); |
125 | return new CollaborationListContent( $newMemberListJson ); |
126 | } |
127 | |
128 | /** |
129 | * @return string |
130 | */ |
131 | protected function getContentClass() { |
132 | return 'CollaborationListContent'; |
133 | } |
134 | |
135 | /** |
136 | * FIXME is this really true? |
137 | * @return bool |
138 | */ |
139 | public function isParserCacheSupported() { |
140 | return true; |
141 | } |
142 | |
143 | /** |
144 | * @return bool |
145 | */ |
146 | public function supportsDirectApiEditing() { |
147 | return true; |
148 | } |
149 | |
150 | /** |
151 | * @return bool |
152 | */ |
153 | public function supportsRedirects() { |
154 | return true; |
155 | } |
156 | |
157 | /** |
158 | * Turns CollaborationListContent page into redirect |
159 | * |
160 | * Note that wikitext redirects are created, as generally, this content model |
161 | * is used in namespaces that support wikitext, and wikitext redirects are |
162 | * expected. |
163 | * |
164 | * @param Title $destination The page to redirect to |
165 | * @param string $text Text to include in the redirect. |
166 | * @return Content |
167 | */ |
168 | public function makeRedirectContent( Title $destination, $text = '' ) { |
169 | $handler = MediaWikiServices::getInstance() |
170 | ->getContentHandlerFactory() |
171 | ->getContentHandler( CONTENT_MODEL_WIKITEXT ); |
172 | return $handler->makeRedirectContent( $destination, $text ); |
173 | } |
174 | |
175 | /** |
176 | * Beautifies JSON and does subst: prior to save. |
177 | * |
178 | * @param Content $content |
179 | * @param PreSaveTransformParams $pstParams |
180 | * @return CollaborationListContent |
181 | */ |
182 | public function preSaveTransform( Content $content, PreSaveTransformParams $pstParams ): Content { |
183 | '@phan-var CollaborationListContent $content'; |
184 | $parser = MediaWikiServices::getInstance()->getParser(); |
185 | // WikiPage::doEditContent invokes PST before validation. As such, |
186 | // native data may be invalid (though PST result is discarded later in |
187 | // that case). |
188 | $text = $content->getText(); |
189 | // pst will hopefully not make json invalid. Def should not. |
190 | $pst = $parser->preSaveTransform( |
191 | $text, |
192 | $pstParams->getPage(), |
193 | $pstParams->getUser(), |
194 | $pstParams->getParserOptions() |
195 | ); |
196 | |
197 | $pstContent = new CollaborationListContent( $pst ); |
198 | |
199 | if ( !$pstContent->isValid() ) { |
200 | return $content; |
201 | } |
202 | |
203 | return new CollaborationListContent( $pstContent->beautifyJSON() ); |
204 | } |
205 | |
206 | /** |
207 | * Posts the newly created "members" list on-wiki. |
208 | * |
209 | * @param Title $title |
210 | * @param string $summary |
211 | * @param IContextSource $context |
212 | * @todo rework this to use a generic CollaborationList editor function once |
213 | * it exists |
214 | * @return Status |
215 | */ |
216 | public static function postMemberList( Title $title, $summary, |
217 | IContextSource $context |
218 | ) { |
219 | $username = $context->getUser()->getName(); |
220 | $collabList = self::makeMemberList( |
221 | $username, |
222 | $context->msg( 'collaborationkit-hub-members-description' )->text() |
223 | ); |
224 | // Ensure that a valid context is provided to the API in unit tests |
225 | $der = new DerivativeContext( $context ); |
226 | $request = new DerivativeRequest( |
227 | $context->getRequest(), |
228 | [ |
229 | 'action' => 'edit', |
230 | 'title' => $title->getFullText(), |
231 | 'contentmodel' => 'CollaborationListContent', |
232 | 'contentformat' => 'application/json', |
233 | 'text' => $collabList->serialize(), |
234 | 'summary' => $summary, |
235 | 'token' => $context->getUser()->getEditToken(), |
236 | ], |
237 | true // Treat data as POSTed |
238 | ); |
239 | $der->setRequest( $request ); |
240 | try { |
241 | $api = new ApiMain( $der, true ); |
242 | $api->execute(); |
243 | } catch ( ApiUsageException $e ) { |
244 | return Status::newFatal( |
245 | $context->msg( 'collaborationkit-hub-edit-apierror', |
246 | $e->getMessageObject() ) |
247 | ); |
248 | } |
249 | return Status::newGood(); |
250 | } |
251 | } |