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