public static function provideHandlers()
 {
     $models = ContentHandler::getContentModels();
     $handlers = [];
     foreach ($models as $model) {
         $handlers[] = [ContentHandler::getForModelID($model)];
     }
     return $handlers;
 }
Esempio n. 2
0
 /**
  * Show an edit conflict. textbox1 is already shown in showEditForm().
  * If you want to use another entry point to this function, be careful.
  */
 protected function showConflict()
 {
     global $wgOut;
     if (wfRunHooks('EditPageBeforeConflictDiff', array(&$this, &$wgOut))) {
         $wgOut->wrapWikiMsg('<h2>$1</h2>', "yourdiff");
         $content1 = $this->toEditContent($this->textbox1);
         $content2 = $this->toEditContent($this->textbox2);
         $handler = ContentHandler::getForModelID($this->contentModel);
         $de = $handler->createDifferenceEngine($this->mArticle->getContext());
         $de->setContent($content2, $content1);
         $de->showDiff(wfMessage('yourtext')->parse(), wfMessage('storedversion')->text());
         $wgOut->wrapWikiMsg('<h2>$1</h2>', "yourtext");
         $this->showTextbox2();
     }
 }
Esempio n. 3
0
 public function execute()
 {
     $user = $this->getUser();
     $params = $this->extractRequestParams();
     if ($user->isBot()) {
         // sanity
         $this->dieUsage('This interface is not supported for bots', 'botsnotsupported');
     }
     $cache = ObjectCache::getLocalClusterInstance();
     $page = $this->getTitleOrPageId($params);
     $title = $page->getTitle();
     if (!ContentHandler::getForModelID($params['contentmodel'])->isSupportedFormat($params['contentformat'])) {
         $this->dieUsage('Unsupported content model/format', 'badmodelformat');
     }
     $text = null;
     $textHash = null;
     if (strlen($params['stashedtexthash'])) {
         // Load from cache since the client indicates the text is the same as last stash
         $textHash = $params['stashedtexthash'];
         $textKey = $cache->makeKey('stashedit', 'text', $textHash);
         $text = $cache->get($textKey);
         if (!is_string($text)) {
             $this->dieUsage('No stashed text found with the given hash', 'missingtext');
         }
     } elseif ($params['text'] !== null) {
         // Trim and fix newlines so the key SHA1's match (see WebRequest::getText())
         $text = rtrim(str_replace("\r\n", "\n", $params['text']));
         $textHash = sha1($text);
     } else {
         $this->dieUsage('The text or stashedtexthash parameter must be given', 'missingtextparam');
     }
     $textContent = ContentHandler::makeContent($text, $title, $params['contentmodel'], $params['contentformat']);
     $page = WikiPage::factory($title);
     if ($page->exists()) {
         // Page exists: get the merged content with the proposed change
         $baseRev = Revision::newFromPageId($page->getId(), $params['baserevid']);
         if (!$baseRev) {
             $this->dieUsage("No revision ID {$params['baserevid']}", 'missingrev');
         }
         $currentRev = $page->getRevision();
         if (!$currentRev) {
             $this->dieUsage("No current revision of page ID {$page->getId()}", 'missingrev');
         }
         // Merge in the new version of the section to get the proposed version
         $editContent = $page->replaceSectionAtRev($params['section'], $textContent, $params['sectiontitle'], $baseRev->getId());
         if (!$editContent) {
             $this->dieUsage('Could not merge updated section.', 'replacefailed');
         }
         if ($currentRev->getId() == $baseRev->getId()) {
             // Base revision was still the latest; nothing to merge
             $content = $editContent;
         } else {
             // Merge the edit into the current version
             $baseContent = $baseRev->getContent();
             $currentContent = $currentRev->getContent();
             if (!$baseContent || !$currentContent) {
                 $this->dieUsage("Missing content for page ID {$page->getId()}", 'missingrev');
             }
             $handler = ContentHandler::getForModelID($baseContent->getModel());
             $content = $handler->merge3($baseContent, $editContent, $currentContent);
         }
     } else {
         // New pages: use the user-provided content model
         $content = $textContent;
     }
     if (!$content) {
         // merge3() failed
         $this->getResult()->addValue(null, $this->getModuleName(), ['status' => 'editconflict']);
         return;
     }
     // The user will abort the AJAX request by pressing "save", so ignore that
     ignore_user_abort(true);
     if ($user->pingLimiter('stashedit')) {
         $status = 'ratelimited';
     } else {
         $status = self::parseAndStash($page, $content, $user, $params['summary']);
         $textKey = $cache->makeKey('stashedit', 'text', $textHash);
         $cache->set($textKey, $text, self::MAX_CACHE_TTL);
     }
     $stats = MediaWikiServices::getInstance()->getStatsdDataFactory();
     $stats->increment("editstash.cache_stores.{$status}");
     $this->getResult()->addValue(null, $this->getModuleName(), ['status' => $status, 'texthash' => $textHash]);
 }
Esempio n. 4
0
 /**
  * @return ContentHandler
  */
 function getContentHandler()
 {
     if (is_null($this->contentHandler)) {
         $this->contentHandler = ContentHandler::getForModelID($this->getModel());
     }
     return $this->contentHandler;
 }
 public function execute()
 {
     $out = $this->mSpecial->getOutput();
     $out->addModuleStyles('mediawiki.action.history.diff');
     $dbr = wfGetDB(DB_SLAVE);
     $row = $dbr->selectRow('moderation', array('mod_user AS user', 'mod_user_text AS user_text', 'mod_last_oldid AS last_oldid', 'mod_cur_id AS cur_id', 'mod_namespace AS namespace', 'mod_title AS title', 'mod_text AS text', 'mod_stash_key AS stash_key'), array('mod_id' => $this->id), __METHOD__);
     if (!$row) {
         throw new ModerationError('moderation-edit-not-found');
     }
     $title = Title::makeTitle($row->namespace, $row->title);
     $model = $title->getContentModel();
     $out->setPageTitle(wfMessage('difference-title', $title->getPrefixedText()));
     $old_content = false;
     if ($row->cur_id != 0) {
         # Existing page
         $rev = Revision::newFromId($row->last_oldid);
         if ($rev) {
             $old_content = $rev->getContent(Revision::RAW);
             $model = $old_content->getModel();
         }
     }
     if (!$old_content) {
         # New or previously deleted page
         $old_content = ContentHandler::makeContent("", null, $model);
     }
     if ($row->stash_key) {
         $url_params = array('modaction' => 'showimg', 'modid' => $this->id);
         $url_full = $this->mSpecial->getTitle()->getLinkURL($url_params);
         # Check if this file is not an image (e.g. OGG file)
         $is_image = 1;
         $user = $row->user ? User::newFromId($row->user) : User::newFromName($row->user_text, false);
         $stash = RepoGroup::singleton()->getLocalRepo()->getUploadStash($user);
         try {
             $meta = $stash->getMetadata($row->stash_key);
             if ($meta['us_media_type'] != 'BITMAP' && $meta['us_media_type'] != 'DRAWING') {
                 $is_image = 0;
             }
         } catch (MWException $e) {
             # If we can't find it, thumbnail won't work either
             $is_image = 0;
         }
         if ($is_image) {
             $url_params['thumb'] = 1;
             $url_thumb = $this->mSpecial->getTitle()->getLinkURL($url_params);
             $html_img = Xml::element('img', array('src' => $url_thumb));
         } else {
             # Not an image, so no thumbnail is needed.
             # Just print a filename.
             $html_img = $title->getFullText();
         }
         $html_a = Xml::tags('a', array('href' => $url_full), $html_img);
         $out->addHTML($html_a);
     }
     $de = ContentHandler::getForModelID($model)->createDifferenceEngine($this->mSpecial->getContext(), $row->last_oldid, 0, 0, 0, 0);
     $diff = '';
     if (!$row->stash_key || !$title->exists()) {
         $new_content = ContentHandler::makeContent($row->text, null, $model);
         $diff = $de->generateContentDiffBody($old_content, $new_content);
     }
     if ($diff) {
         // TODO: add more information into headers (username, timestamp etc.), as in usual diffs
         $header_before = wfMessage('moderation-diff-header-before')->text();
         $header_after = wfMessage('moderation-diff-header-after')->text();
         $out->addHTML($de->addHeader($diff, $header_before, $header_after));
     } else {
         $out->addWikiMsg($row->stash_key ? $title->exists() ? 'moderation-diff-reupload' : 'moderation-diff-upload-notext' : 'moderation-diff-no-changes');
     }
 }
 /**
  * Extract information from the Revision
  *
  * @param Revision $revision
  * @param object $row Should have a field 'ts_tags' if $this->fld_tags is set
  * @return array
  */
 protected function extractRevisionInfo(Revision $revision, $row)
 {
     $title = $revision->getTitle();
     $user = $this->getUser();
     $vals = array();
     $anyHidden = false;
     if ($this->fld_ids) {
         $vals['revid'] = intval($revision->getId());
         if (!is_null($revision->getParentId())) {
             $vals['parentid'] = intval($revision->getParentId());
         }
     }
     if ($this->fld_flags) {
         $vals['minor'] = $revision->isMinor();
     }
     if ($this->fld_user || $this->fld_userid) {
         if ($revision->isDeleted(Revision::DELETED_USER)) {
             $vals['userhidden'] = true;
             $anyHidden = true;
         }
         if ($revision->userCan(Revision::DELETED_USER, $user)) {
             if ($this->fld_user) {
                 $vals['user'] = $revision->getUserText(Revision::RAW);
             }
             $userid = $revision->getUser(Revision::RAW);
             if (!$userid) {
                 $vals['anon'] = true;
             }
             if ($this->fld_userid) {
                 $vals['userid'] = $userid;
             }
         }
     }
     if ($this->fld_timestamp) {
         $vals['timestamp'] = wfTimestamp(TS_ISO_8601, $revision->getTimestamp());
     }
     if ($this->fld_size) {
         if (!is_null($revision->getSize())) {
             $vals['size'] = intval($revision->getSize());
         } else {
             $vals['size'] = 0;
         }
     }
     if ($this->fld_sha1) {
         if ($revision->isDeleted(Revision::DELETED_TEXT)) {
             $vals['sha1hidden'] = true;
             $anyHidden = true;
         }
         if ($revision->userCan(Revision::DELETED_TEXT, $user)) {
             if ($revision->getSha1() != '') {
                 $vals['sha1'] = wfBaseConvert($revision->getSha1(), 36, 16, 40);
             } else {
                 $vals['sha1'] = '';
             }
         }
     }
     if ($this->fld_contentmodel) {
         $vals['contentmodel'] = $revision->getContentModel();
     }
     if ($this->fld_comment || $this->fld_parsedcomment) {
         if ($revision->isDeleted(Revision::DELETED_COMMENT)) {
             $vals['commenthidden'] = true;
             $anyHidden = true;
         }
         if ($revision->userCan(Revision::DELETED_COMMENT, $user)) {
             $comment = $revision->getComment(Revision::RAW);
             if ($this->fld_comment) {
                 $vals['comment'] = $comment;
             }
             if ($this->fld_parsedcomment) {
                 $vals['parsedcomment'] = Linker::formatComment($comment, $title);
             }
         }
     }
     if ($this->fld_tags) {
         if ($row->ts_tags) {
             $tags = explode(',', $row->ts_tags);
             ApiResult::setIndexedTagName($tags, 'tag');
             $vals['tags'] = $tags;
         } else {
             $vals['tags'] = array();
         }
     }
     $content = null;
     global $wgParser;
     if ($this->fetchContent) {
         $content = $revision->getContent(Revision::FOR_THIS_USER, $this->getUser());
         // Expand templates after getting section content because
         // template-added sections don't count and Parser::preprocess()
         // will have less input
         if ($content && $this->section !== false) {
             $content = $content->getSection($this->section, false);
             if (!$content) {
                 $this->dieUsage("There is no section {$this->section} in r" . $revision->getId(), 'nosuchsection');
             }
         }
         if ($revision->isDeleted(Revision::DELETED_TEXT)) {
             $vals['texthidden'] = true;
             $anyHidden = true;
         } elseif (!$content) {
             $vals['textmissing'] = true;
         }
     }
     if ($this->fld_content && $content) {
         $text = null;
         if ($this->generateXML) {
             if ($content->getModel() === CONTENT_MODEL_WIKITEXT) {
                 $t = $content->getNativeData();
                 # note: don't set $text
                 $wgParser->startExternalParse($title, ParserOptions::newFromContext($this->getContext()), Parser::OT_PREPROCESS);
                 $dom = $wgParser->preprocessToDom($t);
                 if (is_callable(array($dom, 'saveXML'))) {
                     $xml = $dom->saveXML();
                 } else {
                     $xml = $dom->__toString();
                 }
                 $vals['parsetree'] = $xml;
             } else {
                 $vals['badcontentformatforparsetree'] = true;
                 $this->setWarning("Conversion to XML is supported for wikitext only, " . $title->getPrefixedDBkey() . " uses content model " . $content->getModel());
             }
         }
         if ($this->expandTemplates && !$this->parseContent) {
             #XXX: implement template expansion for all content types in ContentHandler?
             if ($content->getModel() === CONTENT_MODEL_WIKITEXT) {
                 $text = $content->getNativeData();
                 $text = $wgParser->preprocess($text, $title, ParserOptions::newFromContext($this->getContext()));
             } else {
                 $this->setWarning("Template expansion is supported for wikitext only, " . $title->getPrefixedDBkey() . " uses content model " . $content->getModel());
                 $vals['badcontentformat'] = true;
                 $text = false;
             }
         }
         if ($this->parseContent) {
             $po = $content->getParserOutput($title, $revision->getId(), ParserOptions::newFromContext($this->getContext()));
             $text = $po->getText();
         }
         if ($text === null) {
             $format = $this->contentFormat ? $this->contentFormat : $content->getDefaultFormat();
             $model = $content->getModel();
             if (!$content->isSupportedFormat($format)) {
                 $name = $title->getPrefixedDBkey();
                 $this->setWarning("The requested format {$this->contentFormat} is not " . "supported for content model {$model} used by {$name}");
                 $vals['badcontentformat'] = true;
                 $text = false;
             } else {
                 $text = $content->serialize($format);
                 // always include format and model.
                 // Format is needed to deserialize, model is needed to interpret.
                 $vals['contentformat'] = $format;
                 $vals['contentmodel'] = $model;
             }
         }
         if ($text !== false) {
             ApiResult::setContentValue($vals, 'content', $text);
         }
     }
     if ($content && (!is_null($this->diffto) || !is_null($this->difftotext))) {
         static $n = 0;
         // Number of uncached diffs we've had
         if ($n < $this->getConfig()->get('APIMaxUncachedDiffs')) {
             $vals['diff'] = array();
             $context = new DerivativeContext($this->getContext());
             $context->setTitle($title);
             $handler = $revision->getContentHandler();
             if (!is_null($this->difftotext)) {
                 $model = $title->getContentModel();
                 if ($this->contentFormat && !ContentHandler::getForModelID($model)->isSupportedFormat($this->contentFormat)) {
                     $name = $title->getPrefixedDBkey();
                     $this->setWarning("The requested format {$this->contentFormat} is not " . "supported for content model {$model} used by {$name}");
                     $vals['diff']['badcontentformat'] = true;
                     $engine = null;
                 } else {
                     $difftocontent = ContentHandler::makeContent($this->difftotext, $title, $model, $this->contentFormat);
                     $engine = $handler->createDifferenceEngine($context);
                     $engine->setContent($content, $difftocontent);
                 }
             } else {
                 $engine = $handler->createDifferenceEngine($context, $revision->getID(), $this->diffto);
                 $vals['diff']['from'] = $engine->getOldid();
                 $vals['diff']['to'] = $engine->getNewid();
             }
             if ($engine) {
                 $difftext = $engine->getDiffBody();
                 ApiResult::setContentValue($vals['diff'], 'body', $difftext);
                 if (!$engine->wasCacheHit()) {
                     $n++;
                 }
             }
         } else {
             $vals['diff']['notcached'] = true;
         }
     }
     if ($anyHidden && $revision->isDeleted(Revision::DELETED_RESTRICTED)) {
         $vals['suppressed'] = true;
     }
     return $vals;
 }
Esempio n. 7
0
 public static function getAllContentFormats()
 {
     global $wgContentHandlers;
     $formats = array();
     foreach ($wgContentHandlers as $model => $class) {
         $handler = ContentHandler::getForModelID($model);
         $formats = array_merge($formats, $handler->getSupportedFormats());
     }
     $formats = array_unique($formats);
     return $formats;
 }
Esempio n. 8
0
 public function execute()
 {
     global $wgMemc;
     $user = $this->getUser();
     $params = $this->extractRequestParams();
     $page = $this->getTitleOrPageId($params);
     $title = $page->getTitle();
     if (!ContentHandler::getForModelID($params['contentmodel'])->isSupportedFormat($params['contentformat'])) {
         $this->dieUsage("Unsupported content model/format", 'badmodelformat');
     }
     // Trim and fix newlines so the key SHA1's match (see RequestContext::getText())
     $text = rtrim(str_replace("\r\n", "\n", $params['text']));
     $textContent = ContentHandler::makeContent($text, $title, $params['contentmodel'], $params['contentformat']);
     $page = WikiPage::factory($title);
     if ($page->exists()) {
         // Page exists: get the merged content with the proposed change
         $baseRev = Revision::newFromPageId($page->getId(), $params['baserevid']);
         if (!$baseRev) {
             $this->dieUsage("No revision ID {$params['baserevid']}", 'missingrev');
         }
         $currentRev = $page->getRevision();
         if (!$currentRev) {
             $this->dieUsage("No current revision of page ID {$page->getId()}", 'missingrev');
         }
         // Merge in the new version of the section to get the proposed version
         $editContent = $page->replaceSectionAtRev($params['section'], $textContent, $params['sectiontitle'], $baseRev->getId());
         if (!$editContent) {
             $this->dieUsage("Could not merge updated section.", 'replacefailed');
         }
         if ($currentRev->getId() == $baseRev->getId()) {
             // Base revision was still the latest; nothing to merge
             $content = $editContent;
         } else {
             // Merge the edit into the current version
             $baseContent = $baseRev->getContent();
             $currentContent = $currentRev->getContent();
             if (!$baseContent || !$currentContent) {
                 $this->dieUsage("Missing content for page ID {$page->getId()}", 'missingrev');
             }
             $handler = ContentHandler::getForModelID($baseContent->getModel());
             $content = $handler->merge3($baseContent, $editContent, $currentContent);
         }
     } else {
         // New pages: use the user-provided content model
         $content = $textContent;
     }
     if (!$content) {
         // merge3() failed
         $this->getResult()->addValue(null, $this->getModuleName(), array('status' => 'editconflict'));
         return;
     }
     // The user will abort the AJAX request by pressing "save", so ignore that
     ignore_user_abort(true);
     // Get a key based on the source text, format, and user preferences
     $key = self::getStashKey($title, $content, $user);
     // De-duplicate requests on the same key
     if ($user->pingLimiter('stashedit')) {
         $status = 'ratelimited';
     } elseif ($wgMemc->lock($key, 0, 30)) {
         /** @noinspection PhpUnusedLocalVariableInspection */
         $unlocker = new ScopedCallback(function () use($key) {
             global $wgMemc;
             $wgMemc->unlock($key);
         });
         $status = self::parseAndStash($page, $content, $user);
     } else {
         $status = 'busy';
     }
     $this->getResult()->addValue(null, $this->getModuleName(), array('status' => $status));
 }
Esempio n. 9
0
 /**
  * @dataProvider provideGetModelForID
  */
 public function testGetModelForID($modelId, $handlerClass)
 {
     $handler = ContentHandler::getForModelID($modelId);
     $this->assertInstanceOf($handlerClass, $handler);
 }
 public static function onShowMissingArticle(Article $article)
 {
     if ($article->getPage()->getContentModel() !== CONTENT_MODEL_FLOW_BOARD) {
         return true;
     }
     if ($article->getTitle()->getNamespace() === NS_TOPIC) {
         // @todo pretty message about invalid workflow
         throw new FlowException('Non-existent topic');
     }
     $emptyContent = ContentHandler::getForModelID(CONTENT_MODEL_FLOW_BOARD)->makeEmptyContent();
     $parserOutput = $emptyContent->getParserOutput($article->getTitle());
     $article->getContext()->getOutput()->addParserOutput($parserOutput);
     return false;
 }
Esempio n. 11
0
 public function testGetFieldsForSearchIndex()
 {
     $searchEngine = $this->newSearchEngine();
     $handler = ContentHandler::getForModelID(CONTENT_MODEL_WIKITEXT);
     $fields = $handler->getFieldsForSearchIndex($searchEngine);
     $this->assertArrayHasKey('category', $fields);
     $this->assertArrayHasKey('external_link', $fields);
     $this->assertArrayHasKey('outgoing_link', $fields);
     $this->assertArrayHasKey('template', $fields);
 }
 function writeOutput($par)
 {
     global $wgLang, $wgMemc, $wgDBname, $wgUser;
     global $wgSitename, $wgLanguageCode;
     global $wgFeedClasses, $wgFilterCallback, $wgWhitelistEdit, $wgParser;
     $this->getOutput()->setRobotpolicy("noindex,nofollow");
     $target = !empty($par) ? $par : $this->getRequest()->getVal("target");
     $t = Title::newFromDBKey($target);
     $update = true;
     if (!$t || !$t->userCan('edit')) {
         return;
     }
     if (!$this->getUser()->isAllowed('edit')) {
         return;
     }
     $article = new Article($t);
     $user = $this->getUser()->getName();
     $real_name = User::whoIsReal($this->getUser()->getID());
     if ($real_name == "") {
         $real_name = $user;
     }
     $dateStr = $wgLang->timeanddate(wfTimestampNow());
     $comment = $this->getRequest()->getVal("comment_text");
     foreach ($this->getRequest()->getValues() as $key => $value) {
         if (strpos($key, "comment_text") === 0) {
             $comment = $value;
             break;
         }
     }
     $topic = $this->getRequest()->getVal("topic_name");
     //echo "$dateStr<br/>";
     // remove leading space, tends to be a problem with a lot of talk page comments as it breaks the
     // HTML on the page
     $comment = preg_replace('/\\n[ ]*/', "\n", trim($comment));
     // Check to see if the user is also getting a thumbs up. If so, append the thumbs message and give a thumbs up
     if ($this->getRequest()->getVal('thumb')) {
         $comment .= "\n\n" . wfMsg('qn_thumbs_up');
         $userName = explode(":", $this->getRequest()->getVal('target'));
         ThumbsUp::quickNoteThumb($this->getRequest()->getVal('revold'), $this->getRequest()->getVal('revnew'), $this->getRequest()->getVal('pageid'), $userName[1]);
     }
     $formattedComment = wfMsg('postcomment_formatted_comment', $dateStr, $user, $real_name, $comment);
     if ($this->getRequest()->getVal('fromajax') == 'true') {
         $this->getOutput()->setArticleBodyOnly(true);
     }
     $text = "";
     $r = Revision::newFromTitle($t);
     if ($r) {
         $text = $r->getText();
     }
     $text .= "\n\n{$formattedComment}\n\n";
     $this->getOutput()->setStatusCode(409);
     //echo "updating with text:<br/> $text";
     //exit;
     $tmp = "";
     if ($this->getUser()->isBlocked()) {
         $this->getOutput()->blockedPage();
         return;
     }
     if (!$this->getUser()->getID() && $wgWhitelistEdit) {
         $this->userNotLoggedInPage();
         return;
     }
     if (wfReadOnly()) {
         $this->getOutput()->readOnlyPage();
         return;
     }
     if ($target == "Spam-Blacklist") {
         $this->getOutput()->readOnlyPage();
         return;
     }
     if ($this->getUser()->pingLimiter()) {
         $this->getOutput()->rateLimited();
         return;
     }
     $editPage = new EditPage($article);
     $contentModel = $t->getContentModel();
     $handler = ContentHandler::getForModelID($contentModel);
     $contentFormat = $handler->getDefaultFormat();
     $content = ContentHandler::makeContent($text, $t, $contentModel, $contentFormat);
     $status = Status::newGood();
     if (!wfRunHooks('EditFilterMergedContent', array($this->getContext(), $content, &$status, '', $wgUser, false))) {
         return;
     }
     if (!$status->isGood()) {
         $errors = $status->getErrorsArray(true);
         foreach ($errors as $error) {
             if (is_array($error)) {
                 $error = count($error) ? $error[0] : '';
             }
             if (preg_match('@^spamprotection@', $error)) {
                 $message = 'Error: found spam link';
                 $this->getOutput()->addHTML($message);
                 return;
             }
         }
         $message = 'EditFilterMergedContent returned an error -- cannot post comment';
         return;
     }
     $matches = array();
     $preg = "/http:\\/\\/[^] \n'\">]*/";
     $mod = str_ireplace('http://www.wikihow.com', '', $comment);
     preg_match_all($preg, $mod, $matches);
     if (sizeof($matches[0]) > 2) {
         $this->getOutput()->showErrorPage("postcomment", "postcomment_urls_limit");
         return;
     }
     if (trim(strip_tags($comment)) == "") {
         $this->getOutput()->showErrorPage("postcomment", "postcomment_nopostingtoadd");
         return;
     }
     if (!$t->userCan('edit')) {
         $this->getOutput()->showErrorPage("postcomment", "postcomment_discussionprotected");
         return;
     }
     $watch = false;
     if ($this->getUser()->getID() > 0) {
         $watch = $this->getUser()->isWatched($t);
     }
     $fc = new FancyCaptcha();
     $pass_captcha = $fc->passCaptcha();
     if (!$pass_captcha && $this->getUser()->getID() == 0) {
         $this->getOutput()->addHTML("Sorry, please enter the correct word. Click <a onclick='window.location.reload(true);'>here</a> to get a new one.<br/><br/>");
         return;
     }
     $article->doEdit($text, "");
     if ($this->getRequest()->getVal('jsonresponse') == 'true') {
         $this->revId = $article->getRevIdFetched();
     }
     // Notify users of usertalk updates
     if ($t->getNamespace() == NS_USER_TALK) {
         AuthorEmailNotification::notifyUserTalk($t->getArticleID(), $this->getUser()->getID(), $comment);
     }
     $this->getOutput()->setStatusCode(200);
     if ($this->getRequest()->getVal('fromajax') == 'true') {
         $this->getOutput()->redirect('');
         $this->getContext()->setTitle($t);
         $formattedComment = $wgParser->preSaveTransform($formattedComment, $t, $this->getUser(), new ParserOptions());
         $this->getOutput()->addHTML($this->getOutput()->parse("\n" . $formattedComment));
         return;
     }
 }
 function approveEditById($id)
 {
     $dbw = wfGetDB(DB_MASTER);
     $row = $dbw->selectRow('moderation', array('mod_id AS id', 'mod_timestamp AS timestamp', 'mod_user AS user', 'mod_user_text AS user_text', 'mod_cur_id AS cur_id', 'mod_namespace AS namespace', 'mod_title AS title', 'mod_comment AS comment', 'mod_minor AS minor', 'mod_bot AS bot', 'mod_last_oldid AS last_oldid', 'mod_ip AS ip', 'mod_header_xff AS header_xff', 'mod_header_ua AS header_ua', 'mod_text AS text', 'mod_merged_revid AS merged_revid', 'mod_rejected AS rejected', 'mod_stash_key AS stash_key'), array('mod_id' => $id), __METHOD__);
     if (!$row) {
         throw new ModerationError('moderation-edit-not-found');
     }
     if ($row->merged_revid) {
         throw new ModerationError('moderation-already-merged');
     }
     if ($row->rejected && $row->timestamp < $this->mSpecial->earliestReapprovableTimestamp) {
         throw new ModerationError('moderation-rejected-long-ago');
     }
     # Prepare everything
     $title = Title::makeTitle($row->namespace, $row->title);
     $model = $title->getContentModel();
     $user = $row->user ? User::newFromId($row->user) : User::newFromName($row->user_text, false);
     $flags = EDIT_DEFER_UPDATES | EDIT_AUTOSUMMARY;
     if ($row->bot && $user->isAllowed('bot')) {
         $flags |= EDIT_FORCE_BOT;
     }
     if ($row->minor) {
         # doEditContent() checks the right
         $flags |= EDIT_MINOR;
     }
     # For CheckUser extension to work properly, IP, XFF and UA
     # should be set to the correct values for the original user
     # (not from the moderator)
     $cuHook = new ModerationCheckUserHook();
     $cuHook->install($row->ip, $row->header_xff, $row->header_ua);
     $approveHook = new ModerationApproveHook();
     $approveHook->install(array('rev_timestamp' => $dbw->timestamp($row->timestamp), 'rev_user' => $user->getId(), 'rev_user_text' => $user->getName()));
     $status = Status::newGood();
     if ($row->stash_key) {
         # This is the upload from stash.
         $stash = RepoGroup::singleton()->getLocalRepo()->getUploadStash($user);
         try {
             $file = $stash->getFile($row->stash_key);
         } catch (MWException $e) {
             throw new ModerationError('moderation-missing-stashed-image');
         }
         $upload = new UploadFromStash($user, $stash);
         $upload->initialize($row->stash_key, $title->getText());
         $status = $upload->performUpload($row->comment, $row->text, 0, $user);
     } else {
         # This is normal edit (not an upload).
         $new_content = ContentHandler::makeContent($row->text, null, $model);
         $page = new WikiPage($title);
         if (!$page->exists()) {
             # New page
             $status = $page->doEditContent($new_content, $row->comment, $flags, false, $user);
         } else {
             # Existing page
             $latest = $page->getLatest();
             if ($latest == $row->last_oldid) {
                 # Page hasn't changed since this edit was queued for moderation.
                 $status = $page->doEditContent($new_content, $row->comment, $flags, $row->last_oldid, $user);
             } else {
                 # Page has changed!
                 # Let's attempt merging, as MediaWiki does in private EditPage::mergeChangesIntoContent().
                 $base_content = $row->last_oldid ? Revision::newFromId($row->last_oldid)->getContent(Revision::RAW) : ContentHandler::makeContent('', null, $model);
                 $latest_content = Revision::newFromId($latest)->getContent(Revision::RAW);
                 $handler = ContentHandler::getForModelID($base_content->getModel());
                 $merged_content = $handler->merge3($base_content, $new_content, $latest_content);
                 if ($merged_content) {
                     $status = $page->doEditContent($merged_content, $row->comment, $flags, $latest, $user);
                 } else {
                     $dbw = wfGetDB(DB_MASTER);
                     $dbw->update('moderation', array('mod_conflict' => 1), array('mod_id' => $id), __METHOD__);
                     $dbw->commit(__METHOD__);
                     throw new ModerationError('moderation-edit-conflict');
                 }
             }
         }
     }
     $approveHook->deinstall();
     $cuHook->deinstall();
     if (!$status->isGood()) {
         throw new ModerationError($status->getMessage());
     }
     $logEntry = new ManualLogEntry('moderation', 'approve');
     $logEntry->setPerformer($this->moderator);
     $logEntry->setTarget($title);
     $logEntry->setParameters(array('revid' => $approveHook->lastRevId));
     $logid = $logEntry->insert();
     $logEntry->publish($logid);
     # Approved edits are removed from "moderation" table,
     # because they already exist in page history, recentchanges etc.
     $dbw = wfGetDB(DB_MASTER);
     $dbw->delete('moderation', array('mod_id' => $id), __METHOD__);
 }
 protected function setUp()
 {
     parent::setUp();
     $this->handler = ContentHandler::getForModelID(CONTENT_MODEL_WIKITEXT);
 }
 private function extractRowInfo($row)
 {
     $revision = new Revision($row);
     $title = $revision->getTitle();
     $vals = array();
     if ($this->fld_ids) {
         $vals['revid'] = intval($revision->getId());
         // $vals['oldid'] = intval( $row->rev_text_id ); // todo: should this be exposed?
         if (!is_null($revision->getParentId())) {
             $vals['parentid'] = intval($revision->getParentId());
         }
     }
     if ($this->fld_flags && $revision->isMinor()) {
         $vals['minor'] = '';
     }
     if ($this->fld_user || $this->fld_userid) {
         if ($revision->isDeleted(Revision::DELETED_USER)) {
             $vals['userhidden'] = '';
         } else {
             if ($this->fld_user) {
                 $vals['user'] = $revision->getUserText();
             }
             $userid = $revision->getUser();
             if (!$userid) {
                 $vals['anon'] = '';
             }
             if ($this->fld_userid) {
                 $vals['userid'] = $userid;
             }
         }
     }
     if ($this->fld_timestamp) {
         $vals['timestamp'] = wfTimestamp(TS_ISO_8601, $revision->getTimestamp());
     }
     if ($this->fld_size) {
         if (!is_null($revision->getSize())) {
             $vals['size'] = intval($revision->getSize());
         } else {
             $vals['size'] = 0;
         }
     }
     if ($this->fld_sha1) {
         if ($revision->getSha1() != '') {
             $vals['sha1'] = wfBaseConvert($revision->getSha1(), 36, 16, 40);
         } else {
             $vals['sha1'] = '';
         }
     }
     if ($this->fld_contentmodel) {
         $vals['contentmodel'] = $revision->getContentModel();
     }
     if ($this->fld_comment || $this->fld_parsedcomment) {
         if ($revision->isDeleted(Revision::DELETED_COMMENT)) {
             $vals['commenthidden'] = '';
         } else {
             $comment = $revision->getComment();
             if ($this->fld_comment) {
                 $vals['comment'] = $comment;
             }
             if ($this->fld_parsedcomment) {
                 $vals['parsedcomment'] = Linker::formatComment($comment, $title);
             }
         }
     }
     if ($this->fld_tags) {
         if ($row->ts_tags) {
             $tags = explode(',', $row->ts_tags);
             $this->getResult()->setIndexedTagName($tags, 'tag');
             $vals['tags'] = $tags;
         } else {
             $vals['tags'] = array();
         }
     }
     if (!is_null($this->token)) {
         $tokenFunctions = $this->getTokenFunctions();
         foreach ($this->token as $t) {
             $val = call_user_func($tokenFunctions[$t], $title->getArticleID(), $title, $revision);
             if ($val === false) {
                 $this->setWarning("Action '{$t}' is not allowed for the current user");
             } else {
                 $vals[$t . 'token'] = $val;
             }
         }
     }
     $content = null;
     global $wgParser;
     if ($this->fld_content || !is_null($this->difftotext)) {
         $content = $revision->getContent();
         // Expand templates after getting section content because
         // template-added sections don't count and Parser::preprocess()
         // will have less input
         if ($this->section !== false) {
             $content = $content->getSection($this->section, false);
             if (!$content) {
                 $this->dieUsage("There is no section {$this->section} in r" . $revision->getId(), 'nosuchsection');
             }
         }
     }
     if ($this->fld_content && !$revision->isDeleted(Revision::DELETED_TEXT)) {
         $text = null;
         if ($this->generateXML) {
             if ($content->getModel() === CONTENT_MODEL_WIKITEXT) {
                 $t = $content->getNativeData();
                 # note: don't set $text
                 $wgParser->startExternalParse($title, ParserOptions::newFromContext($this->getContext()), OT_PREPROCESS);
                 $dom = $wgParser->preprocessToDom($t);
                 if (is_callable(array($dom, 'saveXML'))) {
                     $xml = $dom->saveXML();
                 } else {
                     $xml = $dom->__toString();
                 }
                 $vals['parsetree'] = $xml;
             } else {
                 $this->setWarning("Conversion to XML is supported for wikitext only, " . $title->getPrefixedDBkey() . " uses content model " . $content->getModel() . ")");
             }
         }
         if ($this->expandTemplates && !$this->parseContent) {
             #XXX: implement template expansion for all content types in ContentHandler?
             if ($content->getModel() === CONTENT_MODEL_WIKITEXT) {
                 $text = $content->getNativeData();
                 $text = $wgParser->preprocess($text, $title, ParserOptions::newFromContext($this->getContext()));
             } else {
                 $this->setWarning("Template expansion is supported for wikitext only, " . $title->getPrefixedDBkey() . " uses content model " . $content->getModel() . ")");
                 $text = false;
             }
         }
         if ($this->parseContent) {
             $po = $content->getParserOutput($title, $revision->getId(), ParserOptions::newFromContext($this->getContext()));
             $text = $po->getText();
         }
         if ($text === null) {
             $format = $this->contentFormat ? $this->contentFormat : $content->getDefaultFormat();
             if (!$content->isSupportedFormat($format)) {
                 $model = $content->getModel();
                 $name = $title->getPrefixedDBkey();
                 $this->dieUsage("The requested format {$this->contentFormat} is not supported " . "for content model {$model} used by {$name}", 'badformat');
             }
             $text = $content->serialize($format);
             $vals['contentformat'] = $format;
         }
         if ($text !== false) {
             ApiResult::setContent($vals, $text);
         }
     } elseif ($this->fld_content) {
         $vals['texthidden'] = '';
     }
     if (!is_null($this->diffto) || !is_null($this->difftotext)) {
         global $wgAPIMaxUncachedDiffs;
         static $n = 0;
         // Number of uncached diffs we've had
         if ($n < $wgAPIMaxUncachedDiffs) {
             $vals['diff'] = array();
             $context = new DerivativeContext($this->getContext());
             $context->setTitle($title);
             $handler = $revision->getContentHandler();
             if (!is_null($this->difftotext)) {
                 $model = $title->getContentModel();
                 if ($this->contentFormat && !ContentHandler::getForModelID($model)->isSupportedFormat($this->contentFormat)) {
                     $name = $title->getPrefixedDBkey();
                     $this->dieUsage("The requested format {$this->contentFormat} is not supported for " . "content model {$model} used by {$name}", 'badformat');
                 }
                 $difftocontent = ContentHandler::makeContent($this->difftotext, $title, $model, $this->contentFormat);
                 $engine = $handler->createDifferenceEngine($context);
                 $engine->setContent($content, $difftocontent);
             } else {
                 $engine = $handler->createDifferenceEngine($context, $revision->getID(), $this->diffto);
                 $vals['diff']['from'] = $engine->getOldid();
                 $vals['diff']['to'] = $engine->getNewid();
             }
             $difftext = $engine->getDiffBody();
             ApiResult::setContent($vals['diff'], $difftext);
             if (!$engine->wasCacheHit()) {
                 $n++;
             }
         } else {
             $vals['diff']['notcached'] = '';
         }
     }
     return $vals;
 }
Esempio n. 16
0
 protected function checkContentModel()
 {
     global $wgContentHandlerUseDB;
     $title = $this->getTitle();
     //note: may return null for revisions that have not yet been inserted.
     $model = $this->getContentModel();
     $format = $this->getContentFormat();
     $handler = $this->getContentHandler();
     if (!$handler->isSupportedFormat($format)) {
         $t = $title->getPrefixedDBkey();
         throw new MWException("Can't use format {$format} with content model {$model} on {$t}");
     }
     if (!$wgContentHandlerUseDB && $title) {
         // if $wgContentHandlerUseDB is not set, all revisions must use the default content model and format.
         $defaultModel = ContentHandler::getDefaultModelFor($title);
         $defaultHandler = ContentHandler::getForModelID($defaultModel);
         $defaultFormat = $defaultHandler->getDefaultFormat();
         if ($this->getContentModel() != $defaultModel) {
             $t = $title->getPrefixedDBkey();
             throw new MWException("Can't save non-default content model with \$wgContentHandlerUseDB disabled: " . "model is {$model} , default for {$t} is {$defaultModel}");
         }
         if ($this->getContentFormat() != $defaultFormat) {
             $t = $title->getPrefixedDBkey();
             throw new MWException("Can't use non-default content format with \$wgContentHandlerUseDB disabled: " . "format is {$format}, default for {$t} is {$defaultFormat}");
         }
     }
     $content = $this->getContent(Revision::RAW);
     if (!$content || !$content->isValid()) {
         $t = $title->getPrefixedDBkey();
         throw new MWException("Content of {$t} is not valid! Content model is {$model}");
     }
 }
Esempio n. 17
0
 /**
  * Applies applicable export transformations to $text.
  *
  * @param string $text
  * @param string $model
  * @param string|null $format
  *
  * @return string
  */
 private function exportTransform($text, $model, $format = null)
 {
     try {
         $handler = ContentHandler::getForModelID($model);
         $text = $handler->exportTransform($text, $format);
     } catch (MWException $ex) {
         $this->progress("Unable to apply export transformation for content model '{$model}': " . $ex->getMessage());
     }
     return $text;
 }
 public function onSubmit(array $data)
 {
     global $wgContLang;
     if ($data['pagetitle'] === '') {
         // Initial form view of special page, pass
         return false;
     }
     // At this point, it has to be a POST request. This is enforced by HTMLForm,
     // but lets be safe verify that.
     if (!$this->getRequest()->wasPosted()) {
         throw new RuntimeException("Form submission was not POSTed");
     }
     $this->title = Title::newFromText($data['pagetitle']);
     $user = $this->getUser();
     // Check permissions and make sure the user has permission to edit the specific page
     $errors = $this->title->getUserPermissionsErrors('editcontentmodel', $user);
     $errors = wfMergeErrorArrays($errors, $this->title->getUserPermissionsErrors('edit', $user));
     if ($errors) {
         $out = $this->getOutput();
         $wikitext = $out->formatPermissionsErrorMessage($errors);
         // Hack to get our wikitext parsed
         return Status::newFatal(new RawMessage('$1', array($wikitext)));
     }
     $page = WikiPage::factory($this->title);
     if ($this->oldRevision === null) {
         $this->oldRevision = $page->getRevision() ?: false;
     }
     $oldModel = $this->title->getContentModel();
     if ($this->oldRevision) {
         $oldContent = $this->oldRevision->getContent();
         try {
             $newContent = ContentHandler::makeContent($oldContent->getNativeData(), $this->title, $data['model']);
         } catch (MWException $e) {
             return Status::newFatal($this->msg('changecontentmodel-cannot-convert')->params($this->title->getPrefixedText(), ContentHandler::getLocalizedName($data['model'])));
         }
     } else {
         // Page doesn't exist, create an empty content object
         $newContent = ContentHandler::getForModelID($data['model'])->makeEmptyContent();
     }
     $flags = $this->oldRevision ? EDIT_UPDATE : EDIT_NEW;
     if ($user->isAllowed('bot')) {
         $flags |= EDIT_FORCE_BOT;
     }
     $log = new ManualLogEntry('contentmodel', 'change');
     $log->setPerformer($user);
     $log->setTarget($this->title);
     $log->setComment($data['reason']);
     $log->setParameters(array('4::oldmodel' => $oldModel, '5::newmodel' => $data['model']));
     $formatter = LogFormatter::newFromEntry($log);
     $formatter->setContext(RequestContext::newExtraneousContext($this->title));
     $reason = $formatter->getPlainActionText();
     if ($data['reason'] !== '') {
         $reason .= $this->msg('colon-separator')->inContentLanguage()->text() . $data['reason'];
     }
     # Truncate for whole multibyte characters.
     $reason = $wgContLang->truncate($reason, 255);
     $status = $page->doEditContent($newContent, $reason, $flags, $this->oldRevision ? $this->oldRevision->getId() : false, $user);
     if (!$status->isOK()) {
         return $status;
     }
     $logid = $log->insert();
     $log->publish($logid);
     return $status;
 }
Esempio n. 19
0
 /**
  * Show an edit conflict. textbox1 is already shown in showEditForm().
  * If you want to use another entry point to this function, be careful.
  */
 protected function showConflict()
 {
     global $wgOut;
     if (Hooks::run('EditPageBeforeConflictDiff', [&$this, &$wgOut])) {
         $stats = $wgOut->getContext()->getStats();
         $stats->increment('edit.failures.conflict');
         // Only include 'standard' namespaces to avoid creating unknown numbers of statsd metrics
         if ($this->mTitle->getNamespace() >= NS_MAIN && $this->mTitle->getNamespace() <= NS_CATEGORY_TALK) {
             $stats->increment('edit.failures.conflict.byNamespaceId.' . $this->mTitle->getNamespace());
         }
         $wgOut->wrapWikiMsg('<h2>$1</h2>', "yourdiff");
         $content1 = $this->toEditContent($this->textbox1);
         $content2 = $this->toEditContent($this->textbox2);
         $handler = ContentHandler::getForModelID($this->contentModel);
         $de = $handler->createDifferenceEngine($this->mArticle->getContext());
         $de->setContent($content2, $content1);
         $de->showDiff($this->context->msg('yourtext')->parse(), $this->context->msg('storedversion')->text());
         $wgOut->wrapWikiMsg('<h2>$1</h2>', "yourtext");
         $this->showTextbox2();
     }
 }
Esempio n. 20
0
 /**
  * @see Content::convert()
  *
  * This implementation provides lossless conversion between content models based
  * on TextContent.
  *
  * @param String  $toModel the desired content model, use the CONTENT_MODEL_XXX flags.
  * @param String  $lossy flag, set to "lossy" to allow lossy conversion. If lossy conversion is
  * not allowed, full round-trip conversion is expected to work without losing information.
  *
  * @return Content|bool A content object with the content model $toModel, or false if
  * that conversion is not supported.
  */
 public function convert($toModel, $lossy = '')
 {
     $converted = parent::convert($toModel, $lossy);
     if ($converted !== false) {
         return $converted;
     }
     $toHandler = ContentHandler::getForModelID($toModel);
     if ($toHandler instanceof TextContentHandler) {
         //NOTE: ignore content serialization format - it's just text anyway.
         $text = $this->getNativeData();
         $converted = $toHandler->unserializeContent($text);
     }
     return $converted;
 }
Esempio n. 21
0
 /**
  * Get fields for search index
  * @since 1.28
  * @return SearchIndexField[] Index field definitions for all content handlers
  */
 public function getSearchIndexFields()
 {
     $models = ContentHandler::getContentModels();
     $fields = [];
     foreach ($models as $model) {
         $handler = ContentHandler::getForModelID($model);
         $handlerFields = $handler->getFieldsForSearchIndex($this);
         foreach ($handlerFields as $fieldName => $fieldData) {
             if (empty($fields[$fieldName])) {
                 $fields[$fieldName] = $fieldData;
             } else {
                 // TODO: do we allow some clashes with the same type or reject all of them?
                 $mergeDef = $fields[$fieldName]->merge($fieldData);
                 if (!$mergeDef) {
                     throw new InvalidArgumentException("Duplicate field {$fieldName} for model {$model}");
                 }
                 $fields[$fieldName] = $mergeDef;
             }
         }
     }
     // Hook to allow extensions to produce search mapping fields
     Hooks::run('SearchIndexFields', [&$fields, $this]);
     return $fields;
 }
Esempio n. 22
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);
 }
Esempio n. 23
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);
 }
Esempio n. 24
0
 /**
  * Dumps a "<revision>" section on the output stream, with
  * data filled in from the given database row.
  *
  * @param object $row
  * @return string
  * @access private
  */
 function writeRevision($row)
 {
     wfProfileIn(__METHOD__);
     $out = "    <revision>\n";
     $out .= "      " . Xml::element('id', null, strval($row->rev_id)) . "\n";
     if (isset($row->rev_parent_id) && $row->rev_parent_id) {
         $out .= "      " . Xml::element('parentid', null, strval($row->rev_parent_id)) . "\n";
     }
     $out .= $this->writeTimestamp($row->rev_timestamp);
     if (isset($row->rev_deleted) && $row->rev_deleted & Revision::DELETED_USER) {
         $out .= "      " . Xml::element('contributor', array('deleted' => 'deleted')) . "\n";
     } else {
         $out .= $this->writeContributor($row->rev_user, $row->rev_user_text);
     }
     if (isset($row->rev_minor_edit) && $row->rev_minor_edit) {
         $out .= "      <minor/>\n";
     }
     if (isset($row->rev_deleted) && $row->rev_deleted & Revision::DELETED_COMMENT) {
         $out .= "      " . Xml::element('comment', array('deleted' => 'deleted')) . "\n";
     } elseif ($row->rev_comment != '') {
         $out .= "      " . Xml::elementClean('comment', array(), strval($row->rev_comment)) . "\n";
     }
     if (isset($row->rev_content_model) && !is_null($row->rev_content_model)) {
         $content_model = strval($row->rev_content_model);
     } else {
         // probably using $wgContentHandlerUseDB = false;
         $title = Title::makeTitle($row->page_namespace, $row->page_title);
         $content_model = ContentHandler::getDefaultModelFor($title);
     }
     $content_handler = ContentHandler::getForModelID($content_model);
     if (isset($row->rev_content_format) && !is_null($row->rev_content_format)) {
         $content_format = strval($row->rev_content_format);
     } else {
         // probably using $wgContentHandlerUseDB = false;
         $content_format = $content_handler->getDefaultFormat();
     }
     $text = '';
     if (isset($row->rev_deleted) && $row->rev_deleted & Revision::DELETED_TEXT) {
         $out .= "      " . Xml::element('text', array('deleted' => 'deleted')) . "\n";
     } elseif (isset($row->old_text)) {
         // Raw text from the database may have invalid chars
         $text = strval(Revision::getRevisionText($row));
         $text = $content_handler->exportTransform($text, $content_format);
         $out .= "      " . Xml::elementClean('text', array('xml:space' => 'preserve', 'bytes' => intval($row->rev_len)), strval($text)) . "\n";
     } else {
         // Stub output
         $out .= "      " . Xml::element('text', array('id' => $row->rev_text_id, 'bytes' => intval($row->rev_len)), "") . "\n";
     }
     if (isset($row->rev_sha1) && $row->rev_sha1 && !($row->rev_deleted & Revision::DELETED_TEXT)) {
         $out .= "      " . Xml::element('sha1', null, strval($row->rev_sha1)) . "\n";
     } else {
         $out .= "      <sha1/>\n";
     }
     $out .= "      " . Xml::element('model', null, strval($content_model)) . "\n";
     $out .= "      " . Xml::element('format', null, strval($content_format)) . "\n";
     wfRunHooks('XmlDumpWriterWriteRevision', array(&$this, &$out, $row, $text));
     $out .= "    </revision>\n";
     wfProfileOut(__METHOD__);
     return $out;
 }
 private function updateRevisionOrArchiveRows(DatabaseBase $dbw, $ids, $model, $table)
 {
     $prefix = $table === 'archive' ? 'ar' : 'rev';
     $model_column = "{$prefix}_content_model";
     $format_column = "{$prefix}_content_format";
     $key = "{$prefix}_id";
     $count = count($ids);
     $format = ContentHandler::getForModelID($model)->getDefaultFormat();
     $this->output("Setting {$count} rows to {$model} / {$format}...");
     $dbw->update($table, array($model_column => $model, $format_column => $format), array($key => $ids), __METHOD__);
     $this->output("done.\n");
 }
Esempio n. 26
0
	/**
	 * Return an applicable autosummary if one exists for the given edit.
	 * @param string|null $oldtext the previous text of the page.
	 * @param string|null $newtext The submitted text of the page.
	 * @param int $flags bitmask: a bitmask of flags submitted for the edit.
	 * @return string An appropriate autosummary, or an empty string.
	 *
	 * @deprecated since 1.21, use ContentHandler::getAutosummary() instead
	 */
	public static function getAutosummary( $oldtext, $newtext, $flags ) {
		// NOTE: stub for backwards-compatibility. assumes the given text is wikitext. will break horribly if it isn't.

		ContentHandler::deprecated( __METHOD__, '1.21' );

		$handler = ContentHandler::getForModelID( CONTENT_MODEL_WIKITEXT );
		$oldContent = is_null( $oldtext ) ? null : $handler->unserializeContent( $oldtext );
		$newContent = is_null( $newtext ) ? null : $handler->unserializeContent( $newtext );

		return $handler->getAutosummary( $oldContent, $newContent, $flags );
	}
Esempio n. 27
0
 public function execute()
 {
     $user = $this->getUser();
     $params = $this->extractRequestParams();
     if ($user->isBot()) {
         // sanity
         $this->dieUsage('This interface is not supported for bots', 'botsnotsupported');
     }
     $page = $this->getTitleOrPageId($params);
     $title = $page->getTitle();
     if (!ContentHandler::getForModelID($params['contentmodel'])->isSupportedFormat($params['contentformat'])) {
         $this->dieUsage('Unsupported content model/format', 'badmodelformat');
     }
     // Trim and fix newlines so the key SHA1's match (see RequestContext::getText())
     $text = rtrim(str_replace("\r\n", "\n", $params['text']));
     $textContent = ContentHandler::makeContent($text, $title, $params['contentmodel'], $params['contentformat']);
     $page = WikiPage::factory($title);
     if ($page->exists()) {
         // Page exists: get the merged content with the proposed change
         $baseRev = Revision::newFromPageId($page->getId(), $params['baserevid']);
         if (!$baseRev) {
             $this->dieUsage("No revision ID {$params['baserevid']}", 'missingrev');
         }
         $currentRev = $page->getRevision();
         if (!$currentRev) {
             $this->dieUsage("No current revision of page ID {$page->getId()}", 'missingrev');
         }
         // Merge in the new version of the section to get the proposed version
         $editContent = $page->replaceSectionAtRev($params['section'], $textContent, $params['sectiontitle'], $baseRev->getId());
         if (!$editContent) {
             $this->dieUsage('Could not merge updated section.', 'replacefailed');
         }
         if ($currentRev->getId() == $baseRev->getId()) {
             // Base revision was still the latest; nothing to merge
             $content = $editContent;
         } else {
             // Merge the edit into the current version
             $baseContent = $baseRev->getContent();
             $currentContent = $currentRev->getContent();
             if (!$baseContent || !$currentContent) {
                 $this->dieUsage("Missing content for page ID {$page->getId()}", 'missingrev');
             }
             $handler = ContentHandler::getForModelID($baseContent->getModel());
             $content = $handler->merge3($baseContent, $editContent, $currentContent);
         }
     } else {
         // New pages: use the user-provided content model
         $content = $textContent;
     }
     if (!$content) {
         // merge3() failed
         $this->getResult()->addValue(null, $this->getModuleName(), ['status' => 'editconflict']);
         return;
     }
     // The user will abort the AJAX request by pressing "save", so ignore that
     ignore_user_abort(true);
     // Use the master DB for fast blocking locks
     $dbw = wfGetDB(DB_MASTER);
     // Get a key based on the source text, format, and user preferences
     $key = self::getStashKey($title, $content, $user);
     // De-duplicate requests on the same key
     if ($user->pingLimiter('stashedit')) {
         $status = 'ratelimited';
     } elseif ($dbw->lock($key, __METHOD__, 1)) {
         $status = self::parseAndStash($page, $content, $user);
         $dbw->unlock($key, __METHOD__);
     } else {
         $status = 'busy';
     }
     $this->getStats()->increment("editstash.cache_stores.{$status}");
     $this->getResult()->addValue(null, $this->getModuleName(), ['status' => $status]);
 }