예제 #1
0
 /**
  * Returns the page's content model id (see the CONTENT_MODEL_XXX constants).
  *
  * Will use the revisions actual content model if the page exists,
  * and the page's default if the page doesn't exist yet.
  *
  * @return String
  *
  * @since 1.21
  */
 public function getContentModel()
 {
     if ($this->exists()) {
         # look at the revision's actual content model
         $rev = $this->getRevision();
         if ($rev !== null) {
             return $rev->getContentModel();
         } else {
             $title = $this->mTitle->getPrefixedDBkey();
             wfWarn("Page {$title} exists but has no (visible) revisions!");
         }
     }
     # use the default model for this page
     return $this->mTitle->getContentModel();
 }
예제 #2
0
 /**
  * Does various sanity checks that the move is
  * valid. Only things based on the two titles
  * should be checked here.
  *
  * @return Status
  */
 public function isValidMove()
 {
     global $wgContentHandlerUseDB;
     $status = new Status();
     if ($this->oldTitle->equals($this->newTitle)) {
         $status->fatal('selfmove');
     }
     if (!$this->oldTitle->isMovable()) {
         $status->fatal('immobile-source-namespace', $this->oldTitle->getNsText());
     }
     if ($this->newTitle->isExternal()) {
         $status->fatal('immobile-target-namespace-iw');
     }
     if (!$this->newTitle->isMovable()) {
         $status->fatal('immobile-target-namespace', $this->newTitle->getNsText());
     }
     $oldid = $this->oldTitle->getArticleID();
     if (strlen($this->newTitle->getDBkey()) < 1) {
         $status->fatal('articleexists');
     }
     if ($this->oldTitle->getDBkey() == '' || !$oldid || $this->newTitle->getDBkey() == '') {
         $status->fatal('badarticleerror');
     }
     # The move is allowed only if (1) the target doesn't exist, or
     # (2) the target is a redirect to the source, and has no history
     # (so we can undo bad moves right after they're done).
     if ($this->newTitle->getArticleID() && !$this->isValidMoveTarget()) {
         $status->fatal('articleexists');
     }
     // Content model checks
     if (!$wgContentHandlerUseDB && $this->oldTitle->getContentModel() !== $this->newTitle->getContentModel()) {
         // can't move a page if that would change the page's content model
         $status->fatal('bad-target-model', ContentHandler::getLocalizedName($this->oldTitle->getContentModel()), ContentHandler::getLocalizedName($this->newTitle->getContentModel()));
     }
     // Image-specific checks
     if ($this->oldTitle->inNamespace(NS_FILE)) {
         $status->merge($this->isValidFileMove());
     }
     if ($this->newTitle->inNamespace(NS_FILE) && !$this->oldTitle->inNamespace(NS_FILE)) {
         $status->fatal('nonfile-cannot-move-to-file');
     }
     // Hook for extensions to say a title can't be moved for technical reasons
     Hooks::run('MovePageIsValidMove', array($this->oldTitle, $this->newTitle, $status));
     return $status;
 }
예제 #3
0
 /**
  * Returns the page's content model id (see the CONTENT_MODEL_XXX constants).
  *
  * Will use the revisions actual content model if the page exists,
  * and the page's default if the page doesn't exist yet.
  *
  * @return string
  *
  * @since 1.21
  */
 public function getContentModel()
 {
     if ($this->exists()) {
         $cache = ObjectCache::getMainWANInstance();
         return $cache->getWithSetCallback($cache->makeKey('page', 'content-model', $this->getLatest()), $cache::TTL_MONTH, function () {
             $rev = $this->getRevision();
             if ($rev) {
                 // Look at the revision's actual content model
                 return $rev->getContentModel();
             } else {
                 $title = $this->mTitle->getPrefixedDBkey();
                 wfWarn("Page {$title} exists but has no (visible) revisions!");
                 return $this->mTitle->getContentModel();
             }
         });
     }
     // use the default model for this page
     return $this->mTitle->getContentModel();
 }
예제 #4
0
 /**
  * Returns the appropriate ContentHandler singleton for the given title.
  *
  * @since 1.21
  *
  * @param Title $title
  *
  * @return ContentHandler
  */
 public static function getForTitle(Title $title)
 {
     $modelId = $title->getContentModel();
     return ContentHandler::getForModelID($modelId);
 }
예제 #5
0
 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;
 }
예제 #6
0
 /**
  * Get a result array with information about a title
  * @param int $pageid Page ID (negative for missing titles)
  * @param Title $title
  * @return array|null
  */
 private function extractPageInfo($pageid, $title)
 {
     $pageInfo = array();
     // $title->exists() needs pageid, which is not set for all title objects
     $titleExists = $pageid > 0;
     $ns = $title->getNamespace();
     $dbkey = $title->getDBkey();
     $pageInfo['contentmodel'] = $title->getContentModel();
     $pageInfo['pagelanguage'] = $title->getPageLanguage()->getCode();
     if ($titleExists) {
         $pageInfo['touched'] = wfTimestamp(TS_ISO_8601, $this->pageTouched[$pageid]);
         $pageInfo['lastrevid'] = intval($this->pageLatest[$pageid]);
         $pageInfo['length'] = intval($this->pageLength[$pageid]);
         if (isset($this->pageIsRedir[$pageid]) && $this->pageIsRedir[$pageid]) {
             $pageInfo['redirect'] = true;
         }
         if ($this->pageIsNew[$pageid]) {
             $pageInfo['new'] = true;
         }
     }
     if (!is_null($this->params['token'])) {
         $tokenFunctions = $this->getTokenFunctions();
         $pageInfo['starttimestamp'] = wfTimestamp(TS_ISO_8601, time());
         foreach ($this->params['token'] as $t) {
             $val = call_user_func($tokenFunctions[$t], $pageid, $title);
             if ($val === false) {
                 $this->setWarning("Action '{$t}' is not allowed for the current user");
             } else {
                 $pageInfo[$t . 'token'] = $val;
             }
         }
     }
     if ($this->fld_protection) {
         $pageInfo['protection'] = array();
         if (isset($this->protections[$ns][$dbkey])) {
             $pageInfo['protection'] = $this->protections[$ns][$dbkey];
         }
         ApiResult::setIndexedTagName($pageInfo['protection'], 'pr');
         $pageInfo['restrictiontypes'] = array();
         if (isset($this->restrictionTypes[$ns][$dbkey])) {
             $pageInfo['restrictiontypes'] = $this->restrictionTypes[$ns][$dbkey];
         }
         ApiResult::setIndexedTagName($pageInfo['restrictiontypes'], 'rt');
     }
     if ($this->fld_watched) {
         $pageInfo['watched'] = isset($this->watched[$ns][$dbkey]);
     }
     if ($this->fld_watchers) {
         if (isset($this->watchers[$ns][$dbkey])) {
             $pageInfo['watchers'] = $this->watchers[$ns][$dbkey];
         } elseif ($this->showZeroWatchers) {
             $pageInfo['watchers'] = 0;
         }
     }
     if ($this->fld_notificationtimestamp) {
         $pageInfo['notificationtimestamp'] = '';
         if (isset($this->notificationtimestamps[$ns][$dbkey])) {
             $pageInfo['notificationtimestamp'] = wfTimestamp(TS_ISO_8601, $this->notificationtimestamps[$ns][$dbkey]);
         }
     }
     if ($this->fld_talkid && isset($this->talkids[$ns][$dbkey])) {
         $pageInfo['talkid'] = $this->talkids[$ns][$dbkey];
     }
     if ($this->fld_subjectid && isset($this->subjectids[$ns][$dbkey])) {
         $pageInfo['subjectid'] = $this->subjectids[$ns][$dbkey];
     }
     if ($this->fld_url) {
         $pageInfo['fullurl'] = wfExpandUrl($title->getFullURL(), PROTO_CURRENT);
         $pageInfo['editurl'] = wfExpandUrl($title->getFullURL('action=edit'), PROTO_CURRENT);
         $pageInfo['canonicalurl'] = wfExpandUrl($title->getFullURL(), PROTO_CANONICAL);
     }
     if ($this->fld_readable) {
         $pageInfo['readable'] = $title->userCan('read', $this->getUser());
     }
     if ($this->fld_preload) {
         if ($titleExists) {
             $pageInfo['preload'] = '';
         } else {
             $text = null;
             Hooks::run('EditFormPreloadText', array(&$text, &$title));
             $pageInfo['preload'] = $text;
         }
     }
     if ($this->fld_displaytitle) {
         if (isset($this->displaytitles[$pageid])) {
             $pageInfo['displaytitle'] = $this->displaytitles[$pageid];
         } else {
             $pageInfo['displaytitle'] = $title->getPrefixedText();
         }
     }
     if ($this->params['testactions']) {
         $limit = $this->getMain()->canApiHighLimits() ? self::LIMIT_SML1 : self::LIMIT_SML2;
         if ($this->countTestedActions >= $limit) {
             return null;
             // force a continuation
         }
         $user = $this->getUser();
         $pageInfo['actions'] = array();
         foreach ($this->params['testactions'] as $action) {
             $this->countTestedActions++;
             $pageInfo['actions'][$action] = $title->userCan($action, $user);
         }
     }
     return $pageInfo;
 }
예제 #7
0
 /**
  * Attempt submission (no UI)
  *
  * @param array $result Array to add statuses to, currently with the
  *   possible keys:
  *   - spam (string): Spam string from content if any spam is detected by
  *     matchSpamRegex.
  *   - sectionanchor (string): Section anchor for a section save.
  *   - nullEdit (boolean): Set if doEditContent is OK.  True if null edit,
  *     false otherwise.
  *   - redirect (bool): Set if doEditContent is OK. True if resulting
  *     revision is a redirect.
  * @param bool $bot True if edit is being made under the bot right.
  *
  * @return Status Status object, possibly with a message, but always with
  *   one of the AS_* constants in $status->value,
  *
  * @todo FIXME: This interface is TERRIBLE, but hard to get rid of due to
  *   various error display idiosyncrasies. There are also lots of cases
  *   where error metadata is set in the object and retrieved later instead
  *   of being returned, e.g. AS_CONTENT_TOO_BIG and
  *   AS_BLOCKED_PAGE_FOR_USER. All that stuff needs to be cleaned up some
  * time.
  */
 function internalAttemptSave(&$result, $bot = false)
 {
     global $wgUser, $wgRequest, $wgParser, $wgMaxArticleSize;
     $status = Status::newGood();
     wfProfileIn(__METHOD__);
     wfProfileIn(__METHOD__ . '-checks');
     if (!wfRunHooks('EditPage::attemptSave', array($this))) {
         wfDebug("Hook 'EditPage::attemptSave' aborted article saving\n");
         $status->fatal('hookaborted');
         $status->value = self::AS_HOOK_ERROR;
         wfProfileOut(__METHOD__ . '-checks');
         wfProfileOut(__METHOD__);
         return $status;
     }
     $spam = $wgRequest->getText('wpAntispam');
     if ($spam !== '') {
         wfDebugLog('SimpleAntiSpam', $wgUser->getName() . ' editing "' . $this->mTitle->getPrefixedText() . '" submitted bogus field "' . $spam . '"');
         $status->fatal('spamprotectionmatch', false);
         $status->value = self::AS_SPAM_ERROR;
         wfProfileOut(__METHOD__ . '-checks');
         wfProfileOut(__METHOD__);
         return $status;
     }
     try {
         # Construct Content object
         $textbox_content = $this->toEditContent($this->textbox1);
     } catch (MWContentSerializationException $ex) {
         $status->fatal('content-failed-to-parse', $this->contentModel, $this->contentFormat, $ex->getMessage());
         $status->value = self::AS_PARSE_ERROR;
         wfProfileOut(__METHOD__ . '-checks');
         wfProfileOut(__METHOD__);
         return $status;
     }
     # Check image redirect
     if ($this->mTitle->getNamespace() == NS_FILE && $textbox_content->isRedirect() && !$wgUser->isAllowed('upload')) {
         $code = $wgUser->isAnon() ? self::AS_IMAGE_REDIRECT_ANON : self::AS_IMAGE_REDIRECT_LOGGED;
         $status->setResult(false, $code);
         wfProfileOut(__METHOD__ . '-checks');
         wfProfileOut(__METHOD__);
         return $status;
     }
     # Check for spam
     $match = self::matchSummarySpamRegex($this->summary);
     if ($match === false && $this->section == 'new') {
         # $wgSpamRegex is enforced on this new heading/summary because, unlike
         # regular summaries, it is added to the actual wikitext.
         if ($this->sectiontitle !== '') {
             # This branch is taken when the API is used with the 'sectiontitle' parameter.
             $match = self::matchSpamRegex($this->sectiontitle);
         } else {
             # This branch is taken when the "Add Topic" user interface is used, or the API
             # is used with the 'summary' parameter.
             $match = self::matchSpamRegex($this->summary);
         }
     }
     if ($match === false) {
         $match = self::matchSpamRegex($this->textbox1);
     }
     if ($match !== false) {
         $result['spam'] = $match;
         $ip = $wgRequest->getIP();
         $pdbk = $this->mTitle->getPrefixedDBkey();
         $match = str_replace("\n", '', $match);
         wfDebugLog('SpamRegex', "{$ip} spam regex hit [[{$pdbk}]]: \"{$match}\"");
         $status->fatal('spamprotectionmatch', $match);
         $status->value = self::AS_SPAM_ERROR;
         wfProfileOut(__METHOD__ . '-checks');
         wfProfileOut(__METHOD__);
         return $status;
     }
     if (!wfRunHooks('EditFilter', array($this, $this->textbox1, $this->section, &$this->hookError, $this->summary))) {
         # Error messages etc. could be handled within the hook...
         $status->fatal('hookaborted');
         $status->value = self::AS_HOOK_ERROR;
         wfProfileOut(__METHOD__ . '-checks');
         wfProfileOut(__METHOD__);
         return $status;
     } elseif ($this->hookError != '') {
         # ...or the hook could be expecting us to produce an error
         $status->fatal('hookaborted');
         $status->value = self::AS_HOOK_ERROR_EXPECTED;
         wfProfileOut(__METHOD__ . '-checks');
         wfProfileOut(__METHOD__);
         return $status;
     }
     if ($wgUser->isBlockedFrom($this->mTitle, false)) {
         // Auto-block user's IP if the account was "hard" blocked
         $wgUser->spreadAnyEditBlock();
         # Check block state against master, thus 'false'.
         $status->setResult(false, self::AS_BLOCKED_PAGE_FOR_USER);
         wfProfileOut(__METHOD__ . '-checks');
         wfProfileOut(__METHOD__);
         return $status;
     }
     $this->kblength = (int) (strlen($this->textbox1) / 1024);
     if ($this->kblength > $wgMaxArticleSize) {
         // Error will be displayed by showEditForm()
         $this->tooBig = true;
         $status->setResult(false, self::AS_CONTENT_TOO_BIG);
         wfProfileOut(__METHOD__ . '-checks');
         wfProfileOut(__METHOD__);
         return $status;
     }
     if (!$wgUser->isAllowed('edit')) {
         if ($wgUser->isAnon()) {
             $status->setResult(false, self::AS_READ_ONLY_PAGE_ANON);
             wfProfileOut(__METHOD__ . '-checks');
             wfProfileOut(__METHOD__);
             return $status;
         } else {
             $status->fatal('readonlytext');
             $status->value = self::AS_READ_ONLY_PAGE_LOGGED;
             wfProfileOut(__METHOD__ . '-checks');
             wfProfileOut(__METHOD__);
             return $status;
         }
     }
     if ($this->contentModel !== $this->mTitle->getContentModel() && !$wgUser->isAllowed('editcontentmodel')) {
         $status->setResult(false, self::AS_NO_CHANGE_CONTENT_MODEL);
         wfProfileOut(__METHOD__ . '-checks');
         wfProfileOut(__METHOD__);
         return $status;
     }
     if (wfReadOnly()) {
         $status->fatal('readonlytext');
         $status->value = self::AS_READ_ONLY_PAGE;
         wfProfileOut(__METHOD__ . '-checks');
         wfProfileOut(__METHOD__);
         return $status;
     }
     if ($wgUser->pingLimiter() || $wgUser->pingLimiter('linkpurge', 0)) {
         $status->fatal('actionthrottledtext');
         $status->value = self::AS_RATE_LIMITED;
         wfProfileOut(__METHOD__ . '-checks');
         wfProfileOut(__METHOD__);
         return $status;
     }
     # If the article has been deleted while editing, don't save it without
     # confirmation
     if ($this->wasDeletedSinceLastEdit() && !$this->recreate) {
         $status->setResult(false, self::AS_ARTICLE_WAS_DELETED);
         wfProfileOut(__METHOD__ . '-checks');
         wfProfileOut(__METHOD__);
         return $status;
     }
     wfProfileOut(__METHOD__ . '-checks');
     # Load the page data from the master. If anything changes in the meantime,
     # we detect it by using page_latest like a token in a 1 try compare-and-swap.
     $this->mArticle->loadPageData('fromdbmaster');
     $new = !$this->mArticle->exists();
     if ($new) {
         // Late check for create permission, just in case *PARANOIA*
         if (!$this->mTitle->userCan('create', $wgUser)) {
             $status->fatal('nocreatetext');
             $status->value = self::AS_NO_CREATE_PERMISSION;
             wfDebug(__METHOD__ . ": no create permission\n");
             wfProfileOut(__METHOD__);
             return $status;
         }
         // Don't save a new page if it's blank or if it's a MediaWiki:
         // message with content equivalent to default (allow empty pages
         // in this case to disable messages, see bug 50124)
         $defaultMessageText = $this->mTitle->getDefaultMessageText();
         if ($this->mTitle->getNamespace() === NS_MEDIAWIKI && $defaultMessageText !== false) {
             $defaultText = $defaultMessageText;
         } else {
             $defaultText = '';
         }
         if (!$this->allowBlankArticle && $this->textbox1 === $defaultText) {
             $this->blankArticle = true;
             $status->fatal('blankarticle');
             $status->setResult(false, self::AS_BLANK_ARTICLE);
             wfProfileOut(__METHOD__);
             return $status;
         }
         if (!$this->runPostMergeFilters($textbox_content, $status, $wgUser)) {
             wfProfileOut(__METHOD__);
             return $status;
         }
         $content = $textbox_content;
         $result['sectionanchor'] = '';
         if ($this->section == 'new') {
             if ($this->sectiontitle !== '') {
                 // Insert the section title above the content.
                 $content = $content->addSectionHeader($this->sectiontitle);
             } elseif ($this->summary !== '') {
                 // Insert the section title above the content.
                 $content = $content->addSectionHeader($this->summary);
             }
             $this->summary = $this->newSectionSummary($result['sectionanchor']);
         }
         $status->value = self::AS_SUCCESS_NEW_ARTICLE;
     } else {
         # not $new
         # Article exists. Check for edit conflict.
         $this->mArticle->clear();
         # Force reload of dates, etc.
         $timestamp = $this->mArticle->getTimestamp();
         wfDebug("timestamp: {$timestamp}, edittime: {$this->edittime}\n");
         if ($timestamp != $this->edittime) {
             $this->isConflict = true;
             if ($this->section == 'new') {
                 if ($this->mArticle->getUserText() == $wgUser->getName() && $this->mArticle->getComment() == $this->newSectionSummary()) {
                     // Probably a duplicate submission of a new comment.
                     // This can happen when squid resends a request after
                     // a timeout but the first one actually went through.
                     wfDebug(__METHOD__ . ": duplicate new section submission; trigger edit conflict!\n");
                 } else {
                     // New comment; suppress conflict.
                     $this->isConflict = false;
                     wfDebug(__METHOD__ . ": conflict suppressed; new section\n");
                 }
             } elseif ($this->section == '' && Revision::userWasLastToEdit(DB_MASTER, $this->mTitle->getArticleID(), $wgUser->getId(), $this->edittime)) {
                 # Suppress edit conflict with self, except for section edits where merging is required.
                 wfDebug(__METHOD__ . ": Suppressing edit conflict, same user.\n");
                 $this->isConflict = false;
             }
         }
         // If sectiontitle is set, use it, otherwise use the summary as the section title.
         if ($this->sectiontitle !== '') {
             $sectionTitle = $this->sectiontitle;
         } else {
             $sectionTitle = $this->summary;
         }
         $content = null;
         if ($this->isConflict) {
             wfDebug(__METHOD__ . ": conflict! getting section '{$this->section}' for time '{$this->edittime}'" . " (article time '{$timestamp}')\n");
             $content = $this->mArticle->replaceSectionContent($this->section, $textbox_content, $sectionTitle, $this->edittime);
         } else {
             wfDebug(__METHOD__ . ": getting section '{$this->section}'\n");
             $content = $this->mArticle->replaceSectionContent($this->section, $textbox_content, $sectionTitle);
         }
         if (is_null($content)) {
             wfDebug(__METHOD__ . ": activating conflict; section replace failed.\n");
             $this->isConflict = true;
             $content = $textbox_content;
             // do not try to merge here!
         } elseif ($this->isConflict) {
             # Attempt merge
             if ($this->mergeChangesIntoContent($content)) {
                 // Successful merge! Maybe we should tell the user the good news?
                 $this->isConflict = false;
                 wfDebug(__METHOD__ . ": Suppressing edit conflict, successful merge.\n");
             } else {
                 $this->section = '';
                 $this->textbox1 = ContentHandler::getContentText($content);
                 wfDebug(__METHOD__ . ": Keeping edit conflict, failed merge.\n");
             }
         }
         if ($this->isConflict) {
             $status->setResult(false, self::AS_CONFLICT_DETECTED);
             wfProfileOut(__METHOD__);
             return $status;
         }
         if (!$this->runPostMergeFilters($content, $status, $wgUser)) {
             wfProfileOut(__METHOD__);
             return $status;
         }
         if ($this->section == 'new') {
             // Handle the user preference to force summaries here
             if (!$this->allowBlankSummary && trim($this->summary) == '') {
                 $this->missingSummary = true;
                 $status->fatal('missingsummary');
                 // or 'missingcommentheader' if $section == 'new'. Blegh
                 $status->value = self::AS_SUMMARY_NEEDED;
                 wfProfileOut(__METHOD__);
                 return $status;
             }
             // Do not allow the user to post an empty comment
             if ($this->textbox1 == '') {
                 $this->missingComment = true;
                 $status->fatal('missingcommenttext');
                 $status->value = self::AS_TEXTBOX_EMPTY;
                 wfProfileOut(__METHOD__);
                 return $status;
             }
         } elseif (!$this->allowBlankSummary && !$content->equals($this->getOriginalContent($wgUser)) && !$content->isRedirect() && md5($this->summary) == $this->autoSumm) {
             $this->missingSummary = true;
             $status->fatal('missingsummary');
             $status->value = self::AS_SUMMARY_NEEDED;
             wfProfileOut(__METHOD__);
             return $status;
         }
         # All's well
         wfProfileIn(__METHOD__ . '-sectionanchor');
         $sectionanchor = '';
         if ($this->section == 'new') {
             $this->summary = $this->newSectionSummary($sectionanchor);
         } elseif ($this->section != '') {
             # Try to get a section anchor from the section source, redirect
             # to edited section if header found.
             # XXX: Might be better to integrate this into Article::replaceSection
             # for duplicate heading checking and maybe parsing.
             $hasmatch = preg_match("/^ *([=]{1,6})(.*?)(\\1) *\\n/i", $this->textbox1, $matches);
             # We can't deal with anchors, includes, html etc in the header for now,
             # headline would need to be parsed to improve this.
             if ($hasmatch && strlen($matches[2]) > 0) {
                 $sectionanchor = $wgParser->guessLegacySectionNameFromWikiText($matches[2]);
             }
         }
         $result['sectionanchor'] = $sectionanchor;
         wfProfileOut(__METHOD__ . '-sectionanchor');
         // Save errors may fall down to the edit form, but we've now
         // merged the section into full text. Clear the section field
         // so that later submission of conflict forms won't try to
         // replace that into a duplicated mess.
         $this->textbox1 = $this->toEditText($content);
         $this->section = '';
         $status->value = self::AS_SUCCESS_UPDATE;
     }
     // Check for length errors again now that the section is merged in
     $this->kblength = (int) (strlen($this->toEditText($content)) / 1024);
     if ($this->kblength > $wgMaxArticleSize) {
         $this->tooBig = true;
         $status->setResult(false, self::AS_MAX_ARTICLE_SIZE_EXCEEDED);
         wfProfileOut(__METHOD__);
         return $status;
     }
     $flags = EDIT_DEFER_UPDATES | EDIT_AUTOSUMMARY | ($new ? EDIT_NEW : EDIT_UPDATE) | ($this->minoredit && !$this->isNew ? EDIT_MINOR : 0) | ($bot ? EDIT_FORCE_BOT : 0);
     $doEditStatus = $this->mArticle->doEditContent($content, $this->summary, $flags, false, null, $content->getDefaultFormat());
     if (!$doEditStatus->isOK()) {
         // Failure from doEdit()
         // Show the edit conflict page for certain recognized errors from doEdit(),
         // but don't show it for errors from extension hooks
         $errors = $doEditStatus->getErrorsArray();
         if (in_array($errors[0][0], array('edit-gone-missing', 'edit-conflict', 'edit-already-exists'))) {
             $this->isConflict = true;
             // Destroys data doEdit() put in $status->value but who cares
             $doEditStatus->value = self::AS_END;
         }
         wfProfileOut(__METHOD__);
         return $doEditStatus;
     }
     $result['nullEdit'] = $doEditStatus->hasMessage('edit-no-change');
     if ($result['nullEdit']) {
         // We don't know if it was a null edit until now, so increment here
         $wgUser->pingLimiter('linkpurge');
     }
     $result['redirect'] = $content->isRedirect();
     $this->updateWatchlist();
     wfProfileOut(__METHOD__);
     return $status;
 }
예제 #8
0
 /**
  * Move page to a title which is either a redirect to the
  * source page or nonexistent
  *
  * @fixme This was basically directly moved from Title, it should be split into smaller functions
  * @param User $user the User doing the move
  * @param Title $nt The page to move to, which should be a redirect or nonexistent
  * @param string $reason The reason for the move
  * @param bool $createRedirect Whether to leave a redirect at the old title. Does not check
  *   if the user has the suppressredirect right
  * @throws MWException
  */
 private function moveToInternal(User $user, &$nt, $reason = '', $createRedirect = true)
 {
     global $wgContLang;
     if ($nt->exists()) {
         $moveOverRedirect = true;
         $logType = 'move_redir';
     } else {
         $moveOverRedirect = false;
         $logType = 'move';
     }
     if ($createRedirect) {
         if ($this->oldTitle->getNamespace() == NS_CATEGORY && !wfMessage('category-move-redirect-override')->inContentLanguage()->isDisabled()) {
             $redirectContent = new WikitextContent(wfMessage('category-move-redirect-override')->params($nt->getPrefixedText())->inContentLanguage()->plain());
         } else {
             $contentHandler = ContentHandler::getForTitle($this->oldTitle);
             $redirectContent = $contentHandler->makeRedirectContent($nt, wfMessage('move-redirect-text')->inContentLanguage()->plain());
         }
         // NOTE: If this page's content model does not support redirects, $redirectContent will be null.
     } else {
         $redirectContent = null;
     }
     // Figure out whether the content model is no longer the default
     $oldDefault = ContentHandler::getDefaultModelFor($this->oldTitle);
     $contentModel = $this->oldTitle->getContentModel();
     $newDefault = ContentHandler::getDefaultModelFor($nt);
     $defaultContentModelChanging = $oldDefault !== $newDefault && $oldDefault === $contentModel;
     // bug 57084: log_page should be the ID of the *moved* page
     $oldid = $this->oldTitle->getArticleID();
     $logTitle = clone $this->oldTitle;
     $logEntry = new ManualLogEntry('move', $logType);
     $logEntry->setPerformer($user);
     $logEntry->setTarget($logTitle);
     $logEntry->setComment($reason);
     $logEntry->setParameters(array('4::target' => $nt->getPrefixedText(), '5::noredir' => $redirectContent ? '0' : '1'));
     $formatter = LogFormatter::newFromEntry($logEntry);
     $formatter->setContext(RequestContext::newExtraneousContext($this->oldTitle));
     $comment = $formatter->getPlainActionText();
     if ($reason) {
         $comment .= wfMessage('colon-separator')->inContentLanguage()->text() . $reason;
     }
     # Truncate for whole multibyte characters.
     $comment = $wgContLang->truncate($comment, 255);
     $dbw = wfGetDB(DB_MASTER);
     $oldpage = WikiPage::factory($this->oldTitle);
     $oldcountable = $oldpage->isCountable();
     $newpage = WikiPage::factory($nt);
     if ($moveOverRedirect) {
         $newid = $nt->getArticleID();
         $newcontent = $newpage->getContent();
         # Delete the old redirect. We don't save it to history since
         # by definition if we've got here it's rather uninteresting.
         # We have to remove it so that the next step doesn't trigger
         # a conflict on the unique namespace+title index...
         $dbw->delete('page', array('page_id' => $newid), __METHOD__);
         $newpage->doDeleteUpdates($newid, $newcontent);
     }
     # Save a null revision in the page's history notifying of the move
     $nullRevision = Revision::newNullRevision($dbw, $oldid, $comment, true, $user);
     if (!is_object($nullRevision)) {
         throw new MWException('No valid null revision produced in ' . __METHOD__);
     }
     $nullRevision->insertOn($dbw);
     # Change the name of the target page:
     $dbw->update('page', array('page_namespace' => $nt->getNamespace(), 'page_title' => $nt->getDBkey()), array('page_id' => $oldid), __METHOD__);
     // clean up the old title before reset article id - bug 45348
     if (!$redirectContent) {
         WikiPage::onArticleDelete($this->oldTitle);
     }
     $this->oldTitle->resetArticleID(0);
     // 0 == non existing
     $nt->resetArticleID($oldid);
     $newpage->loadPageData(WikiPage::READ_LOCKING);
     // bug 46397
     $newpage->updateRevisionOn($dbw, $nullRevision);
     Hooks::run('NewRevisionFromEditComplete', array($newpage, $nullRevision, $nullRevision->getParentId(), $user));
     $newpage->doEditUpdates($nullRevision, $user, array('changed' => false, 'moved' => true, 'oldcountable' => $oldcountable));
     // If the default content model changes, we need to populate rev_content_model
     if ($defaultContentModelChanging) {
         $dbw->update('revision', array('rev_content_model' => $contentModel), array('rev_page' => $nt->getArticleID(), 'rev_content_model IS NULL'), __METHOD__);
     }
     if (!$moveOverRedirect) {
         WikiPage::onArticleCreate($nt);
     }
     # Recreate the redirect, this time in the other direction.
     if ($redirectContent) {
         $redirectArticle = WikiPage::factory($this->oldTitle);
         $redirectArticle->loadFromRow(false, WikiPage::READ_LOCKING);
         // bug 46397
         $newid = $redirectArticle->insertOn($dbw);
         if ($newid) {
             // sanity
             $this->oldTitle->resetArticleID($newid);
             $redirectRevision = new Revision(array('title' => $this->oldTitle, 'page' => $newid, 'user_text' => $user->getName(), 'user' => $user->getId(), 'comment' => $comment, 'content' => $redirectContent));
             $redirectRevision->insertOn($dbw);
             $redirectArticle->updateRevisionOn($dbw, $redirectRevision, 0);
             Hooks::run('NewRevisionFromEditComplete', array($redirectArticle, $redirectRevision, false, $user));
             $redirectArticle->doEditUpdates($redirectRevision, $user, array('created' => true));
         }
     }
     # Log the move
     $logid = $logEntry->insert();
     $logEntry->publish($logid);
 }
예제 #9
0
 /**
  * @param $article Article
  */
 public function __construct(Article $article)
 {
     $this->mArticle = $article;
     $this->mTitle = $article->getTitle();
     $this->contentModel = $this->mTitle->getContentModel();
     $handler = ContentHandler::getForModelID($this->contentModel);
     $this->contentFormat = $handler->getDefaultFormat();
 }
 public static function onTitleMoveComplete(Title $oldTitle, Title $newTitle, User $user, $pageid, $redirid, $reason)
 {
     if ($newTitle->getContentModel() === CONTENT_MODEL_FLOW_BOARD) {
         Container::get('board_mover')->commit();
     }
     return true;
 }