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