public static function addApiRevisionData(&$module)
 {
     if (!$module instanceof ApiQueryRevisions) {
         return true;
     }
     $params = $module->extractRequestParams(false);
     if (empty($params['prop']) || !in_array('flagged', $params['prop'])) {
         return true;
     }
     if (!in_array('ids', $params['prop'])) {
         $module->dieUsage('if rvprop=flagged is set, you must also set rvprop=ids', 'missingparam');
     }
     // Get all requested pageids/revids in a mapping:
     // pageid => revid => array_index of the revision
     // we will need this later to add data to the result array
     $result = $module->getResult();
     $data = $result->getData();
     if (!isset($data['query']) || !isset($data['query']['pages'])) {
         return true;
     }
     foreach ($data['query']['pages'] as $pageid => $page) {
         if (array_key_exists('revisions', (array) $page)) {
             foreach ($page['revisions'] as $index => $rev) {
                 if (array_key_exists('revid', (array) $rev)) {
                     $pageids[$pageid][$rev['revid']] = $index;
                 }
             }
         }
     }
     if (empty($pageids)) {
         return true;
     }
     // Construct SQL Query
     $db = $module->getDB();
     $module->resetQueryParams();
     $module->addTables(array('flaggedrevs', 'user'));
     $module->addFields(array('fr_page_id', 'fr_rev_id', 'fr_timestamp', 'fr_quality', 'fr_tags', 'user_name'));
     $module->addWhere('fr_user=user_id');
     $where = array();
     // Construct WHERE-clause to avoid multiplying the number of scanned rows
     // as flaggedrevs table has composite primary key (fr_page_id,fr_rev_id)
     foreach ($pageids as $pageid => $revids) {
         $where[] = $db->makeList(array('fr_page_id' => $pageid, 'fr_rev_id' => array_keys($revids)), LIST_AND);
     }
     $module->addWhere($db->makeList($where, LIST_OR));
     //$module->addOption( 'USE INDEX', array( 'flaggedrevs' => 'page_rev' ) );
     $res = $module->select(__METHOD__);
     // Add flagging data to result array
     foreach ($res as $row) {
         $index = $pageids[$row->fr_page_id][$row->fr_rev_id];
         $data = array('user' => $row->user_name, 'timestamp' => wfTimestamp(TS_ISO_8601, $row->fr_timestamp), 'level' => intval($row->fr_quality), 'level_text' => FlaggedRevs::getQualityLevelText($row->fr_quality), 'tags' => FlaggedRevision::expandRevisionTags($row->fr_tags));
         $result->addValue(array('query', 'pages', $row->fr_page_id, 'revisions', $index), 'flagged', $data);
     }
     return true;
 }
 protected function autoreview_current(User $user)
 {
     $this->output("Auto-reviewing all current page versions...\n");
     if (!$user->getID()) {
         $this->output("Invalid user specified.\n");
         return;
     } elseif (!$user->isAllowed('review')) {
         $this->output("User specified (id: {$user->getID()}) does not have \"review\" rights.\n");
         return;
     }
     $db = wfGetDB(DB_MASTER);
     $this->output("Reviewer username: "******"\n");
     $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("...page table seems to be empty.\n");
         return;
     }
     # Do remaining chunk
     $end += $this->mBatchSize - 1;
     $blockStart = $start;
     $blockEnd = $start + $this->mBatchSize - 1;
     $count = 0;
     $changed = 0;
     $flags = FlaggedRevs::quickTags(FR_CHECKED);
     // Assume basic level
     while ($blockEnd <= $end) {
         $this->output("...doing page_id from {$blockStart} to {$blockEnd}\n");
         $res = $db->select(array('page', 'revision'), '*', array("page_id BETWEEN {$blockStart} AND {$blockEnd}", 'page_namespace' => FlaggedRevs::getReviewNamespaces(), 'rev_id = page_latest'), __METHOD__);
         # Go through and autoreview the current version of every page...
         foreach ($res as $row) {
             $title = Title::newFromRow($row);
             $rev = Revision::newFromRow($row);
             # Is it already reviewed?
             $frev = FlaggedRevision::newFromTitle($title, $row->page_latest, FR_MASTER);
             # Rev should exist, but to be safe...
             if (!$frev && $rev) {
                 $article = new Article($title);
                 $db->begin();
                 FlaggedRevs::autoReviewEdit($article, $user, $rev, $flags, true);
                 FlaggedRevs::HTMLCacheUpdates($article->getTitle());
                 $db->commit();
                 $changed++;
             }
             $count++;
         }
         $db->freeResult($res);
         $blockStart += $this->mBatchSize - 1;
         $blockEnd += $this->mBatchSize - 1;
         // XXX: Don't let deferred jobs array get absurdly large (bug 24375)
         DeferredUpdates::doUpdates('commit');
         wfWaitForSlaves(5);
     }
     $this->output("Auto-reviewing of all pages complete ..." . "{$count} rows [{$changed} changed]\n");
 }
 /**
  * If this edit will be auto-reviewed on submit
  * Note: checking wpReviewEdit does not count as auto-reviewed
  * @param EditPage $editPage
  * @return bool
  */
 protected function editWillBeAutoreviewed(EditPage $editPage)
 {
     $title = $this->article->getTitle();
     // convenience
     if (!$this->article->isReviewable()) {
         return false;
     }
     if ($title->quickUserCan('autoreview')) {
         if (FlaggedRevs::autoReviewNewPages() && !$this->article->exists()) {
             return true;
             // edit will be autoreviewed
         }
         if (!isset($editPage->fr_baseFRev)) {
             $baseRevId = self::getBaseRevId($editPage, $this->getRequest());
             $editPage->fr_baseFRev = FlaggedRevision::newFromTitle($title, $baseRevId);
         }
         if ($editPage->fr_baseFRev) {
             return true;
             // edit will be autoreviewed
         }
     }
     return false;
     // edit won't be autoreviewed
 }
 /**
  * @param FlaggedRevision $frev
  * Removes flagged revision data for this page/id set
  * @return bool
  */
 private function unapproveRevision(FlaggedRevision $frev)
 {
     wfProfileIn(__METHOD__);
     # Get current stable version ID (for logging)
     $oldSv = FlaggedRevision::newFromStable($this->page, FR_MASTER);
     # Delete from flaggedrevs table
     $frev->delete();
     # Update the article review log
     $oldSvId = $oldSv ? $oldSv->getRevId() : 0;
     FlaggedRevsLog::updateReviewLog($this->page, $this->dims, $this->oldFlags, $this->comment, $this->oldid, $oldSvId, false);
     # Get the new stable version as of now
     $sv = FlaggedRevision::determineStable($this->page, FR_MASTER);
     # Update recent changes
     self::updateRecentChanges($frev->getRevision(), 'unpatrol', $sv);
     # Update page and tracking tables and clear cache
     $changed = FlaggedRevs::stableVersionUpdates($this->page, $sv, $oldSv);
     if ($changed) {
         FlaggedRevs::HTMLCacheUpdates($this->page);
         // purge pages that use this page
     }
     # Caller may want to get the change time
     $this->newLastChangeTime = '';
     wfProfileOut(__METHOD__);
     return true;
 }
 /**
  * Updates the flagging tracking tables for this page
  * @param FlaggedRevision $srev The new stable version
  * @param int|null $latest The latest rev ID (optional)
  * @return bool Updates were done
  */
 public function updateStableVersion(FlaggedRevision $srev, $latest = null)
 {
     $rev = $srev->getRevision();
     if (!$this->exists() || !$rev) {
         return false;
         // no bogus entries
     }
     # Get the latest revision ID if not set
     if (!$latest) {
         $latest = $this->mTitle->getLatestRevID(Title::GAID_FOR_UPDATE);
     }
     $dbw = wfGetDB(DB_MASTER);
     # Get the highest quality revision (not necessarily this one)...
     if ($srev->getQuality() === FlaggedRevs::highestReviewTier()) {
         $maxQuality = $srev->getQuality();
         // save a query
     } else {
         $maxQuality = $dbw->selectField(array('flaggedrevs', 'revision'), 'fr_quality', array('fr_page_id' => $this->getId(), 'rev_id = fr_rev_id', 'rev_page = fr_page_id', 'rev_deleted & ' . Revision::DELETED_TEXT => 0), __METHOD__, array('ORDER BY' => 'fr_quality DESC', 'LIMIT' => 1));
         $maxQuality = max($maxQuality, $srev->getQuality());
         // sanity
     }
     # Get the timestamp of the first edit after the stable version (if any)...
     $nextTimestamp = null;
     if ($rev->getId() != $latest) {
         $timestamp = $dbw->timestamp($rev->getTimestamp());
         $nextEditTS = $dbw->selectField('revision', 'rev_timestamp', array('rev_page' => $this->getId(), "rev_timestamp > " . $dbw->addQuotes($timestamp)), __METHOD__, array('ORDER BY' => 'rev_timestamp ASC', 'LIMIT' => 1));
         if ($nextEditTS) {
             // sanity check
             $nextTimestamp = $nextEditTS;
         }
     }
     # Get the new page sync status...
     $synced = !($nextTimestamp !== null || $srev->findPendingTemplateChanges() || $srev->findPendingFileChanges('noForeign'));
     # Alter table metadata
     $dbw->replace('flaggedpages', array('fp_page_id'), array('fp_page_id' => $this->getId(), 'fp_stable' => $rev->getId(), 'fp_reviewed' => $synced ? 1 : 0, 'fp_quality' => $maxQuality === false ? null : $maxQuality, 'fp_pending_since' => $dbw->timestampOrNull($nextTimestamp)), __METHOD__);
     # Update pending edit tracking table
     self::updatePendingList($this->getId(), $latest);
     return true;
 }
 /**
  * Get the stable version of a file
  * @param Title $title
  * @return array (MW timestamp/'0', sha1/'')
  */
 public function getStableFileVersion(Title $title)
 {
     $dbKey = $title->getDBkey();
     $time = '0';
     // missing
     $sha1 = false;
     # All NS_FILE, no need to check namespace
     if (isset($this->stableVersions['files'][$dbKey])) {
         $time = $this->stableVersions['files'][$dbKey]['time'];
         $sha1 = $this->stableVersions['files'][$dbKey]['sha1'];
         return array($time, $sha1);
     }
     $srev = FlaggedRevision::newFromStable($title);
     if ($srev && $srev->getFileTimestamp()) {
         $time = $srev->getFileTimestamp();
         $sha1 = $srev->getFileSha1();
     }
     $this->stableVersions['files'][$dbKey] = array();
     $this->stableVersions['files'][$dbKey]['time'] = $time;
     $this->stableVersions['files'][$dbKey]['sha1'] = $sha1;
     return array($time, $sha1);
 }
 /**
  * Automatically review an revision and add a log entry in the review log.
  *
  * This is called during edit operations after the new revision is added
  * and the page tables updated, but before LinksUpdate is called.
  *
  * $auto is here for revisions checked off to be reviewed. Auto-review
  * triggers on edit, but we don't want those to count as just automatic.
  * This also makes it so the user's name shows up in the page history.
  *
  * If $flags is given, then they will be the review tags. If not, the one
  * from the stable version will be used or minimal tags if that's not possible.
  * If no appropriate tags can be found, then the review will abort.
  */
 public static function autoReviewEdit(WikiPage $article, $user, Revision $rev, array $flags = null, $auto = true)
 {
     wfProfileIn(__METHOD__);
     $title = $article->getTitle();
     // convenience
     # Get current stable version ID (for logging)
     $oldSv = FlaggedRevision::newFromStable($title, FR_MASTER);
     $oldSvId = $oldSv ? $oldSv->getRevId() : 0;
     # Set the auto-review tags from the prior stable version.
     # Normally, this should already be done and given here...
     if (!is_array($flags)) {
         if ($oldSv) {
             # Use the last stable version if $flags not given
             if ($user->isAllowed('bot')) {
                 $flags = $oldSv->getTags();
                 // no change for bot edits
             } else {
                 # Account for perms/tags...
                 $flags = self::getAutoReviewTags($user, $oldSv->getTags());
             }
         } else {
             // new page?
             $flags = self::quickTags(FR_CHECKED);
             // use minimal level
         }
         if (!is_array($flags)) {
             wfProfileOut(__METHOD__);
             return false;
             // can't auto-review this revision
         }
     }
     # Get review property flags
     $propFlags = $auto ? array('auto') : array();
     # Note: this needs to match the prepareContentForEdit() call WikiPage::doEditContent.
     # This is for consistency and also to avoid triggering a second parse otherwise.
     $editInfo = $article->prepareContentForEdit($rev->getContent(), null, $user, $rev->getContentFormat());
     $poutput = $editInfo->output;
     // revision HTML output
     # Get the "review time" versions of templates and files.
     # This tries to make sure each template/file version either came from the stable
     # version of that template/file or was a "review time" version used in the stable
     # version of this page. If a pending version of a template/file is currently vandalism,
     # we try to avoid storing its ID as the "review time" version so it won't show up when
     # someone views the page. If not possible, this stores the current template/file.
     if (FlaggedRevs::inclusionSetting() === FR_INCLUDES_CURRENT) {
         $tVersions = $poutput->getTemplateIds();
         $fVersions = $poutput->getFileSearchOptions();
     } else {
         $tVersions = $oldSv ? $oldSv->getTemplateVersions() : array();
         $fVersions = $oldSv ? $oldSv->getFileVersions() : array();
         foreach ($poutput->getTemplateIds() as $ns => $pages) {
             foreach ($pages as $dbKey => $revId) {
                 if (!isset($tVersions[$ns][$dbKey])) {
                     $srev = FlaggedRevision::newFromStable(Title::makeTitle($ns, $dbKey));
                     if ($srev) {
                         // use stable
                         $tVersions[$ns][$dbKey] = $srev->getRevId();
                     } else {
                         // use current
                         $tVersions[$ns][$dbKey] = $revId;
                     }
                 }
             }
         }
         foreach ($poutput->getFileSearchOptions() as $dbKey => $info) {
             if (!isset($fVersions[$dbKey])) {
                 $srev = FlaggedRevision::newFromStable(Title::makeTitle(NS_FILE, $dbKey));
                 if ($srev && $srev->getFileTimestamp()) {
                     // use stable
                     $fVersions[$dbKey]['time'] = $srev->getFileTimestamp();
                     $fVersions[$dbKey]['sha1'] = $srev->getFileSha1();
                 } else {
                     // use current
                     $fVersions[$dbKey]['time'] = $info['time'];
                     $fVersions[$dbKey]['sha1'] = $info['sha1'];
                 }
             }
         }
     }
     # If this is an image page, get the corresponding file version info...
     $fileData = array('name' => null, 'timestamp' => null, 'sha1' => null);
     if ($title->getNamespace() == NS_FILE) {
         # We must use WikiFilePage process cache on upload or get bitten by slave lag
         $file = $article instanceof WikiFilePage || $article instanceof ImagePage ? $article->getFile() : wfFindFile($title, array('bypassCache' => true));
         // skip cache; bug 31056
         if (is_object($file) && $file->exists()) {
             $fileData['name'] = $title->getDBkey();
             $fileData['timestamp'] = $file->getTimestamp();
             $fileData['sha1'] = $file->getSha1();
         }
     }
     # Our review entry
     $flaggedRevision = new FlaggedRevision(array('rev' => $rev, 'user_id' => $user->getId(), 'timestamp' => $rev->getTimestamp(), 'quality' => FlaggedRevs::getQualityTier($flags, 0), 'tags' => FlaggedRevision::flattenRevisionTags($flags), 'img_name' => $fileData['name'], 'img_timestamp' => $fileData['timestamp'], 'img_sha1' => $fileData['sha1'], 'templateVersions' => $tVersions, 'fileVersions' => $fVersions, 'flags' => implode(',', $propFlags)));
     $flaggedRevision->insert();
     # Update the article review log
     FlaggedRevsLog::updateReviewLog($title, $flags, array(), '', $rev->getId(), $oldSvId, true, $auto);
     # Update page and tracking tables and clear cache
     FlaggedRevs::stableVersionUpdates($article);
     wfProfileOut(__METHOD__);
     return true;
 }
 /**
  * Automatically review an revision and add a log entry in the review log.
  *
  * This is called during edit operations after the new revision is added
  * and the page tables updated, but before LinksUpdate is called.
  *
  * $auto is here for revisions checked off to be reviewed. Auto-review
  * triggers on edit, but we don't want those to count as just automatic.
  * This also makes it so the user's name shows up in the page history.
  *
  * If $flags is given, then they will be the review tags. If not, the one
  * from the stable version will be used or minimal tags if that's not possible.
  * If no appropriate tags can be found, then the review will abort.
  */
 public static function autoReviewEdit(Page $article, $user, Revision $rev, array $flags = null, $auto = true)
 {
     wfProfileIn(__METHOD__);
     $title = $article->getTitle();
     // convenience
     # Get current stable version ID (for logging)
     $oldSv = FlaggedRevision::newFromStable($title, FR_MASTER);
     $oldSvId = $oldSv ? $oldSv->getRevId() : 0;
     # Set the auto-review tags from the prior stable version.
     # Normally, this should already be done and given here...
     if (!is_array($flags)) {
         if ($oldSv) {
             # Use the last stable version if $flags not given
             if ($user->isAllowed('bot')) {
                 $flags = $oldSv->getTags();
                 // no change for bot edits
             } else {
                 # Account for perms/tags...
                 $flags = self::getAutoReviewTags($user, $oldSv->getTags());
             }
         } else {
             // new page?
             $flags = self::quickTags(FR_CHECKED);
             // use minimal level
         }
         if (!is_array($flags)) {
             wfProfileOut(__METHOD__);
             return false;
             // can't auto-review this revision
         }
     }
     # Get review property flags
     $propFlags = $auto ? array('auto') : array();
     # Rev ID is not put into parser on edit, so do the same here.
     # Also, a second parse would be triggered otherwise.
     $editInfo = $article->prepareTextForEdit($rev->getText());
     $poutput = $editInfo->output;
     // revision HTML output
     # If this is an image page, store corresponding file info
     $fileData = array('name' => null, 'timestamp' => null, 'sha1' => null);
     if ($title->getNamespace() == NS_FILE) {
         # We must use WikiFilePage process cache on upload or get bitten by slave lag
         $file = $article instanceof WikiFilePage || $article instanceof ImagePage ? $article->getFile() : wfFindFile($title, array('bypassCache' => true));
         // skip cache; bug 31056
         if (is_object($file) && $file->exists()) {
             $fileData['name'] = $title->getDBkey();
             $fileData['timestamp'] = $file->getTimestamp();
             $fileData['sha1'] = $file->getSha1();
         }
     }
     # Our review entry
     $flaggedRevision = new FlaggedRevision(array('rev' => $rev, 'user_id' => $user->getId(), 'timestamp' => $rev->getTimestamp(), 'quality' => FlaggedRevs::getQualityTier($flags, 0), 'tags' => FlaggedRevision::flattenRevisionTags($flags), 'img_name' => $fileData['name'], 'img_timestamp' => $fileData['timestamp'], 'img_sha1' => $fileData['sha1'], 'templateVersions' => $poutput->getTemplateIds(), 'fileVersions' => $poutput->getFileSearchOptions(), 'flags' => implode(',', $propFlags)));
     $flaggedRevision->insert();
     # Update the article review log
     FlaggedRevsLog::updateReviewLog($title, $flags, array(), '', $rev->getId(), $oldSvId, true, $auto);
     # Update page and tracking tables and clear cache
     FlaggedRevs::stableVersionUpdates($title);
     wfProfileOut(__METHOD__);
     return true;
 }
 /**
  * Hook-Handler for Hook 'BSStateBarBeforeBodyViewAdd'
  * @param StateBar $oStateBar
  * @param array $aBodyViews
  * @return boolean Always true to keep hook running
  */
 public function onStateBarBeforeBodyViewAdd($oStateBar, &$aBodyViews, $oUser, $oTitle)
 {
     $text = '';
     $oRev = BsReviewProcess::newFromPid($oTitle->getArticleID());
     $pages = BsReviewProcess::listReviews($oUser->getId());
     if ($oRev === false) {
         return true;
     }
     $oReviewView = new ViewStateBarBodyElementReview();
     $oReviewView->setReview($oRev);
     $oReviewView->addButton('bs-review-dismiss', 'bs-icon-decline', wfMessage('bs-review-i-dismiss')->plain(), wfMessage('bs-review-i-dismiss')->plain());
     $oReviewView->addButton('bs-review-ok', 'bs-icon-accept', wfMessage('bs-review-i-agree')->plain(), wfMessage('bs-review-i-agree')->plain());
     if ($res = $oRev->isFinished()) {
         //$text = wfMessage( 'bs-review-review-finished' )->plain();
         $oReviewView->setStatusText(wfMessage('bs-review-review-finished')->plain());
         if ($oRev->isSequential()) {
             switch ($res) {
                 case 'date':
                     $text .= wfMessage('bs-review-date')->plain();
                     break;
                 case 'status':
                     $text .= wfMessage('bs-review-agreed')->plain();
                     break;
                 case 'denied':
                     $text .= wfMessage('bs-review-denied-disagreed')->plain();
                     break;
             }
         } else {
             $res = $oRev->currentStatus();
             $res = explode(';', $res);
             if ($res[2]) {
                 $text .= "<br />" . wfMessage('bs-review-accepted', $res[2])->plain();
             }
             if ($res[1]) {
                 $text .= "<br />" . wfMessage('bs-review-rejected', $res[1])->plain();
             }
             if ($res[0]) {
                 $text .= "<br />" . wfMessage('bs-review-abstain', $res[0])->plain();
             }
         }
         $oReviewView->setStatusReasonText($text);
     } else {
         $text = wfMessage('bs-review-reviewed-till', $oRev->getStartdate(), $oRev->getEnddate())->plain();
         $user = User::newFromId($oRev->owner);
         $sName = BsCore::getUserDisplayName($user);
         $text .= '<br />' . wfMessage('bs-review-reviewed-till-extra', $user->getName(), $sName)->text();
         $oReviewView->setStatusText($text);
     }
     // Flagged Revision: Only show the "not accepted" icon on the template page an not on the released page, which is accepted.
     $obj = false;
     $bResult = false;
     wfRunHooks('checkPageIsReviewable', array($oTitle, &$bResult));
     if ($bResult) {
         $obj = FlaggedRevision::newFromStable($oTitle);
     }
     $aComments = array();
     foreach ($oRev->steps as $_step) {
         if (!empty($_step->comment) && $_step->status != -1) {
             $aComments[] = $_step->comment;
         }
     }
     $oReviewView->setPreceedingCommentsList($aComments);
     if (empty($pages) || !in_array($oTitle->getArticleID(), $pages)) {
         $aBodyViews['statebarbodyreview'] = $oReviewView;
         return true;
     }
     $step = $oRev->currentStep($oUser->getId());
     if (!is_object($step)) {
         return true;
     }
     $oReviewView->setVotable(true);
     $sUserName = BsCore::getUserDisplayName($oUser);
     $oReviewView->setComment("<em>{$sUserName}:</em> {$step->comment}");
     wfRunHooks('BsReview::checkStatus::afterMessage', array($step, $oReviewView));
     if ($oTitle->userCan("workflowview", $oUser)) {
         $aBodyViews['statebarbodyreview'] = $oReviewView;
     }
     return true;
 }
 /**
  * Generates a brief review form for a page
  * @return array (html string, error string or true)
  */
 public function getHtml()
 {
     global $wgLang;
     $revId = $this->rev->getId();
     if ($this->rev->isDeleted(Revision::DELETED_TEXT)) {
         return array('', 'review_bad_oldid');
         # The revision must be valid and public
     }
     $article = $this->article;
     // convenience
     $srev = $article->getStableRev();
     # See if the version being displayed is flagged...
     if ($revId == $article->getStable()) {
         $frev = $srev;
         // avoid query
     } else {
         $frev = FlaggedRevision::newFromTitle($article->getTitle(), $revId);
     }
     $oldFlags = $frev ? $frev->getTags() : FlaggedRevs::quickTags(FR_CHECKED);
     // basic tags
     $reviewTime = $frev ? $frev->getTimestamp() : '';
     // last review of rev
     $priorRevId = $this->refRev ? $this->refRev->getId() : 0;
     # If we are reviewing updates to a page, start off with the stable revision's
     # flags. Otherwise, we just fill them in with the selected revision's flags.
     # @TODO: do we want to carry over info for other diffs?
     if ($srev && $srev->getRevId() == $priorRevId) {
         // diff-to-stable
         $flags = $srev->getTags();
         # Check if user is allowed to renew the stable version.
         # If not, then get the flags for the new revision itself.
         if (!FlaggedRevs::userCanSetFlags($this->user, $oldFlags)) {
             $flags = $oldFlags;
         }
         # Re-review button is need for template/file only review case
         $reviewIncludes = $srev->getRevId() == $revId && !$article->stableVersionIsSynced();
     } else {
         // views
         $flags = $oldFlags;
         $reviewIncludes = false;
         // re-review button not needed
     }
     # Disable form for unprivileged users
     $disabled = array();
     if (!$article->getTitle()->quickUserCan('review') || !FlaggedRevs::userCanSetFlags($this->user, $flags)) {
         $disabled = array('disabled' => 'disabled');
     }
     # Begin form...
     $reviewTitle = SpecialPage::getTitleFor('RevisionReview');
     $action = $reviewTitle->getLocalUrl('action=submit');
     $params = array('method' => 'post', 'action' => $action, 'id' => 'mw-fr-reviewform');
     $form = Xml::openElement('form', $params) . "\n";
     $form .= Xml::openElement('fieldset', array('class' => 'flaggedrevs_reviewform noprint')) . "\n";
     # Add appropriate legend text
     $legendMsg = $frev ? 'revreview-reflag' : 'revreview-flag';
     $form .= Xml::openElement('legend', array('id' => 'mw-fr-reviewformlegend'));
     $form .= "<strong>" . wfMessage($legendMsg)->escaped() . "</strong>";
     $form .= Xml::closeElement('legend') . "\n";
     # Show explanatory text
     $form .= $this->topNotice;
     # Check if anyone is reviewing this already and
     # show a conflict warning message as needed...
     if ($priorRevId) {
         list($u, $ts) = FRUserActivity::getUserReviewingDiff($priorRevId, $this->rev->getId());
     } else {
         list($u, $ts) = FRUserActivity::getUserReviewingPage($this->rev->getPage());
     }
     $form .= Xml::openElement('p');
     // Page under review (and not by this user)...
     if ($u !== null && $u != $this->user->getName()) {
         $form .= '<span class="fr-under-review">';
         $msg = $priorRevId ? 'revreview-poss-conflict-c' : 'revreview-poss-conflict-p';
         $form .= wfMessage($msg, $u, $wgLang->date($ts, true), $wgLang->time($ts, true))->parse();
         $form .= "</span>";
         // Page not under review or under review by this user...
     } elseif (!$frev) {
         // rev not already reviewed
         $form .= '<span id="mw-fr-reviewing-status" style="display:none;"></span>';
         // JS widget
     }
     $form .= Xml::closeElement('p') . "\n";
     # Start rating controls
     $css = $disabled ? 'fr-rating-controls-disabled' : 'fr-rating-controls';
     $form .= Xml::openElement('p', array('class' => $css, 'id' => 'fr-rating-controls')) . "\n";
     # Add main checkboxes/selects
     $form .= Xml::openElement('span', array('id' => 'mw-fr-ratingselects', 'class' => 'fr-rating-options')) . "\n";
     $form .= self::ratingInputs($this->user, $flags, (bool) $disabled, (bool) $frev) . "\n";
     $form .= Xml::closeElement('span') . "\n";
     # Don't put buttons & comment field on the same line as tag inputs.
     if (!$disabled && !FlaggedRevs::binaryFlagging()) {
         // $disabled => no comment/buttons
         $form .= "<br />";
     }
     # Start comment & buttons
     $form .= Xml::openElement('span', array('id' => 'mw-fr-confirmreview')) . "\n";
     # Hide comment input if needed
     if (!$disabled) {
         $form .= Xml::inputLabel(wfMessage('revreview-log')->text(), 'wpReason', 'mw-fr-commentbox', 40, '', array('maxlength' => 255, 'class' => 'fr-comment-box'));
     }
     # Add the submit buttons...
     $rejectId = $this->rejectRefRevId();
     // determine if there will be reject button
     $form .= self::submitButtons($rejectId, $frev, (bool) $disabled, $reviewIncludes);
     # Show stability log if there is anything interesting...
     if ($article->isPageLocked()) {
         $form .= ' ' . FlaggedRevsXML::logToggle('revreview-log-toggle-show');
     }
     # End comment & buttons
     $form .= Xml::closeElement('span') . "\n";
     # ..add the actual stability log body here
     if ($article->isPageLocked()) {
         $form .= FlaggedRevsXML::stabilityLogExcerpt($article);
     }
     # End rating controls
     $form .= Xml::closeElement('p') . "\n";
     # Show explanatory text
     $form .= $this->bottomNotice;
     # Get the file version used for File: pages as needed
     $fileKey = $this->getFileVersion();
     # Get template/file version info as needed
     list($templateIDs, $imageSHA1Keys) = $this->getIncludeVersions();
     # Convert these into flat string params
     list($templateParams, $imageParams, $fileVersion) = RevisionReviewForm::getIncludeParams($templateIDs, $imageSHA1Keys, $fileKey);
     # Hidden params
     $form .= Html::hidden('title', $reviewTitle->getPrefixedText()) . "\n";
     $form .= Html::hidden('target', $article->getTitle()->getPrefixedDBKey()) . "\n";
     $form .= Html::hidden('refid', $priorRevId, array('id' => 'mw-fr-input-refid')) . "\n";
     $form .= Html::hidden('oldid', $revId, array('id' => 'mw-fr-input-oldid')) . "\n";
     $form .= Html::hidden('wpEditToken', $this->user->getEditToken()) . "\n";
     $form .= Html::hidden('changetime', $reviewTime, array('id' => 'mw-fr-input-changetime')) . "\n";
     // id for JS
     $form .= Html::hidden('userreviewing', (int) ($u === $this->user->getName()), array('id' => 'mw-fr-user-reviewing')) . "\n";
     // id for JS
     # Add review parameters
     $form .= Html::hidden('templateParams', $templateParams) . "\n";
     $form .= Html::hidden('imageParams', $imageParams) . "\n";
     $form .= Html::hidden('fileVersion', $fileVersion) . "\n";
     # Special token to discourage fiddling...
     $key = $this->request->getSessionData('wsFlaggedRevsKey');
     $checkCode = RevisionReviewForm::validationKey($templateParams, $imageParams, $fileVersion, $revId, $key);
     $form .= Html::hidden('validatedParams', $checkCode) . "\n";
     $form .= Xml::closeElement('fieldset') . "\n";
     $form .= Xml::closeElement('form') . "\n";
     return array($form, true);
 }
 /**
  * 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;
 }
 /**
  * Submit the form parameters for the page config to the DB.
  * 
  * @return mixed (true on success, error string on failure)
  */
 public function doSubmit()
 {
     # Double-check permissions
     if (!$this->isAllowed()) {
         return 'stablize_denied';
     }
     # Parse and cleanup the expiry time given...
     $expiry = $this->getExpiry();
     if ($expiry === false) {
         return 'stabilize_expiry_invalid';
     } elseif ($expiry !== Block::infinity() && $expiry < wfTimestampNow()) {
         return 'stabilize_expiry_old';
     }
     # Update the DB row with the new config...
     $changed = FRPageConfig::setStabilitySettings($this->page, $this->getNewConfig());
     # Log if this actually changed anything...
     if ($changed) {
         $article = new FlaggableWikiPage($this->page);
         if (FlaggedRevs::useOnlyIfProtected()) {
             # Config may have changed to allow stable versions, so refresh
             # the tracking table to account for any hidden reviewed versions...
             $frev = FlaggedRevision::determineStable($this->page, FR_MASTER);
             if ($frev) {
                 $article->updateStableVersion($frev);
             } else {
                 $article->clearStableVersion();
             }
         }
         # Update logs and make a null edit
         $nullRev = $this->updateLogsAndHistory($article);
         # Null edit may have been auto-reviewed already
         $frev = FlaggedRevision::newFromTitle($this->page, $nullRev->getId(), FR_MASTER);
         $updatesDone = (bool) $frev;
         // stableVersionUpdates() already called?
         # Check if this null edit is to be reviewed...
         if ($this->reviewThis && !$frev) {
             $flags = null;
             # Review this revision of the page...
             $ok = FlaggedRevs::autoReviewEdit($article, $this->user, $nullRev, $flags, true);
             if ($ok) {
                 FlaggedRevs::markRevisionPatrolled($nullRev);
                 // reviewed -> patrolled
                 $updatesDone = true;
                 // stableVersionUpdates() already called
             }
         }
         # Update page and tracking tables and clear cache.
         if (!$updatesDone) {
             FlaggedRevs::stableVersionUpdates($this->page);
         }
     }
     # Apply watchlist checkbox value (may be NULL)
     $this->updateWatchlist();
     # Take this opportunity to purge out expired configurations
     FRPageConfig::purgeExpiredConfigurations();
     return true;
 }
 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 checkDiffUrl($titleObj, &$mOldid, &$mNewid, $old, $new)
 {
     if ($new === 'review' && isset($titleObj)) {
         $sRevId = FlaggedRevision::getStableRevId($titleObj);
         if ($sRevId) {
             $mOldid = $sRevId;
             // stable
             $mNewid = 0;
             // cur
         }
     }
     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;
 }