These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /** |
||
3 | * |
||
4 | * |
||
5 | * Created on August 16, 2007 |
||
6 | * |
||
7 | * Copyright © 2007 Iker Labarga "<Firstname><Lastname>@gmail.com" |
||
8 | * |
||
9 | * This program is free software; you can redistribute it and/or modify |
||
10 | * it under the terms of the GNU General Public License as published by |
||
11 | * the Free Software Foundation; either version 2 of the License, or |
||
12 | * (at your option) any later version. |
||
13 | * |
||
14 | * This program is distributed in the hope that it will be useful, |
||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
17 | * GNU General Public License for more details. |
||
18 | * |
||
19 | * You should have received a copy of the GNU General Public License along |
||
20 | * with this program; if not, write to the Free Software Foundation, Inc., |
||
21 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||
22 | * http://www.gnu.org/copyleft/gpl.html |
||
23 | * |
||
24 | * @file |
||
25 | */ |
||
26 | |||
27 | /** |
||
28 | * A module that allows for editing and creating pages. |
||
29 | * |
||
30 | * Currently, this wraps around the EditPage class in an ugly way, |
||
31 | * EditPage.php should be rewritten to provide a cleaner interface, |
||
32 | * see T20654 if you're inspired to fix this. |
||
33 | * |
||
34 | * @ingroup API |
||
35 | */ |
||
36 | class ApiEditPage extends ApiBase { |
||
37 | public function execute() { |
||
38 | $this->useTransactionalTimeLimit(); |
||
39 | |||
40 | $user = $this->getUser(); |
||
41 | $params = $this->extractRequestParams(); |
||
42 | |||
43 | if ( is_null( $params['text'] ) && is_null( $params['appendtext'] ) && |
||
44 | is_null( $params['prependtext'] ) && |
||
45 | $params['undo'] == 0 |
||
46 | ) { |
||
47 | $this->dieUsageMsg( 'missingtext' ); |
||
48 | } |
||
49 | |||
50 | $pageObj = $this->getTitleOrPageId( $params ); |
||
51 | $titleObj = $pageObj->getTitle(); |
||
52 | $apiResult = $this->getResult(); |
||
53 | |||
54 | if ( $params['redirect'] ) { |
||
55 | if ( $params['prependtext'] === null && $params['appendtext'] === null |
||
56 | && $params['section'] !== 'new' |
||
57 | ) { |
||
58 | $this->dieUsage( 'You have attempted to edit using the "redirect"-following' |
||
59 | . ' mode, which must be used in conjuction with section=new, prependtext' |
||
60 | . ', or appendtext.', 'redirect-appendonly' ); |
||
61 | } |
||
62 | if ( $titleObj->isRedirect() ) { |
||
63 | $oldTitle = $titleObj; |
||
64 | |||
65 | $titles = Revision::newFromTitle( $oldTitle, false, Revision::READ_LATEST ) |
||
66 | ->getContent( Revision::FOR_THIS_USER, $user ) |
||
67 | ->getRedirectChain(); |
||
68 | // array_shift( $titles ); |
||
69 | |||
70 | $redirValues = []; |
||
71 | |||
72 | /** @var $newTitle Title */ |
||
73 | foreach ( $titles as $id => $newTitle ) { |
||
74 | |||
75 | if ( !isset( $titles[$id - 1] ) ) { |
||
76 | $titles[$id - 1] = $oldTitle; |
||
77 | } |
||
78 | |||
79 | $redirValues[] = [ |
||
80 | 'from' => $titles[$id - 1]->getPrefixedText(), |
||
81 | 'to' => $newTitle->getPrefixedText() |
||
82 | ]; |
||
83 | |||
84 | $titleObj = $newTitle; |
||
85 | } |
||
86 | |||
87 | ApiResult::setIndexedTagName( $redirValues, 'r' ); |
||
88 | $apiResult->addValue( null, 'redirects', $redirValues ); |
||
89 | |||
90 | // Since the page changed, update $pageObj |
||
91 | $pageObj = WikiPage::factory( $titleObj ); |
||
92 | } |
||
93 | } |
||
94 | |||
95 | if ( !isset( $params['contentmodel'] ) || $params['contentmodel'] == '' ) { |
||
96 | $contentHandler = $pageObj->getContentHandler(); |
||
97 | } else { |
||
98 | $contentHandler = ContentHandler::getForModelID( $params['contentmodel'] ); |
||
99 | } |
||
100 | $contentModel = $contentHandler->getModelID(); |
||
101 | |||
102 | $name = $titleObj->getPrefixedDBkey(); |
||
103 | $model = $contentHandler->getModelID(); |
||
104 | |||
105 | if ( $params['undo'] > 0 ) { |
||
106 | // allow undo via api |
||
107 | } elseif ( $contentHandler->supportsDirectApiEditing() === false ) { |
||
108 | $this->dieUsage( |
||
109 | "Direct editing via API is not supported for content model $model used by $name", |
||
110 | 'no-direct-editing' |
||
111 | ); |
||
112 | } |
||
113 | |||
114 | if ( !isset( $params['contentformat'] ) || $params['contentformat'] == '' ) { |
||
115 | $contentFormat = $contentHandler->getDefaultFormat(); |
||
116 | } else { |
||
117 | $contentFormat = $params['contentformat']; |
||
118 | } |
||
119 | |||
120 | if ( !$contentHandler->isSupportedFormat( $contentFormat ) ) { |
||
121 | |||
122 | $this->dieUsage( "The requested format $contentFormat is not supported for content model " . |
||
123 | " $model used by $name", 'badformat' ); |
||
124 | } |
||
125 | |||
126 | if ( $params['createonly'] && $titleObj->exists() ) { |
||
127 | $this->dieUsageMsg( 'createonly-exists' ); |
||
128 | } |
||
129 | if ( $params['nocreate'] && !$titleObj->exists() ) { |
||
130 | $this->dieUsageMsg( 'nocreate-missing' ); |
||
131 | } |
||
132 | |||
133 | // Now let's check whether we're even allowed to do this |
||
134 | $errors = $titleObj->getUserPermissionsErrors( 'edit', $user ); |
||
135 | if ( !$titleObj->exists() ) { |
||
136 | $errors = array_merge( $errors, $titleObj->getUserPermissionsErrors( 'create', $user ) ); |
||
137 | } |
||
138 | if ( count( $errors ) ) { |
||
139 | if ( is_array( $errors[0] ) ) { |
||
140 | switch ( $errors[0][0] ) { |
||
141 | case 'blockedtext': |
||
142 | $this->dieUsage( |
||
143 | 'You have been blocked from editing', |
||
144 | 'blocked', |
||
145 | 0, |
||
146 | [ 'blockinfo' => ApiQueryUserInfo::getBlockInfo( $user->getBlock() ) ] |
||
147 | ); |
||
148 | break; |
||
149 | case 'autoblockedtext': |
||
150 | $this->dieUsage( |
||
151 | 'Your IP address has been blocked automatically, because it was used by a blocked user', |
||
152 | 'autoblocked', |
||
153 | 0, |
||
154 | [ 'blockinfo' => ApiQueryUserInfo::getBlockInfo( $user->getBlock() ) ] |
||
0 ignored issues
–
show
|
|||
155 | ); |
||
156 | break; |
||
157 | default: |
||
158 | $this->dieUsageMsg( $errors[0] ); |
||
159 | } |
||
160 | } else { |
||
161 | $this->dieUsageMsg( $errors[0] ); |
||
162 | } |
||
163 | } |
||
164 | |||
165 | $toMD5 = $params['text']; |
||
166 | if ( !is_null( $params['appendtext'] ) || !is_null( $params['prependtext'] ) ) { |
||
167 | $content = $pageObj->getContent(); |
||
168 | |||
169 | if ( !$content ) { |
||
170 | if ( $titleObj->getNamespace() == NS_MEDIAWIKI ) { |
||
171 | # If this is a MediaWiki:x message, then load the messages |
||
172 | # and return the message value for x. |
||
173 | $text = $titleObj->getDefaultMessageText(); |
||
174 | if ( $text === false ) { |
||
175 | $text = ''; |
||
176 | } |
||
177 | |||
178 | try { |
||
179 | $content = ContentHandler::makeContent( $text, $this->getTitle() ); |
||
180 | } catch ( MWContentSerializationException $ex ) { |
||
181 | $this->dieUsage( $ex->getMessage(), 'parseerror' ); |
||
182 | |||
183 | return; |
||
184 | } |
||
185 | } else { |
||
186 | # Otherwise, make a new empty content. |
||
187 | $content = $contentHandler->makeEmptyContent(); |
||
188 | } |
||
189 | } |
||
190 | |||
191 | // @todo Add support for appending/prepending to the Content interface |
||
192 | |||
193 | if ( !( $content instanceof TextContent ) ) { |
||
194 | $mode = $contentHandler->getModelID(); |
||
195 | $this->dieUsage( "Can't append to pages using content model $mode", 'appendnotsupported' ); |
||
196 | } |
||
197 | |||
198 | if ( !is_null( $params['section'] ) ) { |
||
199 | if ( !$contentHandler->supportsSections() ) { |
||
200 | $modelName = $contentHandler->getModelID(); |
||
201 | $this->dieUsage( |
||
202 | "Sections are not supported for this content model: $modelName.", |
||
203 | 'sectionsnotsupported' |
||
204 | ); |
||
205 | } |
||
206 | |||
207 | if ( $params['section'] == 'new' ) { |
||
208 | // DWIM if they're trying to prepend/append to a new section. |
||
209 | $content = null; |
||
210 | } else { |
||
211 | // Process the content for section edits |
||
212 | $section = $params['section']; |
||
213 | $content = $content->getSection( $section ); |
||
214 | |||
215 | if ( !$content ) { |
||
216 | $this->dieUsage( "There is no section {$section}.", 'nosuchsection' ); |
||
217 | } |
||
218 | } |
||
219 | } |
||
220 | |||
221 | if ( !$content ) { |
||
222 | $text = ''; |
||
223 | } else { |
||
224 | $text = $content->serialize( $contentFormat ); |
||
225 | } |
||
226 | |||
227 | $params['text'] = $params['prependtext'] . $text . $params['appendtext']; |
||
228 | $toMD5 = $params['prependtext'] . $params['appendtext']; |
||
229 | } |
||
230 | |||
231 | if ( $params['undo'] > 0 ) { |
||
232 | if ( $params['undoafter'] > 0 ) { |
||
233 | if ( $params['undo'] < $params['undoafter'] ) { |
||
234 | list( $params['undo'], $params['undoafter'] ) = |
||
235 | [ $params['undoafter'], $params['undo'] ]; |
||
236 | } |
||
237 | $undoafterRev = Revision::newFromId( $params['undoafter'] ); |
||
238 | } |
||
239 | $undoRev = Revision::newFromId( $params['undo'] ); |
||
240 | View Code Duplication | if ( is_null( $undoRev ) || $undoRev->isDeleted( Revision::DELETED_TEXT ) ) { |
|
241 | $this->dieUsageMsg( [ 'nosuchrevid', $params['undo'] ] ); |
||
242 | } |
||
243 | |||
244 | if ( $params['undoafter'] == 0 ) { |
||
245 | $undoafterRev = $undoRev->getPrevious(); |
||
246 | } |
||
247 | View Code Duplication | if ( is_null( $undoafterRev ) || $undoafterRev->isDeleted( Revision::DELETED_TEXT ) ) { |
|
248 | $this->dieUsageMsg( [ 'nosuchrevid', $params['undoafter'] ] ); |
||
249 | } |
||
250 | |||
251 | View Code Duplication | if ( $undoRev->getPage() != $pageObj->getId() ) { |
|
252 | $this->dieUsageMsg( [ 'revwrongpage', $undoRev->getId(), |
||
253 | $titleObj->getPrefixedText() ] ); |
||
254 | } |
||
255 | View Code Duplication | if ( $undoafterRev->getPage() != $pageObj->getId() ) { |
|
256 | $this->dieUsageMsg( [ 'revwrongpage', $undoafterRev->getId(), |
||
257 | $titleObj->getPrefixedText() ] ); |
||
258 | } |
||
259 | |||
260 | $newContent = $contentHandler->getUndoContent( |
||
261 | $pageObj->getRevision(), |
||
262 | $undoRev, |
||
263 | $undoafterRev |
||
264 | ); |
||
265 | |||
266 | if ( !$newContent ) { |
||
267 | $this->dieUsageMsg( 'undo-failure' ); |
||
268 | } |
||
269 | if ( empty( $params['contentmodel'] ) |
||
270 | && empty( $params['contentformat'] ) |
||
271 | ) { |
||
272 | // If we are reverting content model, the new content model |
||
273 | // might not support the current serialization format, in |
||
274 | // which case go back to the old serialization format, |
||
275 | // but only if the user hasn't specified a format/model |
||
276 | // parameter. |
||
277 | if ( !$newContent->isSupportedFormat( $contentFormat ) ) { |
||
278 | $contentFormat = $undoafterRev->getContentFormat(); |
||
279 | } |
||
280 | // Override content model with model of undid revision. |
||
281 | $contentModel = $newContent->getModel(); |
||
282 | } |
||
283 | $params['text'] = $newContent->serialize( $contentFormat ); |
||
284 | // If no summary was given and we only undid one rev, |
||
285 | // use an autosummary |
||
286 | if ( is_null( $params['summary'] ) && |
||
287 | $titleObj->getNextRevisionID( $undoafterRev->getId() ) == $params['undo'] |
||
288 | ) { |
||
289 | $params['summary'] = wfMessage( 'undo-summary' ) |
||
290 | ->params( $params['undo'], $undoRev->getUserText() )->inContentLanguage()->text(); |
||
291 | } |
||
292 | } |
||
293 | |||
294 | // See if the MD5 hash checks out |
||
295 | if ( !is_null( $params['md5'] ) && md5( $toMD5 ) !== $params['md5'] ) { |
||
296 | $this->dieUsageMsg( 'hashcheckfailed' ); |
||
297 | } |
||
298 | |||
299 | // EditPage wants to parse its stuff from a WebRequest |
||
300 | // That interface kind of sucks, but it's workable |
||
301 | $requestArray = [ |
||
302 | 'wpTextbox1' => $params['text'], |
||
303 | 'format' => $contentFormat, |
||
304 | 'model' => $contentModel, |
||
305 | 'wpEditToken' => $params['token'], |
||
306 | 'wpIgnoreBlankSummary' => true, |
||
307 | 'wpIgnoreBlankArticle' => true, |
||
308 | 'wpIgnoreSelfRedirect' => true, |
||
309 | 'bot' => $params['bot'], |
||
310 | ]; |
||
311 | |||
312 | if ( !is_null( $params['summary'] ) ) { |
||
313 | $requestArray['wpSummary'] = $params['summary']; |
||
314 | } |
||
315 | |||
316 | if ( !is_null( $params['sectiontitle'] ) ) { |
||
317 | $requestArray['wpSectionTitle'] = $params['sectiontitle']; |
||
318 | } |
||
319 | |||
320 | // TODO: Pass along information from 'undoafter' as well |
||
321 | if ( $params['undo'] > 0 ) { |
||
322 | $requestArray['wpUndidRevision'] = $params['undo']; |
||
323 | } |
||
324 | |||
325 | // Watch out for basetimestamp == '' or '0' |
||
326 | // It gets treated as NOW, almost certainly causing an edit conflict |
||
327 | if ( $params['basetimestamp'] !== null && (bool)$this->getMain()->getVal( 'basetimestamp' ) ) { |
||
328 | $requestArray['wpEdittime'] = $params['basetimestamp']; |
||
329 | } else { |
||
330 | $requestArray['wpEdittime'] = $pageObj->getTimestamp(); |
||
331 | } |
||
332 | |||
333 | if ( $params['starttimestamp'] !== null ) { |
||
334 | $requestArray['wpStarttime'] = $params['starttimestamp']; |
||
335 | } else { |
||
336 | $requestArray['wpStarttime'] = wfTimestampNow(); // Fake wpStartime |
||
337 | } |
||
338 | |||
339 | if ( $params['minor'] || ( !$params['notminor'] && $user->getOption( 'minordefault' ) ) ) { |
||
340 | $requestArray['wpMinoredit'] = ''; |
||
341 | } |
||
342 | |||
343 | if ( $params['recreate'] ) { |
||
344 | $requestArray['wpRecreate'] = ''; |
||
345 | } |
||
346 | |||
347 | if ( !is_null( $params['section'] ) ) { |
||
348 | $section = $params['section']; |
||
349 | if ( !preg_match( '/^((T-)?\d+|new)$/', $section ) ) { |
||
350 | $this->dieUsage( "The section parameter must be a valid section id or 'new'", |
||
351 | 'invalidsection' ); |
||
352 | } |
||
353 | $content = $pageObj->getContent(); |
||
354 | if ( $section !== '0' && $section != 'new' |
||
355 | && ( !$content || !$content->getSection( $section ) ) |
||
356 | ) { |
||
357 | $this->dieUsage( "There is no section {$section}.", 'nosuchsection' ); |
||
358 | } |
||
359 | $requestArray['wpSection'] = $params['section']; |
||
360 | } else { |
||
361 | $requestArray['wpSection'] = ''; |
||
362 | } |
||
363 | |||
364 | $watch = $this->getWatchlistValue( $params['watchlist'], $titleObj ); |
||
365 | |||
366 | // Deprecated parameters |
||
367 | if ( $params['watch'] ) { |
||
368 | $watch = true; |
||
369 | } elseif ( $params['unwatch'] ) { |
||
370 | $watch = false; |
||
371 | } |
||
372 | |||
373 | if ( $watch ) { |
||
374 | $requestArray['wpWatchthis'] = ''; |
||
375 | } |
||
376 | |||
377 | // Apply change tags |
||
378 | if ( count( $params['tags'] ) ) { |
||
379 | $tagStatus = ChangeTags::canAddTagsAccompanyingChange( $params['tags'], $user ); |
||
380 | if ( $tagStatus->isOK() ) { |
||
381 | $requestArray['wpChangeTags'] = implode( ',', $params['tags'] ); |
||
382 | } else { |
||
383 | $this->dieStatus( $tagStatus ); |
||
384 | } |
||
385 | } |
||
386 | |||
387 | // Pass through anything else we might have been given, to support extensions |
||
388 | // This is kind of a hack but it's the best we can do to make extensions work |
||
389 | $requestArray += $this->getRequest()->getValues(); |
||
390 | |||
391 | global $wgTitle, $wgRequest; |
||
392 | |||
393 | $req = new DerivativeRequest( $this->getRequest(), $requestArray, true ); |
||
394 | |||
395 | // Some functions depend on $wgTitle == $ep->mTitle |
||
396 | // TODO: Make them not or check if they still do |
||
397 | $wgTitle = $titleObj; |
||
398 | |||
399 | $articleContext = new RequestContext; |
||
400 | $articleContext->setRequest( $req ); |
||
401 | $articleContext->setWikiPage( $pageObj ); |
||
402 | $articleContext->setUser( $this->getUser() ); |
||
403 | |||
404 | /** @var $articleObject Article */ |
||
405 | $articleObject = Article::newFromWikiPage( $pageObj, $articleContext ); |
||
406 | |||
407 | $ep = new EditPage( $articleObject ); |
||
408 | |||
409 | $ep->setApiEditOverride( true ); |
||
410 | $ep->setContextTitle( $titleObj ); |
||
411 | $ep->importFormData( $req ); |
||
412 | $content = $ep->textbox1; |
||
413 | |||
414 | // Run hooks |
||
415 | // Handle APIEditBeforeSave parameters |
||
416 | $r = []; |
||
417 | // Deprecated in favour of EditFilterMergedContent |
||
418 | if ( !Hooks::run( 'APIEditBeforeSave', [ $ep, $content, &$r ], '1.28' ) ) { |
||
419 | if ( count( $r ) ) { |
||
420 | $r['result'] = 'Failure'; |
||
421 | $apiResult->addValue( null, $this->getModuleName(), $r ); |
||
422 | |||
423 | return; |
||
424 | } |
||
425 | |||
426 | $this->dieUsageMsg( 'hookaborted' ); |
||
427 | } |
||
428 | |||
429 | // Do the actual save |
||
430 | $oldRevId = $articleObject->getRevIdFetched(); |
||
431 | $result = null; |
||
432 | // Fake $wgRequest for some hooks inside EditPage |
||
433 | // @todo FIXME: This interface SUCKS |
||
434 | $oldRequest = $wgRequest; |
||
435 | $wgRequest = $req; |
||
436 | |||
437 | $status = $ep->attemptSave( $result ); |
||
438 | $wgRequest = $oldRequest; |
||
439 | |||
440 | switch ( $status->value ) { |
||
441 | case EditPage::AS_HOOK_ERROR: |
||
442 | case EditPage::AS_HOOK_ERROR_EXPECTED: |
||
443 | if ( isset( $status->apiHookResult ) ) { |
||
444 | $r = $status->apiHookResult; |
||
445 | $r['result'] = 'Failure'; |
||
446 | $apiResult->addValue( null, $this->getModuleName(), $r ); |
||
447 | return; |
||
448 | } else { |
||
449 | $this->dieUsageMsg( 'hookaborted' ); |
||
450 | } |
||
451 | |||
452 | case EditPage::AS_PARSE_ERROR: |
||
0 ignored issues
–
show
|
|||
453 | $this->dieUsage( $status->getMessage(), 'parseerror' ); |
||
454 | |||
455 | case EditPage::AS_IMAGE_REDIRECT_ANON: |
||
456 | $this->dieUsageMsg( 'noimageredirect-anon' ); |
||
457 | |||
458 | case EditPage::AS_IMAGE_REDIRECT_LOGGED: |
||
459 | $this->dieUsageMsg( 'noimageredirect-logged' ); |
||
460 | |||
461 | case EditPage::AS_SPAM_ERROR: |
||
462 | $this->dieUsageMsg( [ 'spamdetected', $result['spam'] ] ); |
||
463 | |||
464 | case EditPage::AS_BLOCKED_PAGE_FOR_USER: |
||
465 | $this->dieUsage( |
||
466 | 'You have been blocked from editing', |
||
467 | 'blocked', |
||
468 | 0, |
||
469 | [ 'blockinfo' => ApiQueryUserInfo::getBlockInfo( $user->getBlock() ) ] |
||
470 | ); |
||
471 | |||
472 | case EditPage::AS_MAX_ARTICLE_SIZE_EXCEEDED: |
||
473 | case EditPage::AS_CONTENT_TOO_BIG: |
||
474 | $this->dieUsageMsg( [ 'contenttoobig', $this->getConfig()->get( 'MaxArticleSize' ) ] ); |
||
475 | |||
476 | case EditPage::AS_READ_ONLY_PAGE_ANON: |
||
477 | $this->dieUsageMsg( 'noedit-anon' ); |
||
478 | |||
479 | case EditPage::AS_READ_ONLY_PAGE_LOGGED: |
||
480 | $this->dieUsageMsg( 'noedit' ); |
||
481 | |||
482 | case EditPage::AS_READ_ONLY_PAGE: |
||
483 | $this->dieReadOnly(); |
||
484 | |||
485 | case EditPage::AS_RATE_LIMITED: |
||
486 | $this->dieUsageMsg( 'actionthrottledtext' ); |
||
487 | |||
488 | case EditPage::AS_ARTICLE_WAS_DELETED: |
||
489 | $this->dieUsageMsg( 'wasdeleted' ); |
||
490 | |||
491 | case EditPage::AS_NO_CREATE_PERMISSION: |
||
492 | $this->dieUsageMsg( 'nocreate-loggedin' ); |
||
493 | |||
494 | case EditPage::AS_NO_CHANGE_CONTENT_MODEL: |
||
495 | $this->dieUsageMsg( 'cantchangecontentmodel' ); |
||
496 | |||
497 | case EditPage::AS_BLANK_ARTICLE: |
||
498 | $this->dieUsageMsg( 'blankpage' ); |
||
499 | |||
500 | case EditPage::AS_CONFLICT_DETECTED: |
||
501 | $this->dieUsageMsg( 'editconflict' ); |
||
502 | |||
503 | case EditPage::AS_TEXTBOX_EMPTY: |
||
504 | $this->dieUsageMsg( 'emptynewsection' ); |
||
505 | |||
506 | case EditPage::AS_CHANGE_TAG_ERROR: |
||
507 | $this->dieStatus( $status ); |
||
508 | |||
509 | case EditPage::AS_SUCCESS_NEW_ARTICLE: |
||
510 | $r['new'] = true; |
||
511 | // fall-through |
||
512 | |||
513 | case EditPage::AS_SUCCESS_UPDATE: |
||
514 | $r['result'] = 'Success'; |
||
515 | $r['pageid'] = intval( $titleObj->getArticleID() ); |
||
516 | $r['title'] = $titleObj->getPrefixedText(); |
||
517 | $r['contentmodel'] = $articleObject->getContentModel(); |
||
518 | $newRevId = $articleObject->getLatest(); |
||
519 | if ( $newRevId == $oldRevId ) { |
||
520 | $r['nochange'] = true; |
||
521 | } else { |
||
522 | $r['oldrevid'] = intval( $oldRevId ); |
||
523 | $r['newrevid'] = intval( $newRevId ); |
||
524 | $r['newtimestamp'] = wfTimestamp( TS_ISO_8601, |
||
525 | $pageObj->getTimestamp() ); |
||
526 | } |
||
527 | break; |
||
528 | |||
529 | case EditPage::AS_SUMMARY_NEEDED: |
||
530 | // Shouldn't happen since we set wpIgnoreBlankSummary, but just in case |
||
531 | $this->dieUsageMsg( 'summaryrequired' ); |
||
532 | |||
533 | case EditPage::AS_END: |
||
534 | default: |
||
535 | // $status came from WikiPage::doEditContent() |
||
536 | $errors = $status->getErrorsArray(); |
||
537 | $this->dieUsageMsg( $errors[0] ); // TODO: Add new errors to message map |
||
538 | break; |
||
539 | } |
||
540 | $apiResult->addValue( null, $this->getModuleName(), $r ); |
||
541 | } |
||
542 | |||
543 | public function mustBePosted() { |
||
544 | return true; |
||
545 | } |
||
546 | |||
547 | public function isWriteMode() { |
||
548 | return true; |
||
549 | } |
||
550 | |||
551 | public function getAllowedParams() { |
||
552 | return [ |
||
553 | 'title' => [ |
||
554 | ApiBase::PARAM_TYPE => 'string', |
||
555 | ], |
||
556 | 'pageid' => [ |
||
557 | ApiBase::PARAM_TYPE => 'integer', |
||
558 | ], |
||
559 | 'section' => null, |
||
560 | 'sectiontitle' => [ |
||
561 | ApiBase::PARAM_TYPE => 'string', |
||
562 | ], |
||
563 | 'text' => [ |
||
564 | ApiBase::PARAM_TYPE => 'text', |
||
565 | ], |
||
566 | 'summary' => null, |
||
567 | 'tags' => [ |
||
568 | ApiBase::PARAM_TYPE => 'tags', |
||
569 | ApiBase::PARAM_ISMULTI => true, |
||
570 | ], |
||
571 | 'minor' => false, |
||
572 | 'notminor' => false, |
||
573 | 'bot' => false, |
||
574 | 'basetimestamp' => [ |
||
575 | ApiBase::PARAM_TYPE => 'timestamp', |
||
576 | ], |
||
577 | 'starttimestamp' => [ |
||
578 | ApiBase::PARAM_TYPE => 'timestamp', |
||
579 | ], |
||
580 | 'recreate' => false, |
||
581 | 'createonly' => false, |
||
582 | 'nocreate' => false, |
||
583 | 'watch' => [ |
||
584 | ApiBase::PARAM_DFLT => false, |
||
585 | ApiBase::PARAM_DEPRECATED => true, |
||
586 | ], |
||
587 | 'unwatch' => [ |
||
588 | ApiBase::PARAM_DFLT => false, |
||
589 | ApiBase::PARAM_DEPRECATED => true, |
||
590 | ], |
||
591 | 'watchlist' => [ |
||
592 | ApiBase::PARAM_DFLT => 'preferences', |
||
593 | ApiBase::PARAM_TYPE => [ |
||
594 | 'watch', |
||
595 | 'unwatch', |
||
596 | 'preferences', |
||
597 | 'nochange' |
||
598 | ], |
||
599 | ], |
||
600 | 'md5' => null, |
||
601 | 'prependtext' => [ |
||
602 | ApiBase::PARAM_TYPE => 'text', |
||
603 | ], |
||
604 | 'appendtext' => [ |
||
605 | ApiBase::PARAM_TYPE => 'text', |
||
606 | ], |
||
607 | 'undo' => [ |
||
608 | ApiBase::PARAM_TYPE => 'integer' |
||
609 | ], |
||
610 | 'undoafter' => [ |
||
611 | ApiBase::PARAM_TYPE => 'integer' |
||
612 | ], |
||
613 | 'redirect' => [ |
||
614 | ApiBase::PARAM_TYPE => 'boolean', |
||
615 | ApiBase::PARAM_DFLT => false, |
||
616 | ], |
||
617 | 'contentformat' => [ |
||
618 | ApiBase::PARAM_TYPE => ContentHandler::getAllContentFormats(), |
||
619 | ], |
||
620 | 'contentmodel' => [ |
||
621 | ApiBase::PARAM_TYPE => ContentHandler::getContentModels(), |
||
622 | ], |
||
623 | 'token' => [ |
||
624 | // Standard definition automatically inserted |
||
625 | ApiBase::PARAM_HELP_MSG_APPEND => [ 'apihelp-edit-param-token' ], |
||
626 | ], |
||
627 | ]; |
||
628 | } |
||
629 | |||
630 | public function needsToken() { |
||
631 | return 'csrf'; |
||
632 | } |
||
633 | |||
634 | protected function getExamplesMessages() { |
||
635 | return [ |
||
636 | 'action=edit&title=Test&summary=test%20summary&' . |
||
637 | 'text=article%20content&basetimestamp=2007-08-24T12:34:54Z&token=123ABC' |
||
638 | => 'apihelp-edit-example-edit', |
||
639 | 'action=edit&title=Test&summary=NOTOC&minor=&' . |
||
640 | 'prependtext=__NOTOC__%0A&basetimestamp=2007-08-24T12:34:54Z&token=123ABC' |
||
641 | => 'apihelp-edit-example-prepend', |
||
642 | 'action=edit&title=Test&undo=13585&undoafter=13579&' . |
||
643 | 'basetimestamp=2007-08-24T12:34:54Z&token=123ABC' |
||
644 | => 'apihelp-edit-example-undo', |
||
645 | ]; |
||
646 | } |
||
647 | |||
648 | public function getHelpUrls() { |
||
649 | return 'https://www.mediawiki.org/wiki/API:Edit'; |
||
650 | } |
||
651 | } |
||
652 |
Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code: