MediaWiki
REL1_21
|
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 // Process the content for section edits 00163 $section = intval( $params['section'] ); 00164 $content = $content->getSection( $section ); 00165 00166 if ( !$content ) { 00167 $this->dieUsage( "There is no section {$section}.", 'nosuchsection' ); 00168 } 00169 } 00170 00171 if ( !$content ) { 00172 $text = ''; 00173 } else { 00174 $text = $content->serialize( $contentFormat ); 00175 } 00176 00177 $params['text'] = $params['prependtext'] . $text . $params['appendtext']; 00178 $toMD5 = $params['prependtext'] . $params['appendtext']; 00179 } 00180 00181 if ( $params['undo'] > 0 ) { 00182 if ( $params['undoafter'] > 0 ) { 00183 if ( $params['undo'] < $params['undoafter'] ) { 00184 list( $params['undo'], $params['undoafter'] ) = 00185 array( $params['undoafter'], $params['undo'] ); 00186 } 00187 $undoafterRev = Revision::newFromID( $params['undoafter'] ); 00188 } 00189 $undoRev = Revision::newFromID( $params['undo'] ); 00190 if ( is_null( $undoRev ) || $undoRev->isDeleted( Revision::DELETED_TEXT ) ) { 00191 $this->dieUsageMsg( array( 'nosuchrevid', $params['undo'] ) ); 00192 } 00193 00194 if ( $params['undoafter'] == 0 ) { 00195 $undoafterRev = $undoRev->getPrevious(); 00196 } 00197 if ( is_null( $undoafterRev ) || $undoafterRev->isDeleted( Revision::DELETED_TEXT ) ) { 00198 $this->dieUsageMsg( array( 'nosuchrevid', $params['undoafter'] ) ); 00199 } 00200 00201 if ( $undoRev->getPage() != $pageObj->getID() ) { 00202 $this->dieUsageMsg( array( 'revwrongpage', $undoRev->getID(), $titleObj->getPrefixedText() ) ); 00203 } 00204 if ( $undoafterRev->getPage() != $pageObj->getID() ) { 00205 $this->dieUsageMsg( array( 'revwrongpage', $undoafterRev->getID(), $titleObj->getPrefixedText() ) ); 00206 } 00207 00208 $newContent = $contentHandler->getUndoContent( $pageObj->getRevision(), $undoRev, $undoafterRev ); 00209 00210 if ( !$newContent ) { 00211 $this->dieUsageMsg( 'undo-failure' ); 00212 } 00213 00214 $params['text'] = $newContent->serialize( $params['contentformat'] ); 00215 00216 // If no summary was given and we only undid one rev, 00217 // use an autosummary 00218 if ( is_null( $params['summary'] ) && $titleObj->getNextRevisionID( $undoafterRev->getID() ) == $params['undo'] ) { 00219 $params['summary'] = wfMessage( 'undo-summary', $params['undo'], $undoRev->getUserText() )->inContentLanguage()->text(); 00220 } 00221 } 00222 00223 // See if the MD5 hash checks out 00224 if ( !is_null( $params['md5'] ) && md5( $toMD5 ) !== $params['md5'] ) { 00225 $this->dieUsageMsg( 'hashcheckfailed' ); 00226 } 00227 00228 // EditPage wants to parse its stuff from a WebRequest 00229 // That interface kind of sucks, but it's workable 00230 $requestArray = array( 00231 'wpTextbox1' => $params['text'], 00232 'format' => $contentFormat, 00233 'model' => $contentHandler->getModelID(), 00234 'wpEditToken' => $params['token'], 00235 'wpIgnoreBlankSummary' => '' 00236 ); 00237 00238 if ( !is_null( $params['summary'] ) ) { 00239 $requestArray['wpSummary'] = $params['summary']; 00240 } 00241 00242 if ( !is_null( $params['sectiontitle'] ) ) { 00243 $requestArray['wpSectionTitle'] = $params['sectiontitle']; 00244 } 00245 00246 // TODO: Pass along information from 'undoafter' as well 00247 if ( $params['undo'] > 0 ) { 00248 $requestArray['wpUndidRevision'] = $params['undo']; 00249 } 00250 00251 // Watch out for basetimestamp == '' 00252 // wfTimestamp() treats it as NOW, almost certainly causing an edit conflict 00253 if ( !is_null( $params['basetimestamp'] ) && $params['basetimestamp'] != '' ) { 00254 $requestArray['wpEdittime'] = wfTimestamp( TS_MW, $params['basetimestamp'] ); 00255 } else { 00256 $requestArray['wpEdittime'] = $pageObj->getTimestamp(); 00257 } 00258 00259 if ( !is_null( $params['starttimestamp'] ) && $params['starttimestamp'] != '' ) { 00260 $requestArray['wpStarttime'] = wfTimestamp( TS_MW, $params['starttimestamp'] ); 00261 } else { 00262 $requestArray['wpStarttime'] = wfTimestampNow(); // Fake wpStartime 00263 } 00264 00265 if ( $params['minor'] || ( !$params['notminor'] && $user->getOption( 'minordefault' ) ) ) { 00266 $requestArray['wpMinoredit'] = ''; 00267 } 00268 00269 if ( $params['recreate'] ) { 00270 $requestArray['wpRecreate'] = ''; 00271 } 00272 00273 if ( !is_null( $params['section'] ) ) { 00274 $section = intval( $params['section'] ); 00275 if ( $section == 0 && $params['section'] != '0' && $params['section'] != 'new' ) { 00276 $this->dieUsage( "The section parameter must be set to an integer or 'new'", "invalidsection" ); 00277 } 00278 $requestArray['wpSection'] = $params['section']; 00279 } else { 00280 $requestArray['wpSection'] = ''; 00281 } 00282 00283 $watch = $this->getWatchlistValue( $params['watchlist'], $titleObj ); 00284 00285 // Deprecated parameters 00286 if ( $params['watch'] ) { 00287 $watch = true; 00288 } elseif ( $params['unwatch'] ) { 00289 $watch = false; 00290 } 00291 00292 if ( $watch ) { 00293 $requestArray['wpWatchthis'] = ''; 00294 } 00295 00296 global $wgTitle, $wgRequest; 00297 00298 $req = new DerivativeRequest( $this->getRequest(), $requestArray, true ); 00299 00300 // Some functions depend on $wgTitle == $ep->mTitle 00301 // TODO: Make them not or check if they still do 00302 $wgTitle = $titleObj; 00303 00304 $articleContext = new RequestContext; 00305 $articleContext->setRequest( $req ); 00306 $articleContext->setWikiPage( $pageObj ); 00307 $articleContext->setUser( $this->getUser() ); 00308 00310 $articleObject = Article::newFromWikiPage( $pageObj, $articleContext ); 00311 00312 $ep = new EditPage( $articleObject ); 00313 00314 // allow editing of non-textual content. 00315 $ep->allowNonTextContent = true; 00316 00317 $ep->setContextTitle( $titleObj ); 00318 $ep->importFormData( $req ); 00319 00320 // Run hooks 00321 // Handle APIEditBeforeSave parameters 00322 $r = array(); 00323 if ( !wfRunHooks( 'APIEditBeforeSave', array( $ep, $ep->textbox1, &$r ) ) ) { 00324 if ( count( $r ) ) { 00325 $r['result'] = 'Failure'; 00326 $apiResult->addValue( null, $this->getModuleName(), $r ); 00327 return; 00328 } else { 00329 $this->dieUsageMsg( 'hookaborted' ); 00330 } 00331 } 00332 00333 // Do the actual save 00334 $oldRevId = $articleObject->getRevIdFetched(); 00335 $result = null; 00336 // Fake $wgRequest for some hooks inside EditPage 00337 // @todo FIXME: This interface SUCKS 00338 $oldRequest = $wgRequest; 00339 $wgRequest = $req; 00340 00341 $status = $ep->internalAttemptSave( $result, $user->isAllowed( 'bot' ) && $params['bot'] ); 00342 $wgRequest = $oldRequest; 00343 global $wgMaxArticleSize; 00344 00345 switch( $status->value ) { 00346 case EditPage::AS_HOOK_ERROR: 00347 case EditPage::AS_HOOK_ERROR_EXPECTED: 00348 $this->dieUsageMsg( 'hookaborted' ); 00349 00350 case EditPage::AS_PARSE_ERROR: 00351 $this->dieUsage( $status->getMessage(), 'parseerror' ); 00352 00353 case EditPage::AS_IMAGE_REDIRECT_ANON: 00354 $this->dieUsageMsg( 'noimageredirect-anon' ); 00355 00356 case EditPage::AS_IMAGE_REDIRECT_LOGGED: 00357 $this->dieUsageMsg( 'noimageredirect-logged' ); 00358 00359 case EditPage::AS_SPAM_ERROR: 00360 $this->dieUsageMsg( array( 'spamdetected', $result['spam'] ) ); 00361 00362 case EditPage::AS_BLOCKED_PAGE_FOR_USER: 00363 $this->dieUsageMsg( 'blockedtext' ); 00364 00365 case EditPage::AS_MAX_ARTICLE_SIZE_EXCEEDED: 00366 case EditPage::AS_CONTENT_TOO_BIG: 00367 $this->dieUsageMsg( array( 'contenttoobig', $wgMaxArticleSize ) ); 00368 00369 case EditPage::AS_READ_ONLY_PAGE_ANON: 00370 $this->dieUsageMsg( 'noedit-anon' ); 00371 00372 case EditPage::AS_READ_ONLY_PAGE_LOGGED: 00373 $this->dieUsageMsg( 'noedit' ); 00374 00375 case EditPage::AS_READ_ONLY_PAGE: 00376 $this->dieReadOnly(); 00377 00378 case EditPage::AS_RATE_LIMITED: 00379 $this->dieUsageMsg( 'actionthrottledtext' ); 00380 00381 case EditPage::AS_ARTICLE_WAS_DELETED: 00382 $this->dieUsageMsg( 'wasdeleted' ); 00383 00384 case EditPage::AS_NO_CREATE_PERMISSION: 00385 $this->dieUsageMsg( 'nocreate-loggedin' ); 00386 00387 case EditPage::AS_BLANK_ARTICLE: 00388 $this->dieUsageMsg( 'blankpage' ); 00389 00390 case EditPage::AS_CONFLICT_DETECTED: 00391 $this->dieUsageMsg( 'editconflict' ); 00392 00393 // case EditPage::AS_SUMMARY_NEEDED: Can't happen since we set wpIgnoreBlankSummary 00394 case EditPage::AS_TEXTBOX_EMPTY: 00395 $this->dieUsageMsg( 'emptynewsection' ); 00396 00397 case EditPage::AS_SUCCESS_NEW_ARTICLE: 00398 $r['new'] = ''; 00399 // fall-through 00400 00401 case EditPage::AS_SUCCESS_UPDATE: 00402 $r['result'] = 'Success'; 00403 $r['pageid'] = intval( $titleObj->getArticleID() ); 00404 $r['title'] = $titleObj->getPrefixedText(); 00405 $r['contentmodel'] = $titleObj->getContentModel(); 00406 $newRevId = $articleObject->getLatest(); 00407 if ( $newRevId == $oldRevId ) { 00408 $r['nochange'] = ''; 00409 } else { 00410 $r['oldrevid'] = intval( $oldRevId ); 00411 $r['newrevid'] = intval( $newRevId ); 00412 $r['newtimestamp'] = wfTimestamp( TS_ISO_8601, 00413 $pageObj->getTimestamp() ); 00414 } 00415 break; 00416 00417 case EditPage::AS_SUMMARY_NEEDED: 00418 $this->dieUsageMsg( 'summaryrequired' ); 00419 00420 case EditPage::AS_END: 00421 default: 00422 // $status came from WikiPage::doEdit() 00423 $errors = $status->getErrorsArray(); 00424 $this->dieUsageMsg( $errors[0] ); // TODO: Add new errors to message map 00425 break; 00426 } 00427 $apiResult->addValue( null, $this->getModuleName(), $r ); 00428 } 00429 00430 public function mustBePosted() { 00431 return true; 00432 } 00433 00434 public function isWriteMode() { 00435 return true; 00436 } 00437 00438 public function getDescription() { 00439 return 'Create and edit pages.'; 00440 } 00441 00442 public function getPossibleErrors() { 00443 global $wgMaxArticleSize; 00444 00445 return array_merge( parent::getPossibleErrors(), 00446 $this->getTitleOrPageIdErrorMessage(), 00447 array( 00448 array( 'missingtext' ), 00449 array( 'createonly-exists' ), 00450 array( 'nocreate-missing' ), 00451 array( 'nosuchrevid', 'undo' ), 00452 array( 'nosuchrevid', 'undoafter' ), 00453 array( 'revwrongpage', 'id', 'text' ), 00454 array( 'undo-failure' ), 00455 array( 'hashcheckfailed' ), 00456 array( 'hookaborted' ), 00457 array( 'code' => 'parseerror', 'info' => 'Failed to parse the given text.' ), 00458 array( 'noimageredirect-anon' ), 00459 array( 'noimageredirect-logged' ), 00460 array( 'spamdetected', 'spam' ), 00461 array( 'summaryrequired' ), 00462 array( 'blockedtext' ), 00463 array( 'contenttoobig', $wgMaxArticleSize ), 00464 array( 'noedit-anon' ), 00465 array( 'noedit' ), 00466 array( 'actionthrottledtext' ), 00467 array( 'wasdeleted' ), 00468 array( 'nocreate-loggedin' ), 00469 array( 'blankpage' ), 00470 array( 'editconflict' ), 00471 array( 'emptynewsection' ), 00472 array( 'unknownerror', 'retval' ), 00473 array( 'code' => 'nosuchsection', 'info' => 'There is no section section.' ), 00474 array( 'code' => 'invalidsection', 'info' => 'The section parameter must be set to an integer or \'new\'' ), 00475 array( 'code' => 'sectionsnotsupported', 'info' => 'Sections are not supported for this type of page.' ), 00476 array( 'code' => 'editnotsupported', 'info' => 'Editing of this type of page is not supported using ' 00477 . 'the text based edit API.' ), 00478 array( 'code' => 'appendnotsupported', 'info' => 'This type of page can not be edited by appending ' 00479 . 'or prepending text.' ), 00480 array( 'code' => 'badformat', 'info' => 'The requested serialization format can not be applied to ' 00481 . 'the page\'s content model' ), 00482 array( 'customcssprotected' ), 00483 array( 'customjsprotected' ), 00484 ) 00485 ); 00486 } 00487 00488 public function getAllowedParams() { 00489 return array( 00490 'title' => array( 00491 ApiBase::PARAM_TYPE => 'string', 00492 ), 00493 'pageid' => array( 00494 ApiBase::PARAM_TYPE => 'integer', 00495 ), 00496 'section' => null, 00497 'sectiontitle' => array( 00498 ApiBase::PARAM_TYPE => 'string', 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 'api.php?action=edit&title=Test&summary=test%20summary&text=article%20content&basetimestamp=20070824123454&token=%2B\\' 00639 => 'Edit a page (anonymous user)', 00640 'api.php?action=edit&title=Test&summary=NOTOC&minor=&prependtext=__NOTOC__%0A&basetimestamp=20070824123454&token=%2B\\' 00641 => 'Prepend __NOTOC__ to a page (anonymous user)', 00642 'api.php?action=edit&title=Test&undo=13585&undoafter=13579&basetimestamp=20070824123454&token=%2B\\' 00643 => 'Undo r13579 through r13585 with autosummary (anonymous user)', 00644 ); 00645 } 00646 00647 public function getHelpUrls() { 00648 return 'https://www.mediawiki.org/wiki/API:Edit'; 00649 } 00650 }