Beispiel #1
0
 function importFormData(&$request)
 {
     # These fields need to be checked for encoding.
     # Also remove trailing whitespace, but don't remove _initial_
     # whitespace from the text boxes. This may be significant formatting.
     EditPage::importFormData($request);
     // create the wikiHow wrapper object
     if ($request->wasPosted()) {
         $whow = WikihowArticleEditor::newFromRequest($request);
         $whow->mIsNew = false;
         $this->whow = $whow;
         $this->textbox1 = $this->whow->formatWikiText();
     }
 }
 public function submitFlags(&$params)
 {
     global $wgUser, $webplatformSectionCommentsSMW;
     $aTemp = json_decode($params['flags'], true);
     $aProperties = array();
     foreach ($aTemp as $key => $value) {
         $aTempKey = array();
         if (preg_match('#.*?\\[(.*?)\\]\\[.*?\\]#', $key, $aTempKey) && $value != '1') {
             $aProperties[$aTempKey[1]][] = $value;
         }
     }
     $sbuiltString = '';
     foreach ($aProperties as $key => $value) {
         $sbuiltString .= "\n|" . $key . '=';
         $aTemp = array();
         foreach ($value as $key => $val) {
             $aTemp[] = $val;
         }
         $sbuiltString .= implode(',', $aTemp);
     }
     $oArticle = Article::newFromID($params['pageId']);
     $sContent = $oArticle->fetchContent();
     $sNewContent = preg_replace('#(\\{\\{' . $webplatformSectionCommentsSMW['template'] . ').*?(\\}\\})#s', "\$1{$sbuiltString}\n\$2", $sContent);
     $aData = array('wpTextbox1' => $sNewContent, 'wpSummary' => 'no summary', 'wpStarttime' => 'nostarttime', 'wpEdittime' => 'noedittime', 'wpEditToken' => $wgUser->isLoggedIn() ? $wgUser->editToken() : EDIT_TOKEN_SUFFIX, 'wpSave' => '', 'action' => 'submit');
     $oRequest = new FauxRequest($aData, true);
     $oEditor = new EditPage($oArticle);
     $oEditor->importFormData($oRequest);
     // Try to save the page!
     $aResultDetails = array();
     $oSaveResult = $oEditor->internalAttemptSave($aResultDetails);
     // Return value was made an object in MW 1.19
     if (is_object($oSaveResult)) {
         $sSaveResultCode = $oSaveResult->value;
     } else {
         $sSaveResultCode = $oSaveResult;
     }
     $params['html_response'] = $sSaveResultCode;
 }
 public function execute()
 {
     $user = $this->getUser();
     $params = $this->extractRequestParams();
     $title = Title::newFromText($params['page']);
     if (!$title) {
         $this->dieUsageMsg('invalidtitle', $params['page']);
     }
     $isSafeAction = in_array($params['paction'], self::$SAFE_ACTIONS, true);
     $availableNamespaces = $this->veConfig->get('VisualEditorAvailableNamespaces');
     if (!$isSafeAction && (!isset($availableNamespaces[$title->getNamespace()]) || !$availableNamespaces[$title->getNamespace()])) {
         $this->dieUsage("VisualEditor is not enabled in namespace " . $title->getNamespace(), 'novenamespace');
     }
     $parserParams = array();
     if (isset($params['oldid'])) {
         $parserParams['oldid'] = $params['oldid'];
     }
     $html = $params['html'];
     if (substr($html, 0, 11) === 'rawdeflate,') {
         $deflated = base64_decode(substr($html, 11));
         wfSuppressWarnings();
         $html = gzinflate($deflated);
         wfRestoreWarnings();
         if ($deflated === $html || $html === false) {
             $this->dieUsage("HTML provided is not properly deflated", 'invaliddeflate');
         }
     }
     wfDebugLog('visualeditor', "called on '{$title}' with paction: '{$params['paction']}'");
     switch ($params['paction']) {
         case 'parse':
         case 'metadata':
             // Dirty hack to provide the correct context for edit notices
             global $wgTitle;
             // FIXME NOOOOOOOOES
             $wgTitle = $title;
             RequestContext::getMain()->setTitle($title);
             // Get information about current revision
             if ($title->exists()) {
                 $latestRevision = Revision::newFromTitle($title);
                 if ($latestRevision === null) {
                     $this->dieUsage('Could not find latest revision for title', 'latestnotfound');
                 }
                 $revision = null;
                 if (!isset($parserParams['oldid']) || $parserParams['oldid'] === 0) {
                     $parserParams['oldid'] = $latestRevision->getId();
                     $revision = $latestRevision;
                 } else {
                     $revision = Revision::newFromId($parserParams['oldid']);
                     if ($revision === null) {
                         $this->dieUsage('Could not find revision ID ' . $parserParams['oldid'], 'oldidnotfound');
                     }
                 }
                 $restoring = $revision && !$revision->isCurrent();
                 $baseTimestamp = $latestRevision->getTimestamp();
                 $oldid = intval($parserParams['oldid']);
                 // If requested, request HTML from Parsoid/RESTBase
                 if ($params['paction'] === 'parse') {
                     $content = $this->requestRestbase('GET', 'page/html/' . urlencode($title->getPrefixedDBkey()) . '/' . $oldid, array());
                     if ($content === false) {
                         $this->dieUsage('Error contacting the document server', 'docserver');
                     }
                 }
             } else {
                 $content = '';
                 $baseTimestamp = wfTimestampNow();
                 $oldid = 0;
                 $restoring = false;
             }
             // Get edit notices
             $notices = $title->getEditNotices();
             // Anonymous user notice
             if ($user->isAnon()) {
                 $notices[] = $this->msg('anoneditwarning', '{{fullurl:Special:UserLogin|returnto={{FULLPAGENAMEE}}}}', '{{fullurl:Special:UserLogin/signup|returnto={{FULLPAGENAMEE}}}}')->parseAsBlock();
             }
             // Old revision notice
             if ($restoring) {
                 $notices[] = $this->msg('editingold')->parseAsBlock();
             }
             // New page notices
             if (!$title->exists()) {
                 $notices[] = $this->msg($user->isLoggedIn() ? 'newarticletext' : 'newarticletextanon', wfExpandUrl(Skin::makeInternalOrExternalUrl($this->msg('helppage')->inContentLanguage()->text())))->parseAsBlock();
                 // Page protected from creation
                 if ($title->getRestrictions('create')) {
                     $notices[] = $this->msg('titleprotectedwarning')->parseAsBlock();
                 }
             }
             // Look at protection status to set up notices + surface class(es)
             $protectedClasses = array();
             if (MWNamespace::getRestrictionLevels($title->getNamespace()) !== array('')) {
                 // Page protected from editing
                 if ($title->isProtected('edit')) {
                     # Is the title semi-protected?
                     if ($title->isSemiProtected()) {
                         $protectedClasses[] = 'mw-textarea-sprotected';
                         $noticeMsg = 'semiprotectedpagewarning';
                     } else {
                         $protectedClasses[] = 'mw-textarea-protected';
                         # Then it must be protected based on static groups (regular)
                         $noticeMsg = 'protectedpagewarning';
                     }
                     $notices[] = $this->msg($noticeMsg)->parseAsBlock() . $this->getLastLogEntry($title, 'protect');
                 }
                 // Deal with cascading edit protection
                 list($sources, $restrictions) = $title->getCascadeProtectionSources();
                 if (isset($restrictions['edit'])) {
                     $protectedClasses[] = ' mw-textarea-cprotected';
                     $notice = $this->msg('cascadeprotectedwarning')->parseAsBlock() . '<ul>';
                     // Unfortunately there's no nice way to get only the pages which cause
                     // editing to be restricted
                     foreach ($sources as $source) {
                         $notice .= "<li>" . Linker::link($source) . "</li>";
                     }
                     $notice .= '</ul>';
                     $notices[] = $notice;
                 }
             }
             // Permission notice
             $permErrors = $title->getUserPermissionsErrors('create', $user);
             if ($permErrors && !$title->exists()) {
                 $notices[] = $this->msg('permissionserrorstext-withaction', 1, $this->msg('action-createpage')) . "<br>" . call_user_func_array(array($this, 'msg'), $permErrors[0])->parse();
             }
             // Show notice when editing user / user talk page of a user that doesn't exist
             // or who is blocked
             // HACK of course this code is partly duplicated from EditPage.php :(
             if ($title->getNamespace() == NS_USER || $title->getNamespace() == NS_USER_TALK) {
                 $parts = explode('/', $title->getText(), 2);
                 $targetUsername = $parts[0];
                 $targetUser = User::newFromName($targetUsername, false);
                 if (!($targetUser && $targetUser->isLoggedIn()) && !User::isIP($targetUsername)) {
                     // User does not exist
                     $notices[] = "<div class=\"mw-userpage-userdoesnotexist error\">\n" . $this->msg('userpage-userdoesnotexist', wfEscapeWikiText($targetUsername)) . "\n</div>";
                 } elseif ($targetUser->isBlocked()) {
                     // Show log extract if the user is currently blocked
                     $notices[] = $this->msg('blocked-notice-logextract', $targetUser->getName())->parseAsBlock() . $this->getLastLogEntry($targetUser->getUserPage(), 'block');
                 }
             }
             // Blocked user notice
             if ($user->isBlockedFrom($title) && $user->getBlock()->prevents('edit') !== false) {
                 $notices[] = call_user_func_array(array($this, 'msg'), $user->getBlock()->getPermissionsError($this->getContext()))->parseAsBlock();
             }
             // Blocked user notice for global blocks
             if (class_exists('GlobalBlocking')) {
                 $error = GlobalBlocking::getUserBlockErrors($user, $this->getRequest()->getIP());
                 if (count($error)) {
                     $notices[] = call_user_func_array(array($this, 'msg'), $error)->parseAsBlock();
                 }
             }
             // HACK: Build a fake EditPage so we can get checkboxes from it
             $article = new Article($title);
             // Deliberately omitting ,0 so oldid comes from request
             $ep = new EditPage($article);
             $req = $this->getRequest();
             $req->setVal('format', 'text/x-wiki');
             $ep->importFormData($req);
             // By reference for some reason (bug 52466)
             $tabindex = 0;
             $states = array('minor' => false, 'watch' => false);
             $checkboxes = $ep->getCheckboxes($tabindex, $states);
             // HACK: Find out which red links are on the page
             // We do the lookup for the current version. This might not be entirely complete
             // if we're loading an oldid, but it'll probably be close enough, and LinkCache
             // will automatically request any additional data it needs.
             $links = array();
             $wikipage = WikiPage::factory($title);
             $popts = $wikipage->makeParserOptions('canonical');
             $cached = ParserCache::singleton()->get($article, $popts, true);
             $links = array('missing' => array(), 'known' => $restoring || !$cached ? array() : 1);
             if ($cached) {
                 foreach ($cached->getLinks() as $namespace => $cachedTitles) {
                     foreach ($cachedTitles as $cachedTitleText => $exists) {
                         $cachedTitle = Title::makeTitle($namespace, $cachedTitleText);
                         if (!$cachedTitle->isKnown()) {
                             $links['missing'][] = $cachedTitle->getPrefixedText();
                         } elseif ($links['known'] !== 1) {
                             $links['known'][] = $cachedTitle->getPrefixedText();
                         }
                     }
                 }
             }
             // Add information about current page
             if (!$title->isKnown()) {
                 $links['missing'][] = $title->getPrefixedText();
             } elseif ($links['known'] !== 1) {
                 $links['known'][] = $title->getPrefixedText();
             }
             // On parser cache miss, just don't bother populating red link data
             $result = array('result' => 'success', 'notices' => $notices, 'checkboxes' => $checkboxes, 'links' => $links, 'protectedClasses' => implode(' ', $protectedClasses), 'watched' => $user->isWatched($title), 'basetimestamp' => $baseTimestamp, 'starttimestamp' => wfTimestampNow(), 'oldid' => $oldid);
             if ($params['paction'] === 'parse') {
                 $result['content'] = $content;
             }
             break;
         case 'parsefragment':
             $wikitext = $params['wikitext'];
             if ($params['pst']) {
                 $wikitext = $this->pstWikitext($title, $wikitext);
             }
             $content = $this->parseWikitextFragment($title, $wikitext);
             if ($content === false) {
                 $this->dieUsage('Error contacting the document server', 'docserver');
             } else {
                 $result = array('result' => 'success', 'content' => $content);
             }
             break;
         case 'serialize':
             if ($params['cachekey'] !== null) {
                 $content = $this->trySerializationCache($params['cachekey']);
                 if (!is_string($content)) {
                     $this->dieUsage('No cached serialization found with that key', 'badcachekey');
                 }
             } else {
                 if ($params['html'] === null) {
                     $this->dieUsageMsg('missingparam', 'html');
                 }
                 $content = $this->postHTML($title, $html, $parserParams, $params['etag']);
                 if ($content === false) {
                     $this->dieUsage('Error contacting the document server', 'docserver');
                 }
             }
             $result = array('result' => 'success', 'content' => $content);
             break;
         case 'diff':
             if ($params['cachekey'] !== null) {
                 $wikitext = $this->trySerializationCache($params['cachekey']);
                 if (!is_string($wikitext)) {
                     $this->dieUsage('No cached serialization found with that key', 'badcachekey');
                 }
             } else {
                 $wikitext = $this->postHTML($title, $html, $parserParams, $params['etag']);
                 if ($wikitext === false) {
                     $this->dieUsage('Error contacting the document server', 'docserver');
                 }
             }
             $diff = $this->diffWikitext($title, $wikitext);
             if ($diff['result'] === 'fail') {
                 $this->dieUsage('Diff failed', 'difffailed');
             }
             $result = $diff;
             break;
         case 'serializeforcache':
             if (!isset($parserParams['oldid'])) {
                 $parserParams['oldid'] = Revision::newFromTitle($title)->getId();
             }
             $key = $this->storeInSerializationCache($title, $parserParams['oldid'], $html, $params['etag']);
             $result = array('result' => 'success', 'cachekey' => $key);
             break;
         case 'getlanglinks':
             $langlinks = $this->getLangLinks($title);
             if ($langlinks === false) {
                 $this->dieUsage('Error querying MediaWiki API', 'api-langlinks-error');
             } else {
                 $result = array('result' => 'success', 'langlinks' => $langlinks);
             }
             break;
     }
     $this->getResult()->addValue(null, $this->getModuleName(), $result);
 }
 /**
  * Performs an edit and checks the result.
  *
  * @param string|Title $title The title of the page to edit
  * @param string|null $baseText Some text to create the page with before attempting the edit.
  * @param User|string|null $user The user to perform the edit as.
  * @param array $edit An array of request parameters used to define the edit to perform.
  *              Some well known fields are:
  *              * wpTextbox1: the text to submit
  *              * wpSummary: the edit summary
  *              * wpEditToken: the edit token (will be inserted if not provided)
  *              * wpEdittime: timestamp of the edit's base revision (will be inserted
  *                if not provided)
  *              * wpStarttime: timestamp when the edit started (will be inserted if not provided)
  *              * wpSectionTitle: the section to edit
  *              * wpMinorEdit: mark as minor edit
  *              * wpWatchthis: whether to watch the page
  * @param int|null $expectedCode The expected result code (EditPage::AS_XXX constants).
  *                  Set to null to skip the check.
  * @param string|null $expectedText The text expected to be on the page after the edit.
  *                  Set to null to skip the check.
  * @param string|null $message An optional message to show along with any error message.
  *
  * @return WikiPage The page that was just edited, useful for getting the edit's rev_id, etc.
  */
 protected function assertEdit($title, $baseText, $user = null, array $edit, $expectedCode = null, $expectedText = null, $message = null)
 {
     if (is_string($title)) {
         $ns = $this->getDefaultWikitextNS();
         $title = Title::newFromText($title, $ns);
     }
     $this->assertNotNull($title);
     if (is_string($user)) {
         $user = User::newFromName($user);
         if ($user->getId() === 0) {
             $user->addToDatabase();
         }
     }
     $page = WikiPage::factory($title);
     if ($baseText !== null) {
         $content = ContentHandler::makeContent($baseText, $title);
         $page->doEditContent($content, "base text for test");
         $this->forceRevisionDate($page, '20120101000000');
         //sanity check
         $page->clear();
         $currentText = ContentHandler::getContentText($page->getContent());
         # EditPage rtrim() the user input, so we alter our expected text
         # to reflect that.
         $this->assertEditedTextEquals($baseText, $currentText);
     }
     if ($user == null) {
         $user = $GLOBALS['wgUser'];
     } else {
         $this->setMwGlobals('wgUser', $user);
     }
     if (!isset($edit['wpEditToken'])) {
         $edit['wpEditToken'] = $user->getEditToken();
     }
     if (!isset($edit['wpEdittime'])) {
         $edit['wpEdittime'] = $page->exists() ? $page->getTimestamp() : '';
     }
     if (!isset($edit['wpStarttime'])) {
         $edit['wpStarttime'] = wfTimestampNow();
     }
     $req = new FauxRequest($edit, true);
     // session ??
     $article = new Article($title);
     $article->getContext()->setTitle($title);
     $ep = new EditPage($article);
     $ep->setContextTitle($title);
     $ep->importFormData($req);
     $bot = isset($edit['bot']) ? (bool) $edit['bot'] : false;
     // this is where the edit happens!
     // Note: don't want to use EditPage::AttemptSave, because it messes with $wgOut
     // and throws exceptions like PermissionsError
     $status = $ep->internalAttemptSave($result, $bot);
     if ($expectedCode !== null) {
         // check edit code
         $this->assertEquals($expectedCode, $status->value, "Expected result code mismatch. {$message}");
     }
     $page = WikiPage::factory($title);
     if ($expectedText !== null) {
         // check resulting page text
         $content = $page->getContent();
         $text = ContentHandler::getContentText($content);
         # EditPage rtrim() the user input, so we alter our expected text
         # to reflect that.
         $this->assertEditedTextEquals($expectedText, $text, "Expected article text mismatch. {$message}");
     }
     return $page;
 }
Beispiel #5
0
 public function execute()
 {
     $user = $this->getUser();
     $params = $this->extractRequestParams();
     if (is_null($params['text']) && is_null($params['appendtext']) && is_null($params['prependtext']) && $params['undo'] == 0) {
         $this->dieUsageMsg('missingtext');
     }
     $pageObj = $this->getTitleOrPageId($params);
     $titleObj = $pageObj->getTitle();
     $apiResult = $this->getResult();
     if ($params['redirect']) {
         if ($titleObj->isRedirect()) {
             $oldTitle = $titleObj;
             $titles = Revision::newFromTitle($oldTitle, false, Revision::READ_LATEST)->getContent(Revision::FOR_THIS_USER, $user)->getRedirectChain();
             // array_shift( $titles );
             $redirValues = array();
             /** @var $newTitle Title */
             foreach ($titles as $id => $newTitle) {
                 if (!isset($titles[$id - 1])) {
                     $titles[$id - 1] = $oldTitle;
                 }
                 $redirValues[] = array('from' => $titles[$id - 1]->getPrefixedText(), 'to' => $newTitle->getPrefixedText());
                 $titleObj = $newTitle;
             }
             $apiResult->setIndexedTagName($redirValues, 'r');
             $apiResult->addValue(null, 'redirects', $redirValues);
             // Since the page changed, update $pageObj
             $pageObj = WikiPage::factory($titleObj);
         }
     }
     if (!isset($params['contentmodel']) || $params['contentmodel'] == '') {
         $contentHandler = $pageObj->getContentHandler();
     } else {
         $contentHandler = ContentHandler::getForModelID($params['contentmodel']);
     }
     // @todo ask handler whether direct editing is supported at all! make allowFlatEdit() method or some such
     if (!isset($params['contentformat']) || $params['contentformat'] == '') {
         $params['contentformat'] = $contentHandler->getDefaultFormat();
     }
     $contentFormat = $params['contentformat'];
     if (!$contentHandler->isSupportedFormat($contentFormat)) {
         $name = $titleObj->getPrefixedDBkey();
         $model = $contentHandler->getModelID();
         $this->dieUsage("The requested format {$contentFormat} is not supported for content model " . " {$model} used by {$name}", 'badformat');
     }
     if ($params['createonly'] && $titleObj->exists()) {
         $this->dieUsageMsg('createonly-exists');
     }
     if ($params['nocreate'] && !$titleObj->exists()) {
         $this->dieUsageMsg('nocreate-missing');
     }
     // Now let's check whether we're even allowed to do this
     $errors = $titleObj->getUserPermissionsErrors('edit', $user);
     if (!$titleObj->exists()) {
         $errors = array_merge($errors, $titleObj->getUserPermissionsErrors('create', $user));
     }
     if (count($errors)) {
         $this->dieUsageMsg($errors[0]);
     }
     $toMD5 = $params['text'];
     if (!is_null($params['appendtext']) || !is_null($params['prependtext'])) {
         $content = $pageObj->getContent();
         if (!$content) {
             if ($titleObj->getNamespace() == NS_MEDIAWIKI) {
                 # If this is a MediaWiki:x message, then load the messages
                 # and return the message value for x.
                 $text = $titleObj->getDefaultMessageText();
                 if ($text === false) {
                     $text = '';
                 }
                 try {
                     $content = ContentHandler::makeContent($text, $this->getTitle());
                 } catch (MWContentSerializationException $ex) {
                     $this->dieUsage($ex->getMessage(), 'parseerror');
                     return;
                 }
             } else {
                 # Otherwise, make a new empty content.
                 $content = $contentHandler->makeEmptyContent();
             }
         }
         // @todo Add support for appending/prepending to the Content interface
         if (!$content instanceof TextContent) {
             $mode = $contentHandler->getModelID();
             $this->dieUsage("Can't append to pages using content model {$mode}", 'appendnotsupported');
         }
         if (!is_null($params['section'])) {
             if (!$contentHandler->supportsSections()) {
                 $modelName = $contentHandler->getModelID();
                 $this->dieUsage("Sections are not supported for this content model: {$modelName}.", 'sectionsnotsupported');
             }
             // Process the content for section edits
             $section = intval($params['section']);
             $content = $content->getSection($section);
             if (!$content) {
                 $this->dieUsage("There is no section {$section}.", 'nosuchsection');
             }
         }
         if (!$content) {
             $text = '';
         } else {
             $text = $content->serialize($contentFormat);
         }
         $params['text'] = $params['prependtext'] . $text . $params['appendtext'];
         $toMD5 = $params['prependtext'] . $params['appendtext'];
     }
     if ($params['undo'] > 0) {
         if ($params['undoafter'] > 0) {
             if ($params['undo'] < $params['undoafter']) {
                 list($params['undo'], $params['undoafter']) = array($params['undoafter'], $params['undo']);
             }
             $undoafterRev = Revision::newFromID($params['undoafter']);
         }
         $undoRev = Revision::newFromID($params['undo']);
         if (is_null($undoRev) || $undoRev->isDeleted(Revision::DELETED_TEXT)) {
             $this->dieUsageMsg(array('nosuchrevid', $params['undo']));
         }
         if ($params['undoafter'] == 0) {
             $undoafterRev = $undoRev->getPrevious();
         }
         if (is_null($undoafterRev) || $undoafterRev->isDeleted(Revision::DELETED_TEXT)) {
             $this->dieUsageMsg(array('nosuchrevid', $params['undoafter']));
         }
         if ($undoRev->getPage() != $pageObj->getID()) {
             $this->dieUsageMsg(array('revwrongpage', $undoRev->getID(), $titleObj->getPrefixedText()));
         }
         if ($undoafterRev->getPage() != $pageObj->getID()) {
             $this->dieUsageMsg(array('revwrongpage', $undoafterRev->getID(), $titleObj->getPrefixedText()));
         }
         $newContent = $contentHandler->getUndoContent($pageObj->getRevision(), $undoRev, $undoafterRev);
         if (!$newContent) {
             $this->dieUsageMsg('undo-failure');
         }
         $params['text'] = $newContent->serialize($params['contentformat']);
         // If no summary was given and we only undid one rev,
         // use an autosummary
         if (is_null($params['summary']) && $titleObj->getNextRevisionID($undoafterRev->getID()) == $params['undo']) {
             $params['summary'] = wfMessage('undo-summary', $params['undo'], $undoRev->getUserText())->inContentLanguage()->text();
         }
     }
     // See if the MD5 hash checks out
     if (!is_null($params['md5']) && md5($toMD5) !== $params['md5']) {
         $this->dieUsageMsg('hashcheckfailed');
     }
     // EditPage wants to parse its stuff from a WebRequest
     // That interface kind of sucks, but it's workable
     $requestArray = array('wpTextbox1' => $params['text'], 'format' => $contentFormat, 'model' => $contentHandler->getModelID(), 'wpEditToken' => $params['token'], 'wpIgnoreBlankSummary' => '');
     if (!is_null($params['summary'])) {
         $requestArray['wpSummary'] = $params['summary'];
     }
     if (!is_null($params['sectiontitle'])) {
         $requestArray['wpSectionTitle'] = $params['sectiontitle'];
     }
     // TODO: Pass along information from 'undoafter' as well
     if ($params['undo'] > 0) {
         $requestArray['wpUndidRevision'] = $params['undo'];
     }
     // Watch out for basetimestamp == ''
     // wfTimestamp() treats it as NOW, almost certainly causing an edit conflict
     if (!is_null($params['basetimestamp']) && $params['basetimestamp'] != '') {
         $requestArray['wpEdittime'] = wfTimestamp(TS_MW, $params['basetimestamp']);
     } else {
         $requestArray['wpEdittime'] = $pageObj->getTimestamp();
     }
     if (!is_null($params['starttimestamp']) && $params['starttimestamp'] != '') {
         $requestArray['wpStarttime'] = wfTimestamp(TS_MW, $params['starttimestamp']);
     } else {
         $requestArray['wpStarttime'] = wfTimestampNow();
         // Fake wpStartime
     }
     if ($params['minor'] || !$params['notminor'] && $user->getOption('minordefault')) {
         $requestArray['wpMinoredit'] = '';
     }
     if ($params['recreate']) {
         $requestArray['wpRecreate'] = '';
     }
     if (!is_null($params['section'])) {
         $section = intval($params['section']);
         if ($section == 0 && $params['section'] != '0' && $params['section'] != 'new') {
             $this->dieUsage("The section parameter must be set to an integer or 'new'", "invalidsection");
         }
         $requestArray['wpSection'] = $params['section'];
     } else {
         $requestArray['wpSection'] = '';
     }
     $watch = $this->getWatchlistValue($params['watchlist'], $titleObj);
     // Deprecated parameters
     if ($params['watch']) {
         $watch = true;
     } elseif ($params['unwatch']) {
         $watch = false;
     }
     if ($watch) {
         $requestArray['wpWatchthis'] = '';
     }
     global $wgTitle, $wgRequest;
     $req = new DerivativeRequest($this->getRequest(), $requestArray, true);
     // Some functions depend on $wgTitle == $ep->mTitle
     // TODO: Make them not or check if they still do
     $wgTitle = $titleObj;
     $articleContext = new RequestContext();
     $articleContext->setRequest($req);
     $articleContext->setWikiPage($pageObj);
     $articleContext->setUser($this->getUser());
     /** @var $articleObject Article */
     $articleObject = Article::newFromWikiPage($pageObj, $articleContext);
     $ep = new EditPage($articleObject);
     // allow editing of non-textual content.
     $ep->allowNonTextContent = true;
     $ep->setContextTitle($titleObj);
     $ep->importFormData($req);
     // Run hooks
     // Handle APIEditBeforeSave parameters
     $r = array();
     if (!wfRunHooks('APIEditBeforeSave', array($ep, $ep->textbox1, &$r))) {
         if (count($r)) {
             $r['result'] = 'Failure';
             $apiResult->addValue(null, $this->getModuleName(), $r);
             return;
         } else {
             $this->dieUsageMsg('hookaborted');
         }
     }
     // Do the actual save
     $oldRevId = $articleObject->getRevIdFetched();
     $result = null;
     // Fake $wgRequest for some hooks inside EditPage
     // @todo FIXME: This interface SUCKS
     $oldRequest = $wgRequest;
     $wgRequest = $req;
     $status = $ep->internalAttemptSave($result, $user->isAllowed('bot') && $params['bot']);
     $wgRequest = $oldRequest;
     global $wgMaxArticleSize;
     switch ($status->value) {
         case EditPage::AS_HOOK_ERROR:
         case EditPage::AS_HOOK_ERROR_EXPECTED:
             $this->dieUsageMsg('hookaborted');
         case EditPage::AS_PARSE_ERROR:
             $this->dieUsage($status->getMessage(), 'parseerror');
         case EditPage::AS_IMAGE_REDIRECT_ANON:
             $this->dieUsageMsg('noimageredirect-anon');
         case EditPage::AS_IMAGE_REDIRECT_LOGGED:
             $this->dieUsageMsg('noimageredirect-logged');
         case EditPage::AS_SPAM_ERROR:
             $this->dieUsageMsg(array('spamdetected', $result['spam']));
         case EditPage::AS_BLOCKED_PAGE_FOR_USER:
             $this->dieUsageMsg('blockedtext');
         case EditPage::AS_MAX_ARTICLE_SIZE_EXCEEDED:
         case EditPage::AS_CONTENT_TOO_BIG:
             $this->dieUsageMsg(array('contenttoobig', $wgMaxArticleSize));
         case EditPage::AS_READ_ONLY_PAGE_ANON:
             $this->dieUsageMsg('noedit-anon');
         case EditPage::AS_READ_ONLY_PAGE_LOGGED:
             $this->dieUsageMsg('noedit');
         case EditPage::AS_READ_ONLY_PAGE:
             $this->dieReadOnly();
         case EditPage::AS_RATE_LIMITED:
             $this->dieUsageMsg('actionthrottledtext');
         case EditPage::AS_ARTICLE_WAS_DELETED:
             $this->dieUsageMsg('wasdeleted');
         case EditPage::AS_NO_CREATE_PERMISSION:
             $this->dieUsageMsg('nocreate-loggedin');
         case EditPage::AS_BLANK_ARTICLE:
             $this->dieUsageMsg('blankpage');
         case EditPage::AS_CONFLICT_DETECTED:
             $this->dieUsageMsg('editconflict');
             // case EditPage::AS_SUMMARY_NEEDED: Can't happen since we set wpIgnoreBlankSummary
         // case EditPage::AS_SUMMARY_NEEDED: Can't happen since we set wpIgnoreBlankSummary
         case EditPage::AS_TEXTBOX_EMPTY:
             $this->dieUsageMsg('emptynewsection');
         case EditPage::AS_SUCCESS_NEW_ARTICLE:
             $r['new'] = '';
             // fall-through
         // fall-through
         case EditPage::AS_SUCCESS_UPDATE:
             $r['result'] = 'Success';
             $r['pageid'] = intval($titleObj->getArticleID());
             $r['title'] = $titleObj->getPrefixedText();
             $r['contentmodel'] = $titleObj->getContentModel();
             $newRevId = $articleObject->getLatest();
             if ($newRevId == $oldRevId) {
                 $r['nochange'] = '';
             } else {
                 $r['oldrevid'] = intval($oldRevId);
                 $r['newrevid'] = intval($newRevId);
                 $r['newtimestamp'] = wfTimestamp(TS_ISO_8601, $pageObj->getTimestamp());
             }
             break;
         case EditPage::AS_SUMMARY_NEEDED:
             $this->dieUsageMsg('summaryrequired');
         case EditPage::AS_END:
         default:
             // $status came from WikiPage::doEdit()
             $errors = $status->getErrorsArray();
             $this->dieUsageMsg($errors[0]);
             // TODO: Add new errors to message map
             break;
     }
     $apiResult->addValue(null, $this->getModuleName(), $r);
 }
Beispiel #6
0
 static function printForm(&$form_name, &$target_name, $alt_forms = array(), $redirectOnError = false)
 {
     global $wgOut, $wgRequest, $wgUser, $sfgFormPrinter;
     // initialize some variables
     $target_title = null;
     $page_name_formula = null;
     $form_title = Title::makeTitleSafe(SF_NS_FORM, $form_name);
     // If the given form is not a valid title, bail out.
     if (!$form_title) {
         return 'sf_formedit_badurl';
     }
     $form_article = new Article($form_title, 0);
     $form_definition = $form_article->getContent();
     // If the form page is a redirect, use the other form
     // instead.
     if ($form_title->isRedirect()) {
         $form_title = Title::newFromRedirectRecurse($form_definition);
         $form_article = new Article($form_title, 0);
         $form_definition = $form_article->getContent();
     }
     $form_definition = StringUtils::delimiterReplace('<noinclude>', '</noinclude>', '', $form_definition);
     if (is_null($target_name)) {
         $target_name = '';
     }
     if ($target_name === '') {
         // parse the form to see if it has a 'page name' value set
         $matches;
         if (preg_match('/{{{info.*page name\\s*=\\s*(.*)}}}/m', $form_definition, $matches)) {
             $page_name_elements = SFUtils::getFormTagComponents($matches[1]);
             $page_name_formula = $page_name_elements[0];
         } elseif (count($alt_forms) == 0) {
             return 'sf_formedit_badurl';
         }
     } else {
         $target_title = Title::newFromText($target_name);
         if ($target_title && $target_title->exists()) {
             if ($wgRequest->getVal('query') == 'true') {
                 $page_contents = null;
                 //$page_is_source = false;
             } else {
                 // If page already exists and 'redlink'
                 // is in the query string, redirect to
                 // the actual page, just like
                 // MediaWiki does it.
                 if ($wgRequest->getBool('redlink')) {
                     $wgOut->redirect($target_title->getFullURL());
                     wfProfileOut(__METHOD__);
                     return;
                 }
                 $target_article = new Article($target_title, 0);
                 $page_contents = $target_article->getContent();
                 //$page_is_source = true;
             }
         } else {
             $target_name = str_replace('_', ' ', $target_name);
         }
     }
     if (!$form_title || !$form_title->exists()) {
         if (count($alt_forms) > 0) {
             $text = '<div class="infoMessage">' . wfMsg('sf_formedit_altformsonly') . ' ' . self::printAltFormsList($alt_forms, $form_name) . "</div>\n";
         } else {
             $text = Html::rawElement('p', array('class' => 'error'), wfMsgExt('sf_formstart_badform', 'parseinline', SFUtils::linkText(SF_NS_FORM, $form_name))) . "\n";
         }
     } elseif ($target_name === '' && $page_name_formula === '') {
         $text = Html::element('p', array('class' => 'error'), wfMsg('sf_formedit_badurl')) . "\n";
     } else {
         $save_page = $wgRequest->getCheck('wpSave');
         $preview_page = $wgRequest->getCheck('wpPreview');
         $diff_page = $wgRequest->getCheck('wpDiff');
         $form_submitted = $save_page || $preview_page || $diff_page;
         // get 'preload' query value, if it exists
         if (!$form_submitted) {
             if ($wgRequest->getCheck('preload')) {
                 $page_is_source = true;
                 $page_contents = SFFormUtils::getPreloadedText($wgRequest->getVal('preload'));
             } else {
                 // let other extensions preload the page, if they want
                 wfRunHooks('sfEditFormPreloadText', array(&$page_contents, $target_title, $form_title));
                 $page_is_source = $page_contents != null;
             }
         } else {
             $page_is_source = false;
             $page_contents = null;
         }
         list($form_text, $javascript_text, $data_text, $form_page_title, $generated_page_name) = $sfgFormPrinter->formHTML($form_definition, $form_submitted, $page_is_source, $form_article->getID(), $page_contents, $target_name, $page_name_formula);
         // Before we do anything else, set the form header
         // title - this needs to be done after formHTML() is
         // called, because otherwise it doesn't take hold
         // for some reason if the form is disabled.
         if (empty($target_title)) {
             $s = wfMsg('sf_formedit_createtitlenotarget', $form_title->getText());
         } elseif ($target_title->exists()) {
             $s = wfMsg('sf_formedit_edittitle', $form_title->getText(), $target_title->getPrefixedText());
         } else {
             $s = wfMsg('sf_formedit_createtitle', $form_title->getText(), $target_title->getPrefixedText());
         }
         $wgOut->setPageTitle($s);
         if ($form_submitted) {
             if (!is_null($page_name_formula) && $page_name_formula !== '') {
                 $target_name = $generated_page_name;
                 // prepend a super-page, if one was specified
                 if ($wgRequest->getCheck('super_page')) {
                     $target_name = $wgRequest->getVal('super_page') . '/' . $target_name;
                 }
                 // prepend a namespace, if one was specified
                 if ($wgRequest->getCheck('namespace')) {
                     $target_name = $wgRequest->getVal('namespace') . ':' . $target_name;
                 }
                 // replace "unique number" tag with one
                 // that won't get erased by the next line
                 $target_name = preg_replace('/<unique number(.*)>/', '{num\\1}', $target_name, 1);
                 // if any formula stuff is still in the
                 // name after the parsing, just remove it
                 $target_name = StringUtils::delimiterReplace('<', '>', '', $target_name);
                 // now run the parser on it
                 global $wgParser;
                 // ...but first, replace spaces back
                 // with underlines, in case a magic word
                 // or parser function name contains
                 // underlines - hopefully this won't
                 // cause problems of its own
                 $target_name = str_replace(' ', '_', $target_name);
                 $target_name = $wgParser->preprocess($target_name, $wgOut->getTitle(), ParserOptions::newFromUser(null));
                 $title_number = "";
                 $isRandom = false;
                 $randomNumHasPadding = false;
                 $randomNumDigits = 6;
                 if (strpos($target_name, '{num') !== false) {
                     // Random number
                     if (preg_match('/{num;random(;(0)?([1-9][0-9]*))?}/', $target_name, $matches)) {
                         $isRandom = true;
                         $randomNumHasPadding = array_key_exists(2, $matches);
                         $randomNumDigits = array_key_exists(3, $matches) ? $matches[3] : $randomNumDigits;
                         $title_number = self::makeRandomNumber($randomNumDigits, $randomNumHasPadding);
                     } else {
                         // get unique number start value
                         // from target name; if it's not
                         // there, or it's not a positive
                         // number, start it out as blank
                         preg_match('/{num.*start[_]*=[_]*([^;]*).*}/', $target_name, $matches);
                         if (count($matches) == 2 && is_numeric($matches[1]) && $matches[1] >= 0) {
                             // the "start" value"
                             $title_number = $matches[1];
                         }
                     }
                     // set target title
                     $target_title = Title::newFromText(preg_replace('/{num.*}/', $title_number, $target_name));
                     // if title exists already
                     // cycle through numbers for
                     // this tag until we find one
                     // that gives a nonexistent page
                     // title
                     while ($target_title->exists()) {
                         if ($isRandom) {
                             $title_number = self::makeRandomNumber($randomNumDigits, $randomNumHasPadding);
                         } elseif ($title_number == "") {
                             $title_number = 2;
                         } else {
                             $title_number = str_pad($title_number + 1, strlen($title_number), '0', STR_PAD_LEFT);
                         }
                         $target_title = Title::newFromText(preg_replace('/{num.*}/', $title_number, $target_name));
                     }
                     $target_name = $target_title->getPrefixedText();
                 } else {
                     $target_title = Title::newFromText($target_name);
                 }
             }
             if (is_null($target_title)) {
                 if ($target_name) {
                     return array('sf_formstart_badtitle', array($target_name));
                 } else {
                     return 'sf_formedit_emptytitle';
                 }
             }
             if ($save_page) {
                 $permErrors = $target_title->getUserPermissionsErrors('edit', $wgUser);
                 if ($permErrors) {
                     // just return the first error and let them fix it one by one
                     return array_shift($permErrors);
                 }
                 // Set up all the variables for the
                 // page save.
                 $data = array('wpTextbox1' => $data_text, 'wpSummary' => $wgRequest->getVal('wpSummary'), 'wpStarttime' => $wgRequest->getVal('wpStarttime'), 'wpEdittime' => $wgRequest->getVal('wpEdittime'), 'wpEditToken' => $wgUser->isLoggedIn() ? $wgUser->editToken() : EDIT_TOKEN_SUFFIX, 'wpSave' => '', 'action' => 'submit');
                 if ($wgRequest->getCheck('wpMinoredit')) {
                     $data['wpMinoredit'] = true;
                 }
                 if ($wgRequest->getCheck('wpWatchthis')) {
                     $data['wpWatchthis'] = true;
                 }
                 $request = new FauxRequest($data, true);
                 // Find existing article if it exists,
                 // or create a new one.
                 $article = new Article($target_title, 0);
                 $editor = new EditPage($article);
                 $editor->importFormData($request);
                 // Try to save the page!
                 $resultDetails = array();
                 $saveResult = $editor->internalAttemptSave($resultDetails);
                 // Return value was made an object in MW 1.19
                 if (is_object($saveResult)) {
                     $saveResultCode = $saveResult->value;
                 } else {
                     $saveResultCode = $saveResult;
                 }
                 if (($saveResultCode == EditPage::AS_HOOK_ERROR || $saveResultCode == EditPage::AS_HOOK_ERROR_EXPECTED) && $redirectOnError) {
                     $wgOut->clearHTML();
                     $wgOut->setArticleBodyOnly(true);
                     // Lets other code process additional form-definition syntax
                     wfRunHooks('sfWritePageData', array($form_name, $target_title, &$data_text));
                     $text = SFUtils::printRedirectForm($target_title, $data_text, $wgRequest->getVal('wpSummary'), $save_page, $preview_page, $diff_page, $wgRequest->getCheck('wpMinoredit'), $wgRequest->getCheck('wpWatchthis'), $wgRequest->getVal('wpStarttime'), $wgRequest->getVal('wpEdittime'));
                 } else {
                     if ($saveResultCode == EditPage::AS_SUCCESS_UPDATE || $saveResultCode == EditPage::AS_SUCCESS_NEW_ARTICLE) {
                         $wgOut->redirect($target_title->getFullURL());
                     }
                     return SFUtils::processEditErrors($saveResultCode);
                 }
             } else {
                 // Lets other code process additional form-definition syntax
                 wfRunHooks('sfWritePageData', array($form_name, $target_title, &$data_text));
                 $text = SFUtils::printRedirectForm($target_title, $data_text, $wgRequest->getVal('wpSummary'), $save_page, $preview_page, $diff_page, $wgRequest->getCheck('wpMinoredit'), $wgRequest->getCheck('wpWatchthis'), $wgRequest->getVal('wpStarttime'), $wgRequest->getVal('wpEdittime'));
                 // extract its data
             }
         } else {
             // override the default title for this page if
             // a title was specified in the form
             if ($form_page_title != null) {
                 if ($target_name === '') {
                     $wgOut->setPageTitle($form_page_title);
                 } else {
                     $wgOut->setPageTitle("{$form_page_title}: {$target_title->getPrefixedText()}");
                 }
             }
             $text = "";
             if (count($alt_forms) > 0) {
                 $text .= '<div class="infoMessage">' . wfMsg('sf_formedit_altforms') . ' ';
                 $text .= self::printAltFormsList($alt_forms, $target_name);
                 $text .= "</div>\n";
             }
             $text .= '<form name="createbox" id="sfForm" method="post" class="createbox">';
             $pre_form_html = '';
             wfRunHooks('sfHTMLBeforeForm', array(&$target_title, &$pre_form_html));
             $text .= $pre_form_html;
             $text .= $form_text;
         }
     }
     SFUtils::addJavascriptAndCSS();
     if (!empty($javascript_text)) {
         $wgOut->addScript('		<script type="text/javascript">' . "\n{$javascript_text}\n" . '</script>' . "\n");
     }
     $wgOut->addHTML($text);
     return null;
 }
 /**
  * @todo document
  */
 function importFormData(&$request)
 {
     global $wgLang, $wgUser, $wgStructuredParts;
     $fname = 'StructuredEditPage::importFormData';
     wfProfileIn($fname);
     parent::importFormData($request);
     if ($request->wasPosted()) {
         # These fields need to be checked for encoding.
         # Also remove trailing whitespace, but don't remove _initial_
         # whitespace from the text boxes. This may be significant formatting.
         $ns = $this->mArticle->mTitle->getNamespace();
         if (isset($wgStructuredParts[$ns])) {
             foreach ($wgStructuredParts[$ns] as $item) {
                 $this->{$item['name']} = $this->safeUnicodeInput($request, $item['name']);
                 #print("attempting to access {$item['name']}<br>\n");
                 #print("got ".$this->{$item['name']}."\n");
             }
         }
         wfProfileOut($fname);
     }
 }
Beispiel #8
0
 public function execute()
 {
     $user = $this->getUser();
     $params = $this->extractRequestParams();
     if (is_null($params['text']) && is_null($params['appendtext']) && is_null($params['prependtext']) && $params['undo'] == 0) {
         $this->dieUsageMsg('missingtext');
     }
     $pageObj = $this->getTitleOrPageId($params);
     $titleObj = $pageObj->getTitle();
     $apiResult = $this->getResult();
     if ($params['redirect']) {
         if ($params['prependtext'] === null && $params['appendtext'] === null && $params['section'] !== 'new') {
             $this->dieUsage('You have attempted to edit using the "redirect"-following' . ' mode, which must be used in conjuction with section=new, prependtext' . ', or appendtext.', 'redirect-appendonly');
         }
         if ($titleObj->isRedirect()) {
             $oldTitle = $titleObj;
             $titles = Revision::newFromTitle($oldTitle, false, Revision::READ_LATEST)->getContent(Revision::FOR_THIS_USER, $user)->getRedirectChain();
             // array_shift( $titles );
             $redirValues = array();
             /** @var $newTitle Title */
             foreach ($titles as $id => $newTitle) {
                 if (!isset($titles[$id - 1])) {
                     $titles[$id - 1] = $oldTitle;
                 }
                 $redirValues[] = array('from' => $titles[$id - 1]->getPrefixedText(), 'to' => $newTitle->getPrefixedText());
                 $titleObj = $newTitle;
             }
             ApiResult::setIndexedTagName($redirValues, 'r');
             $apiResult->addValue(null, 'redirects', $redirValues);
             // Since the page changed, update $pageObj
             $pageObj = WikiPage::factory($titleObj);
         }
     }
     if (!isset($params['contentmodel']) || $params['contentmodel'] == '') {
         $contentHandler = $pageObj->getContentHandler();
     } else {
         $contentHandler = ContentHandler::getForModelID($params['contentmodel']);
     }
     $name = $titleObj->getPrefixedDBkey();
     $model = $contentHandler->getModelID();
     if ($contentHandler->supportsDirectApiEditing() === false) {
         $this->dieUsage("Direct editing via API is not supported for content model {$model} used by {$name}", 'no-direct-editing');
     }
     if (!isset($params['contentformat']) || $params['contentformat'] == '') {
         $params['contentformat'] = $contentHandler->getDefaultFormat();
     }
     $contentFormat = $params['contentformat'];
     if (!$contentHandler->isSupportedFormat($contentFormat)) {
         $this->dieUsage("The requested format {$contentFormat} is not supported for content model " . " {$model} used by {$name}", 'badformat');
     }
     if ($params['createonly'] && $titleObj->exists()) {
         $this->dieUsageMsg('createonly-exists');
     }
     if ($params['nocreate'] && !$titleObj->exists()) {
         $this->dieUsageMsg('nocreate-missing');
     }
     // Now let's check whether we're even allowed to do this
     $errors = $titleObj->getUserPermissionsErrors('edit', $user);
     if (!$titleObj->exists()) {
         $errors = array_merge($errors, $titleObj->getUserPermissionsErrors('create', $user));
     }
     if (count($errors)) {
         if (is_array($errors[0])) {
             switch ($errors[0][0]) {
                 case 'blockedtext':
                     $this->dieUsage('You have been blocked from editing', 'blocked', 0, array('blockinfo' => ApiQueryUserInfo::getBlockInfo($user->getBlock())));
                     break;
                 case 'autoblockedtext':
                     $this->dieUsage('Your IP address has been blocked automatically, because it was used by a blocked user', 'autoblocked', 0, array('blockinfo' => ApiQueryUserInfo::getBlockInfo($user->getBlock())));
                     break;
                 default:
                     $this->dieUsageMsg($errors[0]);
             }
         } else {
             $this->dieUsageMsg($errors[0]);
         }
     }
     $toMD5 = $params['text'];
     if (!is_null($params['appendtext']) || !is_null($params['prependtext'])) {
         $content = $pageObj->getContent();
         if (!$content) {
             if ($titleObj->getNamespace() == NS_MEDIAWIKI) {
                 # If this is a MediaWiki:x message, then load the messages
                 # and return the message value for x.
                 $text = $titleObj->getDefaultMessageText();
                 if ($text === false) {
                     $text = '';
                 }
                 try {
                     $content = ContentHandler::makeContent($text, $this->getTitle());
                 } catch (MWContentSerializationException $ex) {
                     $this->dieUsage($ex->getMessage(), 'parseerror');
                     return;
                 }
             } else {
                 # Otherwise, make a new empty content.
                 $content = $contentHandler->makeEmptyContent();
             }
         }
         // @todo Add support for appending/prepending to the Content interface
         if (!$content instanceof TextContent) {
             $mode = $contentHandler->getModelID();
             $this->dieUsage("Can't append to pages using content model {$mode}", 'appendnotsupported');
         }
         if (!is_null($params['section'])) {
             if (!$contentHandler->supportsSections()) {
                 $modelName = $contentHandler->getModelID();
                 $this->dieUsage("Sections are not supported for this content model: {$modelName}.", 'sectionsnotsupported');
             }
             if ($params['section'] == 'new') {
                 // DWIM if they're trying to prepend/append to a new section.
                 $content = null;
             } else {
                 // Process the content for section edits
                 $section = $params['section'];
                 $content = $content->getSection($section);
                 if (!$content) {
                     $this->dieUsage("There is no section {$section}.", 'nosuchsection');
                 }
             }
         }
         if (!$content) {
             $text = '';
         } else {
             $text = $content->serialize($contentFormat);
         }
         $params['text'] = $params['prependtext'] . $text . $params['appendtext'];
         $toMD5 = $params['prependtext'] . $params['appendtext'];
     }
     if ($params['undo'] > 0) {
         if ($params['undoafter'] > 0) {
             if ($params['undo'] < $params['undoafter']) {
                 list($params['undo'], $params['undoafter']) = array($params['undoafter'], $params['undo']);
             }
             $undoafterRev = Revision::newFromId($params['undoafter']);
         }
         $undoRev = Revision::newFromId($params['undo']);
         if (is_null($undoRev) || $undoRev->isDeleted(Revision::DELETED_TEXT)) {
             $this->dieUsageMsg(array('nosuchrevid', $params['undo']));
         }
         if ($params['undoafter'] == 0) {
             $undoafterRev = $undoRev->getPrevious();
         }
         if (is_null($undoafterRev) || $undoafterRev->isDeleted(Revision::DELETED_TEXT)) {
             $this->dieUsageMsg(array('nosuchrevid', $params['undoafter']));
         }
         if ($undoRev->getPage() != $pageObj->getID()) {
             $this->dieUsageMsg(array('revwrongpage', $undoRev->getID(), $titleObj->getPrefixedText()));
         }
         if ($undoafterRev->getPage() != $pageObj->getID()) {
             $this->dieUsageMsg(array('revwrongpage', $undoafterRev->getID(), $titleObj->getPrefixedText()));
         }
         $newContent = $contentHandler->getUndoContent($pageObj->getRevision(), $undoRev, $undoafterRev);
         if (!$newContent) {
             $this->dieUsageMsg('undo-failure');
         }
         $params['text'] = $newContent->serialize($params['contentformat']);
         // If no summary was given and we only undid one rev,
         // use an autosummary
         if (is_null($params['summary']) && $titleObj->getNextRevisionID($undoafterRev->getID()) == $params['undo']) {
             $params['summary'] = wfMessage('undo-summary')->params($params['undo'], $undoRev->getUserText())->inContentLanguage()->text();
         }
     }
     // See if the MD5 hash checks out
     if (!is_null($params['md5']) && md5($toMD5) !== $params['md5']) {
         $this->dieUsageMsg('hashcheckfailed');
     }
     // EditPage wants to parse its stuff from a WebRequest
     // That interface kind of sucks, but it's workable
     $requestArray = array('wpTextbox1' => $params['text'], 'format' => $contentFormat, 'model' => $contentHandler->getModelID(), 'wpEditToken' => $params['token'], 'wpIgnoreBlankSummary' => true, 'wpIgnoreBlankArticle' => true, 'wpIgnoreSelfRedirect' => true, 'bot' => $params['bot']);
     if (!is_null($params['summary'])) {
         $requestArray['wpSummary'] = $params['summary'];
     }
     if (!is_null($params['sectiontitle'])) {
         $requestArray['wpSectionTitle'] = $params['sectiontitle'];
     }
     // TODO: Pass along information from 'undoafter' as well
     if ($params['undo'] > 0) {
         $requestArray['wpUndidRevision'] = $params['undo'];
     }
     // Watch out for basetimestamp == '' or '0'
     // It gets treated as NOW, almost certainly causing an edit conflict
     if ($params['basetimestamp'] !== null && (bool) $this->getMain()->getVal('basetimestamp')) {
         $requestArray['wpEdittime'] = $params['basetimestamp'];
     } else {
         $requestArray['wpEdittime'] = $pageObj->getTimestamp();
     }
     if ($params['starttimestamp'] !== null) {
         $requestArray['wpStarttime'] = $params['starttimestamp'];
     } else {
         $requestArray['wpStarttime'] = wfTimestampNow();
         // Fake wpStartime
     }
     if ($params['minor'] || !$params['notminor'] && $user->getOption('minordefault')) {
         $requestArray['wpMinoredit'] = '';
     }
     if ($params['recreate']) {
         $requestArray['wpRecreate'] = '';
     }
     if (!is_null($params['section'])) {
         $section = $params['section'];
         if (!preg_match('/^((T-)?\\d+|new)$/', $section)) {
             $this->dieUsage("The section parameter must be a valid section id or 'new'", "invalidsection");
         }
         $content = $pageObj->getContent();
         if ($section !== '0' && $section != 'new' && (!$content || !$content->getSection($section))) {
             $this->dieUsage("There is no section {$section}.", 'nosuchsection');
         }
         $requestArray['wpSection'] = $params['section'];
     } else {
         $requestArray['wpSection'] = '';
     }
     $watch = $this->getWatchlistValue($params['watchlist'], $titleObj);
     // Deprecated parameters
     if ($params['watch']) {
         $this->logFeatureUsage('action=edit&watch');
         $watch = true;
     } elseif ($params['unwatch']) {
         $this->logFeatureUsage('action=edit&unwatch');
         $watch = false;
     }
     if ($watch) {
         $requestArray['wpWatchthis'] = '';
     }
     // Apply change tags
     if (count($params['tags'])) {
         if ($user->isAllowed('applychangetags')) {
             $requestArray['wpChangeTags'] = implode(',', $params['tags']);
         } else {
             $this->dieUsage('You don\'t have permission to set change tags.', 'taggingnotallowed');
         }
     }
     // Pass through anything else we might have been given, to support extensions
     // This is kind of a hack but it's the best we can do to make extensions work
     $requestArray += $this->getRequest()->getValues();
     global $wgTitle, $wgRequest;
     $req = new DerivativeRequest($this->getRequest(), $requestArray, true);
     // Some functions depend on $wgTitle == $ep->mTitle
     // TODO: Make them not or check if they still do
     $wgTitle = $titleObj;
     $articleContext = new RequestContext();
     $articleContext->setRequest($req);
     $articleContext->setWikiPage($pageObj);
     $articleContext->setUser($this->getUser());
     /** @var $articleObject Article */
     $articleObject = Article::newFromWikiPage($pageObj, $articleContext);
     $ep = new EditPage($articleObject);
     $ep->setApiEditOverride(true);
     $ep->setContextTitle($titleObj);
     $ep->importFormData($req);
     $content = $ep->textbox1;
     // The following is needed to give the hook the full content of the
     // new revision rather than just the current section. (Bug 52077)
     if (!is_null($params['section']) && $contentHandler->supportsSections() && $titleObj->exists()) {
         // If sectiontitle is set, use it, otherwise use the summary as the section title (for
         // backwards compatibility with old forms/bots).
         if ($ep->sectiontitle !== '') {
             $sectionTitle = $ep->sectiontitle;
         } else {
             $sectionTitle = $ep->summary;
         }
         $contentObj = $contentHandler->unserializeContent($content, $contentFormat);
         $fullContentObj = $articleObject->replaceSectionContent($params['section'], $contentObj, $sectionTitle);
         if ($fullContentObj) {
             $content = $fullContentObj->serialize($contentFormat);
         } else {
             // This most likely means we have an edit conflict which means that the edit
             // wont succeed anyway.
             $this->dieUsageMsg('editconflict');
         }
     }
     // Run hooks
     // Handle APIEditBeforeSave parameters
     $r = array();
     if (!Hooks::run('APIEditBeforeSave', array($ep, $content, &$r))) {
         if (count($r)) {
             $r['result'] = 'Failure';
             $apiResult->addValue(null, $this->getModuleName(), $r);
             return;
         }
         $this->dieUsageMsg('hookaborted');
     }
     // Do the actual save
     $oldRevId = $articleObject->getRevIdFetched();
     $result = null;
     // Fake $wgRequest for some hooks inside EditPage
     // @todo FIXME: This interface SUCKS
     $oldRequest = $wgRequest;
     $wgRequest = $req;
     $status = $ep->attemptSave($result);
     $wgRequest = $oldRequest;
     switch ($status->value) {
         case EditPage::AS_HOOK_ERROR:
         case EditPage::AS_HOOK_ERROR_EXPECTED:
             if (isset($status->apiHookResult)) {
                 $r = $status->apiHookResult;
                 $r['result'] = 'Failure';
                 $apiResult->addValue(null, $this->getModuleName(), $r);
                 return;
             } else {
                 $this->dieUsageMsg('hookaborted');
             }
         case EditPage::AS_PARSE_ERROR:
             $this->dieUsage($status->getMessage(), 'parseerror');
         case EditPage::AS_IMAGE_REDIRECT_ANON:
             $this->dieUsageMsg('noimageredirect-anon');
         case EditPage::AS_IMAGE_REDIRECT_LOGGED:
             $this->dieUsageMsg('noimageredirect-logged');
         case EditPage::AS_SPAM_ERROR:
             $this->dieUsageMsg(array('spamdetected', $result['spam']));
         case EditPage::AS_BLOCKED_PAGE_FOR_USER:
             $this->dieUsage('You have been blocked from editing', 'blocked', 0, array('blockinfo' => ApiQueryUserInfo::getBlockInfo($user->getBlock())));
         case EditPage::AS_MAX_ARTICLE_SIZE_EXCEEDED:
         case EditPage::AS_CONTENT_TOO_BIG:
             $this->dieUsageMsg(array('contenttoobig', $this->getConfig()->get('MaxArticleSize')));
         case EditPage::AS_READ_ONLY_PAGE_ANON:
             $this->dieUsageMsg('noedit-anon');
         case EditPage::AS_READ_ONLY_PAGE_LOGGED:
             $this->dieUsageMsg('noedit');
         case EditPage::AS_READ_ONLY_PAGE:
             $this->dieReadOnly();
         case EditPage::AS_RATE_LIMITED:
             $this->dieUsageMsg('actionthrottledtext');
         case EditPage::AS_ARTICLE_WAS_DELETED:
             $this->dieUsageMsg('wasdeleted');
         case EditPage::AS_NO_CREATE_PERMISSION:
             $this->dieUsageMsg('nocreate-loggedin');
         case EditPage::AS_NO_CHANGE_CONTENT_MODEL:
             $this->dieUsageMsg('cantchangecontentmodel');
         case EditPage::AS_BLANK_ARTICLE:
             $this->dieUsageMsg('blankpage');
         case EditPage::AS_CONFLICT_DETECTED:
             $this->dieUsageMsg('editconflict');
         case EditPage::AS_TEXTBOX_EMPTY:
             $this->dieUsageMsg('emptynewsection');
         case EditPage::AS_CHANGE_TAG_ERROR:
             $this->dieStatus($status);
         case EditPage::AS_SUCCESS_NEW_ARTICLE:
             $r['new'] = true;
             // fall-through
         // fall-through
         case EditPage::AS_SUCCESS_UPDATE:
             $r['result'] = 'Success';
             $r['pageid'] = intval($titleObj->getArticleID());
             $r['title'] = $titleObj->getPrefixedText();
             $r['contentmodel'] = $articleObject->getContentModel();
             $newRevId = $articleObject->getLatest();
             if ($newRevId == $oldRevId) {
                 $r['nochange'] = true;
             } else {
                 $r['oldrevid'] = intval($oldRevId);
                 $r['newrevid'] = intval($newRevId);
                 $r['newtimestamp'] = wfTimestamp(TS_ISO_8601, $pageObj->getTimestamp());
             }
             break;
         case EditPage::AS_SUMMARY_NEEDED:
             // Shouldn't happen since we set wpIgnoreBlankSummary, but just in case
             $this->dieUsageMsg('summaryrequired');
         case EditPage::AS_END:
         default:
             // $status came from WikiPage::doEdit()
             $errors = $status->getErrorsArray();
             $this->dieUsageMsg($errors[0]);
             // TODO: Add new errors to message map
             break;
     }
     $apiResult->addValue(null, $this->getModuleName(), $r);
 }
 /**
  * We need to read the hidden checkboxes to know if the
  * visual editor was used or not
  */
 function importFormData(&$request)
 {
     if ($request->wasPosted()) {
         # MeanEditor: take note if the visual editor was used or not
         $this->noVisualEditor = $request->getVal('wpNoVisualEditor');
         $this->userWantsTraditionalEditor = $request->getCheck('wpWantTraditionalEditor');
     } else {
         $this->noVisualEditor = false;
         $this->userWantsTraditionalEditor = false;
     }
     return parent::importFormData($request);
 }
 public function execute($par)
 {
     global $wgUser, $wgRequest, $wgOut, $wgCommentboxNamespaces;
     if (!$wgRequest->wasPosted()) {
         $wgOut->redirect(Title::newMainPage()->getFullURL());
         return;
     }
     $this->setHeaders();
     $Pagename = $wgRequest->getText('wpPageName');
     $Author = $wgRequest->getText('wpAuthor', '');
     $Comment = $wgRequest->getText('wpComment', '');
     $title = Title::newFromText($Pagename);
     if ($title == NULL || !$title->exists()) {
         $this->fail('commentbox-error-page-nonexistent');
         return;
     }
     if (!array_key_exists($title->getNamespace(), $wgCommentboxNamespaces) || !$wgCommentboxNamespaces[$title->getNamespace()]) {
         $this->fail('commentbox-error-namespace', $title);
         return;
     }
     if ($Comment == '' || $Comment == wfMsgNoTrans('commentbox-prefill')) {
         $this->fail('commentbox-error-empty-comment', $title);
         return;
     }
     if (!$title->userCan('edit')) {
         $this->displayRestrictionError();
         return;
     }
     // TODO: Integrate with SpamBlacklist etc.
     // Currently, no http/https-links are allowed at all
     $matches = array();
     if (preg_match('@https?://[-.\\w]+@', $Comment, $matches) || preg_match('@https?://[-.\\w]+@', $Author, $matches)) {
         $wgOut->setPageTitle(wfMsg('spamprotectiontitle'));
         $wgOut->setRobotPolicy('noindex,nofollow');
         $wgOut->setArticleRelated(false);
         $wgOut->addWikiMsg('spamprotectiontext');
         $wgOut->addWikiMsg('spamprotectionmatch', "<nowiki>{$matches[0]}</nowiki>");
         $wgOut->returnToMain(false, $title);
         return;
     }
     $article = new Article($title);
     $text = $article->getContent();
     $subject = '';
     if (!preg_match(wfMsgForContentNoTrans('commentbox-regex'), $text)) {
         $subject = wfMsgForContent('commentbox-first-comment-heading') . "\n";
     }
     $sig = $wgUser->isLoggedIn() ? "-- ~~~~" : "-- {$Author} ~~~~~";
     // Append <br /> after each newline, except if the user started a new paragraph
     $Comment = preg_replace('/(?<!\\n)\\n(?!\\n)/', "<br />\n", $Comment);
     $text .= "\n\n" . $subject . $Comment . "\n<br />" . $sig;
     $reqArr = array('wpTextbox1' => $text, 'wpSummary' => wfMsgForContent('commentbox-log'), 'wpEditToken' => $wgUser->editToken(), 'wpIgnoreBlankSummary' => '', 'wpStarttime' => wfTimestampNow(), 'wpEdittime' => $article->getTimestamp());
     $request = new FauxRequest($reqArr, true);
     $ep = new EditPage($article);
     $ep->setContextTitle($title);
     $ep->importFormData($request);
     $details = array();
     // Passed by ref
     $status = $ep->internalAttemptSave($details);
     $retval = $status->value;
     switch ($retval) {
         case EditPage::AS_SUCCESS_UPDATE:
             $wgOut->redirect($title->getFullURL());
             break;
         case EditPage::AS_SPAM_ERROR:
             $ep->spamPageWithContent($details['spam']);
             break;
         case EditPage::AS_BLOCKED_PAGE_FOR_USER:
             $wgOut->blockedPage();
             break;
         case EditPage::AS_READ_ONLY_PAGE_ANON:
         case EditPage::AS_READ_ONLY_PAGE_LOGGED:
             $wgOut->permissionRequired('edit');
             break;
         case EditPage::AS_READ_ONLY_PAGE:
             $wgOut->readOnlyPage();
     }
 }
 /**
  * Override importFormData  to add possibility to prevent save during post request
  */
 function importFormData(&$request)
 {
     parent::importFormData($request);
     if ($this->mPreventSave) {
         $this->save = false;
     }
 }
    /**
     * Show the special page.
     *
     * @param $par Mixed: parameter passed to the special page or null
     */
    public function execute($par)
    {
        global $wgRequest, $wgOut, $wgUser;
        if (wfReadOnly()) {
            $wgOut->readOnlyPage();
            return;
        }
        $this->setHeaders();
        if ($wgRequest->wasPosted()) {
            // 1. Retrieve POST vars. First, we want "crOrigTitle", holding the
            // title of the page we're writing to, and "crRedirectTitle",
            // holding the title of the page we're redirecting to.
            $crOrigTitle = $wgRequest->getText('crOrigTitle');
            $crRedirectTitle = $wgRequest->getText('crRedirectTitle');
            // 2. We need to construct a "FauxRequest", or fake a request that
            // MediaWiki would otherwise get naturally by a client browser to
            // do whatever it has to do. Let's put together the params.
            $title = $crOrigTitle;
            // a. We know our title, so we can instantiate a "Title" and
            // "Article" object. We don't actually plug this into the
            // FauxRequest, but they're required for the writing process,
            // and they contain important information on the article in
            // question that's being edited.
            $crEditTitle = Title::newFromText($crOrigTitle);
            // First, construct "Title". "Article" relies on the former object being set.
            $crEditArticle = new Article($crEditTitle, 0);
            // Then, construct "Article". This is where most of the article's information is.
            $wpStarttime = wfTimestampNow();
            // POST var "wpStarttime" stores when the edit was started.
            $wpEdittime = $crEditArticle->getTimestamp();
            // POST var "wpEdittime" stores when the article was ''last edited''. This is used to check against edit conflicts, and also why we needed to construct "Article" so early. "Article" contains the article's last edittime.
            $wpTextbox1 = "#REDIRECT [[{$crRedirectTitle}]]\r\n";
            // POST var "wpTextbox1" stores the content that's actually going to be written. This is where we write the #REDIRECT [[Article]] stuff. We plug in $crRedirectTitle here.
            $wpSave = 1;
            $wpMinoredit = 1;
            // TODO: Decide on this; should this really be marked and hardcoded as a minor edit, or not? Or should we provide an option? --Digi 11/4/07
            $wpEditToken = htmlspecialchars($wgUser->editToken());
            // 3. Put together the params that we'll use in "FauxRequest" into a single array.
            $crRequestParams = array('title' => $title, 'wpStarttime' => $wpStarttime, 'wpEdittime' => $wpEdittime, 'wpTextbox1' => $wpTextbox1, 'wpSave' => $wpSave, 'wpMinoredit' => $wpMinoredit, 'wpEditToken' => $wpEditToken);
            // 4. Construct "FauxRequest"! Using a FauxRequest object allows
            // for a transparent interface of generated request params that
            // aren't retrieved from the client itself (i.e. $_REQUEST).
            // It's a very useful tool.
            $crRequest = new FauxRequest($crRequestParams, true);
            // 5. Construct "EditPage", which contains routines to write all
            // the data. This is where all the magic happens.
            $crEdit = new EditPage($crEditArticle);
            // We plug in the "Article" object here so EditPage can center on the article that we need to edit.
            // a. We have to plug in the correct information that we just
            // generated. While we fed EditPage with the correct "Article"
            // object, it doesn't have the correct "Title" object.
            // The "Title" object actually points to Special:CreateRedirect,
            // which don't do us any good. Instead, explicitly plug in the
            // correct objects; the objects "Article" and "Title" that we
            // generated earlier. This will center EditPage on the correct article.
            $crEdit->mArticle = $crEditArticle;
            $crEdit->mTitle = $crEditTitle;
            // b. Then import the "form data" (or the FauxRequest object that
            // we just constructed). EditPage now has all the information we
            // generated.
            $crEdit->importFormData($crRequest);
            $permErrors = $crEditTitle->getUserPermissionsErrors('edit', $wgUser);
            // Can this title be created?
            if (!$crEditTitle->exists()) {
                $permErrors = array_merge($permErrors, wfArrayDiff2($crEditTitle->getUserPermissionsErrors('create', $wgUser), $permErrors));
            }
            if ($permErrors) {
                wfDebug(__METHOD__ . ": User can't edit\n");
                $wgOut->addWikiText($crEdit->formatPermissionsErrorMessage($permErrors, 'edit'));
                wfProfileOut(__METHOD__);
                return;
            }
            $resultDetails = false;
            $status = $crEdit->internalAttemptSave($resultDetails, $wgUser->isAllowed('bot') && $wgRequest->getBool('bot', true));
            $value = $status->value;
            if ($value == EditPage::AS_SUCCESS_UPDATE || $value == EditPage::AS_SUCCESS_NEW_ARTICLE) {
                $wgOut->wrapWikiMsg("<div class=\"mw-createredirect-done\">\n\$1</div>", array('createredirect-redirect-done', $crOrigTitle, $crRedirectTitle));
            }
            switch ($value) {
                case EditPage::AS_SPAM_ERROR:
                    $crEdit->spamPageWithContent($resultDetails['spam']);
                    return;
                case EditPage::AS_BLOCKED_PAGE_FOR_USER:
                    $crEdit->blockedPage();
                    return;
                case EditPage::AS_READ_ONLY_PAGE_ANON:
                    $crEdit->userNotLoggedInPage();
                    return;
                case EditPage::AS_READ_ONLY_PAGE_LOGGED:
                case EditPage::AS_READ_ONLY_PAGE:
                    $wgOut->readOnlyPage();
                    return;
                case EditPage::AS_RATE_LIMITED:
                    $wgOut->rateLimited();
                    break;
                case EditPage::AS_NO_CREATE_PERMISSION:
                    $crEdit->noCreatePermission();
                    return;
            }
            $wgOut->mRedirect = '';
            $wgOut->mRedirectCode = '';
            // TODO: Implement error handling (i.e. "Edit conflict!" or "You don't have permissions to edit this page!") --Digi 11/4/07
        }
        $action = htmlspecialchars($this->getTitle()->getLocalURL());
        // Also retrieve "crTitle". If this GET var is found, we autofill the
        // "Redirect to:" field with that text.
        $crTitle = $wgRequest->getText('crRedirectTitle', $wgRequest->getText('crTitle', $par));
        $crTitle = Title::newFromText($crTitle);
        $crTitle = htmlspecialchars(isset($crTitle) ? $crTitle->getPrefixedText() : '');
        $msgPageTitle = wfMsgHtml('createredirect-page-title');
        $msgRedirectTo = wfMsgHtml('createredirect-redirect-to');
        $msgSave = wfMsgHtml('createredirect-save');
        // 2. Start rendering the output! The output is entirely the form.
        // It's all HTML, and may be self-explanatory.
        $wgOut->addHTML(wfMsgHtml('createredirect-instructions'));
        $wgOut->addHTML(<<<END
<form id="redirectform" name="redirectform" method="post" action="{$action}">
<table>
<tr>
<td><label for="crOrigTitle">{$msgPageTitle}</label></td>
<td><input type="text" name="crOrigTitle" id="crOrigTitle" size="60" tabindex="1" /></td>
</tr>
<tr>
<td><label for="crRedirectTitle">{$msgRedirectTo}</label></td>
<td><input type="text" name="crRedirectTitle" id="crRedirectTitle" value="{$crTitle}" size="60" tabindex="2" /></td>
</tr>
<tr>
<td></td>
<td><input type="submit" name="crWrite" id="crWrite" value="{$msgSave}" tabindex="4" /></td>
</tr>
</table>
</form>
END
);
    }
 public function execute()
 {
     global $wgUser;
     $params = $this->extractRequestParams();
     if (is_null($params['title'])) {
         $this->dieUsageMsg(array('missingparam', 'title'));
     }
     if (is_null($params['xpath'])) {
         $this->dieUsage(array('missingparam', 'xpath'));
     }
     $titleObj = Title::newFromText($params['title']);
     if (!$titleObj || $titleObj->isExternal()) {
         $this->dieUsageMsg(array('invalidtitle', $params['title']));
     }
     // Some functions depend on $wgTitle == $ep->mTitle
     global $wgTitle;
     $wgTitle = $titleObj;
     if ($params['nocreate'] && !$titleObj->exists()) {
         $this->dieUsageMsg(array('nocreate-missing'));
     }
     // Now let's check whether we're even allowed to do this
     $errors = $titleObj->getUserPermissionsErrors('edit', $wgUser);
     if (!$titleObj->exists()) {
         $errors = array_merge($errors, $titleObj->getUserPermissionsErrors('create', $wgUser));
     }
     if (count($errors)) {
         $this->dieUsageMsg($errors[0]);
     }
     $articleObj = new Article($titleObj);
     if (!is_null($params['rid'])) {
         $revObj = Revision::newFromID($params['rid']);
         if (is_null($revObj) || $revObj->isDeleted(Revision::DELETED_TEXT)) {
             $this->dieUsageMsg(array('nosuchrevid', $params['rid']));
         }
         if ($revObj->getPage() != $articleObj->getID()) {
             $this->dieUsageMsg(array('revwrongpage', $revObj->getID(), $titleObj->getPrefixedText()));
         }
         if (!$params['force_update'] && !$revObj->isCurrent()) {
             $this->dieUsage("Page revision id is not current '{$titleObj->getPrefixedText()} ({$params['rid']})'", 'revnotcurrent');
         }
     } else {
         $params['rid'] = 0;
     }
     $verb = $params['verb'];
     $xpath = $params['xpath'];
     try {
         $wom = WOMProcessor::getPageObject($titleObj, $params['rid']);
         $obj_ids = WOMProcessor::getObjIdByXPath2($wom, $xpath);
         $obj_id = null;
         foreach ($obj_ids as $id) {
             if ($id != '') {
                 $obj_id = $id;
                 break;
             }
         }
         if ($obj_id == null) {
             throw new MWException(__METHOD__ . ": object does not found, xpath: {$xpath}");
         }
         if ($verb == 'remove') {
             $wom->removePageObject($obj_id);
         } elseif ($verb == 'removeall') {
             foreach ($obj_ids as $id) {
                 if ($id == '') {
                     continue;
                 }
                 $wom->removePageObject($id);
             }
         } else {
             if (is_null($params['text'])) {
                 $this->dieUsageMsg(array('missingparam', 'text'));
             }
             $toMD5 = $params['text'];
             // See if the MD5 hash checks out
             if (!is_null($params['md5']) && md5($toMD5) !== $params['md5']) {
                 $this->dieUsageMsg(array('hashcheckfailed'));
             }
             $text = $params['text'];
             if ($verb == 'insert') {
                 $text = WOMProcessor::getValidText($text, $wom->getObject($obj_id)->getParent(), $wom);
                 // no need to parse or merge object model but use text
                 $wom->insertPageObject(new WOMTextModel($text), $obj_id);
             } elseif ($verb == 'update') {
                 $text = WOMProcessor::getValidText($text, $wom->getObject($obj_id)->getParent(), $wom);
                 $wom->updatePageObject(new WOMTextModel($text), $obj_id);
             } elseif ($verb == 'append') {
                 $parent = $wom->getObject($obj_id);
                 if (!$parent instanceof WikiObjectModelCollection) {
                     throw new MWException(__METHOD__ . ": Object is not a collection object '{$title} ({$revision_id}) - {$obj_id}'");
                 }
                 $text = WOMProcessor::getValidText($text, $parent, $wom);
                 $wom->appendChildObject(new WOMTextModel($text), $obj_id);
             } elseif ($verb == 'attribute') {
                 $obj = $wom->getObject($obj_id);
                 $kv = explode('=', $text, 2);
                 if (count($kv) != 2) {
                     throw new MWException(__METHOD__ . ": value should be 'key=value' in attribute mode");
                 }
                 $obj->setXMLAttribute(trim($kv[0]), trim($kv[1]));
             }
         }
         $ep = new EditPage($articleObj);
         // EditPage wants to parse its stuff from a WebRequest
         // That interface kind of sucks, but it's workable
         $reqArr = array('wpTextbox1' => $wom->getWikiText(), 'wpEditToken' => $params['token'], 'wpIgnoreBlankSummary' => '', 'wpSection' => '');
         if (!is_null($params['summary'])) {
             $reqArr['wpSummary'] = $params['summary'];
         }
         // Watch out for basetimestamp == ''
         // wfTimestamp() treats it as NOW, almost certainly causing an edit conflict
         if (!is_null($params['basetimestamp']) && $params['basetimestamp'] != '') {
             $reqArr['wpEdittime'] = wfTimestamp(TS_MW, $params['basetimestamp']);
         } else {
             $reqArr['wpEdittime'] = $articleObj->getTimestamp();
         }
         if (!is_null($params['starttimestamp']) && $params['starttimestamp'] != '') {
             $reqArr['wpStarttime'] = wfTimestamp(TS_MW, $params['starttimestamp']);
         } else {
             $reqArr['wpStarttime'] = $reqArr['wpEdittime'];
         }
         // Fake wpStartime
         if ($params['minor'] || !$params['notminor'] && $wgUser->getOption('minordefault')) {
             $reqArr['wpMinoredit'] = '';
         }
         // Handle watchlist settings
         switch ($params['watchlist']) {
             case 'watch':
                 $watch = true;
                 break;
             case 'unwatch':
                 $watch = false;
                 break;
             case 'preferences':
                 if ($titleObj->exists()) {
                     $watch = $wgUser->getOption('watchdefault') || $titleObj->userIsWatching();
                 } else {
                     $watch = $wgUser->getOption('watchcreations');
                 }
                 break;
             case 'nochange':
             default:
                 $watch = $titleObj->userIsWatching();
         }
         // Deprecated parameters
         if ($params['watch']) {
             $watch = true;
         } elseif ($params['unwatch']) {
             $watch = false;
         }
         if ($watch) {
             $reqArr['wpWatchthis'] = '';
         }
         $req = new FauxRequest($reqArr, true);
         $ep->importFormData($req);
         // Run hooks
         // Handle CAPTCHA parameters
         global $wgRequest;
         if (!is_null($params['captchaid'])) {
             $wgRequest->setVal('wpCaptchaId', $params['captchaid']);
         }
         if (!is_null($params['captchaword'])) {
             $wgRequest->setVal('wpCaptchaWord', $params['captchaword']);
         }
         $r = array();
         if (!wfRunHooks('APIEditBeforeSave', array($ep, $ep->textbox1, &$r))) {
             if (count($r)) {
                 $r['result'] = "Failure";
                 $this->getResult()->addValue(null, $this->getModuleName(), $r);
                 return;
             } else {
                 $this->dieUsageMsg(array('hookaborted'));
             }
         }
         // Do the actual save
         $oldRevId = $articleObj->getRevIdFetched();
         $result = null;
         // Fake $wgRequest for some hooks inside EditPage
         // FIXME: This interface SUCKS
         $oldRequest = $wgRequest;
         $wgRequest = $req;
         $retval = $ep->internalAttemptSave($result, $wgUser->isAllowed('bot') && $params['bot']);
         $wgRequest = $oldRequest;
         switch ($retval) {
             case EditPage::AS_HOOK_ERROR:
             case EditPage::AS_HOOK_ERROR_EXPECTED:
                 $this->dieUsageMsg(array('hookaborted'));
             case EditPage::AS_IMAGE_REDIRECT_ANON:
                 $this->dieUsageMsg(array('noimageredirect-anon'));
             case EditPage::AS_IMAGE_REDIRECT_LOGGED:
                 $this->dieUsageMsg(array('noimageredirect-logged'));
             case EditPage::AS_SPAM_ERROR:
                 $this->dieUsageMsg(array('spamdetected', $result['spam']));
             case EditPage::AS_FILTERING:
                 $this->dieUsageMsg(array('filtered'));
             case EditPage::AS_BLOCKED_PAGE_FOR_USER:
                 $this->dieUsageMsg(array('blockedtext'));
             case EditPage::AS_MAX_ARTICLE_SIZE_EXCEEDED:
             case EditPage::AS_CONTENT_TOO_BIG:
                 global $wgMaxArticleSize;
                 $this->dieUsageMsg(array('contenttoobig', $wgMaxArticleSize));
             case EditPage::AS_READ_ONLY_PAGE_ANON:
                 $this->dieUsageMsg(array('noedit-anon'));
             case EditPage::AS_READ_ONLY_PAGE_LOGGED:
                 $this->dieUsageMsg(array('noedit'));
             case EditPage::AS_READ_ONLY_PAGE:
                 $this->dieReadOnly();
             case EditPage::AS_RATE_LIMITED:
                 $this->dieUsageMsg(array('actionthrottledtext'));
             case EditPage::AS_ARTICLE_WAS_DELETED:
                 $this->dieUsageMsg(array('wasdeleted'));
             case EditPage::AS_NO_CREATE_PERMISSION:
                 $this->dieUsageMsg(array('nocreate-loggedin'));
             case EditPage::AS_BLANK_ARTICLE:
                 $this->dieUsageMsg(array('blankpage'));
             case EditPage::AS_CONFLICT_DETECTED:
                 $this->dieUsageMsg(array('editconflict'));
                 // case EditPage::AS_SUMMARY_NEEDED: Can't happen since we set wpIgnoreBlankSummary
             // case EditPage::AS_SUMMARY_NEEDED: Can't happen since we set wpIgnoreBlankSummary
             case EditPage::AS_TEXTBOX_EMPTY:
                 $this->dieUsageMsg(array('emptynewsection'));
             case EditPage::AS_SUCCESS_NEW_ARTICLE:
                 $r['new'] = '';
             case EditPage::AS_SUCCESS_UPDATE:
                 $r['result'] = "Success";
                 $r['pageid'] = intval($titleObj->getArticleID());
                 $r['title'] = $titleObj->getPrefixedText();
                 // HACK: We create a new Article object here because getRevIdFetched()
                 // refuses to be run twice, and because Title::getLatestRevId()
                 // won't fetch from the master unless we select for update, which we
                 // don't want to do.
                 $newArticle = new Article($titleObj);
                 $newRevId = $newArticle->getRevIdFetched();
                 if ($newRevId == $oldRevId) {
                     $r['nochange'] = '';
                 } else {
                     $r['oldrevid'] = intval($oldRevId);
                     $r['newrevid'] = intval($newRevId);
                     $r['newtimestamp'] = wfTimestamp(TS_ISO_8601, $newArticle->getTimestamp());
                 }
                 break;
             case EditPage::AS_END:
                 // This usually means some kind of race condition
                 // or DB weirdness occurred. Fall through to throw an unknown
                 // error.
                 // This needs fixing higher up, as Article::doEdit should be
                 // used rather than Article::updateArticle, so that specific
                 // error conditions can be returned
             // This usually means some kind of race condition
             // or DB weirdness occurred. Fall through to throw an unknown
             // error.
             // This needs fixing higher up, as Article::doEdit should be
             // used rather than Article::updateArticle, so that specific
             // error conditions can be returned
             default:
                 $this->dieUsageMsg(array('unknownerror', $retval));
         }
         $this->getResult()->addValue(null, $this->getModuleName(), $r);
     } catch (Exception $e) {
         $this->dieUsage($e->getMessage(), 'WOM error');
     }
 }
Beispiel #14
0
 protected function setupEditPage($targetContent)
 {
     global $wgUser;
     // Find existing target article if it exists, or create a new one.
     $article = new Article(Title::newFromText($this->mOptions['target']));
     $summary = array_key_exists('wpSummary', $this->mOptions) ? $this->mOptions['wpSummary'] : '';
     $startTime = array_key_exists('wpStartTime', $this->mOptions) ? $this->mOptions['wpStarttime'] : wfTimestampNow();
     $editTime = array_key_exists('wpEdittime', $this->mOptions) ? $this->mOptions['wpEdittime'] : '';
     // set up a normal edit page
     // we'll feed it our data to simulate a normal edit
     $editor = new EditPage($article);
     // set up simulated form data
     $data = array('wpTextbox1' => $targetContent, 'wpSummary' => $summary, 'wpStarttime' => $startTime, 'wpEdittime' => $editTime, 'wpEditToken' => $wgUser->isLoggedIn() ? $wgUser->editToken() : EDIT_TOKEN_SUFFIX, 'action' => 'submit');
     // set up a faux request with the simulated data
     $request = new FauxRequest($data, true);
     // and import it into the edit page
     $editor->importFormData($request);
     return $editor;
 }
 /**
  * We need to read the checkbox and the hidden value to know if the
  * visual editor was used or not
  */
 function importFormData(&$request)
 {
     global $wgUser;
     if ($request->wasPosted()) {
         # Reuse values from the previous submission
         $this->noVisualEditor = $request->getVal('wpNoVisualEditor');
         $this->userWantsTraditionalEditor = $request->getCheck('wpWantTraditionalEditor');
     } else {
         # Default values
         $this->noVisualEditor = false;
         $this->userWantsTraditionalEditor = $wgUser->getOption('prefer_traditional_editor');
     }
     return parent::importFormData($request);
 }
Beispiel #16
0
 /**
  * @depends testAutoMerge
  */
 public function testCheckDirectEditingDisallowed_forNonTextContent()
 {
     $title = Title::newFromText('Dummy:NonTextPageForEditPage');
     $page = WikiPage::factory($title);
     $article = new Article($title);
     $article->getContext()->setTitle($title);
     $ep = new EditPage($article);
     $ep->setContextTitle($title);
     $user = $GLOBALS['wgUser'];
     $edit = ['wpTextbox1' => serialize('non-text content'), 'wpEditToken' => $user->getEditToken(), 'wpEdittime' => '', 'wpStarttime' => wfTimestampNow()];
     $req = new FauxRequest($edit, true);
     $ep->importFormData($req);
     $this->setExpectedException('MWException', 'This content model is not supported: testing');
     $ep->internalAttemptSave($result, false);
 }
Beispiel #17
0
 public function execute()
 {
     global $wgVisualEditorNamespaces, $wgVisualEditorParsoidURL, $wgVisualEditorParsoidTimeout, $wgDevelEnvironment;
     $user = $this->getUser();
     $params = $this->extractRequestParams();
     $page = Title::newFromText($params['page']);
     if (!$page) {
         $this->dieUsageMsg('invalidtitle', $params['page']);
     }
     if (!in_array($page->getNamespace(), $wgVisualEditorNamespaces)) {
         $this->dieUsage("VisualEditor is not enabled in namespace " . $page->getNamespace(), 'novenamespace');
     }
     $parserParams = array();
     if (isset($params['oldwt'])) {
         $parserParams['oldwt'] = $params['oldwt'];
     } else {
         if (isset($params['oldid'])) {
             $parserParams['oldid'] = $params['oldid'];
         }
     }
     switch ($params['paction']) {
         case 'parsewt':
             // FIXME: Perhaps requestParsoid method should be used here
             $postData = array('wt' => $params['wikitext']);
             $content = Http::post($wgVisualEditorParsoidURL . '/' . urlencode($this->getApiSource()) . '/' . urlencode($page->getPrefixedDBkey()), array('postData' => $postData, 'timeout' => $wgVisualEditorParsoidTimeout, 'noProxy' => !empty($wgDevelEnvironment)));
             $result = array('result' => 'success', 'content' => $content);
             break;
         case 'parse':
             $parsed = $this->getHTML($page, $parserParams);
             // Dirty hack to provide the correct context for edit notices
             global $wgTitle;
             // FIXME NOOOOOOOOES
             $wgTitle = $page;
             RequestContext::getMain()->setTitle($page);
             // TODO: In MW 1.19.7 method getEditNotices does not exist so for now fallback to just an empty
             // but in future figure out what's the proper backward compatibility solution.
             // #back-compat
             // $notices = $page->getEditNotices();
             $notices = array();
             $anoneditwarning = false;
             $anoneditwarningMessage = $this->msg('VisualEditor-anoneditwarning');
             if ($user->isAnon() && $anoneditwarningMessage->exists()) {
                 $notices[] = $anoneditwarningMessage->parseAsBlock();
                 $anoneditwarning = true;
             }
             if ($parsed && $parsed['restoring']) {
                 $notices[] = $this->msg('editingold')->parseAsBlock();
             }
             // Creating new page
             if (!$page->exists()) {
                 $notices[] = $this->msg($user->isLoggedIn() ? 'newarticletext' : 'newarticletextanon', Skin::makeInternalOrExternalUrl($this->msg('helppage')->inContentLanguage()->text()))->parseAsBlock();
                 // Page protected from creation
                 if ($page->getRestrictions('create')) {
                     $notices[] = $this->msg('titleprotectedwarning')->parseAsBlock();
                 }
             }
             // Look at protection status to set up notices + surface class(es)
             $protectedClasses = array();
             if (MWNamespace::getRestrictionLevels($page->getNamespace()) !== array('')) {
                 // Page protected from editing
                 if ($page->isProtected('edit')) {
                     # Is the title semi-protected?
                     if ($page->isSemiProtected()) {
                         $protectedClasses[] = 'mw-textarea-sprotected';
                         $noticeMsg = 'semiprotectedpagewarning';
                     } else {
                         $protectedClasses[] = 'mw-textarea-protected';
                         # Then it must be protected based on static groups (regular)
                         $noticeMsg = 'protectedpagewarning';
                     }
                     $notices[] = $this->msg($noticeMsg)->parseAsBlock();
                 }
                 // Deal with cascading edit protection
                 list($sources, $restrictions) = $page->getCascadeProtectionSources();
                 if (isset($restrictions['edit'])) {
                     $protectedClasses[] = ' mw-textarea-cprotected';
                     $notice = $this->msg('cascadeprotectedwarning')->parseAsBlock() . '<ul>';
                     // Unfortunately there's no nice way to get only the pages which cause
                     // editing to be restricted
                     foreach ($sources as $source) {
                         $notice .= "<li>" . Linker::link($source) . "</li>";
                     }
                     $notice .= '</ul>';
                     $notices[] = $notice;
                 }
             }
             // Show notice when editing user / user talk page of a user that doesn't exist
             // or who is blocked
             // HACK of course this code is partly duplicated from EditPage.php :(
             if ($page->getNamespace() == NS_USER || $page->getNamespace() == NS_USER_TALK) {
                 $parts = explode('/', $page->getText(), 2);
                 $targetUsername = $parts[0];
                 $targetUser = User::newFromName($targetUsername, false);
                 if (!($targetUser && $targetUser->isLoggedIn()) && !User::isIP($targetUsername)) {
                     // User does not exist
                     $notices[] = "<div class=\"mw-userpage-userdoesnotexist error\">\n" . $this->msg('userpage-userdoesnotexist', wfEscapeWikiText($targetUsername)) . "\n</div>";
                 }
                 // Some upstream code is deleted from here, more information:
                 // https://github.com/Wikia/app/commit/d54b481d3f6e5b092b212a2c98b2cb5452bee26c
                 // https://github.com/Wikia/app/commit/681e7437078206460f7c0cb1837095e656d8ba85
             }
             if (class_exists('GlobalBlocking')) {
                 $error = GlobalBlocking::getUserBlockErrors($user, $this->getRequest()->getIP());
                 if (count($error)) {
                     $notices[] = call_user_func_array(array($this, 'msg'), $error)->parseAsBlock();
                 }
             }
             // HACK: Build a fake EditPage so we can get checkboxes from it
             $article = new Article($page);
             // Deliberately omitting ,0 so oldid comes from request
             $ep = new EditPage($article);
             $req = $this->getRequest();
             $req->setVal('format', 'text/x-wiki');
             $ep->importFormData($req);
             // By reference for some reason (bug 52466)
             $tabindex = 0;
             $states = array('minor' => false, 'watch' => false);
             $checkboxes = $ep->getCheckboxes($tabindex, $states);
             // HACK: Find out which red links are on the page
             // We do the lookup for the current version. This might not be entirely complete
             // if we're loading an oldid, but it'll probably be close enough, and LinkCache
             // will automatically request any additional data it needs.
             $links = array();
             $wikipage = WikiPage::factory($page);
             $popts = $wikipage->makeParserOptions('canonical');
             $cached = ParserCache::singleton()->get($article, $popts, true);
             if ($cached) {
                 foreach ($cached->getLinks() as $ns => $dbks) {
                     foreach ($dbks as $dbk => $id) {
                         $links[Title::makeTitle($ns, $dbk)->getPrefixedText()] = array('missing' => $id == 0);
                     }
                 }
             }
             // On parser cache miss, just don't bother populating red link data
             if ($parsed === false) {
                 $this->dieUsage('Error contacting the Parsoid server', 'parsoidserver');
             } else {
                 $result = array_merge(array('result' => 'success', 'notices' => $notices, 'checkboxes' => $checkboxes, 'links' => $links, 'protectedClasses' => implode(' ', $protectedClasses), 'anoneditwarning' => $anoneditwarning), $parsed['result']);
             }
             break;
         case 'parsefragment':
             $content = $this->parseWikitextFragment($page, $params['wikitext']);
             if ($content === false) {
                 $this->dieUsage('Error contacting the Parsoid server', 'parsoidserver');
             } else {
                 $result = array('result' => 'success', 'content' => $content);
             }
             break;
         case 'serialize':
             if ($params['cachekey'] !== null) {
                 $content = $this->trySerializationCache($params['cachekey']);
                 if (!is_string($content)) {
                     $this->dieUsage('No cached serialization found with that key', 'badcachekey');
                 }
             } else {
                 if ($params['html'] === null) {
                     $this->dieUsageMsg('missingparam', 'html');
                 }
                 $html = $params['html'];
                 $content = $this->postHTML($page, $html, $parserParams);
                 if ($content === false) {
                     $this->dieUsage('Error contacting the Parsoid server', 'parsoidserver');
                 }
             }
             $result = array('result' => 'success', 'content' => $content);
             break;
         case 'diff':
             if ($params['cachekey'] !== null) {
                 $wikitext = $this->trySerializationCache($params['cachekey']);
                 if (!is_string($wikitext)) {
                     $this->dieUsage('No cached serialization found with that key', 'badcachekey');
                 }
             } else {
                 $wikitext = $this->postHTML($page, $params['html'], $parserParams);
                 if ($wikitext === false) {
                     $this->dieUsage('Error contacting the Parsoid server', 'parsoidserver');
                 }
             }
             $diff = $this->diffWikitext($page, $wikitext);
             if ($diff['result'] === 'fail') {
                 $this->dieUsage('Diff failed', 'difffailed');
             }
             $result = $diff;
             break;
         case 'serializeforcache':
             $key = $this->storeInSerializationCache($page, $parserParams['oldid'], $params['html']);
             $result = array('result' => 'success', 'cachekey' => $key);
             break;
         case 'getlanglinks':
             $langlinks = $this->getLangLinks($page);
             if ($langlinks === false) {
                 $this->dieUsage('Error querying MediaWiki API', 'parsoidserver');
             } else {
                 $result = array('result' => 'success', 'langlinks' => $langlinks);
             }
             break;
     }
     $this->getResult()->addValue(null, $this->getModuleName(), $result);
 }
Beispiel #18
0
 public function execute()
 {
     global $wgUser;
     $params = $this->extractRequestParams();
     if (is_null($params['text']) && is_null($params['appendtext']) && is_null($params['prependtext']) && $params['undo'] == 0) {
         $this->dieUsageMsg(array('missingtext'));
     }
     $titleObj = Title::newFromText($params['title']);
     if (!$titleObj || $titleObj->isExternal()) {
         $this->dieUsageMsg(array('invalidtitle', $params['title']));
     }
     if ($params['redirect']) {
         if ($titleObj->isRedirect()) {
             $oldTitle = $titleObj;
             $titles = Title::newFromRedirectArray(Revision::newFromTitle($oldTitle)->getText(Revision::FOR_THIS_USER));
             $redirValues = array();
             foreach ($titles as $id => $newTitle) {
                 if (!isset($titles[$id - 1])) {
                     $titles[$id - 1] = $oldTitle;
                 }
                 $redirValues[] = array('from' => $titles[$id - 1]->getPrefixedText(), 'to' => $newTitle->getPrefixedText());
                 $titleObj = $newTitle;
             }
             $this->getResult()->setIndexedTagName($redirValues, 'r');
             $this->getResult()->addValue(null, 'redirects', $redirValues);
         }
     }
     // Some functions depend on $wgTitle == $ep->mTitle
     global $wgTitle;
     $wgTitle = $titleObj;
     if ($params['createonly'] && $titleObj->exists()) {
         $this->dieUsageMsg(array('createonly-exists'));
     }
     if ($params['nocreate'] && !$titleObj->exists()) {
         $this->dieUsageMsg(array('nocreate-missing'));
     }
     // Now let's check whether we're even allowed to do this
     $errors = $titleObj->getUserPermissionsErrors('edit', $wgUser);
     if (!$titleObj->exists()) {
         $errors = array_merge($errors, $titleObj->getUserPermissionsErrors('create', $wgUser));
     }
     if (count($errors)) {
         $this->dieUsageMsg($errors[0]);
     }
     $articleObj = new Article($titleObj);
     $toMD5 = $params['text'];
     if (!is_null($params['appendtext']) || !is_null($params['prependtext'])) {
         // For non-existent pages, Article::getContent()
         // returns an interface message rather than ''
         // We do want getContent()'s behavior for non-existent
         // MediaWiki: pages, though
         if ($articleObj->getID() == 0 && $titleObj->getNamespace() != NS_MEDIAWIKI) {
             $content = '';
         } else {
             $content = $articleObj->getContent();
         }
         if (!is_null($params['section'])) {
             // Process the content for section edits
             global $wgParser;
             $section = intval($params['section']);
             $content = $wgParser->getSection($content, $section, false);
             if ($content === false) {
                 $this->dieUsage("There is no section {$section}.", 'nosuchsection');
             }
         }
         $params['text'] = $params['prependtext'] . $content . $params['appendtext'];
         $toMD5 = $params['prependtext'] . $params['appendtext'];
     }
     if ($params['undo'] > 0) {
         if ($params['undoafter'] > 0) {
             if ($params['undo'] < $params['undoafter']) {
                 list($params['undo'], $params['undoafter']) = array($params['undoafter'], $params['undo']);
             }
             $undoafterRev = Revision::newFromID($params['undoafter']);
         }
         $undoRev = Revision::newFromID($params['undo']);
         if (is_null($undoRev) || $undoRev->isDeleted(Revision::DELETED_TEXT)) {
             $this->dieUsageMsg(array('nosuchrevid', $params['undo']));
         }
         if ($params['undoafter'] == 0) {
             $undoafterRev = $undoRev->getPrevious();
         }
         if (is_null($undoafterRev) || $undoafterRev->isDeleted(Revision::DELETED_TEXT)) {
             $this->dieUsageMsg(array('nosuchrevid', $params['undoafter']));
         }
         if ($undoRev->getPage() != $articleObj->getID()) {
             $this->dieUsageMsg(array('revwrongpage', $undoRev->getID(), $titleObj->getPrefixedText()));
         }
         if ($undoafterRev->getPage() != $articleObj->getID()) {
             $this->dieUsageMsg(array('revwrongpage', $undoafterRev->getID(), $titleObj->getPrefixedText()));
         }
         $newtext = $articleObj->getUndoText($undoRev, $undoafterRev);
         if ($newtext === false) {
             $this->dieUsageMsg(array('undo-failure'));
         }
         $params['text'] = $newtext;
         // If no summary was given and we only undid one rev,
         // use an autosummary
         if (is_null($params['summary']) && $titleObj->getNextRevisionID($undoafterRev->getID()) == $params['undo']) {
             $params['summary'] = wfMsgForContent('undo-summary', $params['undo'], $undoRev->getUserText());
         }
     }
     // See if the MD5 hash checks out
     if (!is_null($params['md5']) && md5($toMD5) !== $params['md5']) {
         $this->dieUsageMsg(array('hashcheckfailed'));
     }
     $ep = new EditPage($articleObj);
     // EditPage wants to parse its stuff from a WebRequest
     // That interface kind of sucks, but it's workable
     $reqArr = array('wpTextbox1' => $params['text'], 'wpEditToken' => $params['token'], 'wpIgnoreBlankSummary' => '');
     if (!is_null($params['summary'])) {
         $reqArr['wpSummary'] = $params['summary'];
     }
     // Watch out for basetimestamp == ''
     // wfTimestamp() treats it as NOW, almost certainly causing an edit conflict
     if (!is_null($params['basetimestamp']) && $params['basetimestamp'] != '') {
         $reqArr['wpEdittime'] = wfTimestamp(TS_MW, $params['basetimestamp']);
     } else {
         $reqArr['wpEdittime'] = $articleObj->getTimestamp();
     }
     if (!is_null($params['starttimestamp']) && $params['starttimestamp'] != '') {
         $reqArr['wpStarttime'] = wfTimestamp(TS_MW, $params['starttimestamp']);
     } else {
         $reqArr['wpStarttime'] = wfTimestampNow();
         // Fake wpStartime
     }
     if ($params['minor'] || !$params['notminor'] && $wgUser->getOption('minordefault')) {
         $reqArr['wpMinoredit'] = '';
     }
     if ($params['recreate']) {
         $reqArr['wpRecreate'] = '';
     }
     if (!is_null($params['section'])) {
         $section = intval($params['section']);
         if ($section == 0 && $params['section'] != '0' && $params['section'] != 'new') {
             $this->dieUsage("The section parameter must be set to an integer or 'new'", "invalidsection");
         }
         $reqArr['wpSection'] = $params['section'];
     } else {
         $reqArr['wpSection'] = '';
     }
     $watch = $this->getWatchlistValue($params['watchlist'], $titleObj);
     // Deprecated parameters
     if ($params['watch']) {
         $watch = true;
     } elseif ($params['unwatch']) {
         $watch = false;
     }
     if ($watch) {
         $reqArr['wpWatchthis'] = '';
     }
     $req = new FauxRequest($reqArr, true);
     $ep->importFormData($req);
     // Run hooks
     // Handle CAPTCHA parameters
     global $wgRequest;
     if (!is_null($params['captchaid'])) {
         $wgRequest->setVal('wpCaptchaId', $params['captchaid']);
     }
     if (!is_null($params['captchaword'])) {
         $wgRequest->setVal('wpCaptchaWord', $params['captchaword']);
     }
     $r = array();
     if (!wfRunHooks('APIEditBeforeSave', array($ep, $ep->textbox1, &$r))) {
         if (count($r)) {
             $r['result'] = 'Failure';
             $this->getResult()->addValue(null, $this->getModuleName(), $r);
             return;
         } else {
             $this->dieUsageMsg(array('hookaborted'));
         }
     }
     // Do the actual save
     $oldRevId = $articleObj->getRevIdFetched();
     $result = null;
     // Fake $wgRequest for some hooks inside EditPage
     // FIXME: This interface SUCKS
     $oldRequest = $wgRequest;
     $wgRequest = $req;
     $retval = $ep->internalAttemptSave($result, $wgUser->isAllowed('bot') && $params['bot']);
     $wgRequest = $oldRequest;
     global $wgMaxArticleSize;
     switch ($retval) {
         case EditPage::AS_HOOK_ERROR:
         case EditPage::AS_HOOK_ERROR_EXPECTED:
             $this->dieUsageMsg(array('hookaborted'));
         case EditPage::AS_IMAGE_REDIRECT_ANON:
             $this->dieUsageMsg(array('noimageredirect-anon'));
         case EditPage::AS_IMAGE_REDIRECT_LOGGED:
             $this->dieUsageMsg(array('noimageredirect-logged'));
         case EditPage::AS_SPAM_ERROR:
             $this->dieUsageMsg(array('spamdetected', $result['spam']));
         case EditPage::AS_FILTERING:
             $this->dieUsageMsg(array('filtered'));
         case EditPage::AS_BLOCKED_PAGE_FOR_USER:
             $this->dieUsageMsg(array('blockedtext'));
         case EditPage::AS_MAX_ARTICLE_SIZE_EXCEEDED:
         case EditPage::AS_CONTENT_TOO_BIG:
             $this->dieUsageMsg(array('contenttoobig', $wgMaxArticleSize));
         case EditPage::AS_READ_ONLY_PAGE_ANON:
             $this->dieUsageMsg(array('noedit-anon'));
         case EditPage::AS_READ_ONLY_PAGE_LOGGED:
             $this->dieUsageMsg(array('noedit'));
         case EditPage::AS_READ_ONLY_PAGE:
             $this->dieReadOnly();
         case EditPage::AS_RATE_LIMITED:
             $this->dieUsageMsg(array('actionthrottledtext'));
         case EditPage::AS_ARTICLE_WAS_DELETED:
             $this->dieUsageMsg(array('wasdeleted'));
         case EditPage::AS_NO_CREATE_PERMISSION:
             $this->dieUsageMsg(array('nocreate-loggedin'));
         case EditPage::AS_BLANK_ARTICLE:
             $this->dieUsageMsg(array('blankpage'));
         case EditPage::AS_CONFLICT_DETECTED:
             $this->dieUsageMsg(array('editconflict'));
             // case EditPage::AS_SUMMARY_NEEDED: Can't happen since we set wpIgnoreBlankSummary
         // case EditPage::AS_SUMMARY_NEEDED: Can't happen since we set wpIgnoreBlankSummary
         case EditPage::AS_TEXTBOX_EMPTY:
             $this->dieUsageMsg(array('emptynewsection'));
         case EditPage::AS_SUCCESS_NEW_ARTICLE:
             $r['new'] = '';
         case EditPage::AS_SUCCESS_UPDATE:
             $r['result'] = 'Success';
             $r['pageid'] = intval($titleObj->getArticleID());
             $r['title'] = $titleObj->getPrefixedText();
             // HACK: We create a new Article object here because getRevIdFetched()
             // refuses to be run twice, and because Title::getLatestRevId()
             // won't fetch from the master unless we select for update, which we
             // don't want to do.
             $newArticle = new Article($titleObj);
             $newRevId = $newArticle->getRevIdFetched();
             if ($newRevId == $oldRevId) {
                 $r['nochange'] = '';
             } else {
                 $r['oldrevid'] = intval($oldRevId);
                 $r['newrevid'] = intval($newRevId);
                 $r['newtimestamp'] = wfTimestamp(TS_ISO_8601, $newArticle->getTimestamp());
             }
             break;
         case EditPage::AS_SUMMARY_NEEDED:
             $this->dieUsageMsg(array('summaryrequired'));
         case EditPage::AS_END:
             // This usually means some kind of race condition
             // or DB weirdness occurred. Fall through to throw an unknown
             // error.
             // This needs fixing higher up, as Article::doEdit should be
             // used rather than Article::updateArticle, so that specific
             // error conditions can be returned
         // This usually means some kind of race condition
         // or DB weirdness occurred. Fall through to throw an unknown
         // error.
         // This needs fixing higher up, as Article::doEdit should be
         // used rather than Article::updateArticle, so that specific
         // error conditions can be returned
         default:
             $this->dieUsageMsg(array('unknownerror', $retval));
     }
     $this->getResult()->addValue(null, $this->getModuleName(), $r);
 }
 function importFormData(&$request)
 {
     # These fields need to be checked for encoding.
     # Also remove trailing whitespace, but don't remove _initial_
     # whitespace from the text boxes. This may be significant formatting.
     EditPage::importFormData($request);
 }
 protected function setupEditPage($targetContent)
 {
     // Find existing target article if it exists, or create a new one.
     $targetTitle = Title::newFromText($this->mOptions['target']);
     // if the specified target title is invalid, give up
     if (!$targetTitle instanceof Title) {
         throw new MWException(wfMessage('sf_autoedit_invalidtargetspecified', $this->mOptions['target'])->parse());
     }
     $article = new Article($targetTitle);
     // set up a normal edit page
     // we'll feed it our data to simulate a normal edit
     $editor = new EditPage($article);
     // set up form data:
     // merge data coming from the web request on top of some defaults
     $data = array_merge(array('wpTextbox1' => $targetContent, 'wpSummary' => '', 'wpStarttime' => wfTimestampNow(), 'wpEdittime' => '', 'wpEditToken' => isset($this->mOptions['token']) ? $this->mOptions['token'] : $this->getUser()->getEditToken(), 'action' => 'submit'), $this->mOptions);
     if (array_key_exists('format', $data)) {
         unset($data['format']);
     }
     // set up a faux request with the simulated data
     $request = new FauxRequest($data, true);
     // and import it into the edit page
     $editor->importFormData($request);
     $editor->sfFauxRequest = $request;
     return $editor;
 }
Beispiel #21
0
 public function execute()
 {
     global $wgUser;
     $this->getMain()->requestWriteMode();
     $params = $this->extractRequestParams();
     if (is_null($params['title'])) {
         $this->dieUsageMsg(array('missingparam', 'title'));
     }
     if (is_null($params['text']) && is_null($params['appendtext']) && is_null($params['prependtext'])) {
         $this->dieUsageMsg(array('missingtext'));
     }
     if (is_null($params['token'])) {
         $this->dieUsageMsg(array('missingparam', 'token'));
     }
     if (!$wgUser->matchEditToken($params['token'])) {
         $this->dieUsageMsg(array('sessionfailure'));
     }
     $titleObj = Title::newFromText($params['title']);
     if (!$titleObj) {
         $this->dieUsageMsg(array('invalidtitle', $params['title']));
     }
     if ($params['createonly'] && $titleObj->exists()) {
         $this->dieUsageMsg(array('createonly-exists'));
     }
     if ($params['nocreate'] && !$titleObj->exists()) {
         $this->dieUsageMsg(array('nocreate-missing'));
     }
     // Now let's check whether we're even allowed to do this
     $errors = $titleObj->getUserPermissionsErrors('edit', $wgUser);
     if (!$titleObj->exists()) {
         $errors = array_merge($errors, $titleObj->getUserPermissionsErrors('create', $wgUser));
     }
     if (count($errors)) {
         $this->dieUsageMsg($errors[0]);
     }
     $articleObj = new Article($titleObj);
     $toMD5 = $params['text'];
     if (!is_null($params['appendtext']) || !is_null($params['prependtext'])) {
         $content = $articleObj->getContent();
         $params['text'] = $params['prependtext'] . $content . $params['appendtext'];
         $toMD5 = $params['prependtext'] . $params['appendtext'];
     }
     # See if the MD5 hash checks out
     if (isset($params['md5'])) {
         if (md5($toMD5) !== $params['md5']) {
             $this->dieUsageMsg(array('hashcheckfailed'));
         }
     }
     $ep = new EditPage($articleObj);
     // EditPage wants to parse its stuff from a WebRequest
     // That interface kind of sucks, but it's workable
     $reqArr = array('wpTextbox1' => $params['text'], 'wpEdittoken' => $params['token'], 'wpIgnoreBlankSummary' => '');
     if (!is_null($params['summary'])) {
         $reqArr['wpSummary'] = $params['summary'];
     }
     # Watch out for basetimestamp == ''
     # wfTimestamp() treats it as NOW, almost certainly causing an edit conflict
     if (!is_null($params['basetimestamp']) && $params['basetimestamp'] != '') {
         $reqArr['wpEdittime'] = wfTimestamp(TS_MW, $params['basetimestamp']);
     } else {
         $reqArr['wpEdittime'] = $articleObj->getTimestamp();
     }
     if (!is_null($params['starttimestamp']) && $params['starttimestamp'] != '') {
         $reqArr['wpStarttime'] = wfTimestamp(TS_MW, $params['starttimestamp']);
     } else {
         # Fake wpStartime
         $reqArr['wpStarttime'] = $reqArr['wpEdittime'];
     }
     if ($params['minor'] || !$params['notminor'] && $wgUser->getOption('minordefault')) {
         $reqArr['wpMinoredit'] = '';
     }
     if ($params['recreate']) {
         $reqArr['wpRecreate'] = '';
     }
     if (!is_null($params['section'])) {
         $section = intval($params['section']);
         if ($section == 0 && $params['section'] != '0' && $params['section'] != 'new') {
             $this->dieUsage("The section parameter must be set to an integer or 'new'", "invalidsection");
         }
         $reqArr['wpSection'] = $params['section'];
     } else {
         $reqArr['wpSection'] = '';
     }
     if ($params['watch']) {
         $watch = true;
     } else {
         if ($params['unwatch']) {
             $watch = false;
         } else {
             if ($titleObj->userIsWatching()) {
                 $watch = true;
             } else {
                 if ($wgUser->getOption('watchdefault')) {
                     $watch = true;
                 } else {
                     if ($wgUser->getOption('watchcreations') && !$titleObj->exists()) {
                         $watch = true;
                     } else {
                         $watch = false;
                     }
                 }
             }
         }
     }
     if ($watch) {
         $reqArr['wpWatchthis'] = '';
     }
     $req = new FauxRequest($reqArr, true);
     $ep->importFormData($req);
     # Run hooks
     # Handle CAPTCHA parameters
     global $wgRequest;
     if (isset($params['captchaid'])) {
         $wgRequest->setVal('wpCaptchaId', $params['captchaid']);
     }
     if (isset($params['captchaword'])) {
         $wgRequest->setVal('wpCaptchaWord', $params['captchaword']);
     }
     $r = array();
     if (!wfRunHooks('APIEditBeforeSave', array(&$ep, $ep->textbox1, &$r))) {
         if (count($r)) {
             $r['result'] = "Failure";
             $this->getResult()->addValue(null, $this->getModuleName(), $r);
             return;
         } else {
             $this->dieUsageMsg(array('hookaborted'));
         }
     }
     # Do the actual save
     $oldRevId = $articleObj->getRevIdFetched();
     $result = null;
     # *Something* is setting $wgTitle to a title corresponding to "Msg",
     # but that breaks API mode detection through is_null($wgTitle)
     global $wgTitle;
     $wgTitle = null;
     # Fake $wgRequest for some hooks inside EditPage
     # FIXME: This interface SUCKS
     $oldRequest = $wgRequest;
     $wgRequest = $req;
     $retval = $ep->internalAttemptSave($result, $wgUser->isAllowed('bot') && $params['bot']);
     $wgRequest = $oldRequest;
     switch ($retval) {
         case EditPage::AS_HOOK_ERROR:
         case EditPage::AS_HOOK_ERROR_EXPECTED:
             $this->dieUsageMsg(array('hookaborted'));
         case EditPage::AS_IMAGE_REDIRECT_ANON:
             $this->dieUsageMsg(array('noimageredirect-anon'));
         case EditPage::AS_IMAGE_REDIRECT_LOGGED:
             $this->dieUsageMsg(array('noimageredirect-logged'));
         case EditPage::AS_SPAM_ERROR:
             $this->dieUsageMsg(array('spamdetected', $result['spam']));
         case EditPage::AS_FILTERING:
             $this->dieUsageMsg(array('filtered'));
         case EditPage::AS_BLOCKED_PAGE_FOR_USER:
             $this->dieUsageMsg(array('blockedtext'));
         case EditPage::AS_MAX_ARTICLE_SIZE_EXCEEDED:
         case EditPage::AS_CONTENT_TOO_BIG:
             global $wgMaxArticleSize;
             $this->dieUsageMsg(array('contenttoobig', $wgMaxArticleSize));
         case EditPage::AS_READ_ONLY_PAGE_ANON:
             $this->dieUsageMsg(array('noedit-anon'));
         case EditPage::AS_READ_ONLY_PAGE_LOGGED:
             $this->dieUsageMsg(array('noedit'));
         case EditPage::AS_READ_ONLY_PAGE:
             $this->dieUsageMsg(array('readonlytext'));
         case EditPage::AS_RATE_LIMITED:
             $this->dieUsageMsg(array('actionthrottledtext'));
         case EditPage::AS_ARTICLE_WAS_DELETED:
             $this->dieUsageMsg(array('wasdeleted'));
         case EditPage::AS_NO_CREATE_PERMISSION:
             $this->dieUsageMsg(array('nocreate-loggedin'));
         case EditPage::AS_BLANK_ARTICLE:
             $this->dieUsageMsg(array('blankpage'));
         case EditPage::AS_CONFLICT_DETECTED:
             $this->dieUsageMsg(array('editconflict'));
             #case EditPage::AS_SUMMARY_NEEDED: Can't happen since we set wpIgnoreBlankSummary
         #case EditPage::AS_SUMMARY_NEEDED: Can't happen since we set wpIgnoreBlankSummary
         case EditPage::AS_TEXTBOX_EMPTY:
             $this->dieUsageMsg(array('emptynewsection'));
         case EditPage::AS_END:
             # This usually means some kind of race condition
             # or DB weirdness occurred. Throw an unknown error here.
             $this->dieUsageMsg(array('unknownerror'));
         case EditPage::AS_SUCCESS_NEW_ARTICLE:
             $r['new'] = '';
         case EditPage::AS_SUCCESS_UPDATE:
             $r['result'] = "Success";
             $r['pageid'] = $titleObj->getArticleID();
             $r['title'] = $titleObj->getPrefixedText();
             # HACK: We create a new Article object here because getRevIdFetched()
             # refuses to be run twice, and because Title::getLatestRevId()
             # won't fetch from the master unless we select for update, which we
             # don't want to do.
             $newArticle = new Article($titleObj);
             $newRevId = $newArticle->getRevIdFetched();
             if ($newRevId == $oldRevId) {
                 $r['nochange'] = '';
             } else {
                 $r['oldrevid'] = $oldRevId;
                 $r['newrevid'] = $newRevId;
             }
             break;
         default:
             $this->dieUsageMsg(array('unknownerror', $retval));
     }
     $this->getResult()->addValue(null, $this->getModuleName(), $r);
 }