function EditOwn($title, $user, $action, &$result) { static $cache = array(); global $wgEditOwnExcludedNamespaces, $wgEditOwnActions; if (!is_array($wgEditOwnExcludedNamespaces)) { // Prevent PHP from whining $wgEditOwnExcludedNamespaces = array(); } if (!in_array($action, $wgEditOwnActions) || $user->isAllowed('editall') || in_array($title->getNamespace(), $wgEditOwnExcludedNamespaces)) { $result = null; return true; } if (isset($cache[$user->getName()][$title->getArticleId()])) { $result = $cache[$user->getName()][$title->getArticleId()]; return is_null($result); } if (!$title->exists()) { // Creation is allowed $cache[$user->getName()][$title->getArticleId()] = null; $result = null; return true; } // Since there's no easy way to get the first revision, // we'll just do a DB query $dbr = wfGetDb(DB_SLAVE); $res = $dbr->select('revision', Revision::selectFields(), array('rev_page' => $title->getArticleId()), __METHOD__, array('ORDER BY' => 'rev_timestamp', 'LIMIT' => 1)); $row = $dbr->fetchObject($res); if (!$row) { // Title with no revs, weird... allow creation $cache[$user->getName()][$title->getArticleId()] = null; $result = null; return true; } $rev = new Revision($row); if ($user->getName() == $rev->getRawUserText()) { $cache[$user->getName()][$title->getArticleId()] = null; $result = null; return true; } $cache[$user->getName()][$title->getArticleId()] = false; $result = false; return false; }
private function extractRowInfo($row) { $revision = new Revision($row); $title = $revision->getTitle(); $user = $this->getUser(); $vals = array(); $anyHidden = false; 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'] = ''; $anyHidden = true; } if ($revision->userCan(Revision::DELETED_USER, $user)) { if ($this->fld_user) { $vals['user'] = $revision->getRawUserText(); } $userid = $revision->getRawUser(); 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->isDeleted(Revision::DELETED_TEXT)) { $vals['sha1hidden'] = ''; $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'] = ''; $anyHidden = true; } if ($revision->userCan(Revision::DELETED_COMMENT, $user)) { $comment = $revision->getRawComment(); 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->diffto) || !is_null($this->difftotext)) { $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'] = ''; $anyHidden = true; } elseif (!$content) { $vals['textmissing'] = ''; } } 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()), 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(); $model = $content->getModel(); if (!$content->isSupportedFormat($format)) { $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); // 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::setContent($vals, $text); } } if ($content && (!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'] = ''; } } if ($anyHidden && $revision->isDeleted(Revision::DELETED_RESTRICTED)) { $vals['suppressed'] = ''; } return $vals; }
/** * This function will return the number of revisions which a rollback * would revert and, if $verify is set it will verify that a revision * can be reverted (that the user isn't the only contributor and the * revision we might rollback to isn't deleted). These checks can only * function as an additional check as this function only checks against * the last $wgShowRollbackEditCount edits. * * Returns null if $wgShowRollbackEditCount is disabled or false if $verify * is set and the user is the only contributor of the page. * * @param Revision $rev * @param bool $verify Try to verify that this revision can really be rolled back * @return int|bool|null */ public static function getRollbackEditCount($rev, $verify) { global $wgShowRollbackEditCount; if (!is_int($wgShowRollbackEditCount) || !$wgShowRollbackEditCount > 0) { // Nothing has happened, indicate this by returning 'null' return null; } $dbr = wfGetDB(DB_SLAVE); // Up to the value of $wgShowRollbackEditCount revisions are counted $res = $dbr->select('revision', array('rev_user_text', 'rev_deleted'), array('rev_page' => $rev->getTitle()->getArticleID()), __METHOD__, array('USE INDEX' => array('revision' => 'page_timestamp'), 'ORDER BY' => 'rev_timestamp DESC', 'LIMIT' => $wgShowRollbackEditCount + 1)); $editCount = 0; $moreRevs = false; foreach ($res as $row) { if ($rev->getRawUserText() != $row->rev_user_text) { if ($verify && ($row->rev_deleted & Revision::DELETED_TEXT || $row->rev_deleted & Revision::DELETED_USER)) { // If the user or the text of the revision we might rollback // to is deleted in some way we can't rollback. Similar to // the sanity checks in WikiPage::commitRollback. return false; } $moreRevs = true; break; } $editCount++; } if ($verify && $editCount <= $wgShowRollbackEditCount && !$moreRevs) { // We didn't find at least $wgShowRollbackEditCount revisions made by the current user // and there weren't any other revisions. That means that the current user is the only // editor, so we can't rollback return false; } return $editCount; }