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