public function testPageDataFromTitle() { $title = Title::makeTitle(NS_MAIN, "somePage"); $article = new FlaggableWikiPage($title); $user = $this->user; $article->doEdit("Some text to insert", "creating a page", EDIT_NEW, false, $user); $data = (array) $article->pageDataFromTitle(wfGetDB(DB_SLAVE), $title); $this->assertEquals(true, array_key_exists('fpc_override', $data), "data->fpc_override field exists"); $this->assertEquals(true, array_key_exists('fp_stable', $data), "data->fp_stable field exists"); $this->assertEquals(true, array_key_exists('fp_pending_since', $data), "data->fp_pending_since field exists"); $this->assertEquals(true, array_key_exists('fp_reviewed', $data), "data->fp_reviewed field exists"); }
/** * This function does essentially the same as RevisionReview::AjaxReview, * except that it generates the template and image parameters itself. */ public function execute() { global $wgUser; $params = $this->extractRequestParams(); // Check basic permissions if (!$wgUser->isAllowed('review')) { $this->dieUsage("You don't have the right to review revisions.", 'permissiondenied'); } elseif ($wgUser->isBlocked(false)) { $this->dieUsageMsg(array('blockedtext')); } $newRev = Revision::newFromId($params['oldid']); if (!$newRev || !$newRev->getTitle()) { $this->dieUsage("Cannot find a revision with the specified ID.", 'notarget'); } $title = $newRev->getTitle(); $fa = FlaggableWikiPage::getTitleInstance($title); if (!$fa->isReviewable()) { $this->dieUsage("Provided page is not reviewable.", 'notreviewable'); } $status = false; if ($params['previd']) { // changes $oldRev = Revision::newFromId($params['previd']); if (!$oldRev || $oldRev->getPage() != $newRev->getPage()) { $this->dieUsage("Revisions do not belong to the same page.", 'notarget'); } // Mark as reviewing... if ($params['reviewing']) { $status = FRUserActivity::setUserReviewingDiff($wgUser, $params['previd'], $params['oldid']); // Unmark as reviewing... } else { $status = FRUserActivity::clearUserReviewingDiff($wgUser, $params['previd'], $params['oldid']); } } else { // Mark as reviewing... if ($params['reviewing']) { $status = FRUserActivity::setUserReviewingPage($wgUser, $newRev->getPage()); // Unmark as reviewing... } else { $status = FRUserActivity::clearUserReviewingPage($wgUser, $newRev->getPage()); } } # Success in setting flag... if ($status === true) { $this->getResult()->addValue(null, $this->getModuleName(), array('result' => 'Success')); # Failure... } else { $this->getResult()->addValue(null, $this->getModuleName(), array('result' => 'Failure')); } }
protected function list_reviewable_pages($fileHandle) { global $wgFlaggedRevsNamespaces, $wgUseSquid, $wgUseFileCache; $this->output("Building list of all reviewable pages to purge ...\n"); if (!$wgUseSquid && !$wgUseFileCache) { $this->output("Squid/file cache not enabled ... nothing to purge.\n"); return; } elseif (empty($wgFlaggedRevsNamespaces)) { $this->output("There are no reviewable namespaces ... nothing to purge.\n"); return; } $db = wfGetDB(DB_MASTER); $start = $db->selectField('page', 'MIN(page_id)', false, __FUNCTION__); $end = $db->selectField('page', 'MAX(page_id)', false, __FUNCTION__); if (is_null($start) || is_null($end)) { $this->output("... page table seems to be empty.\n"); return; } # Do remaining chunk $end += $this->mBatchSize - 1; $blockStart = $start; $blockEnd = $start + $this->mBatchSize - 1; $count = 0; while ($blockEnd <= $end) { $this->output("... doing page_id from {$blockStart} to {$blockEnd}\n"); $res = $db->select('page', '*', array("page_id BETWEEN {$blockStart} AND {$blockEnd}", 'page_namespace' => $wgFlaggedRevsNamespaces), __FUNCTION__); # Go through and append each purgeable page... foreach ($res as $row) { $title = Title::newFromRow($row); $fa = FlaggableWikiPage::getTitleInstance($title); if ($fa->isReviewable()) { # Need to purge this page - add to list fwrite($fileHandle, $title->getPrefixedDBKey() . "\n"); $count++; } } $db->freeResult($res); $blockStart += $this->mBatchSize - 1; $blockEnd += $this->mBatchSize - 1; wfWaitForSlaves(5); // not really needed } $this->output("List of reviewable pages to purge complete ... {$count} pages\n"); }
/** * This function does essentially the same as RevisionReview::AjaxReview, * except that it generates the template and image parameters itself. */ public function execute() { global $wgUser; $params = $this->extractRequestParams(); // Check basic permissions if (!$wgUser->isAllowed('review')) { $this->dieUsage("You don't have the right to review revisions.", 'permissiondenied'); } elseif ($wgUser->isBlocked(false)) { $this->dieUsageMsg(array('blockedtext')); } // Get target rev and title $revid = (int) $params['revid']; $rev = Revision::newFromId($revid); if (!$rev) { $this->dieUsage("Cannot find a revision with the specified ID.", 'notarget'); } $title = $rev->getTitle(); // Construct submit form... $form = new RevisionReviewForm($wgUser); $form->setPage($title); $form->setOldId($revid); $form->setApprove(empty($params['unapprove'])); $form->setUnapprove(!empty($params['unapprove'])); if (isset($params['comment'])) { $form->setComment($params['comment']); } // The flagging parameters have the form 'flag_$name'. // Extract them and put the values into $form->dims foreach (FlaggedRevs::getTags() as $tag) { $form->setDim($tag, (int) $params['flag_' . $tag]); } if ($form->getAction() === 'approve') { $article = new FlaggableWikiPage($title); // Get the file version used for File: pages $file = $article->getFile(); if ($file) { $fileVer = array('time' => $file->getTimestamp(), 'sha1' => $file->getSha1()); } else { $fileVer = null; } // Now get the template and image parameters needed list($templateIds, $fileTimeKeys) = FRInclusionCache::getRevIncludes($article, $rev, $wgUser); // Get version parameters for review submission (flat strings) list($templateParams, $imageParams, $fileParam) = RevisionReviewForm::getIncludeParams($templateIds, $fileTimeKeys, $fileVer); // Set the version parameters... $form->setTemplateParams($templateParams); $form->setFileParams($imageParams); $form->setFileVersion($fileParam); $form->bypassValidationKey(); // always OK; uses current templates/files } $status = $form->ready(); // all params set # Try to do the actual review $status = $form->submit(); # Approve/de-approve success if ($status === true) { $this->getResult()->addValue(null, $this->getModuleName(), array('result' => 'Success')); # Approve-specific failures } elseif ($form->getAction() === 'approve') { if ($status === 'review_denied') { $this->dieUsage("You don't have the necessary rights to set the specified flags.", 'permissiondenied'); } elseif ($status === 'review_too_low') { $this->dieUsage("Either all or none of the flags have to be set to zero.", 'mixedapproval'); } elseif ($status === 'review_bad_key') { $this->dieUsage("You don't have the necessary rights to set the specified flags.", 'permissiondenied'); } elseif ($status === 'review_bad_tags') { $this->dieUsage("The specified flags are not valid.", 'invalidtags'); } elseif ($status === 'review_bad_oldid') { $this->dieUsage("No revision with the specified ID.", 'notarget'); } else { // FIXME: review_param_missing? better msg? $this->dieUsageMsg(array('unknownerror', '')); } # De-approve specific failure } elseif ($form->getAction() === 'unapprove') { if ($status === 'review_denied') { $this->dieUsage("You don't have the necessary rights to remove the flags.", 'permissiondenied'); } elseif ($status === 'review_not_flagged') { $this->dieUsage("No flagged revision with the specified ID.", 'notarget'); } else { // FIXME: review_param_missing? better msg? $this->dieUsageMsg(array('unknownerror', '')); } # Generic failures } else { if ($status === 'review_page_unreviewable') { $this->dieUsage("Provided page is not reviewable.", 'notreviewable'); } elseif ($status === 'review_page_notexists') { $this->dieUsage("Provided page does not exist.", 'notarget'); } } }
/** * Add [checked version] and such to left and right side of diff */ protected static function diffReviewMarkers(FlaggableWikiPage $article, $oldRev, $newRev) { $table = ''; $srev = $article->getStableRev(); # Diff between two revisions if ($oldRev && $newRev) { list($msg, $class) = self::getDiffRevMsgAndClass($oldRev, $srev); $table .= "<table class='fr-diff-ratings'><tr>"; $table .= "<td width='50%' align='center'>"; $table .= "<span class='{$class}'>[" . wfMsgHtml($msg) . "]</span>"; list($msg, $class) = self::getDiffRevMsgAndClass($newRev, $srev); $table .= "</td><td width='50%' align='center'>"; $table .= "<span class='{$class}'>[" . wfMsgHtml($msg) . "]</span>"; $table .= "</td></tr></table>\n"; # New page "diffs" - just one rev } elseif ($newRev) { list($msg, $class) = self::getDiffRevMsgAndClass($newRev, $srev); $table .= "<table class='fr-diff-ratings'>"; $table .= "<tr><td align='center'><span class='{$class}'>"; $table .= '[' . wfMsgHtml($msg) . ']'; $table .= "</span></td></tr></table>\n"; } return $table; }
/** * Load any objects after ready() called * @return mixed (true on success, error string on failure) */ protected function doBuildOnReady() { $this->article = FlaggableWikiPage::getTitleInstance($this->page); return true; }
/** * Update the page tables with a new stable version. * @param WikiPage|Title $page * @param FlaggedRevision|null $sv, the new stable version (optional) * @param FlaggedRevision|null $oldSv, the old stable version (optional) * @param Object editInfo Article edit info about the current revision (optional) * @return bool stable version text/file changed and FR_INCLUDES_STABLE */ public static function stableVersionUpdates($page, $sv = null, $oldSv = null, $editInfo = null) { if ($page instanceof FlaggableWikiPage) { $article = $page; } elseif ($page instanceof WikiPage) { $article = FlaggableWikiPage::getTitleInstance($page->getTitle()); } elseif ($page instanceof Title) { $article = FlaggableWikiPage::getTitleInstance($page); } else { throw new MWException("First argument must be a Title or WikiPage."); } $title = $article->getTitle(); $changed = false; if ($oldSv === null) { // optional $oldSv = FlaggedRevision::newFromStable($title, FR_MASTER); } if ($sv === null) { // optional $sv = FlaggedRevision::determineStable($title, FR_MASTER); } if (!$sv) { # Empty flaggedrevs data for this page if there is no stable version $article->clearStableVersion(); # Check if pages using this need to be refreshed... if (FlaggedRevs::inclusionSetting() == FR_INCLUDES_STABLE) { $changed = (bool) $oldSv; } } else { # Update flagged page related fields $article->updateStableVersion($sv, $editInfo ? $editInfo->revid : null); # Check if pages using this need to be invalidated/purged... if (FlaggedRevs::inclusionSetting() == FR_INCLUDES_STABLE) { $changed = !$oldSv || $sv->getRevId() != $oldSv->getRevId() || $sv->getFileTimestamp() != $oldSv->getFileTimestamp() || $sv->getFileSha1() != $oldSv->getFileSha1(); } # Update template/file version cache... if ($editInfo && $sv->getRevId() != $editInfo->revid) { FRInclusionCache::setRevIncludes($title, $editInfo->revid, $editInfo->output); } } # Lazily rebuild dependancies on next parse (we invalidate below) FlaggedRevs::clearStableOnlyDeps($title->getArticleID()); # Clear page cache $title->invalidateCache(); self::purgeSquid($title); return $changed; }
/** * Mark auto-reviewed edits as patrolled */ public static function autoMarkPatrolled(RecentChange &$rc) { if (empty($rc->mAttribs['rc_this_oldid'])) { return true; } $fa = FlaggableWikiPage::getTitleInstance($rc->getTitle()); $fa->loadPageData('fromdbmaster'); // Is the page reviewable? if ($fa->isReviewable()) { $revId = $rc->mAttribs['rc_this_oldid']; // If the edit we just made was reviewed, then it's the stable rev $frev = FlaggedRevision::newFromTitle($rc->getTitle(), $revId, FR_MASTER); // Reviewed => patrolled if ($frev) { RevisionReviewForm::updateRecentChanges($rc, 'patrol', $frev); $rc->mAttribs['rc_patrolled'] = 1; // make sure irc/email notifs know status } return true; } return true; }
protected function updateLogsAndHistory(FlaggableWikiPage $article) { global $wgContLang; $newConfig = $this->getNewConfig(); $oldConfig = $this->getOldConfig(); $reason = $this->getReason(); # Insert stability log entry... FlaggedRevsLog::updateStabilityLog($this->page, $newConfig, $oldConfig, $reason); # Build null-edit comment...<action: reason [settings] (expiry)> if (FRPageConfig::configIsReset($newConfig)) { $type = "stable-logentry-reset"; $settings = ''; // no level, expiry info } else { $type = "stable-logentry-config"; // Settings message in text form (e.g. [x=a,y=b,z]) $params = FlaggedRevsLog::stabilityLogParams($newConfig); $settings = FlaggedRevsLogView::stabilitySettings($params, true); } $comment = $wgContLang->ucfirst(wfMsgForContent($type, $this->page->getPrefixedText())); // action if ($reason != '') { $comment .= wfMsgForContent('colon-separator') . $reason; // add reason } if ($settings != '') { $comment .= " {$settings}"; // add settings } # Insert a null revision... $dbw = wfGetDB(DB_MASTER); $nullRev = Revision::newNullRevision($dbw, $article->getId(), $comment, true); $nullRev->insertOn($dbw); # Update page record and touch page $oldLatest = $nullRev->getParentId(); $article->updateRevisionOn($dbw, $nullRev, $oldLatest); wfRunHooks('NewRevisionFromEditComplete', array($article, $nullRev, $oldLatest, $this->user)); # Return null Revision object for autoreview check return $nullRev; }
protected function update_flaggedpages($start = null) { $this->output("Populating and correcting flaggedpages/flaggedpage_config columns\n"); $BATCH_SIZE = 300; $db = wfGetDB(DB_MASTER); if ($start === null) { $start = $db->selectField('page', 'MIN(page_id)', false, __METHOD__); } $end = $db->selectField('page', 'MAX(page_id)', false, __METHOD__); if (is_null($start) || is_null($end)) { $this->output("...flaggedpages table seems to be empty.\n"); return; } # Do remaining chunk $end += $BATCH_SIZE - 1; $blockStart = $start; $blockEnd = $start + $BATCH_SIZE - 1; $count = $deleted = $fixed = 0; while ($blockEnd <= $end) { $this->output("...doing page_id from {$blockStart} to {$blockEnd}\n"); $cond = "page_id BETWEEN {$blockStart} AND {$blockEnd}"; $res = $db->select('page', array('page_id', 'page_namespace', 'page_title', 'page_latest'), $cond, __METHOD__); # Go through and update the de-normalized references... $db->begin(); foreach ($res as $row) { $title = Title::newFromRow($row); $article = new FlaggableWikiPage($title); $oldFrev = FlaggedRevision::newFromStable($title, FR_MASTER); $frev = FlaggedRevision::determineStable($title, FR_MASTER); # Update fp_stable, fp_quality, and fp_reviewed if ($frev) { $article->updateStableVersion($frev, $row->page_latest); $changed = !$oldFrev || $oldFrev->getRevId() != $frev->getRevId(); # Somethings broke? Delete the row... } else { $article->clearStableVersion(); if ($db->affectedRows() > 0) { $deleted++; } $changed = (bool) $oldFrev; } # Get the latest revision $revRow = $db->selectRow('revision', '*', array('rev_page' => $row->page_id), __METHOD__, array('ORDER BY' => 'rev_timestamp DESC')); # Correct page_latest if needed (import/files made plenty of bad rows) if ($revRow) { $revision = new Revision($revRow); if ($article->updateIfNewerOn($db, $revision)) { $fixed++; } } if ($changed) { # Lazily rebuild dependancies on next parse (we invalidate below) FlaggedRevs::clearStableOnlyDeps($title); $title->invalidateCache(); } $count++; } $db->freeResult($res); # Remove manual config settings that simply restate the site defaults $db->delete('flaggedpage_config', array("fpc_page_id BETWEEN {$blockStart} AND {$blockEnd}", 'fpc_override' => intval(FlaggedRevs::isStableShownByDefault()), 'fpc_level' => ''), __METHOD__); $deleted = $deleted + $db->affectedRows(); $db->commit(); $blockStart += $BATCH_SIZE; $blockEnd += $BATCH_SIZE; wfWaitForSlaves(5); } $this->output("flaggedpage columns update complete ..." . " {$count} rows [{$fixed} fixed] [{$deleted} deleted]\n"); }
public static function addToHistLine(HistoryPager $history, $row, &$s, &$liClasses) { $fa = FlaggableWikiPage::getTitleInstance($history->getTitle()); if (!$fa->isReviewable()) { return true; // nothing to do here } # Fetch and process cache the stable revision if (!isset($history->fr_stableRevId)) { $srev = $fa->getStableRev(); $history->fr_stableRevId = $srev ? $srev->getRevId() : null; $history->fr_stableRevUTS = $srev ? wfTimestamp(TS_UNIX, $srev->getRevTimestamp()) : null; $history->fr_pendingRevs = false; } if (!$history->fr_stableRevId) { return true; // nothing to do here } $title = $history->getTitle(); $revId = (int) $row->rev_id; // Pending revision: highlight and add diff link $link = $class = ''; if (wfTimestamp(TS_UNIX, $row->rev_timestamp) > $history->fr_stableRevUTS) { $class = 'flaggedrevs-pending'; $link = wfMsgExt('revreview-hist-pending-difflink', 'parseinline', $title->getPrefixedText(), $history->fr_stableRevId, $revId); $link = '<span class="plainlinks mw-fr-hist-difflink">' . $link . '</span>'; $history->fr_pendingRevs = true; // pending rev shown above stable // Reviewed revision: highlight and add link } elseif (isset($row->fr_quality)) { if (!($row->rev_deleted & Revision::DELETED_TEXT)) { # Add link to stable version of *this* rev, if any list($link, $class) = self::markHistoryRow($title, $row); # Space out and demark the stable revision if ($revId == $history->fr_stableRevId && $history->fr_pendingRevs) { $liClasses[] = 'fr-hist-stable-margin'; } } } # Style the row as needed if ($class) { $s = "<span class='{$class}'>{$s}</span>"; } # Add stable old version link if ($link) { $s .= " {$link}"; } return true; }
/** * When an edit is made to a page: * (a) If the page is reviewable, silently mark the edit patrolled if it was auto-reviewed * (b) If the page can be patrolled, auto-patrol the edit patrolled as normal * (c) If the page is new and $wgUseNPPatrol is on, auto-patrol the edit patrolled as normal * (d) If the edit is neither reviewable nor patrolleable, silently mark it patrolled */ public static function autoMarkPatrolled(RecentChange &$rc) { if (empty($rc->mAttribs['rc_this_oldid'])) { return true; } $fa = FlaggableWikiPage::getTitleInstance($rc->getTitle()); $fa->loadPageData('fromdbmaster'); // Is the page reviewable? if ($fa->isReviewable()) { $revId = $rc->mAttribs['rc_this_oldid']; $quality = FlaggedRevision::getRevQuality($revId, FR_MASTER); // Reviewed => patrolled if ($quality !== false && $quality >= FR_CHECKED) { RevisionReviewForm::updateRecentChanges($rc, 'patrol', $fa->getStableRev()); $rc->mAttribs['rc_patrolled'] = 1; // make sure irc/email notifs know status } return true; } return true; }