/** * Check that we can perform the rename * * @param User $oldUser * @param User $newUser * * @return Status */ public function validate(User $oldUser, User $newUser) { $status = new Status(); if (!User::isCreatableName($newUser->getName())) { $status->fatal('centralauth-rename-badusername'); } $caOldUser = CentralAuthUser::getInstance($oldUser); if (!$caOldUser->exists()) { $status->fatal('centralauth-rename-doesnotexist'); } $caNewUser = CentralAuthUser::getInstance($newUser); if ($caNewUser->exists()) { $status->fatal('centralauth-rename-alreadyexists'); } $unattached = $caNewUser->listUnattached(); if ($unattached) { $status->fatal('centralauth-rename-unattached-intheway'); } // Check we're not currently renaming the user $renameState = $caOldUser->renameInProgress(); if ($renameState) { $status->fatal('centralauth-rename-alreadyinprogress', $renameState[1]); } return $status; }
/** * Hook function for EditFilterMergedContent * * @param IContextSource $context * @param Content $content * @param Status $status * @param string $summary * @param User $user * @param bool $minoredit * * @return bool */ static function filterMergedContent(IContextSource $context, Content $content, Status $status, $summary, User $user, $minoredit) { $title = $context->getTitle(); if (isset($title->spamBlackListFiltered) && $title->spamBlackListFiltered) { // already filtered return true; } // get the link from the not-yet-saved page content. // no need to generate html to get external links $pout = $content->getParserOutput($title, null, null, false); $links = array_keys($pout->getExternalLinks()); // HACK: treat the edit summary as a link if ($summary !== '') { $links[] = $summary; } $spamObj = BaseBlacklist::getInstance('spam'); $matches = $spamObj->filter($links, $title); if ($matches !== false) { $status->fatal('spamprotectiontext'); foreach ($matches as $match) { $status->fatal('spamprotectionmatch', $match); } } // Always return true, EditPage will look at $status->isOk(). return true; }
/** * MovePageCheckPermissions hook (1.25+) * * @param Title $oldTitle * @param Title $newTitle * @param User $user * @param $reason * @param Status $status * @return bool */ public static function onMovePageCheckPermissions(Title $oldTitle, Title $newTitle, User $user, $reason, Status $status) { $titleBlacklist = TitleBlacklist::singleton(); $blacklisted = $titleBlacklist->userCannot($newTitle, $user, 'move'); if (!$blacklisted) { $blacklisted = $titleBlacklist->userCannot($oldTitle, $user, 'edit'); } if ($blacklisted instanceof TitleBlacklistEntry) { $errmsg = $blacklisted->getErrorMessage('move'); ApiBase::$messageMap[$errmsg] = array('code' => $errmsg, 'info' => 'TitleBlacklist prevents this new title from being created or old title from being edited'); $status->fatal($errmsg, $blacklisted->getRaw(), $oldTitle->getFullText(), $newTitle->getFullText()); return false; } return true; }
/** * Send out the message * * @param $data Array * @return Status */ protected function submit(array $data) { $spamlist = $this->getSpamlist($data['spamlist']); // Prep the HTML comment message $data['comment'] = array($this->getUser()->getName(), wfWikiID(), $spamlist->getFullURL('', false, PROTO_CANONICAL)); // Log it. $this->logToWiki($spamlist, $data['subject']); // Insert it into the job queue. $pages = MassMessage::getParserFunctionTargets($spamlist, $this->getContext()); if (!is_array($pages)) { $this->status->fatal($pages); return $this->status; } $params = array('data' => $data, 'pages' => $pages); $job = new MassMessageSubmitJob($spamlist, $params); JobQueueGroup::singleton()->push($job); $this->count = count($pages); return $this->status; }
/** * Log an unexpected exception for this backend. * This also sets the Status object to have a fatal error. * * @param Status|null $status * @param string $func * @param array $params * @param string $err Error string * @param int $code HTTP status * @param string $desc HTTP status description */ public function onError($status, $func, array $params, $err = '', $code = 0, $desc = '') { if ($status instanceof Status) { $status->fatal('backend-fail-internal', $this->name); } if ($code == 401) { // possibly a stale token $this->srvCache->delete($this->getCredsCacheKey($this->swiftUser)); } wfDebugLog('SwiftBackend', "HTTP {$code} ({$desc}) in '{$func}' (given '" . FormatJson::encode($params) . "')" . ($err ? ": {$err}" : "")); }
/** * @see SwiftFileBackend::doExecuteOpHandlesInternal() */ protected function _getResponseDelete(CF_Async_Op $cfOp, Status $status, array $params) { try { $cfOp->getLastResponse(); } catch (NoSuchContainerException $e) { $status->fatal('backend-fail-delete', $params['src']); } catch (NoSuchObjectException $e) { if (empty($params['ignoreMissingSource'])) { $status->fatal('backend-fail-delete', $params['src']); } } }
/** * Actually attempt the history move * * @todo if all versions of page A are moved to B and then a user * tries to do a reverse-merge via the "unmerge" log link, then page * A will still be a redirect (as it was after the original merge), * though it will have the old revisions back from before (as expected). * The user may have to "undo" the redirect manually to finish the "unmerge". * Maybe this should delete redirects at the source page of merges? * * @param User $user * @param string $reason * @return Status status of the history merge */ public function merge(User $user, $reason = '') { $status = new Status(); // Check validity and permissions required for merge $validCheck = $this->isValidMerge(); // Check this first to check for null pages if (!$validCheck->isOK()) { return $validCheck; } $permCheck = $this->checkPermissions($user, $reason); if (!$permCheck->isOK()) { return $permCheck; } $this->dbw->update('revision', array('rev_page' => $this->dest->getArticleID()), array('rev_page' => $this->source->getArticleID(), $this->timeWhere), __METHOD__); // Check if this did anything $this->revisionsMerged = $this->dbw->affectedRows(); if ($this->revisionsMerged < 1) { $status->fatal('mergehistory-fail-no-change'); return $status; } // Make the source page a redirect if no revisions are left $haveRevisions = $this->dbw->selectField('revision', 'rev_timestamp', array('rev_page' => $this->source->getArticleID()), __METHOD__, array('FOR UPDATE')); if (!$haveRevisions) { if ($reason) { $reason = wfMessage('mergehistory-comment', $this->source->getPrefixedText(), $this->dest->getPrefixedText(), $reason)->inContentLanguage()->text(); } else { $reason = wfMessage('mergehistory-autocomment', $this->source->getPrefixedText(), $this->dest->getPrefixedText())->inContentLanguage()->text(); } $contentHandler = ContentHandler::getForTitle($this->source); $redirectContent = $contentHandler->makeRedirectContent($this->dest, wfMessage('mergehistory-redirect-text')->inContentLanguage()->plain()); if ($redirectContent) { $redirectPage = WikiPage::factory($this->source); $redirectRevision = new Revision(array('title' => $this->source, 'page' => $this->source->getArticleID(), 'comment' => $reason, 'content' => $redirectContent)); $redirectRevision->insertOn($this->dbw); $redirectPage->updateRevisionOn($this->dbw, $redirectRevision); // Now, we record the link from the redirect to the new title. // It should have no other outgoing links... $this->dbw->delete('pagelinks', array('pl_from' => $this->dest->getArticleID()), __METHOD__); $this->dbw->insert('pagelinks', array('pl_from' => $this->dest->getArticleID(), 'pl_from_namespace' => $this->dest->getNamespace(), 'pl_namespace' => $this->dest->getNamespace(), 'pl_title' => $this->dest->getDBkey()), __METHOD__); } else { // Warning if we couldn't create the redirect $status->warning('mergehistory-warning-redirect-not-created'); } } else { $this->source->invalidateCache(); // update histories } $this->dest->invalidateCache(); // update histories // Update our logs $logEntry = new ManualLogEntry('merge', 'merge'); $logEntry->setPerformer($user); $logEntry->setComment($reason); $logEntry->setTarget($this->source); $logEntry->setParameters(array('4::dest' => $this->dest->getPrefixedText(), '5::mergepoint' => $this->timestampLimit->getTimestamp(TS_MW))); $logId = $logEntry->insert(); $logEntry->publish($logId); Hooks::run('ArticleMergeComplete', array($this->source, $this->dest)); return $status; }
/** * @covers Status::hasMessage */ public function testHasMessage() { $status = new Status(); $status->fatal('bad'); $status->fatal(wfMessage('bad-msg')); $this->assertTrue($status->hasMessage('bad')); $this->assertTrue($status->hasMessage('bad-msg')); $this->assertTrue($status->hasMessage(wfMessage('bad-msg'))); $this->assertFalse($status->hasMessage('good')); }
/** * Run hooks that can filter edits just before they get saved. * * @param Content $content The Content to filter. * @param Status $status For reporting the outcome to the caller * @param User $user The user performing the edit * * @return bool */ protected function runPostMergeFilters(Content $content, Status $status, User $user) { // Run old style post-section-merge edit filter if (!ContentHandler::runLegacyHooks('EditFilterMerged', array($this, $content, &$this->hookError, $this->summary))) { # Error messages etc. could be handled within the hook... $status->fatal('hookaborted'); $status->value = self::AS_HOOK_ERROR; return false; } elseif ($this->hookError != '') { # ...or the hook could be expecting us to produce an error $status->fatal('hookaborted'); $status->value = self::AS_HOOK_ERROR_EXPECTED; return false; } // Run new style post-section-merge edit filter if (!wfRunHooks('EditFilterMergedContent', array($this->mArticle->getContext(), $content, $status, $this->summary, $user, $this->minoredit))) { # Error messages etc. could be handled within the hook... // XXX: $status->value may already be something informative... $this->hookError = $status->getWikiText(); $status->fatal('hookaborted'); $status->value = self::AS_HOOK_ERROR; return false; } elseif (!$status->isOK()) { # ...or the hook could be expecting us to produce an error // FIXME this sucks, we should just use the Status object throughout $this->hookError = $status->getWikiText(); $status->fatal('hookaborted'); $status->value = self::AS_HOOK_ERROR_EXPECTED; return false; } return true; }
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']); $titleWithNewContentModel = clone $this->title; $titleWithNewContentModel->setContentModel($data['model']); $user = $this->getUser(); // Check permissions and make sure the user has permission to: $errors = wfMergeErrorArrays($this->title->getUserPermissionsErrors('editcontentmodel', $user), $this->title->getUserPermissionsErrors('edit', $user), $titleWithNewContentModel->getUserPermissionsErrors('editcontentmodel', $user), $titleWithNewContentModel->getUserPermissionsErrors('edit', $user)); if ($errors) { $out = $this->getOutput(); $wikitext = $out->formatPermissionsErrorMessage($errors); // Hack to get our wikitext parsed return Status::newFatal(new RawMessage('$1', [$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(); } // All other checks have passed, let's check rate limits if ($user->pingLimiter('editcontentmodel')) { throw new ThrottledError(); } $flags = $this->oldRevision ? EDIT_UPDATE : EDIT_NEW; $flags |= EDIT_INTERNAL; if ($user->isAllowed('bot')) { $flags |= EDIT_FORCE_BOT; } $log = new ManualLogEntry('contentmodel', $this->oldRevision ? 'change' : 'new'); $log->setPerformer($user); $log->setTarget($this->title); $log->setComment($data['reason']); $log->setParameters(['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); // Run edit filters $derivativeContext = new DerivativeContext($this->getContext()); $derivativeContext->setTitle($this->title); $derivativeContext->setWikiPage($page); $status = new Status(); if (!Hooks::run('EditFilterMergedContent', [$derivativeContext, $newContent, $status, $reason, $user, false])) { if ($status->isGood()) { // TODO: extensions should really specify an error message $status->fatal('hookaborted'); } return $status; } $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; }
/** * Sanity checks for when a file is being moved * * @return Status */ protected function isValidFileMove() { $status = new Status(); $file = wfLocalFile($this->oldTitle); $file->load(File::READ_LATEST); if ($file->exists()) { if ($this->newTitle->getText() != wfStripIllegalFilenameChars($this->newTitle->getText())) { $status->fatal('imageinvalidfilename'); } if (!File::checkExtensionCompatibility($file, $this->newTitle->getDBkey())) { $status->fatal('imagetypemismatch'); } } if (!$this->newTitle->inNamespace(NS_FILE)) { $status->fatal('imagenocrossnamespace'); } return $status; }
/** * Run hooks that can filter edits just before they get saved. * * @param Content $content The Content to filter. * @param Status $status For reporting the outcome to the caller * @param User $user The user performing the edit * * @return bool */ protected function runPostMergeFilters(Content $content, Status $status, User $user) { // Run old style post-section-merge edit filter if (!ContentHandler::runLegacyHooks('EditFilterMerged', array($this, $content, &$this->hookError, $this->summary))) { # Error messages etc. could be handled within the hook... $status->fatal('hookaborted'); $status->value = self::AS_HOOK_ERROR; return false; } elseif ($this->hookError != '') { # ...or the hook could be expecting us to produce an error $status->fatal('hookaborted'); $status->value = self::AS_HOOK_ERROR_EXPECTED; return false; } // Run new style post-section-merge edit filter if (!Hooks::run('EditFilterMergedContent', array($this->mArticle->getContext(), $content, $status, $this->summary, $user, $this->minoredit))) { # Error messages etc. could be handled within the hook... if ($status->isGood()) { $status->fatal('hookaborted'); // Not setting $this->hookError here is a hack to allow the hook // to cause a return to the edit page without $this->hookError // being set. This is used by ConfirmEdit to display a captcha // without any error message cruft. } else { $this->hookError = $status->getWikiText(); } // Use the existing $status->value if the hook set it if (!$status->value) { $status->value = self::AS_HOOK_ERROR; } return false; } elseif (!$status->isOK()) { # ...or the hook could be expecting us to produce an error // FIXME this sucks, we should just use the Status object throughout $this->hookError = $status->getWikiText(); $status->fatal('hookaborted'); $status->value = self::AS_HOOK_ERROR_EXPECTED; return false; } return true; }
/** * Sets HTTPRequest status member to a fatal value with the error * message if the returned integer value of the status code was * not successful (< 300) or a redirect (>=300 and < 400). (see * RFC2616, section 10, * http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html for a * list of status codes.) * * @return nothing */ protected function setStatus() { if (!$this->respHeaders) { $this->parseHeader(); } if ((int) $this->respStatus > 399) { list($code, $message) = explode(" ", $this->respStatus, 2); $this->status->fatal("http-bad-status", $code, $message); } }
/** * @see FSFileBackend::doExecuteOpHandlesInternal() */ protected function _getResponseDelete($errors, Status $status, array $params, $cmd) { if ($errors !== '' && !(wfIsWindows() && $errors[0] === " ")) { $status->fatal('backend-fail-delete', $params['src']); trigger_error("{$cmd}\n{$errors}", E_USER_WARNING); // command output } }
public static function onMovePageIsValidMove(Title $oldTitle, Title $newTitle, Status $status) { global $wgFlowOccupyNamespaces, $wgUser; // We only care about moving flow boards if ($oldTitle->getContentModel() !== CONTENT_MODEL_FLOW_BOARD) { return true; } // pages within the Topic namespace are not movable if ($oldTitle->getNamespace() === NS_TOPIC) { $status->fatal('flow-error-move-topic'); return false; } $occupationController = self::getOccupationController(); if (!$occupationController->isTalkpageOccupied($newTitle, false) && !$wgUser->isAllowed('flow-create-board')) { $status->fatal('flow-error-move-no-create-permissions'); return false; } return true; }
/** * An efficient edit filter callback based on the text after section merging * @param RequestContext $context * @param Content $content * @param Status $status * @param $summary * @param $user * @param $minorEdit * @return bool */ function confirmEditMerged($context, $content, $status, $summary, $user, $minorEdit) { $legacyMode = !defined('MW_EDITFILTERMERGED_SUPPORTS_API'); if (defined('MW_API') && $legacyMode) { # API mode # The CAPTCHA was already checked and approved return true; } $page = $context->getWikiPage(); if (!$this->doConfirmEdit($page, $content, false, true)) { if ($legacyMode) { $status->fatal('hookaborted'); } $status->value = EditPage::AS_HOOK_ERROR_EXPECTED; $status->apiHookResult = array(); $this->addCaptchaAPI($status->apiHookResult); $page->ConfirmEdit_ActivateCaptcha = true; return $legacyMode; } return true; }
/** * An efficient edit filter callback based on the text after section merging * @param RequestContext $context * @param Content $content * @param Status $status * @param $summary * @param $user * @param $minorEdit * @return bool */ function confirmEditMerged($context, $content, $status, $summary, $user, $minorEdit) { $legacyMode = !defined('MW_EDITFILTERMERGED_SUPPORTS_API'); if (defined('MW_API') && $legacyMode) { # API mode # The CAPTCHA was already checked and approved return true; } if (!$context->canUseWikiPage()) { // we check WikiPage only // try to get an appropriate title for this page $title = $context->getTitle(); if ($title instanceof Title) { $title = $title->getFullText(); } else { // otherwise it's an unknown page where this function is called from $title = 'unknown'; } // log this error, it could be a problem in another extension, edits should always have a WikiPage if // they go through EditFilterMergedContent. wfDebug(__METHOD__ . ': Skipped ConfirmEdit check: No WikiPage for title ' . $title); return true; } $page = $context->getWikiPage(); if (!$this->doConfirmEdit($page, $content, false, $context)) { if ($legacyMode) { $status->fatal('hookaborted'); } $status->value = EditPage::AS_HOOK_ERROR_EXPECTED; $status->apiHookResult = array(); $this->addCaptchaAPI($status->apiHookResult); $page->ConfirmEdit_ActivateCaptcha = true; return $legacyMode; } return true; }