/**
  * Determine if the current user is allowed to view a particular
  * field of this revision, if it's marked as deleted.
  * @param $rc RCCacheEntry
  * @param $field Integer
  * @param $user User object to check, or null to use $wgUser
  * @return Boolean
  */
 public static function userCan($rc, $field, User $user = null)
 {
     if ($rc->mAttribs['rc_type'] == RC_LOG) {
         return LogEventsList::userCanBitfield($rc->mAttribs['rc_deleted'], $field, $user);
     } else {
         return Revision::userCanBitfield($rc->mAttribs['rc_deleted'], $field, $user);
     }
 }
 /**
  * Extracts from a single sql row the data needed to describe one recent change.
  *
  * @param stdClass $row The row from which to extract the data.
  * @return array An array mapping strings (descriptors) to their respective string values.
  * @access public
  */
 public function extractRowInfo($row)
 {
     /* Determine the title of the page that has been changed. */
     $title = Title::makeTitle($row->rc_namespace, $row->rc_title);
     $user = $this->getUser();
     /* Our output data. */
     $vals = array();
     $type = intval($row->rc_type);
     $vals['type'] = RecentChange::parseFromRCType($type);
     $anyHidden = false;
     /* Create a new entry in the result for the title. */
     if ($this->fld_title || $this->fld_ids) {
         if ($type === RC_LOG && $row->rc_deleted & LogPage::DELETED_ACTION) {
             $vals['actionhidden'] = true;
             $anyHidden = true;
         }
         if ($type !== RC_LOG || LogEventsList::userCanBitfield($row->rc_deleted, LogPage::DELETED_ACTION, $user)) {
             if ($this->fld_title) {
                 ApiQueryBase::addTitleInfo($vals, $title);
             }
             if ($this->fld_ids) {
                 $vals['pageid'] = intval($row->rc_cur_id);
                 $vals['revid'] = intval($row->rc_this_oldid);
                 $vals['old_revid'] = intval($row->rc_last_oldid);
             }
         }
     }
     if ($this->fld_ids) {
         $vals['rcid'] = intval($row->rc_id);
     }
     /* Add user data and 'anon' flag, if user is anonymous. */
     if ($this->fld_user || $this->fld_userid) {
         if ($row->rc_deleted & Revision::DELETED_USER) {
             $vals['userhidden'] = true;
             $anyHidden = true;
         }
         if (Revision::userCanBitfield($row->rc_deleted, Revision::DELETED_USER, $user)) {
             if ($this->fld_user) {
                 $vals['user'] = $row->rc_user_text;
             }
             if ($this->fld_userid) {
                 $vals['userid'] = $row->rc_user;
             }
             if (!$row->rc_user) {
                 $vals['anon'] = true;
             }
         }
     }
     /* Add flags, such as new, minor, bot. */
     if ($this->fld_flags) {
         $vals['bot'] = (bool) $row->rc_bot;
         $vals['new'] = $row->rc_type == RC_NEW;
         $vals['minor'] = (bool) $row->rc_minor;
     }
     /* Add sizes of each revision. (Only available on 1.10+) */
     if ($this->fld_sizes) {
         $vals['oldlen'] = intval($row->rc_old_len);
         $vals['newlen'] = intval($row->rc_new_len);
     }
     /* Add the timestamp. */
     if ($this->fld_timestamp) {
         $vals['timestamp'] = wfTimestamp(TS_ISO_8601, $row->rc_timestamp);
     }
     /* Add edit summary / log summary. */
     if ($this->fld_comment || $this->fld_parsedcomment) {
         if ($row->rc_deleted & Revision::DELETED_COMMENT) {
             $vals['commenthidden'] = true;
             $anyHidden = true;
         }
         if (Revision::userCanBitfield($row->rc_deleted, Revision::DELETED_COMMENT, $user)) {
             if ($this->fld_comment && isset($row->rc_comment)) {
                 $vals['comment'] = $row->rc_comment;
             }
             if ($this->fld_parsedcomment && isset($row->rc_comment)) {
                 $vals['parsedcomment'] = Linker::formatComment($row->rc_comment, $title);
             }
         }
     }
     if ($this->fld_redirect) {
         $vals['redirect'] = (bool) $row->page_is_redirect;
     }
     /* Add the patrolled flag */
     if ($this->fld_patrolled) {
         $vals['patrolled'] = $row->rc_patrolled == 1;
         $vals['unpatrolled'] = ChangesList::isUnpatrolled($row, $user);
     }
     if ($this->fld_loginfo && $row->rc_type == RC_LOG) {
         if ($row->rc_deleted & LogPage::DELETED_ACTION) {
             $vals['actionhidden'] = true;
             $anyHidden = true;
         }
         if (LogEventsList::userCanBitfield($row->rc_deleted, LogPage::DELETED_ACTION, $user)) {
             $vals['logid'] = intval($row->rc_logid);
             $vals['logtype'] = $row->rc_log_type;
             $vals['logaction'] = $row->rc_log_action;
             $vals['logparams'] = LogFormatter::newFromRow($row)->formatParametersForApi();
         }
     }
     if ($this->fld_tags) {
         if ($row->ts_tags) {
             $tags = explode(',', $row->ts_tags);
             ApiResult::setIndexedTagName($tags, 'tag');
             $vals['tags'] = $tags;
         } else {
             $vals['tags'] = array();
         }
     }
     if ($this->fld_sha1 && $row->rev_sha1 !== null) {
         if ($row->rev_deleted & Revision::DELETED_TEXT) {
             $vals['sha1hidden'] = true;
             $anyHidden = true;
         }
         if (Revision::userCanBitfield($row->rev_deleted, Revision::DELETED_TEXT, $user)) {
             if ($row->rev_sha1 !== '') {
                 $vals['sha1'] = wfBaseConvert($row->rev_sha1, 36, 16, 40);
             } else {
                 $vals['sha1'] = '';
             }
         }
     }
     if (!is_null($this->token)) {
         $tokenFunctions = $this->getTokenFunctions();
         foreach ($this->token as $t) {
             $val = call_user_func($tokenFunctions[$t], $row->rc_cur_id, $title, RecentChange::newFromRow($row));
             if ($val === false) {
                 $this->setWarning("Action '{$t}' is not allowed for the current user");
             } else {
                 $vals[$t . 'token'] = $val;
             }
         }
     }
     if ($anyHidden && $row->rc_deleted & Revision::DELETED_RESTRICTED) {
         $vals['suppressed'] = true;
     }
     return $vals;
 }
Beispiel #3
0
 /**
  * Determine if the current user is allowed to view a particular
  * field of this image file, if it's marked as deleted.
  *
  * @param $field Integer
  * @return bool
  */
 function userCan($field)
 {
     $this->load();
     return Revision::userCanBitfield($this->deleted, $field);
 }
 public function execute()
 {
     $user = $this->getUser();
     // Before doing anything at all, let's check permissions
     if (!$user->isAllowed('deletedhistory')) {
         $this->dieUsage('You don\'t have permission to view deleted file information', 'permissiondenied');
     }
     $db = $this->getDB();
     $params = $this->extractRequestParams();
     $prop = array_flip($params['prop']);
     $fld_sha1 = isset($prop['sha1']);
     $fld_timestamp = isset($prop['timestamp']);
     $fld_user = isset($prop['user']);
     $fld_size = isset($prop['size']);
     $fld_dimensions = isset($prop['dimensions']);
     $fld_description = isset($prop['description']) || isset($prop['parseddescription']);
     $fld_mime = isset($prop['mime']);
     $fld_mediatype = isset($prop['mediatype']);
     $fld_metadata = isset($prop['metadata']);
     $fld_bitdepth = isset($prop['bitdepth']);
     $fld_archivename = isset($prop['archivename']);
     $this->addTables('filearchive');
     $this->addFields(ArchivedFile::selectFields());
     $this->addFields(array('fa_id', 'fa_name', 'fa_timestamp', 'fa_deleted'));
     $this->addFieldsIf('fa_sha1', $fld_sha1);
     $this->addFieldsIf(array('fa_user', 'fa_user_text'), $fld_user);
     $this->addFieldsIf(array('fa_height', 'fa_width', 'fa_size'), $fld_dimensions || $fld_size);
     $this->addFieldsIf('fa_description', $fld_description);
     $this->addFieldsIf(array('fa_major_mime', 'fa_minor_mime'), $fld_mime);
     $this->addFieldsIf('fa_media_type', $fld_mediatype);
     $this->addFieldsIf('fa_metadata', $fld_metadata);
     $this->addFieldsIf('fa_bits', $fld_bitdepth);
     $this->addFieldsIf('fa_archive_name', $fld_archivename);
     if (!is_null($params['continue'])) {
         $cont = explode('|', $params['continue']);
         $this->dieContinueUsageIf(count($cont) != 3);
         $op = $params['dir'] == 'descending' ? '<' : '>';
         $cont_from = $db->addQuotes($cont[0]);
         $cont_timestamp = $db->addQuotes($db->timestamp($cont[1]));
         $cont_id = (int) $cont[2];
         $this->dieContinueUsageIf($cont[2] !== (string) $cont_id);
         $this->addWhere("fa_name {$op} {$cont_from} OR " . "(fa_name = {$cont_from} AND " . "(fa_timestamp {$op} {$cont_timestamp} OR " . "(fa_timestamp = {$cont_timestamp} AND " . "fa_id {$op}= {$cont_id} )))");
     }
     // Image filters
     $dir = $params['dir'] == 'descending' ? 'older' : 'newer';
     $from = $params['from'] === null ? null : $this->titlePartToKey($params['from'], NS_FILE);
     $to = $params['to'] === null ? null : $this->titlePartToKey($params['to'], NS_FILE);
     $this->addWhereRange('fa_name', $dir, $from, $to);
     if (isset($params['prefix'])) {
         $this->addWhere('fa_name' . $db->buildLike($this->titlePartToKey($params['prefix'], NS_FILE), $db->anyString()));
     }
     $sha1Set = isset($params['sha1']);
     $sha1base36Set = isset($params['sha1base36']);
     if ($sha1Set || $sha1base36Set) {
         $sha1 = false;
         if ($sha1Set) {
             $sha1 = strtolower($params['sha1']);
             if (!$this->validateSha1Hash($sha1)) {
                 $this->dieUsage('The SHA1 hash provided is not valid', 'invalidsha1hash');
             }
             $sha1 = wfBaseConvert($sha1, 16, 36, 31);
         } elseif ($sha1base36Set) {
             $sha1 = strtolower($params['sha1base36']);
             if (!$this->validateSha1Base36Hash($sha1)) {
                 $this->dieUsage('The SHA1Base36 hash provided is not valid', 'invalidsha1base36hash');
             }
         }
         if ($sha1) {
             $this->addWhereFld('fa_sha1', $sha1);
         }
     }
     // Exclude files this user can't view.
     if (!$user->isAllowed('deletedtext')) {
         $bitmask = File::DELETED_FILE;
     } elseif (!$user->isAllowedAny('suppressrevision', 'viewsuppressed')) {
         $bitmask = File::DELETED_FILE | File::DELETED_RESTRICTED;
     } else {
         $bitmask = 0;
     }
     if ($bitmask) {
         $this->addWhere($this->getDB()->bitAnd('fa_deleted', $bitmask) . " != {$bitmask}");
     }
     $limit = $params['limit'];
     $this->addOption('LIMIT', $limit + 1);
     $sort = $params['dir'] == 'descending' ? ' DESC' : '';
     $this->addOption('ORDER BY', array('fa_name' . $sort, 'fa_timestamp' . $sort, 'fa_id' . $sort));
     $res = $this->select(__METHOD__);
     $count = 0;
     $result = $this->getResult();
     foreach ($res as $row) {
         if (++$count > $limit) {
             // We've reached the one extra which shows that there are
             // additional pages to be had. Stop here...
             $this->setContinueEnumParameter('continue', "{$row->fa_name}|{$row->fa_timestamp}|{$row->fa_id}");
             break;
         }
         $file = array();
         $file['id'] = (int) $row->fa_id;
         $file['name'] = $row->fa_name;
         $title = Title::makeTitle(NS_FILE, $row->fa_name);
         self::addTitleInfo($file, $title);
         if ($fld_description && Revision::userCanBitfield($row->fa_deleted, File::DELETED_COMMENT, $user)) {
             $file['description'] = $row->fa_description;
             if (isset($prop['parseddescription'])) {
                 $file['parseddescription'] = Linker::formatComment($row->fa_description, $title);
             }
         }
         if ($fld_user && Revision::userCanBitfield($row->fa_deleted, File::DELETED_USER, $user)) {
             $file['userid'] = (int) $row->fa_user;
             $file['user'] = $row->fa_user_text;
         }
         if ($fld_sha1) {
             $file['sha1'] = wfBaseConvert($row->fa_sha1, 36, 16, 40);
         }
         if ($fld_timestamp) {
             $file['timestamp'] = wfTimestamp(TS_ISO_8601, $row->fa_timestamp);
         }
         if ($fld_size || $fld_dimensions) {
             $file['size'] = $row->fa_size;
             $pageCount = ArchivedFile::newFromRow($row)->pageCount();
             if ($pageCount !== false) {
                 $file['pagecount'] = $pageCount;
             }
             $file['height'] = $row->fa_height;
             $file['width'] = $row->fa_width;
         }
         if ($fld_mediatype) {
             $file['mediatype'] = $row->fa_media_type;
         }
         if ($fld_metadata) {
             $file['metadata'] = $row->fa_metadata ? ApiQueryImageInfo::processMetaData(unserialize($row->fa_metadata), $result) : null;
         }
         if ($fld_bitdepth) {
             $file['bitdepth'] = $row->fa_bits;
         }
         if ($fld_mime) {
             $file['mime'] = "{$row->fa_major_mime}/{$row->fa_minor_mime}";
         }
         if ($fld_archivename && !is_null($row->fa_archive_name)) {
             $file['archivename'] = $row->fa_archive_name;
         }
         if ($row->fa_deleted & File::DELETED_FILE) {
             $file['filehidden'] = true;
         }
         if ($row->fa_deleted & File::DELETED_COMMENT) {
             $file['commenthidden'] = true;
         }
         if ($row->fa_deleted & File::DELETED_USER) {
             $file['userhidden'] = true;
         }
         if ($row->fa_deleted & File::DELETED_RESTRICTED) {
             // This file is deleted for normal admins
             $file['suppressed'] = true;
         }
         $fit = $result->addValue(array('query', $this->getModuleName()), null, $file);
         if (!$fit) {
             $this->setContinueEnumParameter('continue', "{$row->fa_name}|{$row->fa_timestamp}|{$row->fa_id}");
             break;
         }
     }
     $result->addIndexedTagName(array('query', $this->getModuleName()), 'fa');
 }
 /**
  * Extract fields from the database row and append them to a result array
  *
  * @param $row
  * @return array
  */
 private function extractRowInfo($row)
 {
     $vals = array();
     $anyHidden = false;
     if ($row->rev_deleted & Revision::DELETED_TEXT) {
         $vals['texthidden'] = '';
         $anyHidden = true;
     }
     // Any rows where we can't view the user were filtered out in the query.
     $vals['userid'] = $row->rev_user;
     $vals['user'] = $row->rev_user_text;
     if ($row->rev_deleted & Revision::DELETED_USER) {
         $vals['userhidden'] = '';
         $anyHidden = true;
     }
     if ($this->fld_ids) {
         $vals['pageid'] = intval($row->rev_page);
         $vals['revid'] = intval($row->rev_id);
         // $vals['textid'] = intval( $row->rev_text_id ); // todo: Should this field be exposed?
         if (!is_null($row->rev_parent_id)) {
             $vals['parentid'] = intval($row->rev_parent_id);
         }
     }
     $title = Title::makeTitle($row->page_namespace, $row->page_title);
     if ($this->fld_title) {
         ApiQueryBase::addTitleInfo($vals, $title);
     }
     if ($this->fld_timestamp) {
         $vals['timestamp'] = wfTimestamp(TS_ISO_8601, $row->rev_timestamp);
     }
     if ($this->fld_flags) {
         if ($row->rev_parent_id == 0 && !is_null($row->rev_parent_id)) {
             $vals['new'] = '';
         }
         if ($row->rev_minor_edit) {
             $vals['minor'] = '';
         }
         if ($row->page_latest == $row->rev_id) {
             $vals['top'] = '';
         }
     }
     if (($this->fld_comment || $this->fld_parsedcomment) && isset($row->rev_comment)) {
         if ($row->rev_deleted & Revision::DELETED_COMMENT) {
             $vals['commenthidden'] = '';
             $anyHidden = true;
         }
         $userCanView = Revision::userCanBitfield($row->rev_deleted, Revision::DELETED_COMMENT, $this->getUser());
         if ($userCanView) {
             if ($this->fld_comment) {
                 $vals['comment'] = $row->rev_comment;
             }
             if ($this->fld_parsedcomment) {
                 $vals['parsedcomment'] = Linker::formatComment($row->rev_comment, $title);
             }
         }
     }
     if ($this->fld_patrolled && $row->rc_patrolled) {
         $vals['patrolled'] = '';
     }
     if ($this->fld_size && !is_null($row->rev_len)) {
         $vals['size'] = intval($row->rev_len);
     }
     if ($this->fld_sizediff && !is_null($row->rev_len) && !is_null($row->rev_parent_id)) {
         $parentLen = isset($this->parentLens[$row->rev_parent_id]) ? $this->parentLens[$row->rev_parent_id] : 0;
         $vals['sizediff'] = intval($row->rev_len - $parentLen);
     }
     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 ($anyHidden && $row->rev_deleted & Revision::DELETED_RESTRICTED) {
         $vals['suppressed'] = '';
     }
     return $vals;
 }
 /**
  * Determine if the current user is allowed to view a particular
  * field of this FileStore image file, if it's marked as deleted.
  * @param int $field
  * @param null|User $user User object to check, or null to use $wgUser
  * @return bool
  */
 public function userCan($field, User $user = null)
 {
     $this->load();
     return Revision::userCanBitfield($this->deleted, $field, $user);
 }
 private function extractRowInfo($row)
 {
     /* Determine the title of the page that has been changed. */
     $title = Title::makeTitle($row->rc_namespace, $row->rc_title);
     $user = $this->getUser();
     /* Our output data. */
     $vals = array();
     $type = intval($row->rc_type);
     /* Determine what kind of change this was. */
     switch ($type) {
         case RC_EDIT:
             $vals['type'] = 'edit';
             break;
         case RC_NEW:
             $vals['type'] = 'new';
             break;
         case RC_MOVE:
             $vals['type'] = 'move';
             break;
         case RC_LOG:
             $vals['type'] = 'log';
             break;
         case RC_EXTERNAL:
             $vals['type'] = 'external';
             break;
         case RC_MOVE_OVER_REDIRECT:
             $vals['type'] = 'move over redirect';
             break;
         default:
             $vals['type'] = $type;
     }
     $anyHidden = false;
     /* Create a new entry in the result for the title. */
     if ($this->fld_title || $this->fld_ids) {
         // These should already have been filtered out of the query, but just in case.
         if ($type === RC_LOG && $row->rc_deleted & LogPage::DELETED_ACTION) {
             $vals['actionhidden'] = '';
             $anyHidden = true;
         }
         if ($type !== RC_LOG || LogEventsList::userCanBitfield($row->rc_deleted, LogPage::DELETED_ACTION, $user)) {
             if ($this->fld_title) {
                 ApiQueryBase::addTitleInfo($vals, $title);
             }
             if ($this->fld_ids) {
                 $vals['pageid'] = intval($row->rc_cur_id);
                 $vals['revid'] = intval($row->rc_this_oldid);
                 $vals['old_revid'] = intval($row->rc_last_oldid);
             }
         }
     }
     /* Add user data and 'anon' flag, if user is anonymous. */
     if ($this->fld_user || $this->fld_userid) {
         if ($row->rc_deleted & Revision::DELETED_USER) {
             $vals['userhidden'] = '';
             $anyHidden = true;
         }
         if (Revision::userCanBitfield($row->rc_deleted, Revision::DELETED_USER, $user)) {
             if ($this->fld_userid) {
                 $vals['userid'] = $row->rc_user;
                 // for backwards compatibility
                 $vals['user'] = $row->rc_user;
             }
             if ($this->fld_user) {
                 $vals['user'] = $row->rc_user_text;
             }
             if (!$row->rc_user) {
                 $vals['anon'] = '';
             }
         }
     }
     /* Add flags, such as new, minor, bot. */
     if ($this->fld_flags) {
         if ($row->rc_bot) {
             $vals['bot'] = '';
         }
         if ($row->rc_type == RC_NEW) {
             $vals['new'] = '';
         }
         if ($row->rc_minor) {
             $vals['minor'] = '';
         }
     }
     /* Add sizes of each revision. (Only available on 1.10+) */
     if ($this->fld_sizes) {
         $vals['oldlen'] = intval($row->rc_old_len);
         $vals['newlen'] = intval($row->rc_new_len);
     }
     /* Add the timestamp. */
     if ($this->fld_timestamp) {
         $vals['timestamp'] = wfTimestamp(TS_ISO_8601, $row->rc_timestamp);
     }
     if ($this->fld_notificationtimestamp) {
         $vals['notificationtimestamp'] = $row->wl_notificationtimestamp == null ? '' : wfTimestamp(TS_ISO_8601, $row->wl_notificationtimestamp);
     }
     /* Add edit summary / log summary. */
     if ($this->fld_comment || $this->fld_parsedcomment) {
         if ($row->rc_deleted & Revision::DELETED_COMMENT) {
             $vals['commenthidden'] = '';
             $anyHidden = true;
         }
         if (Revision::userCanBitfield($row->rc_deleted, Revision::DELETED_COMMENT, $user)) {
             if ($this->fld_comment && isset($row->rc_comment)) {
                 $vals['comment'] = $row->rc_comment;
             }
             if ($this->fld_parsedcomment && isset($row->rc_comment)) {
                 $vals['parsedcomment'] = Linker::formatComment($row->rc_comment, $title);
             }
         }
     }
     /* Add the patrolled flag */
     if ($this->fld_patrol && $row->rc_patrolled == 1) {
         $vals['patrolled'] = '';
     }
     if ($this->fld_patrol && ChangesList::isUnpatrolled($row, $user)) {
         $vals['unpatrolled'] = '';
     }
     if ($this->fld_loginfo && $row->rc_type == RC_LOG) {
         if ($row->rc_deleted & LogPage::DELETED_ACTION) {
             $vals['actionhidden'] = '';
             $anyHidden = true;
         }
         if (LogEventsList::userCanBitfield($row->rc_deleted, LogPage::DELETED_ACTION, $user)) {
             $vals['logid'] = intval($row->rc_logid);
             $vals['logtype'] = $row->rc_log_type;
             $vals['logaction'] = $row->rc_log_action;
             $logEntry = DatabaseLogEntry::newFromRow((array) $row);
             ApiQueryLogEvents::addLogParams($this->getResult(), $vals, $logEntry->getParameters(), $logEntry->getType(), $logEntry->getSubtype(), $logEntry->getTimestamp());
         }
     }
     if ($anyHidden && $row->rc_deleted & Revision::DELETED_RESTRICTED) {
         $vals['suppressed'] = '';
     }
     return $vals;
 }
 private function extractRowInfo($row)
 {
     /* Determine the title of the page that has been changed. */
     $title = Title::makeTitle($row->rc_namespace, $row->rc_title);
     $user = $this->getUser();
     /* Our output data. */
     $vals = [];
     $type = intval($row->rc_type);
     $vals['type'] = RecentChange::parseFromRCType($type);
     $anyHidden = false;
     /* Create a new entry in the result for the title. */
     if ($this->fld_title || $this->fld_ids) {
         // These should already have been filtered out of the query, but just in case.
         if ($type === RC_LOG && $row->rc_deleted & LogPage::DELETED_ACTION) {
             $vals['actionhidden'] = true;
             $anyHidden = true;
         }
         if ($type !== RC_LOG || LogEventsList::userCanBitfield($row->rc_deleted, LogPage::DELETED_ACTION, $user)) {
             if ($this->fld_title) {
                 ApiQueryBase::addTitleInfo($vals, $title);
             }
             if ($this->fld_ids) {
                 $vals['pageid'] = intval($row->rc_cur_id);
                 $vals['revid'] = intval($row->rc_this_oldid);
                 $vals['old_revid'] = intval($row->rc_last_oldid);
             }
         }
     }
     /* Add user data and 'anon' flag, if user is anonymous. */
     if ($this->fld_user || $this->fld_userid) {
         if ($row->rc_deleted & Revision::DELETED_USER) {
             $vals['userhidden'] = true;
             $anyHidden = true;
         }
         if (Revision::userCanBitfield($row->rc_deleted, Revision::DELETED_USER, $user)) {
             if ($this->fld_userid) {
                 $vals['userid'] = (int) $row->rc_user;
                 // for backwards compatibility
                 $vals['user'] = (int) $row->rc_user;
             }
             if ($this->fld_user) {
                 $vals['user'] = $row->rc_user_text;
             }
             if (!$row->rc_user) {
                 $vals['anon'] = true;
             }
         }
     }
     /* Add flags, such as new, minor, bot. */
     if ($this->fld_flags) {
         $vals['bot'] = (bool) $row->rc_bot;
         $vals['new'] = $row->rc_type == RC_NEW;
         $vals['minor'] = (bool) $row->rc_minor;
     }
     /* Add sizes of each revision. (Only available on 1.10+) */
     if ($this->fld_sizes) {
         $vals['oldlen'] = intval($row->rc_old_len);
         $vals['newlen'] = intval($row->rc_new_len);
     }
     /* Add the timestamp. */
     if ($this->fld_timestamp) {
         $vals['timestamp'] = wfTimestamp(TS_ISO_8601, $row->rc_timestamp);
     }
     if ($this->fld_notificationtimestamp) {
         $vals['notificationtimestamp'] = $row->wl_notificationtimestamp == null ? '' : wfTimestamp(TS_ISO_8601, $row->wl_notificationtimestamp);
     }
     /* Add edit summary / log summary. */
     if ($this->fld_comment || $this->fld_parsedcomment) {
         if ($row->rc_deleted & Revision::DELETED_COMMENT) {
             $vals['commenthidden'] = true;
             $anyHidden = true;
         }
         if (Revision::userCanBitfield($row->rc_deleted, Revision::DELETED_COMMENT, $user)) {
             if ($this->fld_comment && isset($row->rc_comment)) {
                 $vals['comment'] = $row->rc_comment;
             }
             if ($this->fld_parsedcomment && isset($row->rc_comment)) {
                 $vals['parsedcomment'] = Linker::formatComment($row->rc_comment, $title);
             }
         }
     }
     /* Add the patrolled flag */
     if ($this->fld_patrol) {
         $vals['patrolled'] = $row->rc_patrolled == 1;
         $vals['unpatrolled'] = ChangesList::isUnpatrolled($row, $user);
     }
     if ($this->fld_loginfo && $row->rc_type == RC_LOG) {
         if ($row->rc_deleted & LogPage::DELETED_ACTION) {
             $vals['actionhidden'] = true;
             $anyHidden = true;
         }
         if (LogEventsList::userCanBitfield($row->rc_deleted, LogPage::DELETED_ACTION, $user)) {
             $vals['logid'] = intval($row->rc_logid);
             $vals['logtype'] = $row->rc_log_type;
             $vals['logaction'] = $row->rc_log_action;
             $vals['logparams'] = LogFormatter::newFromRow($row)->formatParametersForApi();
         }
     }
     if ($anyHidden && $row->rc_deleted & Revision::DELETED_RESTRICTED) {
         $vals['suppressed'] = true;
     }
     return $vals;
 }
 /**
  * Determine if the current user is allowed to view a particular
  * field of this FileStore image file, if it's marked as deleted.
  * @param int $field
  * @param null|User $user User object to check, or null to use $wgUser
  * @return bool
  */
 public function userCan($field, User $user = null)
 {
     $this->load();
     $title = $this->getTitle();
     return Revision::userCanBitfield($this->deleted, $field, $user, $title ?: null);
 }
 public function execute()
 {
     $user = $this->getUser();
     // Before doing anything at all, let's check permissions
     if (!$user->isAllowed('deletedhistory')) {
         $this->dieUsage('You don\'t have permission to view deleted revision information', 'permissiondenied');
     }
     $this->setWarning('list=deletedrevs has been deprecated. Please use prop=deletedrevisions or ' . 'list=alldeletedrevisions instead.');
     $this->logFeatureUsage('action=query&list=deletedrevs');
     $db = $this->getDB();
     $params = $this->extractRequestParams(false);
     $prop = array_flip($params['prop']);
     $fld_parentid = isset($prop['parentid']);
     $fld_revid = isset($prop['revid']);
     $fld_user = isset($prop['user']);
     $fld_userid = isset($prop['userid']);
     $fld_comment = isset($prop['comment']);
     $fld_parsedcomment = isset($prop['parsedcomment']);
     $fld_minor = isset($prop['minor']);
     $fld_len = isset($prop['len']);
     $fld_sha1 = isset($prop['sha1']);
     $fld_content = isset($prop['content']);
     $fld_token = isset($prop['token']);
     $fld_tags = isset($prop['tags']);
     if (isset($prop['token'])) {
         $p = $this->getModulePrefix();
         $this->setWarning("{$p}prop=token has been deprecated. Please use action=query&meta=tokens instead.");
     }
     // If we're in a mode that breaks the same-origin policy, no tokens can
     // be obtained
     if ($this->lacksSameOriginSecurity()) {
         $fld_token = false;
     }
     // If user can't undelete, no tokens
     if (!$user->isAllowed('undelete')) {
         $fld_token = false;
     }
     $result = $this->getResult();
     $pageSet = $this->getPageSet();
     $titles = $pageSet->getTitles();
     // This module operates in three modes:
     // 'revs': List deleted revs for certain titles (1)
     // 'user': List deleted revs by a certain user (2)
     // 'all': List all deleted revs in NS (3)
     $mode = 'all';
     if (count($titles) > 0) {
         $mode = 'revs';
     } elseif (!is_null($params['user'])) {
         $mode = 'user';
     }
     if ($mode == 'revs' || $mode == 'user') {
         // Ignore namespace and unique due to inability to know whether they were purposely set
         foreach (array('from', 'to', 'prefix') as $p) {
             if (!is_null($params[$p])) {
                 $this->dieUsage("The '{$p}' parameter cannot be used in modes 1 or 2", 'badparams');
             }
         }
     } else {
         foreach (array('start', 'end') as $p) {
             if (!is_null($params[$p])) {
                 $this->dieUsage("The {$p} parameter cannot be used in mode 3", 'badparams');
             }
         }
     }
     if (!is_null($params['user']) && !is_null($params['excludeuser'])) {
         $this->dieUsage('user and excludeuser cannot be used together', 'badparams');
     }
     $this->addTables('archive');
     $this->addFields(array('ar_title', 'ar_namespace', 'ar_timestamp', 'ar_deleted', 'ar_id'));
     $this->addFieldsIf('ar_parent_id', $fld_parentid);
     $this->addFieldsIf('ar_rev_id', $fld_revid);
     $this->addFieldsIf('ar_user_text', $fld_user);
     $this->addFieldsIf('ar_user', $fld_userid);
     $this->addFieldsIf('ar_comment', $fld_comment || $fld_parsedcomment);
     $this->addFieldsIf('ar_minor_edit', $fld_minor);
     $this->addFieldsIf('ar_len', $fld_len);
     $this->addFieldsIf('ar_sha1', $fld_sha1);
     if ($fld_tags) {
         $this->addTables('tag_summary');
         $this->addJoinConds(array('tag_summary' => array('LEFT JOIN', array('ar_rev_id=ts_rev_id'))));
         $this->addFields('ts_tags');
     }
     if (!is_null($params['tag'])) {
         $this->addTables('change_tag');
         $this->addJoinConds(array('change_tag' => array('INNER JOIN', array('ar_rev_id=ct_rev_id'))));
         $this->addWhereFld('ct_tag', $params['tag']);
     }
     if ($fld_content) {
         // Modern MediaWiki has the content for deleted revs in the 'text'
         // table using fields old_text and old_flags. But revisions deleted
         // pre-1.5 store the content in the 'archive' table directly using
         // fields ar_text and ar_flags, and no corresponding 'text' row. So
         // we have to LEFT JOIN and fetch all four fields, plus ar_text_id
         // to be able to tell the difference.
         $this->addTables('text');
         $this->addJoinConds(array('text' => array('LEFT JOIN', array('ar_text_id=old_id'))));
         $this->addFields(array('ar_text', 'ar_flags', 'ar_text_id', 'old_text', 'old_flags'));
         // This also means stricter restrictions
         if (!$user->isAllowedAny('undelete', 'deletedtext')) {
             $this->dieUsage('You don\'t have permission to view deleted revision content', 'permissiondenied');
         }
     }
     // Check limits
     $userMax = $fld_content ? ApiBase::LIMIT_SML1 : ApiBase::LIMIT_BIG1;
     $botMax = $fld_content ? ApiBase::LIMIT_SML2 : ApiBase::LIMIT_BIG2;
     $limit = $params['limit'];
     if ($limit == 'max') {
         $limit = $this->getMain()->canApiHighLimits() ? $botMax : $userMax;
         $this->getResult()->addParsedLimit($this->getModuleName(), $limit);
     }
     $this->validateLimit('limit', $limit, 1, $userMax, $botMax);
     if ($fld_token) {
         // Undelete tokens are identical for all pages, so we cache one here
         $token = $user->getEditToken('', $this->getMain()->getRequest());
     }
     $dir = $params['dir'];
     // We need a custom WHERE clause that matches all titles.
     if ($mode == 'revs') {
         $lb = new LinkBatch($titles);
         $where = $lb->constructSet('ar', $db);
         $this->addWhere($where);
     } elseif ($mode == 'all') {
         $this->addWhereFld('ar_namespace', $params['namespace']);
         $from = $params['from'] === null ? null : $this->titlePartToKey($params['from'], $params['namespace']);
         $to = $params['to'] === null ? null : $this->titlePartToKey($params['to'], $params['namespace']);
         $this->addWhereRange('ar_title', $dir, $from, $to);
         if (isset($params['prefix'])) {
             $this->addWhere('ar_title' . $db->buildLike($this->titlePartToKey($params['prefix'], $params['namespace']), $db->anyString()));
         }
     }
     if (!is_null($params['user'])) {
         $this->addWhereFld('ar_user_text', $params['user']);
     } elseif (!is_null($params['excludeuser'])) {
         $this->addWhere('ar_user_text != ' . $db->addQuotes($params['excludeuser']));
     }
     if (!is_null($params['user']) || !is_null($params['excludeuser'])) {
         // Paranoia: avoid brute force searches (bug 17342)
         // (shouldn't be able to get here without 'deletedhistory', but
         // check it again just in case)
         if (!$user->isAllowed('deletedhistory')) {
             $bitmask = Revision::DELETED_USER;
         } elseif (!$user->isAllowedAny('suppressrevision', 'viewsuppressed')) {
             $bitmask = Revision::DELETED_USER | Revision::DELETED_RESTRICTED;
         } else {
             $bitmask = 0;
         }
         if ($bitmask) {
             $this->addWhere($db->bitAnd('ar_deleted', $bitmask) . " != {$bitmask}");
         }
     }
     if (!is_null($params['continue'])) {
         $cont = explode('|', $params['continue']);
         $op = $dir == 'newer' ? '>' : '<';
         if ($mode == 'all' || $mode == 'revs') {
             $this->dieContinueUsageIf(count($cont) != 4);
             $ns = intval($cont[0]);
             $this->dieContinueUsageIf(strval($ns) !== $cont[0]);
             $title = $db->addQuotes($cont[1]);
             $ts = $db->addQuotes($db->timestamp($cont[2]));
             $ar_id = (int) $cont[3];
             $this->dieContinueUsageIf(strval($ar_id) !== $cont[3]);
             $this->addWhere("ar_namespace {$op} {$ns} OR " . "(ar_namespace = {$ns} AND " . "(ar_title {$op} {$title} OR " . "(ar_title = {$title} AND " . "(ar_timestamp {$op} {$ts} OR " . "(ar_timestamp = {$ts} AND " . "ar_id {$op}= {$ar_id})))))");
         } else {
             $this->dieContinueUsageIf(count($cont) != 2);
             $ts = $db->addQuotes($db->timestamp($cont[0]));
             $ar_id = (int) $cont[1];
             $this->dieContinueUsageIf(strval($ar_id) !== $cont[1]);
             $this->addWhere("ar_timestamp {$op} {$ts} OR " . "(ar_timestamp = {$ts} AND " . "ar_id {$op}= {$ar_id})");
         }
     }
     $this->addOption('LIMIT', $limit + 1);
     $this->addOption('USE INDEX', array('archive' => $mode == 'user' ? 'usertext_timestamp' : 'name_title_timestamp'));
     if ($mode == 'all') {
         if ($params['unique']) {
             // @todo Does this work on non-MySQL?
             $this->addOption('GROUP BY', 'ar_title');
         } else {
             $sort = $dir == 'newer' ? '' : ' DESC';
             $this->addOption('ORDER BY', array('ar_title' . $sort, 'ar_timestamp' . $sort, 'ar_id' . $sort));
         }
     } else {
         if ($mode == 'revs') {
             // Sort by ns and title in the same order as timestamp for efficiency
             $this->addWhereRange('ar_namespace', $dir, null, null);
             $this->addWhereRange('ar_title', $dir, null, null);
         }
         $this->addTimestampWhereRange('ar_timestamp', $dir, $params['start'], $params['end']);
         // Include in ORDER BY for uniqueness
         $this->addWhereRange('ar_id', $dir, null, null);
     }
     $res = $this->select(__METHOD__);
     $pageMap = array();
     // Maps ns&title to (fake) pageid
     $count = 0;
     $newPageID = 0;
     foreach ($res as $row) {
         if (++$count > $limit) {
             // We've had enough
             if ($mode == 'all' || $mode == 'revs') {
                 $this->setContinueEnumParameter('continue', "{$row->ar_namespace}|{$row->ar_title}|{$row->ar_timestamp}|{$row->ar_id}");
             } else {
                 $this->setContinueEnumParameter('continue', "{$row->ar_timestamp}|{$row->ar_id}");
             }
             break;
         }
         $rev = array();
         $anyHidden = false;
         $rev['timestamp'] = wfTimestamp(TS_ISO_8601, $row->ar_timestamp);
         if ($fld_revid) {
             $rev['revid'] = intval($row->ar_rev_id);
         }
         if ($fld_parentid && !is_null($row->ar_parent_id)) {
             $rev['parentid'] = intval($row->ar_parent_id);
         }
         if ($fld_user || $fld_userid) {
             if ($row->ar_deleted & Revision::DELETED_USER) {
                 $rev['userhidden'] = true;
                 $anyHidden = true;
             }
             if (Revision::userCanBitfield($row->ar_deleted, Revision::DELETED_USER, $user)) {
                 if ($fld_user) {
                     $rev['user'] = $row->ar_user_text;
                 }
                 if ($fld_userid) {
                     $rev['userid'] = $row->ar_user;
                 }
             }
         }
         if ($fld_comment || $fld_parsedcomment) {
             if ($row->ar_deleted & Revision::DELETED_COMMENT) {
                 $rev['commenthidden'] = true;
                 $anyHidden = true;
             }
             if (Revision::userCanBitfield($row->ar_deleted, Revision::DELETED_COMMENT, $user)) {
                 if ($fld_comment) {
                     $rev['comment'] = $row->ar_comment;
                 }
                 if ($fld_parsedcomment) {
                     $title = Title::makeTitle($row->ar_namespace, $row->ar_title);
                     $rev['parsedcomment'] = Linker::formatComment($row->ar_comment, $title);
                 }
             }
         }
         if ($fld_minor) {
             $rev['minor'] = $row->ar_minor_edit == 1;
         }
         if ($fld_len) {
             $rev['len'] = $row->ar_len;
         }
         if ($fld_sha1) {
             if ($row->ar_deleted & Revision::DELETED_TEXT) {
                 $rev['sha1hidden'] = true;
                 $anyHidden = true;
             }
             if (Revision::userCanBitfield($row->ar_deleted, Revision::DELETED_TEXT, $user)) {
                 if ($row->ar_sha1 != '') {
                     $rev['sha1'] = wfBaseConvert($row->ar_sha1, 36, 16, 40);
                 } else {
                     $rev['sha1'] = '';
                 }
             }
         }
         if ($fld_content) {
             if ($row->ar_deleted & Revision::DELETED_TEXT) {
                 $rev['texthidden'] = true;
                 $anyHidden = true;
             }
             if (Revision::userCanBitfield($row->ar_deleted, Revision::DELETED_TEXT, $user)) {
                 if (isset($row->ar_text) && !$row->ar_text_id) {
                     // Pre-1.5 ar_text row (if condition from Revision::newFromArchiveRow)
                     ApiResult::setContentValue($rev, 'text', Revision::getRevisionText($row, 'ar_'));
                 } else {
                     ApiResult::setContentValue($rev, 'text', Revision::getRevisionText($row));
                 }
             }
         }
         if ($fld_tags) {
             if ($row->ts_tags) {
                 $tags = explode(',', $row->ts_tags);
                 ApiResult::setIndexedTagName($tags, 'tag');
                 $rev['tags'] = $tags;
             } else {
                 $rev['tags'] = array();
             }
         }
         if ($anyHidden && $row->ar_deleted & Revision::DELETED_RESTRICTED) {
             $rev['suppressed'] = true;
         }
         if (!isset($pageMap[$row->ar_namespace][$row->ar_title])) {
             $pageID = $newPageID++;
             $pageMap[$row->ar_namespace][$row->ar_title] = $pageID;
             $a['revisions'] = array($rev);
             ApiResult::setIndexedTagName($a['revisions'], 'rev');
             $title = Title::makeTitle($row->ar_namespace, $row->ar_title);
             ApiQueryBase::addTitleInfo($a, $title);
             if ($fld_token) {
                 $a['token'] = $token;
             }
             $fit = $result->addValue(array('query', $this->getModuleName()), $pageID, $a);
         } else {
             $pageID = $pageMap[$row->ar_namespace][$row->ar_title];
             $fit = $result->addValue(array('query', $this->getModuleName(), $pageID, 'revisions'), null, $rev);
         }
         if (!$fit) {
             if ($mode == 'all' || $mode == 'revs') {
                 $this->setContinueEnumParameter('continue', "{$row->ar_namespace}|{$row->ar_title}|{$row->ar_timestamp}|{$row->ar_id}");
             } else {
                 $this->setContinueEnumParameter('continue', "{$row->ar_timestamp}|{$row->ar_id}");
             }
             break;
         }
     }
     $result->addIndexedTagName(array('query', $this->getModuleName()), 'page');
 }
 /**
  * Determine if the current user is allowed to view a particular
  * field of this revision, if it's marked as deleted.
  * @param $rc InterwikiIntegrationRCCacheEntry
  * @param $field Integer
  * @return Boolean
  */
 public static function userCan($rc, $field)
 {
     if ($rc->mAttribs['integration_rc_type'] == RC_LOG) {
         return LogEventsList::userCanBitfield($rc->mAttribs['integration_rc_deleted'], $field);
     } else {
         return Revision::userCanBitfield($rc->mAttribs['integration_rc_deleted'], $field);
     }
 }