Пример #1
0
 /**
  * @dataProvider provideGetGroupsWithPermission
  * @covers User::getGroupsWithPermission
  */
 public function testGetGroupsWithPermission($expected, $right)
 {
     $result = User::getGroupsWithPermission($right);
     sort($result);
     sort($expected);
     $this->assertEquals($expected, $result, "Groups with permission {$right}");
 }
Пример #2
0
 public function __construct($permission, $errors = array())
 {
     global $wgLang;
     $this->permission = $permission;
     if (!count($errors)) {
         $groups = array_map(array('User', 'makeGroupLinkWiki'), User::getGroupsWithPermission($this->permission));
         if ($groups) {
             $errors[] = array('badaccess-groups', $wgLang->commaList($groups), count($groups));
         } else {
             $errors[] = array('badaccess-group0');
         }
     }
     $this->errors = $errors;
 }
Пример #3
0
 /**
  * @param string|null $permission A permission name or null if unknown
  * @param array $errors Error message keys or [key, param...] arrays; must not be empty if
  *   $permission is null
  * @throws \InvalidArgumentException
  */
 public function __construct($permission, $errors = [])
 {
     global $wgLang;
     if ($permission === null && !$errors) {
         throw new \InvalidArgumentException(__METHOD__ . ': $permission and $errors cannot both be empty');
     }
     $this->permission = $permission;
     if (!count($errors)) {
         $groups = array_map(['User', 'makeGroupLinkWiki'], User::getGroupsWithPermission($this->permission));
         if ($groups) {
             $errors[] = ['badaccess-groups', $wgLang->commaList($groups), count($groups)];
         } else {
             $errors[] = ['badaccess-group0'];
         }
     }
     $this->errors = $errors;
 }
Пример #4
0
 function getQueryInfo()
 {
     global $wgMiserMode;
     $conds = $jconds = array();
     $tables = array('image');
     if (!$this->showbots) {
         $tables[] = 'user_groups';
         $conds[] = 'ug_group IS NULL';
         $jconds['user_groups'] = array('LEFT JOIN', array('ug_group' => User::getGroupsWithPermission('bot'), 'ug_user = img_user'));
     }
     if (!$wgMiserMode && $this->like !== null) {
         $dbr = wfGetDB(DB_SLAVE);
         $likeObj = Title::newFromURL($this->like);
         if ($likeObj instanceof Title) {
             $like = $dbr->buildLike($dbr->anyString(), strtolower($likeObj->getDBkey()), $dbr->anyString());
             $conds[] = "LOWER(img_name) {$like}";
         }
     }
     $query = array('tables' => $tables, 'fields' => '*', 'join_conds' => $jconds, 'conds' => $conds);
     return $query;
 }
Пример #5
0
 function getQueryInfo()
 {
     $opts = $this->opts;
     $conds = $jconds = [];
     $tables = ['image'];
     $fields = ['img_name', 'img_user', 'img_timestamp'];
     $options = [];
     if (!$opts->getValue('showbots')) {
         $groupsWithBotPermission = User::getGroupsWithPermission('bot');
         if (count($groupsWithBotPermission)) {
             $tables[] = 'user_groups';
             $conds[] = 'ug_group IS NULL';
             $jconds['user_groups'] = ['LEFT JOIN', ['ug_group' => $groupsWithBotPermission, 'ug_user = img_user']];
         }
     }
     if ($opts->getValue('hidepatrolled')) {
         $tables[] = 'recentchanges';
         $conds['rc_type'] = RC_LOG;
         $conds['rc_log_type'] = 'upload';
         $conds['rc_patrolled'] = 0;
         $conds['rc_namespace'] = NS_FILE;
         $jconds['recentchanges'] = ['INNER JOIN', ['rc_title = img_name', 'rc_user = img_user', 'rc_timestamp = img_timestamp']];
         // We're ordering by img_timestamp, so we have to make sure MariaDB queries `image` first.
         // It sometimes decides to query `recentchanges` first and filesort the result set later
         // to get the right ordering. T124205 / https://mariadb.atlassian.net/browse/MDEV-8880
         $options[] = 'STRAIGHT_JOIN';
     }
     $likeVal = $opts->getValue('like');
     if (!$this->getConfig()->get('MiserMode') && $likeVal !== '') {
         $dbr = wfGetDB(DB_REPLICA);
         $likeObj = Title::newFromText($likeVal);
         if ($likeObj instanceof Title) {
             $like = $dbr->buildLike($dbr->anyString(), strtolower($likeObj->getDBkey()), $dbr->anyString());
             $conds[] = "LOWER(img_name) {$like}";
         }
     }
     $query = ['tables' => $tables, 'fields' => $fields, 'join_conds' => $jconds, 'conds' => $conds, 'options' => $options];
     return $query;
 }
Пример #6
0
 public function execute()
 {
     global $wgOut;
     $repos = CodeRepository::getRepoList();
     if (!count($repos)) {
         global $wgUser;
         $wgOut->addWikiMsg('code-no-repo');
         if ($wgUser->isAllowed('repoadmin')) {
             $wgOut->addWikiMsg('code-create-repo');
         } else {
             $wgOut->addWikiMsg('code-need-repoadmin-rights');
             if (!count(User::getGroupsWithPermission('repoadmin'))) {
                 $wgOut->addWikiMsg('code-need-group-with-rights');
             }
         }
         return;
     }
     $text = '';
     foreach ($repos as $repo) {
         $text .= "* " . self::getNavItem($repo) . "\n";
     }
     $wgOut->addWikiText($text);
 }
 /**
  * @return UserArray
  */
 public static function getAdminsToNotify()
 {
     $groups = User::getGroupsWithPermission('confirmaccount-notify');
     if (!count($groups)) {
         return UserArray::newFromResult(new FakeResultWrapper(array()));
     }
     $dbr = wfGetDB(DB_SLAVE);
     return UserArray::newFromResult($dbr->select(array('user'), array('*'), array('EXISTS (' . $dbr->selectSqlText('user_groups', '1', array('ug_user = user_id', 'ug_group' => $groups)) . ')'), __METHOD__, array('LIMIT' => 200)));
 }
Пример #8
0
 /**
  * Get a description array when the user doesn't have the right to perform
  * $action (i.e. when User::isAllowed() returns false)
  *
  * @param string $action The action to check
  * @param bool $short Short circuit on first error
  * @return array List of errors
  */
 private function missingPermissionError($action, $short)
 {
     // We avoid expensive display logic for quickUserCan's and such
     if ($short) {
         return array('badaccess-group0');
     }
     $groups = array_map(array('User', 'makeGroupLinkWiki'), User::getGroupsWithPermission($action));
     if (count($groups)) {
         global $wgLang;
         return array('badaccess-groups', $wgLang->commaList($groups), count($groups));
     } else {
         return array('badaccess-group0');
     }
 }
Пример #9
0
 /**
  * @deprecated since 1.25
  * @return mixed|string
  */
 public function reallyMakeHelpMsg()
 {
     wfDeprecated(__METHOD__, '1.25');
     $this->setHelp();
     // Use parent to make default message for the main module
     $msg = parent::makeHelpMsg();
     $astriks = str_repeat('*** ', 14);
     $msg .= "\n\n{$astriks} Modules  {$astriks}\n\n";
     foreach ($this->mModuleMgr->getNames('action') as $name) {
         $module = $this->mModuleMgr->getModule($name);
         $msg .= self::makeHelpMsgHeader($module, 'action');
         $msg2 = $module->makeHelpMsg();
         if ($msg2 !== false) {
             $msg .= $msg2;
         }
         $msg .= "\n";
     }
     $msg .= "\n{$astriks} Permissions {$astriks}\n\n";
     foreach (self::$mRights as $right => $rightMsg) {
         $rightsMsg = $this->msg($rightMsg['msg'], $rightMsg['params'])->useDatabase(false)->inLanguage('en')->text();
         $groups = User::getGroupsWithPermission($right);
         $msg .= "* " . $right . " *\n  {$rightsMsg}" . "\nGranted to:\n  " . str_replace('*', 'all', implode(', ', $groups)) . "\n\n";
     }
     $msg .= "\n{$astriks} Formats  {$astriks}\n\n";
     foreach ($this->mModuleMgr->getNames('format') as $name) {
         $module = $this->mModuleMgr->getModule($name);
         $msg .= self::makeHelpMsgHeader($module, 'format');
         $msg2 = $module->makeHelpMsg();
         if ($msg2 !== false) {
             $msg .= $msg2;
         }
         $msg .= "\n";
     }
     $credits = $this->msg('api-credits')->useDatabase('false')->inLanguage('en')->text();
     $credits = str_replace("\n", "\n   ", $credits);
     $msg .= "\n*** Credits: ***\n   {$credits}\n";
     return $msg;
 }
Пример #10
0
 /**
  * @param ApiPageSet $resultPageSet
  * @return void
  */
 private function run($resultPageSet = null)
 {
     $repo = $this->mRepo;
     if (!$repo instanceof LocalRepo) {
         $this->dieUsage('Local file repository does not support querying all images', 'unsupportedrepo');
     }
     $prefix = $this->getModulePrefix();
     $db = $this->getDB();
     $params = $this->extractRequestParams();
     // Table and return fields
     $this->addTables('image');
     $prop = array_flip($params['prop']);
     $this->addFields(LocalFile::selectFields());
     $ascendingOrder = true;
     if ($params['dir'] == 'descending' || $params['dir'] == 'older') {
         $ascendingOrder = false;
     }
     if ($params['sort'] == 'name') {
         // Check mutually exclusive params
         $disallowed = ['start', 'end', 'user'];
         foreach ($disallowed as $pname) {
             if (isset($params[$pname])) {
                 $this->dieUsage("Parameter '{$prefix}{$pname}' can only be used with {$prefix}sort=timestamp", 'badparams');
             }
         }
         if ($params['filterbots'] != 'all') {
             $this->dieUsage("Parameter '{$prefix}filterbots' can only be used with {$prefix}sort=timestamp", 'badparams');
         }
         // Pagination
         if (!is_null($params['continue'])) {
             $cont = explode('|', $params['continue']);
             $this->dieContinueUsageIf(count($cont) != 1);
             $op = $ascendingOrder ? '>' : '<';
             $continueFrom = $db->addQuotes($cont[0]);
             $this->addWhere("img_name {$op}= {$continueFrom}");
         }
         // Image filters
         $from = $params['from'] === null ? null : $this->titlePartToKey($params['from'], NS_FILE);
         $to = $params['to'] === null ? null : $this->titlePartToKey($params['to'], NS_FILE);
         $this->addWhereRange('img_name', $ascendingOrder ? 'newer' : 'older', $from, $to);
         if (isset($params['prefix'])) {
             $this->addWhere('img_name' . $db->buildLike($this->titlePartToKey($params['prefix'], NS_FILE), $db->anyString()));
         }
     } else {
         // Check mutually exclusive params
         $disallowed = ['from', 'to', 'prefix'];
         foreach ($disallowed as $pname) {
             if (isset($params[$pname])) {
                 $this->dieUsage("Parameter '{$prefix}{$pname}' can only be used with {$prefix}sort=name", 'badparams');
             }
         }
         if (!is_null($params['user']) && $params['filterbots'] != 'all') {
             // Since filterbots checks if each user has the bot right, it
             // doesn't make sense to use it with user
             $this->dieUsage("Parameters '{$prefix}user' and '{$prefix}filterbots' cannot be used together", 'badparams');
         }
         // Pagination
         $this->addTimestampWhereRange('img_timestamp', $ascendingOrder ? 'newer' : 'older', $params['start'], $params['end']);
         // Include in ORDER BY for uniqueness
         $this->addWhereRange('img_name', $ascendingOrder ? 'newer' : 'older', null, null);
         if (!is_null($params['continue'])) {
             $cont = explode('|', $params['continue']);
             $this->dieContinueUsageIf(count($cont) != 2);
             $op = $ascendingOrder ? '>' : '<';
             $continueTimestamp = $db->addQuotes($db->timestamp($cont[0]));
             $continueName = $db->addQuotes($cont[1]);
             $this->addWhere("img_timestamp {$op} {$continueTimestamp} OR " . "(img_timestamp = {$continueTimestamp} AND " . "img_name {$op}= {$continueName})");
         }
         // Image filters
         if (!is_null($params['user'])) {
             $this->addWhereFld('img_user_text', $params['user']);
         }
         if ($params['filterbots'] != 'all') {
             $this->addTables('user_groups');
             $this->addJoinConds(['user_groups' => ['LEFT JOIN', ['ug_group' => User::getGroupsWithPermission('bot'), 'ug_user = img_user']]]);
             $groupCond = $params['filterbots'] == 'nobots' ? 'NULL' : 'NOT NULL';
             $this->addWhere("ug_group IS {$groupCond}");
         }
     }
     // Filters not depending on sort
     if (isset($params['minsize'])) {
         $this->addWhere('img_size>=' . intval($params['minsize']));
     }
     if (isset($params['maxsize'])) {
         $this->addWhere('img_size<=' . intval($params['maxsize']));
     }
     $sha1 = false;
     if (isset($params['sha1'])) {
         $sha1 = strtolower($params['sha1']);
         if (!$this->validateSha1Hash($sha1)) {
             $this->dieUsage('The SHA1 hash provided is not valid', 'invalidsha1hash');
         }
         $sha1 = Wikimedia\base_convert($sha1, 16, 36, 31);
     } elseif (isset($params['sha1base36'])) {
         $sha1 = strtolower($params['sha1base36']);
         if (!$this->validateSha1Base36Hash($sha1)) {
             $this->dieUsage('The SHA1Base36 hash provided is not valid', 'invalidsha1base36hash');
         }
     }
     if ($sha1) {
         $this->addWhereFld('img_sha1', $sha1);
     }
     if (!is_null($params['mime'])) {
         if ($this->getConfig()->get('MiserMode')) {
             $this->dieUsage('MIME search disabled in Miser Mode', 'mimesearchdisabled');
         }
         $mimeConds = [];
         foreach ($params['mime'] as $mime) {
             list($major, $minor) = File::splitMime($mime);
             $mimeConds[] = $db->makeList(['img_major_mime' => $major, 'img_minor_mime' => $minor], LIST_AND);
         }
         // safeguard against internal_api_error_DBQueryError
         if (count($mimeConds) > 0) {
             $this->addWhere($db->makeList($mimeConds, LIST_OR));
         } else {
             // no MIME types, no files
             $this->getResult()->addValue('query', $this->getModuleName(), []);
             return;
         }
     }
     $limit = $params['limit'];
     $this->addOption('LIMIT', $limit + 1);
     $sortFlag = '';
     if (!$ascendingOrder) {
         $sortFlag = ' DESC';
     }
     if ($params['sort'] == 'timestamp') {
         $this->addOption('ORDER BY', 'img_timestamp' . $sortFlag);
         if (!is_null($params['user'])) {
             $this->addOption('USE INDEX', ['image' => 'img_usertext_timestamp']);
         } else {
             $this->addOption('USE INDEX', ['image' => 'img_timestamp']);
         }
     } else {
         $this->addOption('ORDER BY', 'img_name' . $sortFlag);
     }
     $res = $this->select(__METHOD__);
     $titles = [];
     $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...
             if ($params['sort'] == 'name') {
                 $this->setContinueEnumParameter('continue', $row->img_name);
             } else {
                 $this->setContinueEnumParameter('continue', "{$row->img_timestamp}|{$row->img_name}");
             }
             break;
         }
         if (is_null($resultPageSet)) {
             $file = $repo->newFileFromRow($row);
             $info = array_merge(['name' => $row->img_name], ApiQueryImageInfo::getInfo($file, $prop, $result));
             self::addTitleInfo($info, $file->getTitle());
             $fit = $result->addValue(['query', $this->getModuleName()], null, $info);
             if (!$fit) {
                 if ($params['sort'] == 'name') {
                     $this->setContinueEnumParameter('continue', $row->img_name);
                 } else {
                     $this->setContinueEnumParameter('continue', "{$row->img_timestamp}|{$row->img_name}");
                 }
                 break;
             }
         } else {
             $titles[] = Title::makeTitle(NS_FILE, $row->img_name);
         }
     }
     if (is_null($resultPageSet)) {
         $result->addIndexedTagName(['query', $this->getModuleName()], 'img');
     } else {
         $resultPageSet->populateFromTitles($titles);
     }
 }
Пример #11
0
 /**
  * Factory function for fatal permission-denied errors
  *
  * @since 1.22
  * @param string $permission User right required
  * @return Status
  */
 static function newFatalPermissionDeniedStatus($permission)
 {
     global $wgLang;
     $groups = array_map(array('User', 'makeGroupLinkWiki'), User::getGroupsWithPermission($permission));
     if ($groups) {
         return Status::newFatal('badaccess-groups', $wgLang->commaList($groups), count($groups));
     } else {
         return Status::newFatal('badaccess-group0');
     }
 }
Пример #12
0
 public function execute()
 {
     $db = $this->getDB();
     $params = $this->extractRequestParams();
     $this->requireMaxOneParameter($params, 'group', 'excludegroup', 'rights', 'excluderights');
     // Only operate on existing pages
     $pages = array_keys($this->getPageSet()->getGoodTitles());
     // Filter out already-processed pages
     if ($params['continue'] !== null) {
         $cont = explode('|', $params['continue']);
         $this->dieContinueUsageIf(count($cont) != 2);
         $cont_page = (int) $cont[0];
         $pages = array_filter($pages, function ($v) use($cont_page) {
             return $v >= $cont_page;
         });
     }
     if (!count($pages)) {
         // Nothing to do
         return;
     }
     // Apply MAX_PAGES, leaving any over the limit for a continue.
     sort($pages);
     $continuePages = null;
     if (count($pages) > self::MAX_PAGES) {
         $continuePages = $pages[self::MAX_PAGES] . '|0';
         $pages = array_slice($pages, 0, self::MAX_PAGES);
     }
     $result = $this->getResult();
     // First, count anons
     $this->addTables('revision');
     $this->addFields(['page' => 'rev_page', 'anons' => 'COUNT(DISTINCT rev_user_text)']);
     $this->addWhereFld('rev_page', $pages);
     $this->addWhere('rev_user = 0');
     $this->addWhere($db->bitAnd('rev_deleted', Revision::DELETED_USER) . ' = 0');
     $this->addOption('GROUP BY', 'rev_page');
     $res = $this->select(__METHOD__);
     foreach ($res as $row) {
         $fit = $result->addValue(['query', 'pages', $row->page], 'anoncontributors', (int) $row->anons);
         if (!$fit) {
             // This not fitting isn't reasonable, so it probably means that
             // some other module used up all the space. Just set a dummy
             // continue and hope it works next time.
             $this->setContinueEnumParameter('continue', $params['continue'] !== null ? $params['continue'] : '0|0');
             return;
         }
     }
     // Next, add logged-in users
     $this->resetQueryParams();
     $this->addTables('revision');
     $this->addFields(['page' => 'rev_page', 'user' => 'rev_user', 'username' => 'MAX(rev_user_text)']);
     $this->addWhereFld('rev_page', $pages);
     $this->addWhere('rev_user != 0');
     $this->addWhere($db->bitAnd('rev_deleted', Revision::DELETED_USER) . ' = 0');
     $this->addOption('GROUP BY', 'rev_page, rev_user');
     $this->addOption('LIMIT', $params['limit'] + 1);
     // Force a sort order to ensure that properties are grouped by page
     // But only if pp_page is not constant in the WHERE clause.
     if (count($pages) > 1) {
         $this->addOption('ORDER BY', 'rev_page, rev_user');
     } else {
         $this->addOption('ORDER BY', 'rev_user');
     }
     $limitGroups = [];
     if ($params['group']) {
         $excludeGroups = false;
         $limitGroups = $params['group'];
     } elseif ($params['excludegroup']) {
         $excludeGroups = true;
         $limitGroups = $params['excludegroup'];
     } elseif ($params['rights']) {
         $excludeGroups = false;
         foreach ($params['rights'] as $r) {
             $limitGroups = array_merge($limitGroups, User::getGroupsWithPermission($r));
         }
         // If no group has the rights requested, no need to query
         if (!$limitGroups) {
             if ($continuePages !== null) {
                 // But we still need to continue for the next page's worth
                 // of anoncontributors
                 $this->setContinueEnumParameter('continue', $continuePages);
             }
             return;
         }
     } elseif ($params['excluderights']) {
         $excludeGroups = true;
         foreach ($params['excluderights'] as $r) {
             $limitGroups = array_merge($limitGroups, User::getGroupsWithPermission($r));
         }
     }
     if ($limitGroups) {
         $limitGroups = array_unique($limitGroups);
         $this->addTables('user_groups');
         $this->addJoinConds(['user_groups' => [$excludeGroups ? 'LEFT OUTER JOIN' : 'INNER JOIN', ['ug_user=rev_user', 'ug_group' => $limitGroups]]]);
         $this->addWhereIf('ug_user IS NULL', $excludeGroups);
     }
     if ($params['continue'] !== null) {
         $cont = explode('|', $params['continue']);
         $this->dieContinueUsageIf(count($cont) != 2);
         $cont_page = (int) $cont[0];
         $cont_user = (int) $cont[1];
         $this->addWhere("rev_page > {$cont_page} OR " . "(rev_page = {$cont_page} AND " . "rev_user >= {$cont_user})");
     }
     $res = $this->select(__METHOD__);
     $count = 0;
     foreach ($res as $row) {
         if (++$count > $params['limit']) {
             // We've reached the one extra which shows that
             // there are additional pages to be had. Stop here...
             $this->setContinueEnumParameter('continue', $row->page . '|' . $row->user);
             return;
         }
         $fit = $this->addPageSubItem($row->page, ['userid' => (int) $row->user, 'name' => $row->username], 'user');
         if (!$fit) {
             $this->setContinueEnumParameter('continue', $row->page . '|' . $row->user);
             return;
         }
     }
     if ($continuePages !== null) {
         $this->setContinueEnumParameter('continue', $continuePages);
     }
 }
 public function execute()
 {
     $params = $this->extractRequestParams();
     $activeUserDays = $this->getConfig()->get('ActiveUserDays');
     if ($params['activeusers']) {
         // Update active user cache
         SpecialActiveUsers::mergeActiveUsers(600, $activeUserDays);
     }
     $db = $this->getDB();
     $prop = $params['prop'];
     if (!is_null($prop)) {
         $prop = array_flip($prop);
         $fld_blockinfo = isset($prop['blockinfo']);
         $fld_editcount = isset($prop['editcount']);
         $fld_groups = isset($prop['groups']);
         $fld_rights = isset($prop['rights']);
         $fld_registration = isset($prop['registration']);
         $fld_implicitgroups = isset($prop['implicitgroups']);
     } else {
         $fld_blockinfo = $fld_editcount = $fld_groups = $fld_registration = $fld_rights = $fld_implicitgroups = false;
     }
     $limit = $params['limit'];
     $this->addTables('user');
     $useIndex = true;
     $dir = $params['dir'] == 'descending' ? 'older' : 'newer';
     $from = is_null($params['from']) ? null : $this->getCanonicalUserName($params['from']);
     $to = is_null($params['to']) ? null : $this->getCanonicalUserName($params['to']);
     # MySQL can't figure out that 'user_name' and 'qcc_title' are the same
     # despite the JOIN condition, so manually sort on the correct one.
     $userFieldToSort = $params['activeusers'] ? 'qcc_title' : 'user_name';
     $this->addWhereRange($userFieldToSort, $dir, $from, $to);
     if (!is_null($params['prefix'])) {
         $this->addWhere($userFieldToSort . $db->buildLike($this->getCanonicalUserName($params['prefix']), $db->anyString()));
     }
     if (!is_null($params['rights']) && count($params['rights'])) {
         $groups = array();
         foreach ($params['rights'] as $r) {
             $groups = array_merge($groups, User::getGroupsWithPermission($r));
         }
         // no group with the given right(s) exists, no need for a query
         if (!count($groups)) {
             $this->getResult()->setIndexedTagName_internal(array('query', $this->getModuleName()), '');
             return;
         }
         $groups = array_unique($groups);
         if (is_null($params['group'])) {
             $params['group'] = $groups;
         } else {
             $params['group'] = array_unique(array_merge($params['group'], $groups));
         }
     }
     if (!is_null($params['group']) && count($params['group'])) {
         // Filter only users that belong to a given group
         $this->addWhere('EXISTS (' . $db->selectSQLText('user_groups', '1', array('ug_user=user_id', 'ug_group' => $params['group'])) . ')');
     }
     if (!is_null($params['excludegroup']) && count($params['excludegroup'])) {
         // Filter only users don't belong to a given group
         $this->addWhere('NOT EXISTS (' . $db->selectSQLText('user_groups', '1', array('ug_user=user_id', 'ug_group' => $params['excludegroup'])) . ')');
     }
     if ($params['witheditsonly']) {
         $this->addWhere('user_editcount > 0');
     }
     $this->showHiddenUsersAddBlockInfo($fld_blockinfo);
     if ($fld_groups || $fld_rights) {
         // Show the groups the given users belong to
         // request more than needed to avoid not getting all rows that belong to one user
         $groupCount = count(User::getAllGroups());
         $sqlLimit = $limit + $groupCount + 1;
         $this->addTables('user_groups', 'ug2');
         $this->addJoinConds(array('ug2' => array('LEFT JOIN', 'ug2.ug_user=user_id')));
         $this->addFields(array('ug_group2' => 'ug2.ug_group'));
     } else {
         $sqlLimit = $limit + 1;
     }
     if ($params['activeusers']) {
         $activeUserSeconds = $activeUserDays * 86400;
         // Filter query to only include users in the active users cache
         $this->addTables('querycachetwo');
         $this->addJoinConds(array('querycachetwo' => array('INNER JOIN', array('qcc_type' => 'activeusers', 'qcc_namespace' => NS_USER, 'qcc_title=user_name'))));
         // Actually count the actions using a subquery (bug 64505 and bug 64507)
         $timestamp = $db->timestamp(wfTimestamp(TS_UNIX) - $activeUserSeconds);
         $this->addFields(array('recentactions' => '(' . $db->selectSQLText('recentchanges', 'COUNT(*)', array('rc_user_text = user_name', 'rc_type != ' . $db->addQuotes(RC_EXTERNAL), 'rc_log_type IS NULL OR rc_log_type != ' . $db->addQuotes('newusers'), 'rc_timestamp >= ' . $db->addQuotes($timestamp))) . ')'));
     }
     $this->addOption('LIMIT', $sqlLimit);
     $this->addFields(array('user_name', 'user_id'));
     $this->addFieldsIf('user_editcount', $fld_editcount);
     $this->addFieldsIf('user_registration', $fld_registration);
     if ($useIndex) {
         $this->addOption('USE INDEX', array('user' => 'user_name'));
     }
     $res = $this->select(__METHOD__);
     $count = 0;
     $lastUserData = false;
     $lastUser = false;
     $result = $this->getResult();
     // This loop keeps track of the last entry. For each new row, if the
     // new row is for different user then the last, the last entry is added
     // to results. Otherwise, the group of the new row is appended to the
     // last entry. The setContinue... is more complex because of this, and
     // takes into account the higher sql limit to make sure all rows that
     // belong to the same user are received.
     foreach ($res as $row) {
         $count++;
         if ($lastUser !== $row->user_name) {
             // Save the last pass's user data
             if (is_array($lastUserData)) {
                 if ($params['activeusers'] && $lastUserData['recentactions'] === 0) {
                     // activeusers cache was out of date
                     $fit = true;
                 } else {
                     $fit = $result->addValue(array('query', $this->getModuleName()), null, $lastUserData);
                 }
                 $lastUserData = null;
                 if (!$fit) {
                     $this->setContinueEnumParameter('from', $lastUserData['name']);
                     break;
                 }
             }
             if ($count > $limit) {
                 // We've reached the one extra which shows that there are
                 // additional pages to be had. Stop here...
                 $this->setContinueEnumParameter('from', $row->user_name);
                 break;
             }
             // Record new user's data
             $lastUser = $row->user_name;
             $lastUserData = array('userid' => $row->user_id, 'name' => $lastUser);
             if ($fld_blockinfo && !is_null($row->ipb_by_text)) {
                 $lastUserData['blockid'] = $row->ipb_id;
                 $lastUserData['blockedby'] = $row->ipb_by_text;
                 $lastUserData['blockedbyid'] = $row->ipb_by;
                 $lastUserData['blockreason'] = $row->ipb_reason;
                 $lastUserData['blockexpiry'] = $row->ipb_expiry;
             }
             if ($row->ipb_deleted) {
                 $lastUserData['hidden'] = '';
             }
             if ($fld_editcount) {
                 $lastUserData['editcount'] = intval($row->user_editcount);
             }
             if ($params['activeusers']) {
                 $lastUserData['recentactions'] = intval($row->recentactions);
                 // @todo 'recenteditcount' is set for BC, remove in 1.25
                 $lastUserData['recenteditcount'] = $lastUserData['recentactions'];
             }
             if ($fld_registration) {
                 $lastUserData['registration'] = $row->user_registration ? wfTimestamp(TS_ISO_8601, $row->user_registration) : '';
             }
         }
         if ($sqlLimit == $count) {
             // @todo BUG!  database contains group name that User::getAllGroups() does not return
             // Should handle this more gracefully
             ApiBase::dieDebug(__METHOD__, 'MediaWiki configuration error: The database contains more ' . 'user groups than known to User::getAllGroups() function');
         }
         $lastUserObj = User::newFromId($row->user_id);
         // Add user's group info
         if ($fld_groups) {
             if (!isset($lastUserData['groups'])) {
                 if ($lastUserObj) {
                     $lastUserData['groups'] = $lastUserObj->getAutomaticGroups();
                 } else {
                     // This should not normally happen
                     $lastUserData['groups'] = array();
                 }
             }
             if (!is_null($row->ug_group2)) {
                 $lastUserData['groups'][] = $row->ug_group2;
             }
             $result->setIndexedTagName($lastUserData['groups'], 'g');
         }
         if ($fld_implicitgroups && !isset($lastUserData['implicitgroups']) && $lastUserObj) {
             $lastUserData['implicitgroups'] = $lastUserObj->getAutomaticGroups();
             $result->setIndexedTagName($lastUserData['implicitgroups'], 'g');
         }
         if ($fld_rights) {
             if (!isset($lastUserData['rights'])) {
                 if ($lastUserObj) {
                     $lastUserData['rights'] = User::getGroupPermissions($lastUserObj->getAutomaticGroups());
                 } else {
                     // This should not normally happen
                     $lastUserData['rights'] = array();
                 }
             }
             if (!is_null($row->ug_group2)) {
                 $lastUserData['rights'] = array_unique(array_merge($lastUserData['rights'], User::getGroupPermissions(array($row->ug_group2))));
             }
             $result->setIndexedTagName($lastUserData['rights'], 'r');
         }
     }
     if (is_array($lastUserData) && !($params['activeusers'] && $lastUserData['recentactions'] === 0)) {
         $fit = $result->addValue(array('query', $this->getModuleName()), null, $lastUserData);
         if (!$fit) {
             $this->setContinueEnumParameter('from', $lastUserData['name']);
         }
     }
     $result->setIndexedTagName_internal(array('query', $this->getModuleName()), 'u');
 }
Пример #14
0
 /**
  * Can $user perform $action on this page? This is an internal function,
  * which checks ONLY that previously checked by userCan (i.e. it leaves out
  * checks on wfReadOnly() and blocks)
  *
  * @param $action \type{\string} action that permission needs to be checked for
  * @param $user \type{User} user to check
  * @param $doExpensiveQueries \type{\bool} Set this to false to avoid doing unnecessary queries.
  * @param $short \type{\bool} Set this to true to stop after the first permission error.
  * @return \type{\array} Array of arrays of the arguments to wfMsg to explain permissions problems.
  */
 private function getUserPermissionsErrorsInternal($action, $user, $doExpensiveQueries = true, $short = false)
 {
     wfProfileIn(__METHOD__);
     $errors = array();
     // First stop is permissions checks, which fail most often, and which are easiest to test.
     if ($action == 'move') {
         if (!$user->isAllowed('move-rootuserpages') && $this->getNamespace() == NS_USER && !$this->isSubpage()) {
             // Show user page-specific message only if the user can move other pages
             $errors[] = array('cant-move-user-page');
         }
         // Check if user is allowed to move files if it's a file
         if ($this->getNamespace() == NS_FILE && !$user->isAllowed('movefile')) {
             $errors[] = array('movenotallowedfile');
         }
         if (!$user->isAllowed('move')) {
             // User can't move anything
             $errors[] = $user->isAnon() ? array('movenologintext') : array('movenotallowed');
         }
     } elseif ($action == 'create') {
         if ($this->isTalkPage() && !$user->isAllowed('createtalk') || !$this->isTalkPage() && !$user->isAllowed('createpage')) {
             $errors[] = $user->isAnon() ? array('nocreatetext') : array('nocreate-loggedin');
         }
     } elseif ($action == 'move-target') {
         if (!$user->isAllowed('move')) {
             // User can't move anything
             $errors[] = $user->isAnon() ? array('movenologintext') : array('movenotallowed');
         } elseif (!$user->isAllowed('move-rootuserpages') && $this->getNamespace() == NS_USER && !$this->isSubpage()) {
             // Show user page-specific message only if the user can move other pages
             $errors[] = array('cant-move-to-user-page');
         }
     } elseif (!$user->isAllowed($action)) {
         $return = null;
         $groups = array_map(array('User', 'makeGroupLinkWiki'), User::getGroupsWithPermission($action));
         if ($groups) {
             $return = array('badaccess-groups', array(implode(', ', $groups), count($groups)));
         } else {
             $return = array("badaccess-group0");
         }
         $errors[] = $return;
     }
     # Short-circuit point
     if ($short && count($errors) > 0) {
         wfProfileOut(__METHOD__);
         return $errors;
     }
     // Use getUserPermissionsErrors instead
     if (!wfRunHooks('userCan', array(&$this, &$user, $action, &$result))) {
         wfProfileOut(__METHOD__);
         return $result ? array() : array(array('badaccess-group0'));
     }
     // Check getUserPermissionsErrors hook
     if (!wfRunHooks('getUserPermissionsErrors', array(&$this, &$user, $action, &$result))) {
         if (is_array($result) && count($result) && !is_array($result[0])) {
             $errors[] = $result;
         } else {
             if (is_array($result) && is_array($result[0])) {
                 $errors = array_merge($errors, $result);
             } else {
                 if ($result !== '' && is_string($result)) {
                     $errors[] = array($result);
                 } else {
                     if ($result === false) {
                         $errors[] = array('badaccess-group0');
                     }
                 }
             }
         }
         # a generic "We don't want them to do that"
     }
     # Short-circuit point
     if ($short && count($errors) > 0) {
         wfProfileOut(__METHOD__);
         return $errors;
     }
     // Check getUserPermissionsErrorsExpensive hook
     if ($doExpensiveQueries && !wfRunHooks('getUserPermissionsErrorsExpensive', array(&$this, &$user, $action, &$result))) {
         if (is_array($result) && count($result) && !is_array($result[0])) {
             $errors[] = $result;
         } else {
             if (is_array($result) && is_array($result[0])) {
                 $errors = array_merge($errors, $result);
             } else {
                 if ($result !== '' && is_string($result)) {
                     $errors[] = array($result);
                 } else {
                     if ($result === false) {
                         $errors[] = array('badaccess-group0');
                     }
                 }
             }
         }
         # a generic "We don't want them to do that"
     }
     # Short-circuit point
     if ($short && count($errors) > 0) {
         wfProfileOut(__METHOD__);
         return $errors;
     }
     # Only 'createaccount' and 'execute' can be performed on
     # special pages, which don't actually exist in the DB.
     $specialOKActions = array('createaccount', 'execute');
     if (NS_SPECIAL == $this->mNamespace && !in_array($action, $specialOKActions)) {
         $errors[] = array('ns-specialprotected');
     }
     # Check $wgNamespaceProtection for restricted namespaces
     if ($this->isNamespaceProtected()) {
         $ns = $this->getNamespace() == NS_MAIN ? wfMsg('nstab-main') : $this->getNsText();
         $errors[] = NS_MEDIAWIKI == $this->mNamespace ? array('protectedinterface') : array('namespaceprotected', $ns);
     }
     # Protect css/js subpages of user pages
     # XXX: this might be better using restrictions
     # XXX: Find a way to work around the php bug that prevents using $this->userCanEditCssJsSubpage() from working
     if ($this->isCssJsSubpage() && !$user->isAllowed('editusercssjs') && !preg_match('/^' . preg_quote($user->getName(), '/') . '\\//', $this->mTextform)) {
         $errors[] = array('customcssjsprotected');
     }
     # Check against page_restrictions table requirements on this
     # page. The user must possess all required rights for this action.
     foreach ($this->getRestrictions($action) as $right) {
         // Backwards compatibility, rewrite sysop -> protect
         if ($right == 'sysop') {
             $right = 'protect';
         }
         if ('' != $right && !$user->isAllowed($right)) {
             // Users with 'editprotected' permission can edit protected pages
             if ($action == 'edit' && $user->isAllowed('editprotected')) {
                 // Users with 'editprotected' permission cannot edit protected pages
                 // with cascading option turned on.
                 if ($this->mCascadeRestriction) {
                     $errors[] = array('protectedpagetext', $right);
                 }
             } else {
                 $errors[] = array('protectedpagetext', $right);
             }
         }
     }
     # Short-circuit point
     if ($short && count($errors) > 0) {
         wfProfileOut(__METHOD__);
         return $errors;
     }
     if ($doExpensiveQueries && !$this->isCssJsSubpage()) {
         # We /could/ use the protection level on the source page, but it's fairly ugly
         #  as we have to establish a precedence hierarchy for pages included by multiple
         #  cascade-protected pages. So just restrict it to people with 'protect' permission,
         #  as they could remove the protection anyway.
         list($cascadingSources, $restrictions) = $this->getCascadeProtectionSources();
         # Cascading protection depends on more than this page...
         # Several cascading protected pages may include this page...
         # Check each cascading level
         # This is only for protection restrictions, not for all actions
         if ($cascadingSources > 0 && isset($restrictions[$action])) {
             foreach ($restrictions[$action] as $right) {
                 $right = $right == 'sysop' ? 'protect' : $right;
                 if ('' != $right && !$user->isAllowed($right)) {
                     $pages = '';
                     foreach ($cascadingSources as $page) {
                         $pages .= '* [[:' . $page->getPrefixedText() . "]]\n";
                     }
                     $errors[] = array('cascadeprotected', count($cascadingSources), $pages);
                 }
             }
         }
     }
     # Short-circuit point
     if ($short && count($errors) > 0) {
         wfProfileOut(__METHOD__);
         return $errors;
     }
     if ($action == 'protect') {
         if ($this->getUserPermissionsErrors('edit', $user) != array()) {
             $errors[] = array('protect-cantedit');
             // If they can't edit, they shouldn't protect.
         }
     }
     if ($action == 'create') {
         $title_protection = $this->getTitleProtection();
         if (is_array($title_protection)) {
             extract($title_protection);
             // is this extract() really needed?
             if ($pt_create_perm == 'sysop') {
                 $pt_create_perm = 'protect';
                 // B/C
             }
             if ($pt_create_perm == '' || !$user->isAllowed($pt_create_perm)) {
                 $errors[] = array('titleprotected', User::whoIs($pt_user), $pt_reason);
             }
         }
     } elseif ($action == 'move') {
         // Check for immobile pages
         if (!MWNamespace::isMovable($this->getNamespace())) {
             // Specific message for this case
             $errors[] = array('immobile-source-namespace', $this->getNsText());
         } elseif (!$this->isMovable()) {
             // Less specific message for rarer cases
             $errors[] = array('immobile-page');
         }
     } elseif ($action == 'move-target') {
         if (!MWNamespace::isMovable($this->getNamespace())) {
             $errors[] = array('immobile-target-namespace', $this->getNsText());
         } elseif (!$this->isMovable()) {
             $errors[] = array('immobile-target-page');
         }
     }
     wfProfileOut(__METHOD__);
     return $errors;
 }
Пример #15
0
function wfSpecialWikiaNewFiles($par, $specialPage)
{
    global $wgOut, $wgLang, $wgRequest, $wgMiserMode;
    global $wmu, $wgOasisHD;
    $wpIlMatch = $wgRequest->getText('wpIlMatch');
    $dbr = wfGetDB(DB_SLAVE);
    $sk = RequestContext::getMain()->getSkin();
    $shownav = !$specialPage->including();
    $hidebots = $wgRequest->getBool('hidebots', 1);
    $hidebotsql = '';
    if ($hidebots) {
        # Make a list of group names which have the 'bot' flag set.
        $botconds = array();
        foreach (User::getGroupsWithPermission('bot') as $groupname) {
            $botconds[] = 'ug_group = ' . $dbr->addQuotes($groupname);
        }
        # If not bot groups, do not set $hidebotsql
        if ($botconds) {
            $isbotmember = $dbr->makeList($botconds, LIST_OR);
            # This join, in conjunction with WHERE ug_group IS NULL, returns
            # only those rows from IMAGE where the uploading user is not a mem-
            # ber of a group which has the 'bot' permission set.
            $ug = $dbr->tableName('user_groups');
            $hidebotsql = " LEFT JOIN {$ug} ON img_user=ug_user AND ({$isbotmember})";
        }
    }
    $image = $dbr->tableName('image');
    $sql = "SELECT img_timestamp from {$image}";
    if ($hidebotsql) {
        $sql .= "{$hidebotsql} WHERE ug_group IS NULL";
    }
    $sql .= ' ORDER BY img_timestamp DESC LIMIT 1';
    $res = $dbr->query($sql, __FUNCTION__);
    $row = $dbr->fetchRow($res);
    if ($row !== false) {
        $ts = $row[0];
    } else {
        $ts = false;
    }
    $dbr->freeResult($res);
    $sql = '';
    # If we were clever, we'd use this to cache.
    $latestTimestamp = wfTimestamp(TS_MW, $ts);
    # Hardcode this for now.
    $limit = 48;
    if ($parval = intval($par)) {
        if ($parval <= $limit && $parval > 0) {
            $limit = $parval;
        }
    }
    $where = array();
    $searchpar = '';
    if ($wpIlMatch != '' && !$wgMiserMode) {
        $nt = Title::newFromUrl($wpIlMatch);
        if ($nt) {
            $m = $dbr->buildLike($dbr->anyString(), strtolower($nt->getDBkey()), $dbr->anyString());
            $where[] = 'LOWER(img_name)' . $m;
            $searchpar = '&wpIlMatch=' . urlencode($wpIlMatch);
        }
    }
    $invertSort = false;
    if ($until = $wgRequest->getVal('until')) {
        $where[] = "img_timestamp < '" . $dbr->timestamp($until) . "'";
    }
    if ($from = $wgRequest->getVal('from')) {
        $where[] = "img_timestamp >= '" . $dbr->timestamp($from) . "'";
        $invertSort = true;
    }
    $sql = 'SELECT img_size, img_name, img_user, img_user_text,' . "img_description,img_timestamp FROM {$image}";
    if ($hidebotsql) {
        $sql .= $hidebotsql;
        $where[] = 'ug_group IS NULL';
    }
    // hook by Wikia, Bartek Lapinski 26.03.2009, for videos and stuff
    wfRunHooks('SpecialNewImages::beforeQuery', array(&$where));
    if (count($where)) {
        $sql .= ' WHERE ' . $dbr->makeList($where, LIST_AND);
    }
    $sql .= ' ORDER BY img_timestamp ' . ($invertSort ? '' : ' DESC');
    $sql .= ' LIMIT ' . ($limit + 1);
    $res = $dbr->query($sql, __FUNCTION__);
    /**
     * We have to flip things around to get the last N after a certain date
     */
    $images = array();
    while ($s = $dbr->fetchObject($res)) {
        if ($invertSort) {
            array_unshift($images, $s);
        } else {
            array_push($images, $s);
        }
    }
    $dbr->freeResult($res);
    $gallery = new WikiaPhotoGallery();
    $gallery->parseParams(array("rowdivider" => true, "hideoverflow" => true));
    //FB#1150 - make the images fit the whole horizontal space in Oasis and Oasis HD
    if (get_class($sk) == 'SkinOasis') {
        if ($wgOasisHD) {
            $gallery->setWidths(202);
        } else {
            $gallery->setWidths(212);
        }
    }
    $firstTimestamp = null;
    $lastTimestamp = null;
    $shownImages = 0;
    foreach ($images as $s) {
        $shownImages++;
        if ($shownImages > $limit) {
            # One extra just to test for whether to show a page link;
            # don't actually show it.
            break;
        }
        $name = $s->img_name;
        $ut = $s->img_user_text;
        $nt = Title::newFromText($name, NS_FILE);
        $ul = $sk->link(Title::makeTitle(NS_USER, $ut), $ut, array('class' => 'wikia-gallery-item-user'));
        $timeago = wfTimeFormatAgo($s->img_timestamp);
        $links = getLinkedFiles($s);
        // If there are more than two files, remove the 2nd and link to the
        // image page
        if (count($links) == 2) {
            array_splice($links, 1);
            $moreFiles = true;
        } else {
            $moreFiles = false;
        }
        $caption = wfMsgHtml('wikianewfiles-uploadby', $ul) . "<br />\n" . "<i>{$timeago}</i><br />\n";
        if (count($links)) {
            $caption .= wfMsg('wikianewfiles-postedin') . "&nbsp;" . $links[0];
        }
        if ($moreFiles) {
            $caption .= ", " . '<a href="' . $nt->getLocalUrl() . '#filelinks" class="wikia-gallery-item-more">' . wfMsgHtml('wikianewfiles-more') . '</a>';
        }
        $gallery->add($nt, $caption);
        $timestamp = wfTimestamp(TS_MW, $s->img_timestamp);
        if (empty($firstTimestamp)) {
            $firstTimestamp = $timestamp;
        }
        $lastTimestamp = $timestamp;
    }
    wfRunHooks('SpecialNewImages::beforeDisplay', array(&$images, &$gallery, &$limit));
    $titleObj = SpecialPage::getTitleFor('Newimages');
    $action = $titleObj->getLocalURL($hidebots ? '' : 'hidebots=0');
    if ($shownav && !$wgMiserMode) {
        $wgOut->addHTML(Xml::openElement('form', array('action' => $action, 'method' => 'post', 'id' => 'imagesearch')) . Xml::fieldset(wfMsg('newimages-legend')) . Xml::inputLabel(wfMsg('newimages-label'), 'wpIlMatch', 'wpIlMatch', 20, $wpIlMatch) . ' ' . Xml::submitButton(wfMsg('ilsubmit'), array('name' => 'wpIlSubmit')) . Xml::closeElement('fieldset') . Xml::closeElement('form'));
    }
    /**
     * Paging controls...
     */
    # If we change bot visibility, this needs to be carried along.
    if (!$hidebots) {
        $botpar = '&hidebots=0';
    } else {
        $botpar = '';
    }
    $now = wfTimestampNow();
    $d = $wgLang->date($now, true);
    $t = $wgLang->time($now, true);
    $dateLink = $sk->link($titleObj, wfMsgHtml('sp-newimages-showfrom', $d, $t), array('class' => 'navigation-filesfrom'), 'from=' . $now . $botpar . $searchpar);
    $botLink = $sk->link($titleObj, wfMsgHtml('showhidebots', $hidebots ? wfMsgHtml('show') : wfMsgHtml('hide')), array('class' => 'navigation-' . ($hidebots ? 'showbots' : 'hidebots')), 'hidebots=' . ($hidebots ? '0' : '1') . $searchpar);
    $opts = array('parsemag', 'escapenoentities');
    $prevLink = wfMsgExt('pager-newer-n', $opts, $wgLang->formatNum($limit));
    if ($firstTimestamp && $firstTimestamp != $latestTimestamp) {
        $wmu['prev'] = $firstTimestamp;
        $prevLink = $sk->link($titleObj, $prevLink, array('class' => 'navigation-newer'), 'from=' . $firstTimestamp . $botpar . $searchpar);
    }
    $nextLink = wfMsgExt('pager-older-n', $opts, $wgLang->formatNum($limit));
    if ($shownImages > $limit && $lastTimestamp) {
        $wmu['next'] = $lastTimestamp;
        $nextLink = $sk->link($titleObj, $nextLink, array('class' => 'navigation-older'), 'until=' . $lastTimestamp . $botpar . $searchpar);
    }
    $prevnext = '<p id="newfiles-nav">' . $botLink . ' ' . wfMsgHtml('viewprevnext', $prevLink, $nextLink, $dateLink) . '</p>';
    if (count($images)) {
        $wmu['gallery'] = $gallery;
        $wgOut->addHTML($gallery->toHTML());
        if ($shownav) {
            $wgOut->addHTML($prevnext);
        }
    } else {
        $wgOut->addWikiMsg('noimages');
    }
}
Пример #16
0
 /**
  * Display an error page noting that a given permission bit is required.
  *
  * @param string $permission key required
  */
 public function permissionRequired($permission)
 {
     global $wgUser;
     $this->setPageTitle(wfMsg('badaccess'));
     $this->setHTMLTitle(wfMsg('errorpagetitle'));
     $this->setRobotPolicy('noindex,nofollow');
     $this->setArticleRelated(false);
     $this->mBodytext = '';
     $groups = array_map(array('User', 'makeGroupLinkWiki'), User::getGroupsWithPermission($permission));
     if ($groups) {
         $this->addWikiMsg('badaccess-groups', implode(', ', $groups), count($groups));
     } else {
         $this->addWikiMsg('badaccess-group0');
     }
     $this->returnToMain();
 }
Пример #17
0
 public function execute()
 {
     $db = $this->getDB();
     $params = $this->extractRequestParams();
     $prop = $params['prop'];
     if (!is_null($prop)) {
         $prop = array_flip($prop);
         $fld_blockinfo = isset($prop['blockinfo']);
         $fld_editcount = isset($prop['editcount']);
         $fld_groups = isset($prop['groups']);
         $fld_rights = isset($prop['rights']);
         $fld_registration = isset($prop['registration']);
         $fld_implicitgroups = isset($prop['implicitgroups']);
     } else {
         $fld_blockinfo = $fld_editcount = $fld_groups = $fld_registration = $fld_rights = $fld_implicitgroups = false;
     }
     $limit = $params['limit'];
     $this->addTables('user');
     $useIndex = true;
     $dir = $params['dir'] == 'descending' ? 'older' : 'newer';
     $from = is_null($params['from']) ? null : $this->keyToTitle($params['from']);
     $to = is_null($params['to']) ? null : $this->keyToTitle($params['to']);
     $this->addWhereRange('user_name', $dir, $from, $to);
     if (!is_null($params['prefix'])) {
         $this->addWhere('user_name' . $db->buildLike($this->keyToTitle($params['prefix']), $db->anyString()));
     }
     if (!is_null($params['rights'])) {
         $groups = array();
         foreach ($params['rights'] as $r) {
             $groups = array_merge($groups, User::getGroupsWithPermission($r));
         }
         $groups = array_unique($groups);
         if (is_null($params['group'])) {
             $params['group'] = $groups;
         } else {
             $params['group'] = array_unique(array_merge($params['group'], $groups));
         }
     }
     if (!is_null($params['group']) && !is_null($params['excludegroup'])) {
         $this->dieUsage('group and excludegroup cannot be used together', 'group-excludegroup');
     }
     if (!is_null($params['group']) && count($params['group'])) {
         $useIndex = false;
         // Filter only users that belong to a given group
         $this->addTables('user_groups', 'ug1');
         $this->addJoinConds(array('ug1' => array('INNER JOIN', array('ug1.ug_user=user_id', 'ug1.ug_group' => $params['group']))));
     }
     if (!is_null($params['excludegroup']) && count($params['excludegroup'])) {
         $useIndex = false;
         // Filter only users don't belong to a given group
         $this->addTables('user_groups', 'ug1');
         if (count($params['excludegroup']) == 1) {
             $exclude = array('ug1.ug_group' => $params['excludegroup'][0]);
         } else {
             $exclude = array($db->makeList(array('ug1.ug_group' => $params['excludegroup']), LIST_OR));
         }
         $this->addJoinConds(array('ug1' => array('LEFT OUTER JOIN', array_merge(array('ug1.ug_user=user_id'), $exclude))));
         $this->addWhere('ug1.ug_user IS NULL');
     }
     if ($params['witheditsonly']) {
         $this->addWhere('user_editcount > 0');
     }
     $this->showHiddenUsersAddBlockInfo($fld_blockinfo);
     if ($fld_groups || $fld_rights) {
         // Show the groups the given users belong to
         // request more than needed to avoid not getting all rows that belong to one user
         $groupCount = count(User::getAllGroups());
         $sqlLimit = $limit + $groupCount + 1;
         $this->addTables('user_groups', 'ug2');
         $this->addJoinConds(array('ug2' => array('LEFT JOIN', 'ug2.ug_user=user_id')));
         $this->addFields('ug2.ug_group ug_group2');
     } else {
         $sqlLimit = $limit + 1;
     }
     if ($params['activeusers']) {
         global $wgActiveUserDays;
         $this->addTables('recentchanges');
         $this->addJoinConds(array('recentchanges' => array('INNER JOIN', 'rc_user_text=user_name')));
         $this->addFields('COUNT(*) AS recentedits');
         $this->addWhere("rc_log_type IS NULL OR rc_log_type != 'newusers'");
         $timestamp = $db->timestamp(wfTimestamp(TS_UNIX) - $wgActiveUserDays * 24 * 3600);
         $this->addWhere("rc_timestamp >= {$db->addQuotes($timestamp)}");
         $this->addOption('GROUP BY', 'user_name');
     }
     $this->addOption('LIMIT', $sqlLimit);
     $this->addFields(array('user_name', 'user_id'));
     $this->addFieldsIf('user_editcount', $fld_editcount);
     $this->addFieldsIf('user_registration', $fld_registration);
     if ($useIndex) {
         $this->addOption('USE INDEX', array('user' => 'user_name'));
     }
     $res = $this->select(__METHOD__);
     $count = 0;
     $lastUserData = false;
     $lastUser = false;
     $result = $this->getResult();
     //
     // This loop keeps track of the last entry.
     // For each new row, if the new row is for different user then the last, the last entry is added to results.
     // Otherwise, the group of the new row is appended to the last entry.
     // The setContinue... is more complex because of this, and takes into account the higher sql limit
     // to make sure all rows that belong to the same user are received.
     foreach ($res as $row) {
         $count++;
         if ($lastUser !== $row->user_name) {
             // Save the last pass's user data
             if (is_array($lastUserData)) {
                 $fit = $result->addValue(array('query', $this->getModuleName()), null, $lastUserData);
                 $lastUserData = null;
                 if (!$fit) {
                     $this->setContinueEnumParameter('from', $this->keyToTitle($lastUserData['name']));
                     break;
                 }
             }
             if ($count > $limit) {
                 // We've reached the one extra which shows that there are additional pages to be had. Stop here...
                 $this->setContinueEnumParameter('from', $this->keyToTitle($row->user_name));
                 break;
             }
             // Record new user's data
             $lastUser = $row->user_name;
             $lastUserData = array('userid' => $row->user_id, 'name' => $lastUser);
             if ($fld_blockinfo && !is_null($row->ipb_by_text)) {
                 $lastUserData['blockedby'] = $row->ipb_by_text;
                 $lastUserData['blockreason'] = $row->ipb_reason;
                 $lastUserData['blockexpiry'] = $row->ipb_expiry;
             }
             if ($row->ipb_deleted) {
                 $lastUserData['hidden'] = '';
             }
             if ($fld_editcount) {
                 $lastUserData['editcount'] = intval($row->user_editcount);
             }
             if ($params['activeusers']) {
                 $lastUserData['recenteditcount'] = intval($row->recentedits);
             }
             if ($fld_registration) {
                 $lastUserData['registration'] = $row->user_registration ? wfTimestamp(TS_ISO_8601, $row->user_registration) : '';
             }
         }
         if ($sqlLimit == $count) {
             // BUG!  database contains group name that User::getAllGroups() does not return
             // TODO: should handle this more gracefully
             ApiBase::dieDebug(__METHOD__, 'MediaWiki configuration error: the database contains more user groups than known to User::getAllGroups() function');
         }
         // Add user's group info
         if ($fld_groups) {
             if (!isset($lastUserData['groups'])) {
                 $lastUserData['groups'] = ApiQueryUsers::getAutoGroups(User::newFromName($lastUser));
             }
             if (!is_null($row->ug_group2)) {
                 $lastUserData['groups'][] = $row->ug_group2;
             }
             $result->setIndexedTagName($lastUserData['groups'], 'g');
         }
         if ($fld_implicitgroups && !isset($lastUserData['implicitgroups'])) {
             $lastUserData['implicitgroups'] = ApiQueryUsers::getAutoGroups(User::newFromName($lastUser));
             $result->setIndexedTagName($lastUserData['implicitgroups'], 'g');
         }
         if ($fld_rights) {
             if (!isset($lastUserData['rights'])) {
                 $lastUserData['rights'] = User::getGroupPermissions(User::newFromName($lastUser)->getAutomaticGroups());
             }
             if (!is_null($row->ug_group2)) {
                 $lastUserData['rights'] = array_unique(array_merge($lastUserData['rights'], User::getGroupPermissions(array($row->ug_group2))));
             }
             $result->setIndexedTagName($lastUserData['rights'], 'r');
         }
     }
     if (is_array($lastUserData)) {
         $fit = $result->addValue(array('query', $this->getModuleName()), null, $lastUserData);
         if (!$fit) {
             $this->setContinueEnumParameter('from', $this->keyToTitle($lastUserData['name']));
         }
     }
     $result->setIndexedTagName_internal(array('query', $this->getModuleName()), 'u');
 }
Пример #18
0
 /**
  * Rebuild pass 4: Mark bot and autopatrolled entries.
  */
 private function rebuildRecentChangesTablePass4()
 {
     global $wgUseRCPatrol, $wgMiserMode;
     $dbw = $this->getDB(DB_MASTER);
     list($recentchanges, $usergroups, $user) = $dbw->tableNamesN('recentchanges', 'user_groups', 'user');
     # @FIXME: recognize other bot account groups (not the same as users with 'bot' rights)
     # @NOTE: users with 'bot' rights choose when edits are bot edits or not. That information
     # may be lost at this point (aside from joining on the patrol log table entries).
     $botgroups = ['bot'];
     $autopatrolgroups = $wgUseRCPatrol ? User::getGroupsWithPermission('autopatrol') : [];
     # Flag our recent bot edits
     if ($botgroups) {
         $botwhere = $dbw->makeList($botgroups);
         $this->output("Flagging bot account edits...\n");
         # Find all users that are bots
         $sql = "SELECT DISTINCT user_name FROM {$usergroups}, {$user} " . "WHERE ug_group IN({$botwhere}) AND user_id = ug_user";
         $res = $dbw->query($sql, __METHOD__);
         $botusers = [];
         foreach ($res as $obj) {
             $botusers[] = $obj->user_name;
         }
         # Fill in the rc_bot field
         if ($botusers) {
             $rcids = $dbw->selectFieldValues('recentchanges', 'rc_id', ['rc_user_text' => $botusers, "rc_timestamp > " . $dbw->addQuotes($dbw->timestamp($this->cutoffFrom)), "rc_timestamp < " . $dbw->addQuotes($dbw->timestamp($this->cutoffTo))], __METHOD__);
             foreach (array_chunk($rcids, $this->mBatchSize) as $rcidBatch) {
                 $dbw->update('recentchanges', ['rc_bot' => 1], ['rc_id' => $rcidBatch], __METHOD__);
                 wfGetLBFactory()->waitForReplication();
             }
         }
     }
     # Flag our recent autopatrolled edits
     if (!$wgMiserMode && $autopatrolgroups) {
         $patrolwhere = $dbw->makeList($autopatrolgroups);
         $patrolusers = [];
         $this->output("Flagging auto-patrolled edits...\n");
         # Find all users in RC with autopatrol rights
         $sql = "SELECT DISTINCT user_name FROM {$usergroups}, {$user} " . "WHERE ug_group IN({$patrolwhere}) AND user_id = ug_user";
         $res = $dbw->query($sql, __METHOD__);
         foreach ($res as $obj) {
             $patrolusers[] = $dbw->addQuotes($obj->user_name);
         }
         # Fill in the rc_patrolled field
         if ($patrolusers) {
             $patrolwhere = implode(',', $patrolusers);
             $sql2 = "UPDATE {$recentchanges} SET rc_patrolled=1 " . "WHERE rc_user_text IN({$patrolwhere}) " . "AND rc_timestamp > " . $dbw->addQuotes($dbw->timestamp($this->cutoffFrom)) . ' ' . "AND rc_timestamp < " . $dbw->addQuotes($dbw->timestamp($this->cutoffTo));
             $dbw->query($sql2);
         }
     }
 }
Пример #19
0
 /**
  * Permissions checks that fail most often, and which are easiest to test.
  *
  * @param $action String the action to check
  * @param $user User user to check
  * @param $errors Array list of current errors
  * @param $doExpensiveQueries Boolean whether or not to perform expensive queries
  * @param $short Boolean short circuit on first error
  *
  * @return Array list of errors
  */
 private function checkQuickPermissions($action, $user, $errors, $doExpensiveQueries, $short)
 {
     if ($action == 'create') {
         if ($this->isTalkPage() && !$user->isAllowed('createtalk') || !$this->isTalkPage() && !$user->isAllowed('createpage')) {
             $errors[] = $user->isAnon() ? array('nocreatetext') : array('nocreate-loggedin');
         }
     } elseif ($action == 'move') {
         if (!$user->isAllowed('move-rootuserpages') && $this->mNamespace == NS_USER && !$this->isSubpage()) {
             // Show user page-specific message only if the user can move other pages
             $errors[] = array('cant-move-user-page');
         }
         // Check if user is allowed to move files if it's a file
         if ($this->mNamespace == NS_FILE && !$user->isAllowed('movefile')) {
             $errors[] = array('movenotallowedfile');
         }
         if (!$user->isAllowed('move')) {
             // User can't move anything
             global $wgGroupPermissions;
             $userCanMove = false;
             if (isset($wgGroupPermissions['user']['move'])) {
                 $userCanMove = $wgGroupPermissions['user']['move'];
             }
             $autoconfirmedCanMove = false;
             if (isset($wgGroupPermissions['autoconfirmed']['move'])) {
                 $autoconfirmedCanMove = $wgGroupPermissions['autoconfirmed']['move'];
             }
             if ($user->isAnon() && ($userCanMove || $autoconfirmedCanMove)) {
                 // custom message if logged-in users without any special rights can move
                 $errors[] = array('movenologintext');
             } else {
                 $errors[] = array('movenotallowed');
             }
         }
     } elseif ($action == 'move-target') {
         if (!$user->isAllowed('move')) {
             // User can't move anything
             $errors[] = array('movenotallowed');
         } elseif (!$user->isAllowed('move-rootuserpages') && $this->mNamespace == NS_USER && !$this->isSubpage()) {
             // Show user page-specific message only if the user can move other pages
             $errors[] = array('cant-move-to-user-page');
         }
     } elseif (!$user->isAllowed($action)) {
         // We avoid expensive display logic for quickUserCan's and such
         $groups = false;
         if (!$short) {
             $groups = array_map(array('User', 'makeGroupLinkWiki'), User::getGroupsWithPermission($action));
         }
         if ($groups) {
             global $wgLang;
             $return = array('badaccess-groups', $wgLang->commaList($groups), count($groups));
         } else {
             $return = array('badaccess-group0');
         }
         $errors[] = $return;
     }
     return $errors;
 }
Пример #20
0
 public function execute()
 {
     $params = $this->extractRequestParams();
     $activeUserDays = $this->getConfig()->get('ActiveUserDays');
     $db = $this->getDB();
     $prop = $params['prop'];
     if (!is_null($prop)) {
         $prop = array_flip($prop);
         $fld_blockinfo = isset($prop['blockinfo']);
         $fld_editcount = isset($prop['editcount']);
         $fld_groups = isset($prop['groups']);
         $fld_rights = isset($prop['rights']);
         $fld_registration = isset($prop['registration']);
         $fld_implicitgroups = isset($prop['implicitgroups']);
         $fld_centralids = isset($prop['centralids']);
     } else {
         $fld_blockinfo = $fld_editcount = $fld_groups = $fld_registration = $fld_rights = $fld_implicitgroups = $fld_centralids = false;
     }
     $limit = $params['limit'];
     $this->addTables('user');
     $dir = $params['dir'] == 'descending' ? 'older' : 'newer';
     $from = is_null($params['from']) ? null : $this->getCanonicalUserName($params['from']);
     $to = is_null($params['to']) ? null : $this->getCanonicalUserName($params['to']);
     # MySQL can't figure out that 'user_name' and 'qcc_title' are the same
     # despite the JOIN condition, so manually sort on the correct one.
     $userFieldToSort = $params['activeusers'] ? 'qcc_title' : 'user_name';
     # Some of these subtable joins are going to give us duplicate rows, so
     # calculate the maximum number of duplicates we might see.
     $maxDuplicateRows = 1;
     $this->addWhereRange($userFieldToSort, $dir, $from, $to);
     if (!is_null($params['prefix'])) {
         $this->addWhere($userFieldToSort . $db->buildLike($this->getCanonicalUserName($params['prefix']), $db->anyString()));
     }
     if (!is_null($params['rights']) && count($params['rights'])) {
         $groups = array();
         foreach ($params['rights'] as $r) {
             $groups = array_merge($groups, User::getGroupsWithPermission($r));
         }
         // no group with the given right(s) exists, no need for a query
         if (!count($groups)) {
             $this->getResult()->addIndexedTagName(array('query', $this->getModuleName()), '');
             return;
         }
         $groups = array_unique($groups);
         if (is_null($params['group'])) {
             $params['group'] = $groups;
         } else {
             $params['group'] = array_unique(array_merge($params['group'], $groups));
         }
     }
     if (!is_null($params['group']) && !is_null($params['excludegroup'])) {
         $this->dieUsage('group and excludegroup cannot be used together', 'group-excludegroup');
     }
     if (!is_null($params['group']) && count($params['group'])) {
         // Filter only users that belong to a given group. This might
         // produce as many rows-per-user as there are groups being checked.
         $this->addTables('user_groups', 'ug1');
         $this->addJoinConds(array('ug1' => array('INNER JOIN', array('ug1.ug_user=user_id', 'ug1.ug_group' => $params['group']))));
         $maxDuplicateRows *= count($params['group']);
     }
     if (!is_null($params['excludegroup']) && count($params['excludegroup'])) {
         // Filter only users don't belong to a given group. This can only
         // produce one row-per-user, because we only keep on "no match".
         $this->addTables('user_groups', 'ug1');
         if (count($params['excludegroup']) == 1) {
             $exclude = array('ug1.ug_group' => $params['excludegroup'][0]);
         } else {
             $exclude = array($db->makeList(array('ug1.ug_group' => $params['excludegroup']), LIST_OR));
         }
         $this->addJoinConds(array('ug1' => array('LEFT OUTER JOIN', array_merge(array('ug1.ug_user=user_id'), $exclude))));
         $this->addWhere('ug1.ug_user IS NULL');
     }
     if ($params['witheditsonly']) {
         $this->addWhere('user_editcount > 0');
     }
     $this->showHiddenUsersAddBlockInfo($fld_blockinfo);
     if ($fld_groups || $fld_rights) {
         $this->addFields(array('groups' => $db->buildGroupConcatField('|', 'user_groups', 'ug_group', 'ug_user=user_id')));
     }
     if ($params['activeusers']) {
         $activeUserSeconds = $activeUserDays * 86400;
         // Filter query to only include users in the active users cache.
         // There shouldn't be any duplicate rows in querycachetwo here.
         $this->addTables('querycachetwo');
         $this->addJoinConds(array('querycachetwo' => array('INNER JOIN', array('qcc_type' => 'activeusers', 'qcc_namespace' => NS_USER, 'qcc_title=user_name'))));
         // Actually count the actions using a subquery (bug 64505 and bug 64507)
         $timestamp = $db->timestamp(wfTimestamp(TS_UNIX) - $activeUserSeconds);
         $this->addFields(array('recentactions' => '(' . $db->selectSQLText('recentchanges', 'COUNT(*)', array('rc_user_text = user_name', 'rc_type != ' . $db->addQuotes(RC_EXTERNAL), 'rc_log_type IS NULL OR rc_log_type != ' . $db->addQuotes('newusers'), 'rc_timestamp >= ' . $db->addQuotes($timestamp))) . ')'));
     }
     $sqlLimit = $limit + $maxDuplicateRows;
     $this->addOption('LIMIT', $sqlLimit);
     $this->addFields(array('user_name', 'user_id'));
     $this->addFieldsIf('user_editcount', $fld_editcount);
     $this->addFieldsIf('user_registration', $fld_registration);
     $res = $this->select(__METHOD__);
     $count = 0;
     $countDuplicates = 0;
     $lastUser = false;
     $result = $this->getResult();
     foreach ($res as $row) {
         $count++;
         if ($lastUser === $row->user_name) {
             // Duplicate row due to one of the needed subtable joins.
             // Ignore it, but count the number of them to sanely handle
             // miscalculation of $maxDuplicateRows.
             $countDuplicates++;
             if ($countDuplicates == $maxDuplicateRows) {
                 ApiBase::dieDebug(__METHOD__, 'Saw more duplicate rows than expected');
             }
             continue;
         }
         $countDuplicates = 0;
         $lastUser = $row->user_name;
         if ($count > $limit) {
             // We've reached the one extra which shows that there are
             // additional pages to be had. Stop here...
             $this->setContinueEnumParameter('from', $row->user_name);
             break;
         }
         if ($count == $sqlLimit) {
             // Should never hit this (either the $countDuplicates check or
             // the $count > $limit check should hit first), but check it
             // anyway just in case.
             ApiBase::dieDebug(__METHOD__, 'Saw more duplicate rows than expected');
         }
         if ($params['activeusers'] && $row->recentactions === 0) {
             // activeusers cache was out of date
             continue;
         }
         $data = array('userid' => (int) $row->user_id, 'name' => $row->user_name);
         if ($fld_centralids) {
             $data += ApiQueryUserInfo::getCentralUserInfo($this->getConfig(), User::newFromId($row->user_id), $params['attachedwiki']);
         }
         if ($fld_blockinfo && !is_null($row->ipb_by_text)) {
             $data['blockid'] = (int) $row->ipb_id;
             $data['blockedby'] = $row->ipb_by_text;
             $data['blockedbyid'] = (int) $row->ipb_by;
             $data['blockedtimestamp'] = wfTimestamp(TS_ISO_8601, $row->ipb_timestamp);
             $data['blockreason'] = $row->ipb_reason;
             $data['blockexpiry'] = $row->ipb_expiry;
         }
         if ($row->ipb_deleted) {
             $data['hidden'] = true;
         }
         if ($fld_editcount) {
             $data['editcount'] = intval($row->user_editcount);
         }
         if ($params['activeusers']) {
             $data['recentactions'] = intval($row->recentactions);
             // @todo 'recenteditcount' is set for BC, remove in 1.25
             $data['recenteditcount'] = $data['recentactions'];
         }
         if ($fld_registration) {
             $data['registration'] = $row->user_registration ? wfTimestamp(TS_ISO_8601, $row->user_registration) : '';
         }
         if ($fld_implicitgroups || $fld_groups || $fld_rights) {
             $implicitGroups = User::newFromId($row->user_id)->getAutomaticGroups();
             if (isset($row->groups) && $row->groups !== '') {
                 $groups = array_merge($implicitGroups, explode('|', $row->groups));
             } else {
                 $groups = $implicitGroups;
             }
             if ($fld_groups) {
                 $data['groups'] = $groups;
                 ApiResult::setIndexedTagName($data['groups'], 'g');
                 ApiResult::setArrayType($data['groups'], 'array');
             }
             if ($fld_implicitgroups) {
                 $data['implicitgroups'] = $implicitGroups;
                 ApiResult::setIndexedTagName($data['implicitgroups'], 'g');
                 ApiResult::setArrayType($data['implicitgroups'], 'array');
             }
             if ($fld_rights) {
                 $data['rights'] = User::getGroupPermissions($groups);
                 ApiResult::setIndexedTagName($data['rights'], 'r');
                 ApiResult::setArrayType($data['rights'], 'array');
             }
         }
         $fit = $result->addValue(array('query', $this->getModuleName()), null, $data);
         if (!$fit) {
             $this->setContinueEnumParameter('from', $data['name']);
             break;
         }
     }
     $result->addIndexedTagName(array('query', $this->getModuleName()), 'u');
 }
Пример #21
0
 function getUserCond()
 {
     $condition = array();
     $join_conds = array();
     $tables = array('revision', 'page', 'user');
     if ($this->contribs == 'newbie') {
         $max = $this->mDb->selectField('user', 'max(user_id)', false, __METHOD__);
         $condition[] = 'rev_user >' . (int) ($max - $max / 100);
         $index = 'user_timestamp';
         # ignore local groups with the bot right
         # @todo FIXME: Global groups may have 'bot' rights
         $groupsWithBotPermission = User::getGroupsWithPermission('bot');
         if (count($groupsWithBotPermission)) {
             $tables[] = 'user_groups';
             $condition[] = 'ug_group IS NULL';
             $join_conds['user_groups'] = array('LEFT JOIN', array('ug_user = rev_user', 'ug_group' => $groupsWithBotPermission));
         }
     } else {
         $uid = User::idFromName($this->target);
         if ($uid) {
             $condition['rev_user'] = $uid;
             $index = 'user_timestamp';
         } else {
             $condition['rev_user_text'] = $this->target;
             $index = 'usertext_timestamp';
         }
     }
     if ($this->deletedOnly) {
         $condition[] = "rev_deleted != '0'";
     }
     if ($this->topOnly) {
         $condition[] = "rev_id = page_latest";
     }
     return array($tables, $index, $condition, $join_conds);
 }
Пример #22
0
 /**
  * Retrieve recently uploaded images from this wiki.  This will filter out video files
  * and images uploaded by bots if necessary.  Additionally, arbitrary constraints can
  * be passed in to filter out additional images.  These constraints can be either of:
  *
  *   $constrain[] = "img_name = 'bar'"
  *   $constrain['img_minor_mime'] = 'youtube'
  *
  * @param int $limit Limit the number of images to return
  * @param int $offset Grab images after an offset.  Used with $limit to page the results
  * @param array $constrain An array of constraint/value that will be used in the query
  * @return array An array of images
  */
 function getImages($limit, $offset = 0, $constrain = array())
 {
     // Load the next set of images, eliminating images uploaded by bots as
     // well as eliminating any video files
     $dbr = wfGetDB(DB_SLAVE);
     $image = $dbr->tableName('image');
     $sql = 'SELECT img_size, img_name, img_user, img_user_text, img_description, img_timestamp ' . "FROM {$image}";
     $botconds = array();
     foreach (User::getGroupsWithPermission('bot') as $groupname) {
         $botconds[] = 'ug_group = ' . $dbr->addQuotes($groupname);
     }
     $where = array();
     if (count($botconds)) {
         $isbotmember = $dbr->makeList($botconds, LIST_OR);
         // LEFT join to the user_groups table on being a bot and then make sure
         // we get null rows back (i.e. we're not a bot)
         $ug = $dbr->tableName('user_groups');
         $sql .= " LEFT JOIN {$ug} ON img_user=ug_user AND ({$isbotmember})";
         $where[] = 'ug_group IS NULL';
     }
     // Eliminate videos from this listing
     $where[] = 'img_media_type != \'VIDEO\'';
     $where[] = 'img_major_mime != \'video\'';
     $where[] = 'img_media_type != \'swf\'';
     // Add any additional constraints
     if ($constrain) {
         foreach ($constrain as $cond) {
             $where[] = $cond;
         }
     }
     $sql .= ' WHERE ' . $dbr->makeList($where, LIST_AND);
     $sql .= ' ORDER BY img_timestamp DESC ';
     $sql .= ' LIMIT ' . ($limit + 1);
     if ($offset) {
         $sql .= " OFFSET {$offset}";
     }
     $res = $dbr->query($sql, __FUNCTION__);
     $images = array();
     while ($s = $dbr->fetchObject($res)) {
         $images[] = $s;
     }
     $dbr->freeResult($res);
     // Load the images into a new gallery
     $gallery = new WikiaPhotoGallery();
     $gallery->parseParams(array("rowdivider" => true, "hideoverflow" => true));
     $gallery->setWidths(212);
     $foundImages = 0;
     foreach ($images as $s) {
         $foundImages++;
         if ($foundImages > $limit) {
             // One extra just to test for whether to show a page link;
             // don't actually show it.
             break;
         }
         $nt = Title::newFromText($s->img_name, NS_FILE);
         $gallery->add($nt);
     }
     $info = array("gallery" => $gallery);
     // Set pagination information
     if ($offset > 0) {
         $info['prev'] = $offset - $limit;
     }
     if ($foundImages > $limit) {
         $info['next'] = $offset + $limit;
     }
     return $info;
 }
Пример #23
0
 /**
  * Determine which restriction levels it makes sense to use in a namespace,
  * optionally filtered by a user's rights.
  *
  * @since 1.23
  * @param int $index Index to check
  * @param User $user User to check
  * @return array
  */
 public static function getRestrictionLevels($index, User $user = null)
 {
     global $wgNamespaceProtection, $wgRestrictionLevels;
     if (!isset($wgNamespaceProtection[$index])) {
         // All levels are valid if there's no namespace restriction.
         // But still filter by user, if necessary
         $levels = $wgRestrictionLevels;
         if ($user) {
             $levels = array_values(array_filter($levels, function ($level) use($user) {
                 $right = $level;
                 if ($right == 'sysop') {
                     $right = 'editprotected';
                     // BC
                 }
                 if ($right == 'autoconfirmed') {
                     $right = 'editsemiprotected';
                     // BC
                 }
                 return $right == '' || $user->isAllowed($right);
             }));
         }
         return $levels;
     }
     // First, get the list of groups that can edit this namespace.
     $namespaceGroups = [];
     $combine = 'array_merge';
     foreach ((array) $wgNamespaceProtection[$index] as $right) {
         if ($right == 'sysop') {
             $right = 'editprotected';
             // BC
         }
         if ($right == 'autoconfirmed') {
             $right = 'editsemiprotected';
             // BC
         }
         if ($right != '') {
             $namespaceGroups = call_user_func($combine, $namespaceGroups, User::getGroupsWithPermission($right));
             $combine = 'array_intersect';
         }
     }
     // Now, keep only those restriction levels where there is at least one
     // group that can edit the namespace but would be blocked by the
     // restriction.
     $usableLevels = [''];
     foreach ($wgRestrictionLevels as $level) {
         $right = $level;
         if ($right == 'sysop') {
             $right = 'editprotected';
             // BC
         }
         if ($right == 'autoconfirmed') {
             $right = 'editsemiprotected';
             // BC
         }
         if ($right != '' && (!$user || $user->isAllowed($right)) && array_diff($namespaceGroups, User::getGroupsWithPermission($right))) {
             $usableLevels[] = $level;
         }
     }
     return $usableLevels;
 }
Пример #24
0
 function getQueryInfo()
 {
     $conds = $jconds = array();
     $tables = array('image');
     if (!$this->showBots) {
         $groupsWithBotPermission = User::getGroupsWithPermission('bot');
         if (count($groupsWithBotPermission)) {
             $tables[] = 'user_groups';
             $conds[] = 'ug_group IS NULL';
             $jconds['user_groups'] = array('LEFT JOIN', array('ug_group' => $groupsWithBotPermission, 'ug_user = img_user'));
         }
     }
     if ($this->hidePatrolled) {
         $tables[] = 'recentchanges';
         $conds['rc_type'] = RC_LOG;
         $conds['rc_log_type'] = 'upload';
         $conds['rc_patrolled'] = 0;
         $jconds['recentchanges'] = array('INNER JOIN', array('rc_title = img_name', 'rc_user = img_user', 'rc_timestamp = img_timestamp'));
     }
     if (!$this->getConfig()->get('MiserMode') && $this->like !== null) {
         $dbr = wfGetDB(DB_SLAVE);
         $likeObj = Title::newFromText($this->like);
         if ($likeObj instanceof Title) {
             $like = $dbr->buildLike($dbr->anyString(), strtolower($likeObj->getDBkey()), $dbr->anyString());
             $conds[] = "LOWER(img_name) {$like}";
         }
     }
     $query = array('tables' => $tables, 'fields' => '*', 'join_conds' => $jconds, 'conds' => $conds);
     return $query;
 }
Пример #25
0
 /**
  * @return mixed|string
  */
 public function reallyMakeHelpMsg()
 {
     $this->setHelp();
     // Use parent to make default message for the main module
     $msg = parent::makeHelpMsg();
     $astriks = str_repeat('*** ', 14);
     $msg .= "\n\n{$astriks} Modules  {$astriks}\n\n";
     foreach (array_keys($this->mModules) as $moduleName) {
         $module = new $this->mModules[$moduleName]($this, $moduleName);
         $msg .= self::makeHelpMsgHeader($module, 'action');
         $msg2 = $module->makeHelpMsg();
         if ($msg2 !== false) {
             $msg .= $msg2;
         }
         $msg .= "\n";
     }
     $msg .= "\n{$astriks} Permissions {$astriks}\n\n";
     foreach (self::$mRights as $right => $rightMsg) {
         $groups = User::getGroupsWithPermission($right);
         $msg .= "* " . $right . " *\n  " . wfMsgReplaceArgs($rightMsg['msg'], $rightMsg['params']) . "\nGranted to:\n  " . str_replace('*', 'all', implode(', ', $groups)) . "\n\n";
     }
     $msg .= "\n{$astriks} Formats  {$astriks}\n\n";
     foreach (array_keys($this->mFormats) as $formatName) {
         $module = $this->createPrinterByName($formatName);
         $msg .= self::makeHelpMsgHeader($module, 'format');
         $msg2 = $module->makeHelpMsg();
         if ($msg2 !== false) {
             $msg .= $msg2;
         }
         $msg .= "\n";
     }
     $msg .= "\n*** Credits: ***\n   " . implode("\n   ", $this->getCredits()) . "\n";
     return $msg;
 }
Пример #26
0
 function __construct($permission)
 {
     global $wgLang;
     $this->permission = $permission;
     $groups = array_map(array('User', 'makeGroupLinkWiki'), User::getGroupsWithPermission($this->permission));
     if ($groups) {
         parent::__construct('badaccess', 'badaccess-groups', array($wgLang->commaList($groups), count($groups)));
     } else {
         parent::__construct('badaccess', 'badaccess-group0');
     }
 }
Пример #27
0
 /**
  * Rebuild pass 4: Mark bot and autopatrolled entries.
  */
 private function rebuildRecentChangesTablePass4()
 {
     global $wgUseRCPatrol;
     $dbw = $this->getDB(DB_MASTER);
     list($recentchanges, $usergroups, $user) = $dbw->tableNamesN('recentchanges', 'user_groups', 'user');
     $botgroups = User::getGroupsWithPermission('bot');
     $autopatrolgroups = $wgUseRCPatrol ? User::getGroupsWithPermission('autopatrol') : array();
     # Flag our recent bot edits
     if (!empty($botgroups)) {
         $botwhere = $dbw->makeList($botgroups);
         $botusers = array();
         $this->output("Flagging bot account edits...\n");
         # Find all users that are bots
         $sql = "SELECT DISTINCT user_name FROM {$usergroups}, {$user} " . "WHERE ug_group IN({$botwhere}) AND user_id = ug_user";
         $res = $dbw->query($sql, DB_MASTER);
         foreach ($res as $obj) {
             $botusers[] = $dbw->addQuotes($obj->user_name);
         }
         # Fill in the rc_bot field
         if (!empty($botusers)) {
             $botwhere = implode(',', $botusers);
             $sql2 = "UPDATE {$recentchanges} SET rc_bot=1 " . "WHERE rc_user_text IN({$botwhere})";
             $dbw->query($sql2);
         }
     }
     global $wgMiserMode;
     # Flag our recent autopatrolled edits
     if (!$wgMiserMode && !empty($autopatrolgroups)) {
         $patrolwhere = $dbw->makeList($autopatrolgroups);
         $patrolusers = array();
         $this->output("Flagging auto-patrolled edits...\n");
         # Find all users in RC with autopatrol rights
         $sql = "SELECT DISTINCT user_name FROM {$usergroups}, {$user} " . "WHERE ug_group IN({$patrolwhere}) AND user_id = ug_user";
         $res = $dbw->query($sql, DB_MASTER);
         foreach ($res as $obj) {
             $patrolusers[] = $dbw->addQuotes($obj->user_name);
         }
         # Fill in the rc_patrolled field
         if (!empty($patrolusers)) {
             $patrolwhere = implode(',', $patrolusers);
             $sql2 = "UPDATE {$recentchanges} SET rc_patrolled=1 " . "WHERE rc_user_text IN({$patrolwhere})";
             $dbw->query($sql2);
         }
     }
 }
Пример #28
0
 function getUserCond()
 {
     $condition = [];
     $join_conds = [];
     $tables = ['revision', 'page', 'user'];
     $index = false;
     if ($this->contribs == 'newbie') {
         $max = $this->mDb->selectField('user', 'max(user_id)', false, __METHOD__);
         $condition[] = 'rev_user >' . (int) ($max - $max / 100);
         # ignore local groups with the bot right
         # @todo FIXME: Global groups may have 'bot' rights
         $groupsWithBotPermission = User::getGroupsWithPermission('bot');
         if (count($groupsWithBotPermission)) {
             $tables[] = 'user_groups';
             $condition[] = 'ug_group IS NULL';
             $join_conds['user_groups'] = ['LEFT JOIN', ['ug_user = rev_user', 'ug_group' => $groupsWithBotPermission]];
         }
         // (T140537) Disallow looking too far in the past for 'newbies' queries. If the user requested
         // a timestamp offset far in the past such that there are no edits by users with user_ids in
         // the range, we would end up scanning all revisions from that offset until start of time.
         $condition[] = 'rev_timestamp > ' . $this->mDb->addQuotes($this->mDb->timestamp(wfTimestamp() - 30 * 24 * 60 * 60));
     } else {
         $uid = User::idFromName($this->target);
         if ($uid) {
             $condition['rev_user'] = $uid;
             $index = 'user_timestamp';
         } else {
             $condition['rev_user_text'] = $this->target;
             $index = 'usertext_timestamp';
         }
     }
     if ($this->deletedOnly) {
         $condition[] = 'rev_deleted != 0';
     }
     if ($this->topOnly) {
         $condition[] = 'rev_id = page_latest';
     }
     if ($this->newOnly) {
         $condition[] = 'rev_parent_id = 0';
     }
     if ($this->hideMinor) {
         $condition[] = 'rev_minor_edit = 0';
     }
     return [$tables, $index, $condition, $join_conds];
 }
Пример #29
0
/**
 * @file
 * @ingroup SpecialPage
 * FIXME: this code is crap, should use Pager and Database::select().
 */
function wfSpecialNewimages($par, $specialPage)
{
    global $wgUser, $wgOut, $wgLang, $wgRequest, $wgMiserMode;
    $wpIlMatch = $wgRequest->getText('wpIlMatch');
    $dbr = wfGetDB(DB_SLAVE);
    $sk = $wgUser->getSkin();
    $shownav = !$specialPage->including();
    $hidebots = $wgRequest->getBool('hidebots', 1);
    $hidebotsql = '';
    if ($hidebots) {
        # Make a list of group names which have the 'bot' flag set.
        $botconds = array();
        foreach (User::getGroupsWithPermission('bot') as $groupname) {
            $botconds[] = 'ug_group = ' . $dbr->addQuotes($groupname);
        }
        # If not bot groups, do not set $hidebotsql
        if ($botconds) {
            $isbotmember = $dbr->makeList($botconds, LIST_OR);
            # This join, in conjunction with WHERE ug_group IS NULL, returns
            # only those rows from IMAGE where the uploading user is not a mem-
            # ber of a group which has the 'bot' permission set.
            $ug = $dbr->tableName('user_groups');
            $hidebotsql = " LEFT JOIN {$ug} ON img_user=ug_user AND ({$isbotmember})";
        }
    }
    $image = $dbr->tableName('image');
    $sql = "SELECT img_timestamp from {$image}";
    if ($hidebotsql) {
        $sql .= "{$hidebotsql} WHERE ug_group IS NULL";
    }
    $sql .= ' ORDER BY img_timestamp DESC LIMIT 1';
    $res = $dbr->query($sql, __FUNCTION__);
    $row = $dbr->fetchRow($res);
    if ($row !== false) {
        $ts = $row[0];
    } else {
        $ts = false;
    }
    $dbr->freeResult($res);
    $sql = '';
    # If we were clever, we'd use this to cache.
    $latestTimestamp = wfTimestamp(TS_MW, $ts);
    # Hardcode this for now.
    $limit = 48;
    if ($parval = intval($par)) {
        if ($parval <= $limit && $parval > 0) {
            $limit = $parval;
        }
    }
    $where = array();
    $searchpar = '';
    if ($wpIlMatch != '' && !$wgMiserMode) {
        $nt = Title::newFromUrl($wpIlMatch);
        if ($nt) {
            $m = $dbr->escapeLike(strtolower($nt->getDBkey()));
            $where[] = "LOWER(img_name) LIKE '%{$m}%'";
            $searchpar = '&wpIlMatch=' . urlencode($wpIlMatch);
        }
    }
    $invertSort = false;
    if ($until = $wgRequest->getVal('until')) {
        $where[] = "img_timestamp < '" . $dbr->timestamp($until) . "'";
    }
    if ($from = $wgRequest->getVal('from')) {
        $where[] = "img_timestamp >= '" . $dbr->timestamp($from) . "'";
        $invertSort = true;
    }
    $sql = 'SELECT img_size, img_name, img_user, img_user_text,' . "img_description,img_timestamp FROM {$image}";
    if ($hidebotsql) {
        $sql .= $hidebotsql;
        $where[] = 'ug_group IS NULL';
    }
    if (count($where)) {
        $sql .= ' WHERE ' . $dbr->makeList($where, LIST_AND);
    }
    $sql .= ' ORDER BY img_timestamp ' . ($invertSort ? '' : ' DESC');
    $sql .= ' LIMIT ' . ($limit + 1);
    $res = $dbr->query($sql, __FUNCTION__);
    /**
     * We have to flip things around to get the last N after a certain date
     */
    $images = array();
    while ($s = $dbr->fetchObject($res)) {
        if ($invertSort) {
            array_unshift($images, $s);
        } else {
            array_push($images, $s);
        }
    }
    $dbr->freeResult($res);
    $gallery = new ImageGallery();
    $firstTimestamp = null;
    $lastTimestamp = null;
    $shownImages = 0;
    foreach ($images as $s) {
        $shownImages++;
        if ($shownImages > $limit) {
            # One extra just to test for whether to show a page link;
            # don't actually show it.
            break;
        }
        $name = $s->img_name;
        $ut = $s->img_user_text;
        $nt = Title::newFromText($name, NS_FILE);
        $ul = $sk->makeLinkObj(Title::makeTitle(NS_USER, $ut), $ut);
        $gallery->add($nt, "{$ul}<br />\n<i>" . $wgLang->timeanddate($s->img_timestamp, true) . "</i><br />\n");
        $timestamp = wfTimestamp(TS_MW, $s->img_timestamp);
        if (empty($firstTimestamp)) {
            $firstTimestamp = $timestamp;
        }
        $lastTimestamp = $timestamp;
    }
    $titleObj = SpecialPage::getTitleFor('Newimages');
    $action = $titleObj->getLocalURL($hidebots ? '' : 'hidebots=0');
    if ($shownav && !$wgMiserMode) {
        $wgOut->addHTML(Xml::openElement('form', array('action' => $action, 'method' => 'post', 'id' => 'imagesearch')) . Xml::fieldset(wfMsg('newimages-legend')) . Xml::inputLabel(wfMsg('newimages-label'), 'wpIlMatch', 'wpIlMatch', 20, $wpIlMatch) . ' ' . Xml::submitButton(wfMsg('ilsubmit'), array('name' => 'wpIlSubmit')) . Xml::closeElement('fieldset') . Xml::closeElement('form'));
    }
    $bydate = wfMsg('bydate');
    $lt = $wgLang->formatNum(min($shownImages, $limit));
    if ($shownav) {
        $text = wfMsgExt('imagelisttext', array('parse'), $lt, $bydate);
        $wgOut->addHTML($text . "\n");
    }
    /**
     * Paging controls...
     */
    # If we change bot visibility, this needs to be carried along.
    if (!$hidebots) {
        $botpar = '&hidebots=0';
    } else {
        $botpar = '';
    }
    $now = wfTimestampNow();
    $d = $wgLang->date($now, true);
    $t = $wgLang->time($now, true);
    $dateLink = $sk->makeKnownLinkObj($titleObj, wfMsgHtml('sp-newimages-showfrom', $d, $t), 'from=' . $now . $botpar . $searchpar);
    $botLink = $sk->makeKnownLinkObj($titleObj, wfMsgHtml('showhidebots', $hidebots ? wfMsgHtml('show') : wfMsgHtml('hide')), 'hidebots=' . ($hidebots ? '0' : '1') . $searchpar);
    $opts = array('parsemag', 'escapenoentities');
    $prevLink = wfMsgExt('pager-newer-n', $opts, $wgLang->formatNum($limit));
    if ($firstTimestamp && $firstTimestamp != $latestTimestamp) {
        $prevLink = $sk->makeKnownLinkObj($titleObj, $prevLink, 'from=' . $firstTimestamp . $botpar . $searchpar);
    }
    $nextLink = wfMsgExt('pager-older-n', $opts, $wgLang->formatNum($limit));
    if ($shownImages > $limit && $lastTimestamp) {
        $nextLink = $sk->makeKnownLinkObj($titleObj, $nextLink, 'until=' . $lastTimestamp . $botpar . $searchpar);
    }
    $prevnext = '<p>' . $botLink . ' ' . wfMsgHtml('viewprevnext', $prevLink, $nextLink, $dateLink) . '</p>';
    if ($shownav) {
        $wgOut->addHTML($prevnext);
    }
    if (count($images)) {
        $wgOut->addHTML($gallery->toHTML());
        if ($shownav) {
            $wgOut->addHTML($prevnext);
        }
    } else {
        $wgOut->addWikiMsg('noimages');
    }
}
Пример #30
0
 public function modifyHelp(array &$help, array $options, array &$tocData)
 {
     // Wish PHP had an "array_insert_before". Instead, we have to manually
     // reindex the array to get 'permissions' in the right place.
     $oldHelp = $help;
     $help = [];
     foreach ($oldHelp as $k => $v) {
         if ($k === 'submodules') {
             $help['permissions'] = '';
         }
         $help[$k] = $v;
     }
     $help['datatypes'] = '';
     $help['credits'] = '';
     // Fill 'permissions'
     $help['permissions'] .= Html::openElement('div', ['class' => 'apihelp-block apihelp-permissions']);
     $m = $this->msg('api-help-permissions');
     if (!$m->isDisabled()) {
         $help['permissions'] .= Html::rawElement('div', ['class' => 'apihelp-block-head'], $m->numParams(count(self::$mRights))->parse());
     }
     $help['permissions'] .= Html::openElement('dl');
     foreach (self::$mRights as $right => $rightMsg) {
         $help['permissions'] .= Html::element('dt', null, $right);
         $rightMsg = $this->msg($rightMsg['msg'], $rightMsg['params'])->parse();
         $help['permissions'] .= Html::rawElement('dd', null, $rightMsg);
         $groups = array_map(function ($group) {
             return $group == '*' ? 'all' : $group;
         }, User::getGroupsWithPermission($right));
         $help['permissions'] .= Html::rawElement('dd', null, $this->msg('api-help-permissions-granted-to')->numParams(count($groups))->params($this->getLanguage()->commaList($groups))->parse());
     }
     $help['permissions'] .= Html::closeElement('dl');
     $help['permissions'] .= Html::closeElement('div');
     // Fill 'datatypes' and 'credits', if applicable
     if (empty($options['nolead'])) {
         $level = $options['headerlevel'];
         $tocnumber =& $options['tocnumber'];
         $header = $this->msg('api-help-datatypes-header')->parse();
         // Add an additional span with sanitized ID
         if (!$this->getConfig()->get('ExperimentalHtmlIds')) {
             $header = Html::element('span', ['id' => Sanitizer::escapeId('main/datatypes')]) . $header;
         }
         $help['datatypes'] .= Html::rawElement('h' . min(6, $level), ['id' => 'main/datatypes', 'class' => 'apihelp-header'], $header);
         $help['datatypes'] .= $this->msg('api-help-datatypes')->parseAsBlock();
         if (!isset($tocData['main/datatypes'])) {
             $tocnumber[$level]++;
             $tocData['main/datatypes'] = ['toclevel' => count($tocnumber), 'level' => $level, 'anchor' => 'main/datatypes', 'line' => $header, 'number' => implode('.', $tocnumber), 'index' => false];
         }
         // Add an additional span with sanitized ID
         if (!$this->getConfig()->get('ExperimentalHtmlIds')) {
             $header = Html::element('span', ['id' => Sanitizer::escapeId('main/credits')]) . $header;
         }
         $header = $this->msg('api-credits-header')->parse();
         $help['credits'] .= Html::rawElement('h' . min(6, $level), ['id' => 'main/credits', 'class' => 'apihelp-header'], $header);
         $help['credits'] .= $this->msg('api-credits')->useDatabase(false)->parseAsBlock();
         if (!isset($tocData['main/credits'])) {
             $tocnumber[$level]++;
             $tocData['main/credits'] = ['toclevel' => count($tocnumber), 'level' => $level, 'anchor' => 'main/credits', 'line' => $header, 'number' => implode('.', $tocnumber), 'index' => false];
         }
     }
 }