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;
 }
 /**
  * Validate and clean up parameters (e.g. from POST request).
  * @return mixed (true on success, error string on failure)
  */
 protected function doCheckParameters()
 {
     $action = $this->getAction();
     if ($action === null) {
         return 'review_param_missing';
         // no action specified (approve, reject, de-approve)
     } elseif (!$this->oldid) {
         return 'review_no_oldid';
         // no revision target
     }
     # Get the revision's current flags (if any)
     $this->oldFrev = FlaggedRevision::newFromTitle($this->page, $this->oldid, FR_MASTER);
     $this->oldFlags = $this->oldFrev ? $this->oldFrev->getTags() : FlaggedRevision::expandRevisionTags('');
     // default
     # Set initial value for newLastChangeTime (if unchanged on submit)
     $this->newLastChangeTime = $this->lastChangeTime;
     # Fill in implicit tag data for binary flag case
     $iDims = $this->implicitDims();
     if ($iDims) {
         $this->dims = $iDims;
         // binary flag case
     }
     if ($action === 'approve') {
         # We must at least rate each category as 1, the minimum
         if (in_array(0, $this->dims, true)) {
             return 'review_too_low';
         }
         # Special token to discourage fiddling with templates/files...
         if (!$this->skipValidationKey) {
             $k = self::validationKey($this->templateParams, $this->imageParams, $this->fileVersion, $this->oldid, $this->sessionKey);
             if ($this->validatedParams !== $k) {
                 return 'review_bad_key';
             }
         }
         # Sanity check tags
         if (!FlaggedRevs::flagsAreValid($this->dims)) {
             return 'review_bad_tags';
         }
         # Check permissions with tags
         if (!FlaggedRevs::userCanSetFlags($this->user, $this->dims, $this->oldFlags)) {
             return 'review_denied';
         }
     } elseif ($action === 'unapprove') {
         # Check permissions with old tags
         if (!FlaggedRevs::userCanSetFlags($this->user, $this->oldFlags)) {
             return 'review_denied';
         }
     }
     return true;
 }
 protected function update_flaggedrevs($start = null)
 {
     $this->output("Populating and correcting flaggedrevs columns\n");
     $BATCH_SIZE = 1000;
     $db = wfGetDB(DB_MASTER);
     if ($start === null) {
         $start = $db->selectField('revision', 'MIN(rev_id)', false, __METHOD__);
     }
     $end = $db->selectField('revision', 'MAX(rev_id)', false, __METHOD__);
     if (is_null($start) || is_null($end)) {
         $this->output("...revision table seems to be empty.\n");
         return;
     }
     # Do remaining chunk
     $end += $BATCH_SIZE - 1;
     $blockStart = $start;
     $blockEnd = $start + $BATCH_SIZE - 1;
     $count = 0;
     $changed = 0;
     while ($blockEnd <= $end) {
         $this->output("...doing fr_rev_id from {$blockStart} to {$blockEnd}\n");
         $cond = "rev_id BETWEEN {$blockStart} AND {$blockEnd} \n\t\t\t\tAND fr_rev_id = rev_id AND page_id = rev_page";
         $res = $db->select(array('revision', 'flaggedrevs', 'page'), array('fr_rev_id', 'fr_tags', 'fr_quality', 'page_namespace', 'page_title', 'fr_img_name', 'fr_img_timestamp', 'fr_img_sha1', 'rev_page'), $cond, __METHOD__);
         $db->begin();
         # Go through and clean up missing items, as well as correct fr_quality...
         foreach ($res as $row) {
             $tags = FlaggedRevision::expandRevisionTags($row->fr_tags);
             # Quality rating levels may have changed due to config tweaks...
             $quality = FlaggedRevs::getQualityTier($tags, 0);
             $file = $row->fr_img_name;
             $fileTime = $row->fr_img_timestamp;
             $fileSha1 = $row->fr_img_sha1;
             # Check for file version to see if it's stored the old way...
             if ($row->page_namespace == NS_FILE && !$file) {
                 $irow = $db->selectRow('flaggedimages', array('fi_img_timestamp', 'fi_img_sha1'), array('fi_rev_id' => $row->fr_rev_id, 'fi_name' => $row->page_title), __METHOD__);
                 $fileTime = $irow ? $irow->fi_img_timestamp : null;
                 $fileSha1 = $irow ? $irow->fi_img_sha1 : null;
                 $file = $irow ? $row->page_title : null;
                 # Fill in from current if broken
                 if (!$irow) {
                     $crow = $db->selectRow('image', array('img_timestamp', 'img_sha1'), array('img_name' => $row->page_title), __METHOD__);
                     $fileTime = $crow ? $crow->img_timestamp : null;
                     $fileSha1 = $crow ? $crow->img_sha1 : null;
                     $file = $crow ? $row->page_title : null;
                 }
             }
             # Check if anything needs updating
             if ($quality != $row->fr_quality || $file != $row->fr_img_name || $fileSha1 != $row->fr_img_sha1 || $fileTime != $row->fr_img_timestamp) {
                 # Update the row...
                 $db->update('flaggedrevs', array('fr_quality' => $quality, 'fr_img_name' => $file, 'fr_img_sha1' => $fileSha1, 'fr_img_timestamp' => $fileTime), array('fr_rev_id' => $row->fr_rev_id), __METHOD__);
                 $changed++;
             }
             $count++;
         }
         $db->commit();
         $db->freeResult($res);
         $blockStart += $BATCH_SIZE;
         $blockEnd += $BATCH_SIZE;
         wfWaitForSlaves(5);
     }
     $this->output("fr_quality and fr_img_* columns update complete ..." . " {$count} rows [{$changed} changed]\n");
 }