MediaWiki
REL1_22
|
00001 <?php 00034 class ApiEditPage extends ApiBase { 00035 00036 public function execute() { 00037 $user = $this->getUser(); 00038 $params = $this->extractRequestParams(); 00039 00040 if ( is_null( $params['text'] ) && is_null( $params['appendtext'] ) && 00041 is_null( $params['prependtext'] ) && 00042 $params['undo'] == 0 ) 00043 { 00044 $this->dieUsageMsg( 'missingtext' ); 00045 } 00046 00047 $pageObj = $this->getTitleOrPageId( $params ); 00048 $titleObj = $pageObj->getTitle(); 00049 $apiResult = $this->getResult(); 00050 00051 if ( $params['redirect'] ) { 00052 if ( $titleObj->isRedirect() ) { 00053 $oldTitle = $titleObj; 00054 00055 $titles = Revision::newFromTitle( $oldTitle, false, Revision::READ_LATEST ) 00056 ->getContent( Revision::FOR_THIS_USER, $user ) 00057 ->getRedirectChain(); 00058 // array_shift( $titles ); 00059 00060 $redirValues = array(); 00061 00063 foreach ( $titles as $id => $newTitle ) { 00064 00065 if ( !isset( $titles[$id - 1] ) ) { 00066 $titles[$id - 1] = $oldTitle; 00067 } 00068 00069 $redirValues[] = array( 00070 'from' => $titles[$id - 1]->getPrefixedText(), 00071 'to' => $newTitle->getPrefixedText() 00072 ); 00073 00074 $titleObj = $newTitle; 00075 } 00076 00077 $apiResult->setIndexedTagName( $redirValues, 'r' ); 00078 $apiResult->addValue( null, 'redirects', $redirValues ); 00079 00080 // Since the page changed, update $pageObj 00081 $pageObj = WikiPage::factory( $titleObj ); 00082 } 00083 } 00084 00085 if ( !isset( $params['contentmodel'] ) || $params['contentmodel'] == '' ) { 00086 $contentHandler = $pageObj->getContentHandler(); 00087 } else { 00088 $contentHandler = ContentHandler::getForModelID( $params['contentmodel'] ); 00089 } 00090 00091 // @todo ask handler whether direct editing is supported at all! make allowFlatEdit() method or some such 00092 00093 if ( !isset( $params['contentformat'] ) || $params['contentformat'] == '' ) { 00094 $params['contentformat'] = $contentHandler->getDefaultFormat(); 00095 } 00096 00097 $contentFormat = $params['contentformat']; 00098 00099 if ( !$contentHandler->isSupportedFormat( $contentFormat ) ) { 00100 $name = $titleObj->getPrefixedDBkey(); 00101 $model = $contentHandler->getModelID(); 00102 00103 $this->dieUsage( "The requested format $contentFormat is not supported for content model " . 00104 " $model used by $name", 'badformat' ); 00105 } 00106 00107 if ( $params['createonly'] && $titleObj->exists() ) { 00108 $this->dieUsageMsg( 'createonly-exists' ); 00109 } 00110 if ( $params['nocreate'] && !$titleObj->exists() ) { 00111 $this->dieUsageMsg( 'nocreate-missing' ); 00112 } 00113 00114 // Now let's check whether we're even allowed to do this 00115 $errors = $titleObj->getUserPermissionsErrors( 'edit', $user ); 00116 if ( !$titleObj->exists() ) { 00117 $errors = array_merge( $errors, $titleObj->getUserPermissionsErrors( 'create', $user ) ); 00118 } 00119 if ( count( $errors ) ) { 00120 $this->dieUsageMsg( $errors[0] ); 00121 } 00122 00123 $toMD5 = $params['text']; 00124 if ( !is_null( $params['appendtext'] ) || !is_null( $params['prependtext'] ) ) 00125 { 00126 $content = $pageObj->getContent(); 00127 00128 if ( !$content ) { 00129 if ( $titleObj->getNamespace() == NS_MEDIAWIKI ) { 00130 # If this is a MediaWiki:x message, then load the messages 00131 # and return the message value for x. 00132 $text = $titleObj->getDefaultMessageText(); 00133 if ( $text === false ) { 00134 $text = ''; 00135 } 00136 00137 try { 00138 $content = ContentHandler::makeContent( $text, $this->getTitle() ); 00139 } catch ( MWContentSerializationException $ex ) { 00140 $this->dieUsage( $ex->getMessage(), 'parseerror' ); 00141 return; 00142 } 00143 } else { 00144 # Otherwise, make a new empty content. 00145 $content = $contentHandler->makeEmptyContent(); 00146 } 00147 } 00148 00149 // @todo Add support for appending/prepending to the Content interface 00150 00151 if ( !( $content instanceof TextContent ) ) { 00152 $mode = $contentHandler->getModelID(); 00153 $this->dieUsage( "Can't append to pages using content model $mode", 'appendnotsupported' ); 00154 } 00155 00156 if ( !is_null( $params['section'] ) ) { 00157 if ( !$contentHandler->supportsSections() ) { 00158 $modelName = $contentHandler->getModelID(); 00159 $this->dieUsage( "Sections are not supported for this content model: $modelName.", 'sectionsnotsupported' ); 00160 } 00161 00162 if ( $params['section'] == 'new' ) { 00163 // DWIM if they're trying to prepend/append to a new section. 00164 $content = null; 00165 } else { 00166 // Process the content for section edits 00167 $section = intval( $params['section'] ); 00168 $content = $content->getSection( $section ); 00169 00170 if ( !$content ) { 00171 $this->dieUsage( "There is no section {$section}.", 'nosuchsection' ); 00172 } 00173 } 00174 } 00175 00176 if ( !$content ) { 00177 $text = ''; 00178 } else { 00179 $text = $content->serialize( $contentFormat ); 00180 } 00181 00182 $params['text'] = $params['prependtext'] . $text . $params['appendtext']; 00183 $toMD5 = $params['prependtext'] . $params['appendtext']; 00184 } 00185 00186 if ( $params['undo'] > 0 ) { 00187 if ( $params['undoafter'] > 0 ) { 00188 if ( $params['undo'] < $params['undoafter'] ) { 00189 list( $params['undo'], $params['undoafter'] ) = 00190 array( $params['undoafter'], $params['undo'] ); 00191 } 00192 $undoafterRev = Revision::newFromID( $params['undoafter'] ); 00193 } 00194 $undoRev = Revision::newFromID( $params['undo'] ); 00195 if ( is_null( $undoRev ) || $undoRev->isDeleted( Revision::DELETED_TEXT ) ) { 00196 $this->dieUsageMsg( array( 'nosuchrevid', $params['undo'] ) ); 00197 } 00198 00199 if ( $params['undoafter'] == 0 ) { 00200 $undoafterRev = $undoRev->getPrevious(); 00201 } 00202 if ( is_null( $undoafterRev ) || $undoafterRev->isDeleted( Revision::DELETED_TEXT ) ) { 00203 $this->dieUsageMsg( array( 'nosuchrevid', $params['undoafter'] ) ); 00204 } 00205 00206 if ( $undoRev->getPage() != $pageObj->getID() ) { 00207 $this->dieUsageMsg( array( 'revwrongpage', $undoRev->getID(), $titleObj->getPrefixedText() ) ); 00208 } 00209 if ( $undoafterRev->getPage() != $pageObj->getID() ) { 00210 $this->dieUsageMsg( array( 'revwrongpage', $undoafterRev->getID(), $titleObj->getPrefixedText() ) ); 00211 } 00212 00213 $newContent = $contentHandler->getUndoContent( $pageObj->getRevision(), $undoRev, $undoafterRev ); 00214 00215 if ( !$newContent ) { 00216 $this->dieUsageMsg( 'undo-failure' ); 00217 } 00218 00219 $params['text'] = $newContent->serialize( $params['contentformat'] ); 00220 00221 // If no summary was given and we only undid one rev, 00222 // use an autosummary 00223 if ( is_null( $params['summary'] ) && $titleObj->getNextRevisionID( $undoafterRev->getID() ) == $params['undo'] ) { 00224 $params['summary'] = wfMessage( 'undo-summary', $params['undo'], $undoRev->getUserText() )->inContentLanguage()->text(); 00225 } 00226 } 00227 00228 // See if the MD5 hash checks out 00229 if ( !is_null( $params['md5'] ) && md5( $toMD5 ) !== $params['md5'] ) { 00230 $this->dieUsageMsg( 'hashcheckfailed' ); 00231 } 00232 00233 // EditPage wants to parse its stuff from a WebRequest 00234 // That interface kind of sucks, but it's workable 00235 $requestArray = array( 00236 'wpTextbox1' => $params['text'], 00237 'format' => $contentFormat, 00238 'model' => $contentHandler->getModelID(), 00239 'wpEditToken' => $params['token'], 00240 'wpIgnoreBlankSummary' => '' 00241 ); 00242 00243 if ( !is_null( $params['summary'] ) ) { 00244 $requestArray['wpSummary'] = $params['summary']; 00245 } 00246 00247 if ( !is_null( $params['sectiontitle'] ) ) { 00248 $requestArray['wpSectionTitle'] = $params['sectiontitle']; 00249 } 00250 00251 // TODO: Pass along information from 'undoafter' as well 00252 if ( $params['undo'] > 0 ) { 00253 $requestArray['wpUndidRevision'] = $params['undo']; 00254 } 00255 00256 // Watch out for basetimestamp == '' 00257 // wfTimestamp() treats it as NOW, almost certainly causing an edit conflict 00258 if ( !is_null( $params['basetimestamp'] ) && $params['basetimestamp'] != '' ) { 00259 $requestArray['wpEdittime'] = wfTimestamp( TS_MW, $params['basetimestamp'] ); 00260 } else { 00261 $requestArray['wpEdittime'] = $pageObj->getTimestamp(); 00262 } 00263 00264 if ( !is_null( $params['starttimestamp'] ) && $params['starttimestamp'] != '' ) { 00265 $requestArray['wpStarttime'] = wfTimestamp( TS_MW, $params['starttimestamp'] ); 00266 } else { 00267 $requestArray['wpStarttime'] = wfTimestampNow(); // Fake wpStartime 00268 } 00269 00270 if ( $params['minor'] || ( !$params['notminor'] && $user->getOption( 'minordefault' ) ) ) { 00271 $requestArray['wpMinoredit'] = ''; 00272 } 00273 00274 if ( $params['recreate'] ) { 00275 $requestArray['wpRecreate'] = ''; 00276 } 00277 00278 if ( !is_null( $params['section'] ) ) { 00279 $section = intval( $params['section'] ); 00280 if ( $section == 0 && $params['section'] != '0' && $params['section'] != 'new' ) { 00281 $this->dieUsage( "The section parameter must be set to an integer or 'new'", "invalidsection" ); 00282 } 00283 $content = $pageObj->getContent(); 00284 if ( $section !== 0 && ( !$content || !$content->getSection( $section ) ) ) { 00285 $this->dieUsage( "There is no section {$section}.", 'nosuchsection' ); 00286 } 00287 $requestArray['wpSection'] = $params['section']; 00288 } else { 00289 $requestArray['wpSection'] = ''; 00290 } 00291 00292 $watch = $this->getWatchlistValue( $params['watchlist'], $titleObj ); 00293 00294 // Deprecated parameters 00295 if ( $params['watch'] ) { 00296 $watch = true; 00297 } elseif ( $params['unwatch'] ) { 00298 $watch = false; 00299 } 00300 00301 if ( $watch ) { 00302 $requestArray['wpWatchthis'] = ''; 00303 } 00304 00305 // Pass through anything else we might have been given, to support extensions 00306 // This is kind of a hack but it's the best we can do to make extensions work 00307 $requestArray += $this->getRequest()->getValues(); 00308 00309 global $wgTitle, $wgRequest; 00310 00311 $req = new DerivativeRequest( $this->getRequest(), $requestArray, true ); 00312 00313 // Some functions depend on $wgTitle == $ep->mTitle 00314 // TODO: Make them not or check if they still do 00315 $wgTitle = $titleObj; 00316 00317 $articleContext = new RequestContext; 00318 $articleContext->setRequest( $req ); 00319 $articleContext->setWikiPage( $pageObj ); 00320 $articleContext->setUser( $this->getUser() ); 00321 00323 $articleObject = Article::newFromWikiPage( $pageObj, $articleContext ); 00324 00325 $ep = new EditPage( $articleObject ); 00326 00327 // allow editing of non-textual content. 00328 $ep->allowNonTextContent = true; 00329 00330 $ep->setContextTitle( $titleObj ); 00331 $ep->importFormData( $req ); 00332 $content = $ep->textbox1; 00333 00334 // The following is needed to give the hook the full content of the 00335 // new revision rather than just the current section. (Bug 52077) 00336 if ( !is_null( $params['section'] ) && $contentHandler->supportsSections() && $titleObj->exists() ) { 00337 00338 $sectionTitle = ''; 00339 // If sectiontitle is set, use it, otherwise use the summary as the section title (for 00340 // backwards compatibility with old forms/bots). 00341 if ( $ep->sectiontitle !== '' ) { 00342 $sectionTitle = $ep->sectiontitle; 00343 } else { 00344 $sectionTitle = $ep->summary; 00345 } 00346 00347 $contentObj = $contentHandler->unserializeContent( $content, $contentFormat ); 00348 00349 $fullContentObj = $articleObject->replaceSectionContent( $params['section'], $contentObj, $sectionTitle ); 00350 if ( $fullContentObj ) { 00351 $content = $fullContentObj->serialize( $contentFormat ); 00352 } else { 00353 // This most likely means we have an edit conflict which means that the edit 00354 // wont succeed anyway. 00355 $this->dieUsageMsg( 'editconflict' ); 00356 } 00357 } 00358 00359 // Run hooks 00360 // Handle APIEditBeforeSave parameters 00361 $r = array(); 00362 if ( !wfRunHooks( 'APIEditBeforeSave', array( $ep, $content, &$r ) ) ) { 00363 if ( count( $r ) ) { 00364 $r['result'] = 'Failure'; 00365 $apiResult->addValue( null, $this->getModuleName(), $r ); 00366 return; 00367 } else { 00368 $this->dieUsageMsg( 'hookaborted' ); 00369 } 00370 } 00371 00372 // Do the actual save 00373 $oldRevId = $articleObject->getRevIdFetched(); 00374 $result = null; 00375 // Fake $wgRequest for some hooks inside EditPage 00376 // @todo FIXME: This interface SUCKS 00377 $oldRequest = $wgRequest; 00378 $wgRequest = $req; 00379 00380 $status = $ep->internalAttemptSave( $result, $user->isAllowed( 'bot' ) && $params['bot'] ); 00381 $wgRequest = $oldRequest; 00382 global $wgMaxArticleSize; 00383 00384 switch ( $status->value ) { 00385 case EditPage::AS_HOOK_ERROR: 00386 case EditPage::AS_HOOK_ERROR_EXPECTED: 00387 $this->dieUsageMsg( 'hookaborted' ); 00388 00389 case EditPage::AS_PARSE_ERROR: 00390 $this->dieUsage( $status->getMessage(), 'parseerror' ); 00391 00392 case EditPage::AS_IMAGE_REDIRECT_ANON: 00393 $this->dieUsageMsg( 'noimageredirect-anon' ); 00394 00395 case EditPage::AS_IMAGE_REDIRECT_LOGGED: 00396 $this->dieUsageMsg( 'noimageredirect-logged' ); 00397 00398 case EditPage::AS_SPAM_ERROR: 00399 $this->dieUsageMsg( array( 'spamdetected', $result['spam'] ) ); 00400 00401 case EditPage::AS_BLOCKED_PAGE_FOR_USER: 00402 $this->dieUsageMsg( 'blockedtext' ); 00403 00404 case EditPage::AS_MAX_ARTICLE_SIZE_EXCEEDED: 00405 case EditPage::AS_CONTENT_TOO_BIG: 00406 $this->dieUsageMsg( array( 'contenttoobig', $wgMaxArticleSize ) ); 00407 00408 case EditPage::AS_READ_ONLY_PAGE_ANON: 00409 $this->dieUsageMsg( 'noedit-anon' ); 00410 00411 case EditPage::AS_READ_ONLY_PAGE_LOGGED: 00412 $this->dieUsageMsg( 'noedit' ); 00413 00414 case EditPage::AS_READ_ONLY_PAGE: 00415 $this->dieReadOnly(); 00416 00417 case EditPage::AS_RATE_LIMITED: 00418 $this->dieUsageMsg( 'actionthrottledtext' ); 00419 00420 case EditPage::AS_ARTICLE_WAS_DELETED: 00421 $this->dieUsageMsg( 'wasdeleted' ); 00422 00423 case EditPage::AS_NO_CREATE_PERMISSION: 00424 $this->dieUsageMsg( 'nocreate-loggedin' ); 00425 00426 case EditPage::AS_BLANK_ARTICLE: 00427 $this->dieUsageMsg( 'blankpage' ); 00428 00429 case EditPage::AS_CONFLICT_DETECTED: 00430 $this->dieUsageMsg( 'editconflict' ); 00431 00432 // case EditPage::AS_SUMMARY_NEEDED: Can't happen since we set wpIgnoreBlankSummary 00433 case EditPage::AS_TEXTBOX_EMPTY: 00434 $this->dieUsageMsg( 'emptynewsection' ); 00435 00436 case EditPage::AS_SUCCESS_NEW_ARTICLE: 00437 $r['new'] = ''; 00438 // fall-through 00439 00440 case EditPage::AS_SUCCESS_UPDATE: 00441 $r['result'] = 'Success'; 00442 $r['pageid'] = intval( $titleObj->getArticleID() ); 00443 $r['title'] = $titleObj->getPrefixedText(); 00444 $r['contentmodel'] = $titleObj->getContentModel(); 00445 $newRevId = $articleObject->getLatest(); 00446 if ( $newRevId == $oldRevId ) { 00447 $r['nochange'] = ''; 00448 } else { 00449 $r['oldrevid'] = intval( $oldRevId ); 00450 $r['newrevid'] = intval( $newRevId ); 00451 $r['newtimestamp'] = wfTimestamp( TS_ISO_8601, 00452 $pageObj->getTimestamp() ); 00453 } 00454 break; 00455 00456 case EditPage::AS_SUMMARY_NEEDED: 00457 $this->dieUsageMsg( 'summaryrequired' ); 00458 00459 case EditPage::AS_END: 00460 default: 00461 // $status came from WikiPage::doEdit() 00462 $errors = $status->getErrorsArray(); 00463 $this->dieUsageMsg( $errors[0] ); // TODO: Add new errors to message map 00464 break; 00465 } 00466 $apiResult->addValue( null, $this->getModuleName(), $r ); 00467 } 00468 00469 public function mustBePosted() { 00470 return true; 00471 } 00472 00473 public function isWriteMode() { 00474 return true; 00475 } 00476 00477 public function getDescription() { 00478 return 'Create and edit pages.'; 00479 } 00480 00481 public function getPossibleErrors() { 00482 global $wgMaxArticleSize; 00483 00484 return array_merge( parent::getPossibleErrors(), 00485 $this->getTitleOrPageIdErrorMessage(), 00486 array( 00487 array( 'missingtext' ), 00488 array( 'createonly-exists' ), 00489 array( 'nocreate-missing' ), 00490 array( 'nosuchrevid', 'undo' ), 00491 array( 'nosuchrevid', 'undoafter' ), 00492 array( 'revwrongpage', 'id', 'text' ), 00493 array( 'undo-failure' ), 00494 array( 'hashcheckfailed' ), 00495 array( 'hookaborted' ), 00496 array( 'code' => 'parseerror', 'info' => 'Failed to parse the given text.' ), 00497 array( 'noimageredirect-anon' ), 00498 array( 'noimageredirect-logged' ), 00499 array( 'spamdetected', 'spam' ), 00500 array( 'summaryrequired' ), 00501 array( 'blockedtext' ), 00502 array( 'contenttoobig', $wgMaxArticleSize ), 00503 array( 'noedit-anon' ), 00504 array( 'noedit' ), 00505 array( 'actionthrottledtext' ), 00506 array( 'wasdeleted' ), 00507 array( 'nocreate-loggedin' ), 00508 array( 'blankpage' ), 00509 array( 'editconflict' ), 00510 array( 'emptynewsection' ), 00511 array( 'unknownerror', 'retval' ), 00512 array( 'code' => 'nosuchsection', 'info' => 'There is no section section.' ), 00513 array( 'code' => 'invalidsection', 'info' => 'The section parameter must be set to an integer or \'new\'' ), 00514 array( 'code' => 'sectionsnotsupported', 'info' => 'Sections are not supported for this type of page.' ), 00515 array( 'code' => 'editnotsupported', 'info' => 'Editing of this type of page is not supported using ' 00516 . 'the text based edit API.' ), 00517 array( 'code' => 'appendnotsupported', 'info' => 'This type of page can not be edited by appending ' 00518 . 'or prepending text.' ), 00519 array( 'code' => 'badformat', 'info' => 'The requested serialization format can not be applied to ' 00520 . 'the page\'s content model' ), 00521 array( 'customcssprotected' ), 00522 array( 'customjsprotected' ), 00523 ) 00524 ); 00525 } 00526 00527 public function getAllowedParams() { 00528 return array( 00529 'title' => array( 00530 ApiBase::PARAM_TYPE => 'string', 00531 ), 00532 'pageid' => array( 00533 ApiBase::PARAM_TYPE => 'integer', 00534 ), 00535 'section' => null, 00536 'sectiontitle' => array( 00537 ApiBase::PARAM_TYPE => 'string', 00538 ), 00539 'text' => null, 00540 'token' => array( 00541 ApiBase::PARAM_TYPE => 'string', 00542 ApiBase::PARAM_REQUIRED => true 00543 ), 00544 'summary' => null, 00545 'minor' => false, 00546 'notminor' => false, 00547 'bot' => false, 00548 'basetimestamp' => null, 00549 'starttimestamp' => null, 00550 'recreate' => false, 00551 'createonly' => false, 00552 'nocreate' => false, 00553 'watch' => array( 00554 ApiBase::PARAM_DFLT => false, 00555 ApiBase::PARAM_DEPRECATED => true, 00556 ), 00557 'unwatch' => array( 00558 ApiBase::PARAM_DFLT => false, 00559 ApiBase::PARAM_DEPRECATED => true, 00560 ), 00561 'watchlist' => array( 00562 ApiBase::PARAM_DFLT => 'preferences', 00563 ApiBase::PARAM_TYPE => array( 00564 'watch', 00565 'unwatch', 00566 'preferences', 00567 'nochange' 00568 ), 00569 ), 00570 'md5' => null, 00571 'prependtext' => null, 00572 'appendtext' => null, 00573 'undo' => array( 00574 ApiBase::PARAM_TYPE => 'integer' 00575 ), 00576 'undoafter' => array( 00577 ApiBase::PARAM_TYPE => 'integer' 00578 ), 00579 'redirect' => array( 00580 ApiBase::PARAM_TYPE => 'boolean', 00581 ApiBase::PARAM_DFLT => false, 00582 ), 00583 'contentformat' => array( 00584 ApiBase::PARAM_TYPE => ContentHandler::getAllContentFormats(), 00585 ), 00586 'contentmodel' => array( 00587 ApiBase::PARAM_TYPE => ContentHandler::getContentModels(), 00588 ) 00589 ); 00590 } 00591 00592 public function getParamDescription() { 00593 $p = $this->getModulePrefix(); 00594 return array( 00595 'title' => "Title of the page you want to edit. Cannot be used together with {$p}pageid", 00596 'pageid' => "Page ID of the page you want to edit. Cannot be used together with {$p}title", 00597 'section' => 'Section number. 0 for the top section, \'new\' for a new section', 00598 'sectiontitle' => 'The title for a new section', 00599 'text' => 'Page content', 00600 'token' => array( 'Edit token. You can get one of these through prop=info.', 00601 "The token should always be sent as the last parameter, or at least, after the {$p}text parameter" 00602 ), 00603 'summary' => "Edit summary. Also section title when {$p}section=new and {$p}sectiontitle is not set", 00604 'minor' => 'Minor edit', 00605 'notminor' => 'Non-minor edit', 00606 'bot' => 'Mark this edit as bot', 00607 'basetimestamp' => array( 'Timestamp of the base revision (obtained through prop=revisions&rvprop=timestamp).', 00608 'Used to detect edit conflicts; leave unset to ignore conflicts' 00609 ), 00610 'starttimestamp' => array( 'Timestamp when you obtained the edit token.', 00611 'Used to detect edit conflicts; leave unset to ignore conflicts' 00612 ), 00613 'recreate' => 'Override any errors about the article having been deleted in the meantime', 00614 'createonly' => 'Don\'t edit the page if it exists already', 00615 'nocreate' => 'Throw an error if the page doesn\'t exist', 00616 'watch' => 'Add the page to your watchlist', 00617 'unwatch' => 'Remove the page from your watchlist', 00618 'watchlist' => 'Unconditionally add or remove the page from your watchlist, use preferences or do not change watch', 00619 'md5' => array( "The MD5 hash of the {$p}text parameter, or the {$p}prependtext and {$p}appendtext parameters concatenated.", 00620 'If set, the edit won\'t be done unless the hash is correct' ), 00621 'prependtext' => "Add this text to the beginning of the page. Overrides {$p}text", 00622 'appendtext' => array( "Add this text to the end of the page. Overrides {$p}text.", 00623 "Use {$p}section=new to append a new section" ), 00624 'undo' => "Undo this revision. Overrides {$p}text, {$p}prependtext and {$p}appendtext", 00625 'undoafter' => 'Undo all revisions from undo to this one. If not set, just undo one revision', 00626 'redirect' => 'Automatically resolve redirects', 00627 'contentformat' => 'Content serialization format used for the input text', 00628 'contentmodel' => 'Content model of the new content', 00629 ); 00630 } 00631 00632 public function getResultProperties() { 00633 return array( 00634 '' => array( 00635 'new' => 'boolean', 00636 'result' => array( 00637 ApiBase::PROP_TYPE => array( 00638 'Success', 00639 'Failure' 00640 ), 00641 ), 00642 'pageid' => array( 00643 ApiBase::PROP_TYPE => 'integer', 00644 ApiBase::PROP_NULLABLE => true 00645 ), 00646 'title' => array( 00647 ApiBase::PROP_TYPE => 'string', 00648 ApiBase::PROP_NULLABLE => true 00649 ), 00650 'nochange' => 'boolean', 00651 'oldrevid' => array( 00652 ApiBase::PROP_TYPE => 'integer', 00653 ApiBase::PROP_NULLABLE => true 00654 ), 00655 'newrevid' => array( 00656 ApiBase::PROP_TYPE => 'integer', 00657 ApiBase::PROP_NULLABLE => true 00658 ), 00659 'newtimestamp' => array( 00660 ApiBase::PROP_TYPE => 'string', 00661 ApiBase::PROP_NULLABLE => true 00662 ) 00663 ) 00664 ); 00665 } 00666 00667 public function needsToken() { 00668 return true; 00669 } 00670 00671 public function getTokenSalt() { 00672 return ''; 00673 } 00674 00675 public function getExamples() { 00676 return array( 00677 'api.php?action=edit&title=Test&summary=test%20summary&text=article%20content&basetimestamp=20070824123454&token=%2B\\' 00678 => 'Edit a page (anonymous user)', 00679 'api.php?action=edit&title=Test&summary=NOTOC&minor=&prependtext=__NOTOC__%0A&basetimestamp=20070824123454&token=%2B\\' 00680 => 'Prepend __NOTOC__ to a page (anonymous user)', 00681 'api.php?action=edit&title=Test&undo=13585&undoafter=13579&basetimestamp=20070824123454&token=%2B\\' 00682 => 'Undo r13579 through r13585 with autosummary (anonymous user)', 00683 ); 00684 } 00685 00686 public function getHelpUrls() { 00687 return 'https://www.mediawiki.org/wiki/API:Edit'; 00688 } 00689 }