/** * @param DatabaseBase $db * @return mixed */ public function doQuery($db) { $ids = array_map('intval', $this->ids); $queryInfo = DatabaseLogEntry::getSelectQueryData(); $queryInfo['conds'] += array('log_id' => $ids); $queryInfo['options'] += array('ORDER BY' => 'log_id DESC'); ChangeTags::modifyDisplayQuery($queryInfo['tables'], $queryInfo['fields'], $queryInfo['conds'], $queryInfo['join_conds'], $queryInfo['options'], ''); return $db->select($queryInfo['tables'], $queryInfo['fields'], $queryInfo['conds'], __METHOD__, $queryInfo['options'], $queryInfo['join_conds']); }
public function getApiData(ApiResult $result) { $logEntry = DatabaseLogEntry::newFromRow($this->row); $user = $this->list->getUser(); $ret = array('id' => $logEntry->getId(), 'type' => $logEntry->getType(), 'action' => $logEntry->getSubtype()); $ret += $logEntry->isDeleted(LogPage::DELETED_USER) ? array('userhidden' => '') : array(); $ret += $logEntry->isDeleted(LogPage::DELETED_COMMENT) ? array('commenthidden' => '') : array(); $ret += $logEntry->isDeleted(LogPage::DELETED_ACTION) ? array('actionhidden' => '') : array(); if (LogEventsList::userCan($this->row, LogPage::DELETED_ACTION, $user)) { $ret['params'] = LogFormatter::newFromEntry($logEntry)->formatParametersForApi(); } if (LogEventsList::userCan($this->row, LogPage::DELETED_USER, $user)) { $ret += array('userid' => $this->row->log_user, 'user' => $this->row->log_user_text); } if (LogEventsList::userCan($this->row, LogPage::DELETED_COMMENT, $user)) { $ret += array('comment' => $this->row->log_comment); } return $ret; }
public function getApiData(ApiResult $result) { $logEntry = DatabaseLogEntry::newFromRow($this->row); $user = $this->list->getUser(); $ret = array('id' => $logEntry->getId(), 'type' => $logEntry->getType(), 'action' => $logEntry->getSubtype()); $ret += $logEntry->isDeleted(LogPage::DELETED_USER) ? array('userhidden' => '') : array(); $ret += $logEntry->isDeleted(LogPage::DELETED_COMMENT) ? array('commenthidden' => '') : array(); $ret += $logEntry->isDeleted(LogPage::DELETED_ACTION) ? array('actionhidden' => '') : array(); if (LogEventsList::userCan($this->row, LogPage::DELETED_ACTION, $user)) { ApiQueryLogEvents::addLogParams($result, $ret, $logEntry->getParameters(), $logEntry->getType(), $logEntry->getSubtype(), $logEntry->getTimestamp(), $logEntry->isLegacy()); } if (LogEventsList::userCan($this->row, LogPage::DELETED_USER, $user)) { $ret += array('userid' => $this->row->log_user, 'user' => $this->row->log_user_text); } if (LogEventsList::userCan($this->row, LogPage::DELETED_COMMENT, $user)) { $ret += array('comment' => $this->row->log_comment); } return $ret; }
/** * Handy shortcut for constructing a formatter directly from * database row. * @param object $row * @see DatabaseLogEntry::getSelectQueryData * @return LogFormatter */ public static function newFromRow($row) { return self::newFromEntry(DatabaseLogEntry::newFromRow($row)); }
/** * @param $row * @return AbuseFilterVariableHolder */ public static function getMoveVarsFromRCRow($row) { if ($row->rc_user) { $user = User::newFromId($row->rc_user); } else { $user = new User(); $user->setName($row->rc_user_text); } $params = array_values(DatabaseLogEntry::newFromRow($row)->getParameters()); $oldTitle = Title::makeTitle($row->rc_namespace, $row->rc_title); $newTitle = Title::makeTitle($params[1], $params[0]); $vars = AbuseFilterVariableHolder::merge(AbuseFilter::generateUserVars($user), AbuseFilter::generateTitleVars($oldTitle, 'MOVED_FROM'), AbuseFilter::generateTitleVars($newTitle, 'MOVED_TO')); $vars->setVar('SUMMARY', $row->rc_comment); $vars->setVar('ACTION', 'move'); return $vars; }
/** * @param stdClass $row A single row from the result set * @return string Formatted HTML list item */ public function logLine($row) { $entry = DatabaseLogEntry::newFromRow($row); $formatter = LogFormatter::newFromEntry($entry); $formatter->setContext($this->getContext()); $formatter->setShowUserToolLinks(!($this->flags & self::NO_EXTRA_USER_LINKS)); $time = htmlspecialchars($this->getLanguage()->userTimeAndDate($entry->getTimestamp(), $this->getUser())); $action = $formatter->getActionText(); if ($this->flags & self::NO_ACTION_LINK) { $revert = ''; } else { $revert = $formatter->getActionLinks(); if ($revert != '') { $revert = '<span class="mw-logevent-actionlink">' . $revert . '</span>'; } } $comment = $formatter->getComment(); // Some user can hide log items and have review links $del = $this->getShowHideLinks($row); // Any tags... list($tagDisplay, $newClasses) = ChangeTags::formatSummaryRow($row->ts_tags, 'logevent', $this->getContext()); $classes = array_merge(array('mw-logline-' . $entry->getType()), $newClasses); return Html::rawElement('li', array('class' => $classes), "{$del} {$time} {$action} {$comment} {$revert} {$tagDisplay}") . "\n"; }
private function extractRowInfo($row) { $logEntry = DatabaseLogEntry::newFromRow($row); $vals = array(ApiResult::META_TYPE => 'assoc'); $anyHidden = false; $user = $this->getUser(); if ($this->fld_ids) { $vals['logid'] = intval($row->log_id); } if ($this->fld_title || $this->fld_parsedcomment) { $title = Title::makeTitle($row->log_namespace, $row->log_title); } if ($this->fld_title || $this->fld_ids || $this->fld_details && $row->log_params !== '') { if (LogEventsList::isDeleted($row, LogPage::DELETED_ACTION)) { $vals['actionhidden'] = true; $anyHidden = true; } if (LogEventsList::userCan($row, LogPage::DELETED_ACTION, $user)) { if ($this->fld_title) { ApiQueryBase::addTitleInfo($vals, $title); } if ($this->fld_ids) { $vals['pageid'] = intval($row->page_id); $vals['logpage'] = intval($row->log_page); } if ($this->fld_details) { $vals['params'] = LogFormatter::newFromEntry($logEntry)->formatParametersForApi(); } } } if ($this->fld_type) { $vals['type'] = $row->log_type; $vals['action'] = $row->log_action; } if ($this->fld_user || $this->fld_userid) { if (LogEventsList::isDeleted($row, LogPage::DELETED_USER)) { $vals['userhidden'] = true; $anyHidden = true; } if (LogEventsList::userCan($row, LogPage::DELETED_USER, $user)) { if ($this->fld_user) { $vals['user'] = $row->user_name === null ? $row->log_user_text : $row->user_name; } if ($this->fld_userid) { $vals['userid'] = intval($row->log_user); } if (!$row->log_user) { $vals['anon'] = true; } } } if ($this->fld_timestamp) { $vals['timestamp'] = wfTimestamp(TS_ISO_8601, $row->log_timestamp); } if (($this->fld_comment || $this->fld_parsedcomment) && isset($row->log_comment)) { if (LogEventsList::isDeleted($row, LogPage::DELETED_COMMENT)) { $vals['commenthidden'] = true; $anyHidden = true; } if (LogEventsList::userCan($row, LogPage::DELETED_COMMENT, $user)) { if ($this->fld_comment) { $vals['comment'] = $row->log_comment; } if ($this->fld_parsedcomment) { $vals['parsedcomment'] = Linker::formatComment($row->log_comment, $title); } } } if ($this->fld_tags) { if ($row->ts_tags) { $tags = explode(',', $row->ts_tags); ApiResult::setIndexedTagName($tags, 'tag'); $vals['tags'] = $tags; } else { $vals['tags'] = array(); } } if ($anyHidden && LogEventsList::isDeleted($row, LogPage::DELETED_RESTRICTED)) { $vals['suppressed'] = true; } return $vals; }
/** * Constructs the most part of the query. Extra conditions are sprinkled in * all over this class. * @return array */ public function getQueryInfo() { $basic = DatabaseLogEntry::getSelectQueryData(); $tables = $basic['tables']; $fields = $basic['fields']; $conds = $basic['conds']; $options = $basic['options']; $joins = $basic['join_conds']; $index = array(); # Add log_search table if there are conditions on it. # This filters the results to only include log rows that have # log_search records with the specified ls_field and ls_value values. if (array_key_exists('ls_field', $this->mConds)) { $tables[] = 'log_search'; $index['log_search'] = 'ls_field_val'; $index['logging'] = 'PRIMARY'; if (!$this->hasEqualsClause('ls_field') || !$this->hasEqualsClause('ls_value')) { # Since (ls_field,ls_value,ls_logid) is unique, if the condition is # to match a specific (ls_field,ls_value) tuple, then there will be # no duplicate log rows. Otherwise, we need to remove the duplicates. $options[] = 'DISTINCT'; } # Avoid usage of the wrong index by limiting # the choices of available indexes. This mainly # avoids site-breaking filesorts. } elseif ($this->title || $this->pattern || $this->performer) { $index['logging'] = array('page_time', 'user_time'); if (count($this->types) == 1) { $index['logging'][] = 'log_user_type_time'; } } elseif (count($this->types) == 1) { $index['logging'] = 'type_time'; } else { $index['logging'] = 'times'; } $options['USE INDEX'] = $index; # Don't show duplicate rows when using log_search $joins['log_search'] = array('INNER JOIN', 'ls_log_id=log_id'); $info = array('tables' => $tables, 'fields' => $fields, 'conds' => array_merge($conds, $this->mConds), 'options' => $options, 'join_conds' => $joins); # Add ChangeTags filter query ChangeTags::modifyDisplayQuery($info['tables'], $info['fields'], $info['conds'], $info['join_conds'], $info['options'], $this->mTagFilter); return $info; }
public function testAutoAccountCreation() { global $wgGroupPermissions, $wgHooks; // PHPUnit seems to have a bug where it will call the ->with() // callbacks for our hooks again after the test is run (WTF?), which // breaks here because $username no longer matches $user by the end of // the testing. $workaroundPHPUnitBug = false; $username = self::usernameForCreation(); $this->initializeManager(); $this->stashMwGlobals(['wgGroupPermissions']); $wgGroupPermissions['*']['createaccount'] = true; $wgGroupPermissions['*']['autocreateaccount'] = false; \ObjectCache::$instances[__METHOD__] = new \HashBagOStuff(); $this->setMwGlobals(['wgMainCacheType' => __METHOD__]); // Set up lots of mocks... $mocks = []; foreach (['pre', 'primary', 'secondary'] as $key) { $class = ucfirst($key) . 'AuthenticationProvider'; $mocks[$key] = $this->getMockForAbstractClass("MediaWiki\\Auth\\{$class}", [], "Mock{$class}"); $mocks[$key]->expects($this->any())->method('getUniqueId')->will($this->returnValue($key)); } $good = StatusValue::newGood(); $callback = $this->callback(function ($user) use(&$username, &$workaroundPHPUnitBug) { return $workaroundPHPUnitBug || $user->getName() === $username; }); $mocks['pre']->expects($this->exactly(12))->method('testUserForCreation')->with($callback, $this->identicalTo(AuthManager::AUTOCREATE_SOURCE_SESSION))->will($this->onConsecutiveCalls(StatusValue::newFatal('ok'), StatusValue::newFatal('ok'), StatusValue::newFatal('fail-in-pre'), $good, $good, $good, $good, $good, $good, $good, $good, $good)); $mocks['primary']->expects($this->any())->method('accountCreationType')->will($this->returnValue(PrimaryAuthenticationProvider::TYPE_CREATE)); $mocks['primary']->expects($this->any())->method('testUserExists')->will($this->returnValue(true)); $mocks['primary']->expects($this->exactly(9))->method('testUserForCreation')->with($callback, $this->identicalTo(AuthManager::AUTOCREATE_SOURCE_SESSION))->will($this->onConsecutiveCalls(StatusValue::newFatal('fail-in-primary'), $good, $good, $good, $good, $good, $good, $good, $good)); $mocks['primary']->expects($this->exactly(3))->method('autoCreatedAccount')->with($callback, $this->identicalTo(AuthManager::AUTOCREATE_SOURCE_SESSION)); $mocks['secondary']->expects($this->exactly(8))->method('testUserForCreation')->with($callback, $this->identicalTo(AuthManager::AUTOCREATE_SOURCE_SESSION))->will($this->onConsecutiveCalls(StatusValue::newFatal('fail-in-secondary'), $good, $good, $good, $good, $good, $good, $good)); $mocks['secondary']->expects($this->exactly(3))->method('autoCreatedAccount')->with($callback, $this->identicalTo(AuthManager::AUTOCREATE_SOURCE_SESSION)); $this->preauthMocks = [$mocks['pre']]; $this->primaryauthMocks = [$mocks['primary']]; $this->secondaryauthMocks = [$mocks['secondary']]; $this->initializeManager(true); $session = $this->request->getSession(); $logger = new \TestLogger(true, function ($m) { $m = str_replace('MediaWiki\\Auth\\AuthManager::autoCreateUser: '******'', $m); return $m; }); $this->manager->setLogger($logger); try { $user = \User::newFromName('UTSysop'); $this->manager->autoCreateUser($user, 'InvalidSource', true); $this->fail('Expected exception not thrown'); } catch (\InvalidArgumentException $ex) { $this->assertSame('Unknown auto-creation source: InvalidSource', $ex->getMessage()); } // First, check an existing user $session->clear(); $user = \User::newFromName('UTSysop'); $this->hook('LocalUserCreated', $this->never()); $ret = $this->manager->autoCreateUser($user, AuthManager::AUTOCREATE_SOURCE_SESSION, true); $this->unhook('LocalUserCreated'); $expect = \Status::newGood(); $expect->warning('userexists'); $this->assertEquals($expect, $ret); $this->assertNotEquals(0, $user->getId()); $this->assertSame('UTSysop', $user->getName()); $this->assertEquals($user->getId(), $session->getUser()->getId()); $this->assertSame([[LogLevel::DEBUG, '{username} already exists locally']], $logger->getBuffer()); $logger->clearBuffer(); $session->clear(); $user = \User::newFromName('UTSysop'); $this->hook('LocalUserCreated', $this->never()); $ret = $this->manager->autoCreateUser($user, AuthManager::AUTOCREATE_SOURCE_SESSION, false); $this->unhook('LocalUserCreated'); $expect = \Status::newGood(); $expect->warning('userexists'); $this->assertEquals($expect, $ret); $this->assertNotEquals(0, $user->getId()); $this->assertSame('UTSysop', $user->getName()); $this->assertEquals(0, $session->getUser()->getId()); $this->assertSame([[LogLevel::DEBUG, '{username} already exists locally']], $logger->getBuffer()); $logger->clearBuffer(); // Wiki is read-only $session->clear(); $this->setMwGlobals(['wgReadOnly' => 'Because']); $user = \User::newFromName($username); $this->hook('LocalUserCreated', $this->never()); $ret = $this->manager->autoCreateUser($user, AuthManager::AUTOCREATE_SOURCE_SESSION, true); $this->unhook('LocalUserCreated'); $this->assertEquals(\Status::newFatal('readonlytext', 'Because'), $ret); $this->assertEquals(0, $user->getId()); $this->assertNotEquals($username, $user->getName()); $this->assertEquals(0, $session->getUser()->getId()); $this->assertSame([[LogLevel::DEBUG, 'denied by wfReadOnly(): {reason}']], $logger->getBuffer()); $logger->clearBuffer(); $this->setMwGlobals(['wgReadOnly' => false]); // Session blacklisted $session->clear(); $session->set('AuthManager::AutoCreateBlacklist', 'test'); $user = \User::newFromName($username); $this->hook('LocalUserCreated', $this->never()); $ret = $this->manager->autoCreateUser($user, AuthManager::AUTOCREATE_SOURCE_SESSION, true); $this->unhook('LocalUserCreated'); $this->assertEquals(\Status::newFatal('test'), $ret); $this->assertEquals(0, $user->getId()); $this->assertNotEquals($username, $user->getName()); $this->assertEquals(0, $session->getUser()->getId()); $this->assertSame([[LogLevel::DEBUG, 'blacklisted in session {sessionid}']], $logger->getBuffer()); $logger->clearBuffer(); $session->clear(); $session->set('AuthManager::AutoCreateBlacklist', StatusValue::newFatal('test2')); $user = \User::newFromName($username); $this->hook('LocalUserCreated', $this->never()); $ret = $this->manager->autoCreateUser($user, AuthManager::AUTOCREATE_SOURCE_SESSION, true); $this->unhook('LocalUserCreated'); $this->assertEquals(\Status::newFatal('test2'), $ret); $this->assertEquals(0, $user->getId()); $this->assertNotEquals($username, $user->getName()); $this->assertEquals(0, $session->getUser()->getId()); $this->assertSame([[LogLevel::DEBUG, 'blacklisted in session {sessionid}']], $logger->getBuffer()); $logger->clearBuffer(); // Uncreatable name $session->clear(); $user = \User::newFromName($username . '@'); $this->hook('LocalUserCreated', $this->never()); $ret = $this->manager->autoCreateUser($user, AuthManager::AUTOCREATE_SOURCE_SESSION, true); $this->unhook('LocalUserCreated'); $this->assertEquals(\Status::newFatal('noname'), $ret); $this->assertEquals(0, $user->getId()); $this->assertNotEquals($username . '@', $user->getId()); $this->assertEquals(0, $session->getUser()->getId()); $this->assertSame([[LogLevel::DEBUG, 'name "{username}" is not creatable']], $logger->getBuffer()); $logger->clearBuffer(); $this->assertSame('noname', $session->get('AuthManager::AutoCreateBlacklist')); // IP unable to create accounts $wgGroupPermissions['*']['createaccount'] = false; $wgGroupPermissions['*']['autocreateaccount'] = false; $session->clear(); $user = \User::newFromName($username); $this->hook('LocalUserCreated', $this->never()); $ret = $this->manager->autoCreateUser($user, AuthManager::AUTOCREATE_SOURCE_SESSION, true); $this->unhook('LocalUserCreated'); $this->assertEquals(\Status::newFatal('authmanager-autocreate-noperm'), $ret); $this->assertEquals(0, $user->getId()); $this->assertNotEquals($username, $user->getName()); $this->assertEquals(0, $session->getUser()->getId()); $this->assertSame([[LogLevel::DEBUG, 'IP lacks the ability to create or autocreate accounts']], $logger->getBuffer()); $logger->clearBuffer(); $this->assertSame('authmanager-autocreate-noperm', $session->get('AuthManager::AutoCreateBlacklist')); // Test that both permutations of permissions are allowed // (this hits the two "ok" entries in $mocks['pre']) $wgGroupPermissions['*']['createaccount'] = false; $wgGroupPermissions['*']['autocreateaccount'] = true; $session->clear(); $user = \User::newFromName($username); $this->hook('LocalUserCreated', $this->never()); $ret = $this->manager->autoCreateUser($user, AuthManager::AUTOCREATE_SOURCE_SESSION, true); $this->unhook('LocalUserCreated'); $this->assertEquals(\Status::newFatal('ok'), $ret); $wgGroupPermissions['*']['createaccount'] = true; $wgGroupPermissions['*']['autocreateaccount'] = false; $session->clear(); $user = \User::newFromName($username); $this->hook('LocalUserCreated', $this->never()); $ret = $this->manager->autoCreateUser($user, AuthManager::AUTOCREATE_SOURCE_SESSION, true); $this->unhook('LocalUserCreated'); $this->assertEquals(\Status::newFatal('ok'), $ret); $logger->clearBuffer(); // Test lock fail $session->clear(); $user = \User::newFromName($username); $this->hook('LocalUserCreated', $this->never()); $cache = \ObjectCache::getLocalClusterInstance(); $lock = $cache->getScopedLock($cache->makeGlobalKey('account', md5($username))); $ret = $this->manager->autoCreateUser($user, AuthManager::AUTOCREATE_SOURCE_SESSION, true); unset($lock); $this->unhook('LocalUserCreated'); $this->assertEquals(\Status::newFatal('usernameinprogress'), $ret); $this->assertEquals(0, $user->getId()); $this->assertNotEquals($username, $user->getName()); $this->assertEquals(0, $session->getUser()->getId()); $this->assertSame([[LogLevel::DEBUG, 'Could not acquire account creation lock']], $logger->getBuffer()); $logger->clearBuffer(); // Test pre-authentication provider fail $session->clear(); $user = \User::newFromName($username); $this->hook('LocalUserCreated', $this->never()); $ret = $this->manager->autoCreateUser($user, AuthManager::AUTOCREATE_SOURCE_SESSION, true); $this->unhook('LocalUserCreated'); $this->assertEquals(\Status::newFatal('fail-in-pre'), $ret); $this->assertEquals(0, $user->getId()); $this->assertNotEquals($username, $user->getName()); $this->assertEquals(0, $session->getUser()->getId()); $this->assertSame([[LogLevel::DEBUG, 'Provider denied creation of {username}: {reason}']], $logger->getBuffer()); $logger->clearBuffer(); $this->assertEquals(StatusValue::newFatal('fail-in-pre'), $session->get('AuthManager::AutoCreateBlacklist')); $session->clear(); $user = \User::newFromName($username); $this->hook('LocalUserCreated', $this->never()); $ret = $this->manager->autoCreateUser($user, AuthManager::AUTOCREATE_SOURCE_SESSION, true); $this->unhook('LocalUserCreated'); $this->assertEquals(\Status::newFatal('fail-in-primary'), $ret); $this->assertEquals(0, $user->getId()); $this->assertNotEquals($username, $user->getName()); $this->assertEquals(0, $session->getUser()->getId()); $this->assertSame([[LogLevel::DEBUG, 'Provider denied creation of {username}: {reason}']], $logger->getBuffer()); $logger->clearBuffer(); $this->assertEquals(StatusValue::newFatal('fail-in-primary'), $session->get('AuthManager::AutoCreateBlacklist')); $session->clear(); $user = \User::newFromName($username); $this->hook('LocalUserCreated', $this->never()); $ret = $this->manager->autoCreateUser($user, AuthManager::AUTOCREATE_SOURCE_SESSION, true); $this->unhook('LocalUserCreated'); $this->assertEquals(\Status::newFatal('fail-in-secondary'), $ret); $this->assertEquals(0, $user->getId()); $this->assertNotEquals($username, $user->getName()); $this->assertEquals(0, $session->getUser()->getId()); $this->assertSame([[LogLevel::DEBUG, 'Provider denied creation of {username}: {reason}']], $logger->getBuffer()); $logger->clearBuffer(); $this->assertEquals(StatusValue::newFatal('fail-in-secondary'), $session->get('AuthManager::AutoCreateBlacklist')); // Test backoff $cache = \ObjectCache::getLocalClusterInstance(); $backoffKey = wfMemcKey('AuthManager', 'autocreate-failed', md5($username)); $cache->set($backoffKey, true); $session->clear(); $user = \User::newFromName($username); $this->hook('LocalUserCreated', $this->never()); $ret = $this->manager->autoCreateUser($user, AuthManager::AUTOCREATE_SOURCE_SESSION, true); $this->unhook('LocalUserCreated'); $this->assertEquals(\Status::newFatal('authmanager-autocreate-exception'), $ret); $this->assertEquals(0, $user->getId()); $this->assertNotEquals($username, $user->getName()); $this->assertEquals(0, $session->getUser()->getId()); $this->assertSame([[LogLevel::DEBUG, '{username} denied by prior creation attempt failures']], $logger->getBuffer()); $logger->clearBuffer(); $this->assertSame(null, $session->get('AuthManager::AutoCreateBlacklist')); $cache->delete($backoffKey); // Test addToDatabase fails $session->clear(); $user = $this->getMock('User', ['addToDatabase']); $user->expects($this->once())->method('addToDatabase')->will($this->returnValue(\Status::newFatal('because'))); $user->setName($username); $ret = $this->manager->autoCreateUser($user, AuthManager::AUTOCREATE_SOURCE_SESSION, true); $this->assertEquals(\Status::newFatal('because'), $ret); $this->assertEquals(0, $user->getId()); $this->assertNotEquals($username, $user->getName()); $this->assertEquals(0, $session->getUser()->getId()); $this->assertSame([[LogLevel::INFO, 'creating new user ({username}) - from: {from}'], [LogLevel::ERROR, '{username} failed with message {message}']], $logger->getBuffer()); $logger->clearBuffer(); $this->assertSame(null, $session->get('AuthManager::AutoCreateBlacklist')); // Test addToDatabase throws an exception $cache = \ObjectCache::getLocalClusterInstance(); $backoffKey = wfMemcKey('AuthManager', 'autocreate-failed', md5($username)); $this->assertFalse($cache->get($backoffKey), 'sanity check'); $session->clear(); $user = $this->getMock('User', ['addToDatabase']); $user->expects($this->once())->method('addToDatabase')->will($this->throwException(new \Exception('Excepted'))); $user->setName($username); try { $this->manager->autoCreateUser($user, AuthManager::AUTOCREATE_SOURCE_SESSION, true); $this->fail('Expected exception not thrown'); } catch (\Exception $ex) { $this->assertSame('Excepted', $ex->getMessage()); } $this->assertEquals(0, $user->getId()); $this->assertEquals(0, $session->getUser()->getId()); $this->assertSame([[LogLevel::INFO, 'creating new user ({username}) - from: {from}'], [LogLevel::ERROR, '{username} failed with exception {exception}']], $logger->getBuffer()); $logger->clearBuffer(); $this->assertSame(null, $session->get('AuthManager::AutoCreateBlacklist')); $this->assertNotEquals(false, $cache->get($backoffKey)); $cache->delete($backoffKey); // Test addToDatabase fails because the user already exists. $session->clear(); $user = $this->getMock('User', ['addToDatabase']); $user->expects($this->once())->method('addToDatabase')->will($this->returnCallback(function () use($username) { $status = \User::newFromName($username)->addToDatabase(); $this->assertTrue($status->isOK(), 'sanity check'); return \Status::newFatal('userexists'); })); $user->setName($username); $ret = $this->manager->autoCreateUser($user, AuthManager::AUTOCREATE_SOURCE_SESSION, true); $expect = \Status::newGood(); $expect->warning('userexists'); $this->assertEquals($expect, $ret); $this->assertNotEquals(0, $user->getId()); $this->assertEquals($username, $user->getName()); $this->assertEquals($user->getId(), $session->getUser()->getId()); $this->assertSame([[LogLevel::INFO, 'creating new user ({username}) - from: {from}'], [LogLevel::INFO, '{username} already exists locally (race)']], $logger->getBuffer()); $logger->clearBuffer(); $this->assertSame(null, $session->get('AuthManager::AutoCreateBlacklist')); // Success! $session->clear(); $username = self::usernameForCreation(); $user = \User::newFromName($username); $this->hook('AuthPluginAutoCreate', $this->once())->with($callback); $this->hideDeprecated('AuthPluginAutoCreate hook (used in ' . get_class($wgHooks['AuthPluginAutoCreate'][0]) . '::onAuthPluginAutoCreate)'); $this->hook('LocalUserCreated', $this->once())->with($callback, $this->equalTo(true)); $ret = $this->manager->autoCreateUser($user, AuthManager::AUTOCREATE_SOURCE_SESSION, true); $this->unhook('LocalUserCreated'); $this->unhook('AuthPluginAutoCreate'); $this->assertEquals(\Status::newGood(), $ret); $this->assertNotEquals(0, $user->getId()); $this->assertEquals($username, $user->getName()); $this->assertEquals($user->getId(), $session->getUser()->getId()); $this->assertSame([[LogLevel::INFO, 'creating new user ({username}) - from: {from}']], $logger->getBuffer()); $logger->clearBuffer(); $dbw = wfGetDB(DB_MASTER); $maxLogId = $dbw->selectField('logging', 'MAX(log_id)', ['log_type' => 'newusers']); $session->clear(); $username = self::usernameForCreation(); $user = \User::newFromName($username); $this->hook('LocalUserCreated', $this->once())->with($callback, $this->equalTo(true)); $ret = $this->manager->autoCreateUser($user, AuthManager::AUTOCREATE_SOURCE_SESSION, false); $this->unhook('LocalUserCreated'); $this->assertEquals(\Status::newGood(), $ret); $this->assertNotEquals(0, $user->getId()); $this->assertEquals($username, $user->getName()); $this->assertEquals(0, $session->getUser()->getId()); $this->assertSame([[LogLevel::INFO, 'creating new user ({username}) - from: {from}']], $logger->getBuffer()); $logger->clearBuffer(); $this->assertSame($maxLogId, $dbw->selectField('logging', 'MAX(log_id)', ['log_type' => 'newusers'])); $this->config->set('NewUserLog', true); $session->clear(); $username = self::usernameForCreation(); $user = \User::newFromName($username); $ret = $this->manager->autoCreateUser($user, AuthManager::AUTOCREATE_SOURCE_SESSION, false); $this->assertEquals(\Status::newGood(), $ret); $logger->clearBuffer(); $data = \DatabaseLogEntry::getSelectQueryData(); $rows = iterator_to_array($dbw->select($data['tables'], $data['fields'], ['log_id > ' . (int) $maxLogId, 'log_type' => 'newusers'] + $data['conds'], __METHOD__, $data['options'], $data['join_conds'])); $this->assertCount(1, $rows); $entry = \DatabaseLogEntry::newFromRow(reset($rows)); $this->assertSame('autocreate', $entry->getSubtype()); $this->assertSame($user->getId(), $entry->getPerformer()->getId()); $this->assertSame($user->getName(), $entry->getPerformer()->getName()); $this->assertSame($user->getUserPage()->getFullText(), $entry->getTarget()->getFullText()); $this->assertSame(['4::userid' => $user->getId()], $entry->getParameters()); $workaroundPHPUnitBug = true; }
/** * @param $row Row: a single row from the result set * @return String: Formatted HTML list item */ public function logLine($row) { # start wikia change $this->fixUserName($row); # end wikia change $entry = DatabaseLogEntry::newFromRow($row); $formatter = LogFormatter::newFromEntry($entry); $formatter->setShowUserToolLinks(!($this->flags & self::NO_EXTRA_USER_LINKS)); $action = $formatter->getActionText(); $comment = $formatter->getComment(); $classes = array('mw-logline-' . $entry->getType()); $title = $entry->getTarget(); $time = $this->logTimestamp($entry); // Extract extra parameters $paramArray = LogPage::extractParams($row->log_params); // Add review/revert links and such... $revert = $this->logActionLinks($row, $title, $paramArray, $comment); // Some user can hide log items and have review links $del = $this->getShowHideLinks($row); if ($del != '') { $del .= ' '; } // Any tags... list($tagDisplay, $newClasses) = ChangeTags::formatSummaryRow($row->ts_tags, 'logevent'); $classes = array_merge($classes, $newClasses); return Xml::tags('li', array("class" => implode(' ', $classes)), $del . "{$time} {$action} {$comment} {$revert} {$tagDisplay}") . "\n"; }
/** * Extracts from a single sql row the data needed to describe one recent change. * * @param mixed $row The row from which to extract the data. * @return array An array mapping strings (descriptors) to their respective string values. * @access public */ public function extractRowInfo($row) { /* Determine the title of the page that has been changed. */ $title = Title::makeTitle($row->rc_namespace, $row->rc_title); $user = $this->getUser(); /* Our output data. */ $vals = array(); $type = intval($row->rc_type); /* Determine what kind of change this was. */ switch ($type) { case RC_EDIT: $vals['type'] = 'edit'; break; case RC_NEW: $vals['type'] = 'new'; break; case RC_MOVE: $vals['type'] = 'move'; break; case RC_LOG: $vals['type'] = 'log'; break; case RC_EXTERNAL: $vals['type'] = 'external'; break; case RC_MOVE_OVER_REDIRECT: $vals['type'] = 'move over redirect'; break; default: $vals['type'] = $type; } $anyHidden = false; /* Create a new entry in the result for the title. */ if ($this->fld_title || $this->fld_ids) { if ($type === RC_LOG && $row->rc_deleted & LogPage::DELETED_ACTION) { $vals['actionhidden'] = ''; $anyHidden = true; } if ($type !== RC_LOG || LogEventsList::userCanBitfield($row->rc_deleted, LogPage::DELETED_ACTION, $user)) { if ($this->fld_title) { ApiQueryBase::addTitleInfo($vals, $title); } if ($this->fld_ids) { $vals['pageid'] = intval($row->rc_cur_id); $vals['revid'] = intval($row->rc_this_oldid); $vals['old_revid'] = intval($row->rc_last_oldid); } } } if ($this->fld_ids) { $vals['rcid'] = intval($row->rc_id); } /* Add user data and 'anon' flag, if user is anonymous. */ if ($this->fld_user || $this->fld_userid) { if ($row->rc_deleted & Revision::DELETED_USER) { $vals['userhidden'] = ''; $anyHidden = true; } if (Revision::userCanBitfield($row->rc_deleted, Revision::DELETED_USER, $user)) { if ($this->fld_user) { $vals['user'] = $row->rc_user_text; } if ($this->fld_userid) { $vals['userid'] = $row->rc_user; } if (!$row->rc_user) { $vals['anon'] = ''; } } } /* Add flags, such as new, minor, bot. */ if ($this->fld_flags) { if ($row->rc_bot) { $vals['bot'] = ''; } if ($row->rc_type == RC_NEW) { $vals['new'] = ''; } if ($row->rc_minor) { $vals['minor'] = ''; } } /* Add sizes of each revision. (Only available on 1.10+) */ if ($this->fld_sizes) { $vals['oldlen'] = intval($row->rc_old_len); $vals['newlen'] = intval($row->rc_new_len); } /* Add the timestamp. */ if ($this->fld_timestamp) { $vals['timestamp'] = wfTimestamp(TS_ISO_8601, $row->rc_timestamp); } /* Add edit summary / log summary. */ if ($this->fld_comment || $this->fld_parsedcomment) { if ($row->rc_deleted & Revision::DELETED_COMMENT) { $vals['commenthidden'] = ''; $anyHidden = true; } if (Revision::userCanBitfield($row->rc_deleted, Revision::DELETED_COMMENT, $user)) { if ($this->fld_comment && isset($row->rc_comment)) { $vals['comment'] = $row->rc_comment; } if ($this->fld_parsedcomment && isset($row->rc_comment)) { $vals['parsedcomment'] = Linker::formatComment($row->rc_comment, $title); } } } if ($this->fld_redirect) { if ($row->page_is_redirect) { $vals['redirect'] = ''; } } /* Add the patrolled flag */ if ($this->fld_patrolled && $row->rc_patrolled == 1) { $vals['patrolled'] = ''; } if ($this->fld_patrolled && ChangesList::isUnpatrolled($row, $user)) { $vals['unpatrolled'] = ''; } if ($this->fld_loginfo && $row->rc_type == RC_LOG) { if ($row->rc_deleted & LogPage::DELETED_ACTION) { $vals['actionhidden'] = ''; $anyHidden = true; } if (LogEventsList::userCanBitfield($row->rc_deleted, LogPage::DELETED_ACTION, $user)) { $vals['logid'] = intval($row->rc_logid); $vals['logtype'] = $row->rc_log_type; $vals['logaction'] = $row->rc_log_action; $logEntry = DatabaseLogEntry::newFromRow((array) $row); ApiQueryLogEvents::addLogParams($this->getResult(), $vals, $logEntry->getParameters(), $logEntry->getType(), $logEntry->getSubtype(), $logEntry->getTimestamp()); } } if ($this->fld_tags) { if ($row->ts_tags) { $tags = explode(',', $row->ts_tags); $this->getResult()->setIndexedTagName($tags, 'tag'); $vals['tags'] = $tags; } else { $vals['tags'] = array(); } } if ($this->fld_sha1 && $row->rev_sha1 !== null) { if ($row->rev_deleted & Revision::DELETED_TEXT) { $vals['sha1hidden'] = ''; $anyHidden = true; } if (Revision::userCanBitfield($row->rev_deleted, Revision::DELETED_TEXT, $user)) { if ($row->rev_sha1 !== '') { $vals['sha1'] = wfBaseConvert($row->rev_sha1, 36, 16, 40); } else { $vals['sha1'] = ''; } } } if (!is_null($this->token)) { $tokenFunctions = $this->getTokenFunctions(); foreach ($this->token as $t) { $val = call_user_func($tokenFunctions[$t], $row->rc_cur_id, $title, RecentChange::newFromRow($row)); if ($val === false) { $this->setWarning("Action '{$t}' is not allowed for the current user"); } else { $vals[$t . 'token'] = $val; } } } if ($anyHidden && $row->rc_deleted & Revision::DELETED_RESTRICTED) { $vals['suppressed'] = ''; } return $vals; }
private function extractRowInfo($row) { /* Determine the title of the page that has been changed. */ $title = Title::makeTitle($row->rc_namespace, $row->rc_title); $user = $this->getUser(); /* Our output data. */ $vals = array(); $type = intval($row->rc_type); /* Determine what kind of change this was. */ switch ($type) { case RC_EDIT: $vals['type'] = 'edit'; break; case RC_NEW: $vals['type'] = 'new'; break; case RC_MOVE: $vals['type'] = 'move'; break; case RC_LOG: $vals['type'] = 'log'; break; case RC_EXTERNAL: $vals['type'] = 'external'; break; case RC_MOVE_OVER_REDIRECT: $vals['type'] = 'move over redirect'; break; default: $vals['type'] = $type; } $anyHidden = false; /* Create a new entry in the result for the title. */ if ($this->fld_title || $this->fld_ids) { // These should already have been filtered out of the query, but just in case. if ($type === RC_LOG && $row->rc_deleted & LogPage::DELETED_ACTION) { $vals['actionhidden'] = ''; $anyHidden = true; } if ($type !== RC_LOG || LogEventsList::userCanBitfield($row->rc_deleted, LogPage::DELETED_ACTION, $user)) { if ($this->fld_title) { ApiQueryBase::addTitleInfo($vals, $title); } if ($this->fld_ids) { $vals['pageid'] = intval($row->rc_cur_id); $vals['revid'] = intval($row->rc_this_oldid); $vals['old_revid'] = intval($row->rc_last_oldid); } } } /* Add user data and 'anon' flag, if user is anonymous. */ if ($this->fld_user || $this->fld_userid) { if ($row->rc_deleted & Revision::DELETED_USER) { $vals['userhidden'] = ''; $anyHidden = true; } if (Revision::userCanBitfield($row->rc_deleted, Revision::DELETED_USER, $user)) { if ($this->fld_userid) { $vals['userid'] = $row->rc_user; // for backwards compatibility $vals['user'] = $row->rc_user; } if ($this->fld_user) { $vals['user'] = $row->rc_user_text; } if (!$row->rc_user) { $vals['anon'] = ''; } } } /* Add flags, such as new, minor, bot. */ if ($this->fld_flags) { if ($row->rc_bot) { $vals['bot'] = ''; } if ($row->rc_type == RC_NEW) { $vals['new'] = ''; } if ($row->rc_minor) { $vals['minor'] = ''; } } /* Add sizes of each revision. (Only available on 1.10+) */ if ($this->fld_sizes) { $vals['oldlen'] = intval($row->rc_old_len); $vals['newlen'] = intval($row->rc_new_len); } /* Add the timestamp. */ if ($this->fld_timestamp) { $vals['timestamp'] = wfTimestamp(TS_ISO_8601, $row->rc_timestamp); } if ($this->fld_notificationtimestamp) { $vals['notificationtimestamp'] = $row->wl_notificationtimestamp == null ? '' : wfTimestamp(TS_ISO_8601, $row->wl_notificationtimestamp); } /* Add edit summary / log summary. */ if ($this->fld_comment || $this->fld_parsedcomment) { if ($row->rc_deleted & Revision::DELETED_COMMENT) { $vals['commenthidden'] = ''; $anyHidden = true; } if (Revision::userCanBitfield($row->rc_deleted, Revision::DELETED_COMMENT, $user)) { if ($this->fld_comment && isset($row->rc_comment)) { $vals['comment'] = $row->rc_comment; } if ($this->fld_parsedcomment && isset($row->rc_comment)) { $vals['parsedcomment'] = Linker::formatComment($row->rc_comment, $title); } } } /* Add the patrolled flag */ if ($this->fld_patrol && $row->rc_patrolled == 1) { $vals['patrolled'] = ''; } if ($this->fld_patrol && ChangesList::isUnpatrolled($row, $user)) { $vals['unpatrolled'] = ''; } if ($this->fld_loginfo && $row->rc_type == RC_LOG) { if ($row->rc_deleted & LogPage::DELETED_ACTION) { $vals['actionhidden'] = ''; $anyHidden = true; } if (LogEventsList::userCanBitfield($row->rc_deleted, LogPage::DELETED_ACTION, $user)) { $vals['logid'] = intval($row->rc_logid); $vals['logtype'] = $row->rc_log_type; $vals['logaction'] = $row->rc_log_action; $logEntry = DatabaseLogEntry::newFromRow((array) $row); ApiQueryLogEvents::addLogParams($this->getResult(), $vals, $logEntry->getParameters(), $logEntry->getType(), $logEntry->getSubtype(), $logEntry->getTimestamp()); } } if ($anyHidden && $row->rc_deleted & Revision::DELETED_RESTRICTED) { $vals['suppressed'] = ''; } return $vals; }
private function extractRowInfo($row) { $vals = array(); if ($this->fld_ids) { $vals['pageid'] = intval($row->rc_cur_id); $vals['revid'] = intval($row->rc_this_oldid); $vals['old_revid'] = intval($row->rc_last_oldid); } $title = Title::makeTitle($row->rc_namespace, $row->rc_title); if ($this->fld_title) { ApiQueryBase::addTitleInfo($vals, $title); } if ($this->fld_user || $this->fld_userid) { if ($this->fld_user) { $vals['user'] = $row->rc_user_text; } if ($this->fld_userid) { $vals['user'] = $row->rc_user; } if (!$row->rc_user) { $vals['anon'] = ''; } } if ($this->fld_flags) { if ($row->rc_type == RC_NEW) { $vals['new'] = ''; } if ($row->rc_minor) { $vals['minor'] = ''; } if ($row->rc_bot) { $vals['bot'] = ''; } } if ($this->fld_patrol && isset($row->rc_patrolled)) { $vals['patrolled'] = ''; } if ($this->fld_timestamp) { $vals['timestamp'] = wfTimestamp(TS_ISO_8601, $row->rc_timestamp); } if ($this->fld_sizes) { $vals['oldlen'] = intval($row->rc_old_len); $vals['newlen'] = intval($row->rc_new_len); } if ($this->fld_notificationtimestamp) { $vals['notificationtimestamp'] = $row->wl_notificationtimestamp == null ? '' : wfTimestamp(TS_ISO_8601, $row->wl_notificationtimestamp); } if ($this->fld_comment && isset($row->rc_comment)) { $vals['comment'] = $row->rc_comment; } if ($this->fld_parsedcomment && isset($row->rc_comment)) { $vals['parsedcomment'] = Linker::formatComment($row->rc_comment, $title); } if ($this->fld_loginfo && $row->rc_type == RC_LOG) { $vals['logid'] = intval($row->rc_logid); $vals['logtype'] = $row->rc_log_type; $vals['logaction'] = $row->rc_log_action; $logEntry = DatabaseLogEntry::newFromRow((array) $row); ApiQueryLogEvents::addLogParams($this->getResult(), $vals, $logEntry->getParameters(), $logEntry->getType(), $logEntry->getSubtype(), $logEntry->getTimestamp()); } return $vals; }
private function extractRowInfo($row) { $vals = array(); $type = intval($row->rc_type); /* Determine what kind of change this was. */ switch ($type) { case RC_EDIT: $vals['type'] = 'edit'; break; case RC_NEW: $vals['type'] = 'new'; break; case RC_MOVE: $vals['type'] = 'move'; break; case RC_LOG: $vals['type'] = 'log'; break; case RC_EXTERNAL: $vals['type'] = 'external'; break; case RC_MOVE_OVER_REDIRECT: $vals['type'] = 'move over redirect'; break; default: $vals['type'] = $type; } if ($this->fld_ids) { $vals['pageid'] = intval($row->rc_cur_id); $vals['revid'] = intval($row->rc_this_oldid); $vals['old_revid'] = intval($row->rc_last_oldid); } $title = Title::makeTitle($row->rc_namespace, $row->rc_title); if ($this->fld_title) { ApiQueryBase::addTitleInfo($vals, $title); } if ($this->fld_user || $this->fld_userid) { if ($this->fld_userid) { $vals['userid'] = $row->rc_user; // for backwards compatibility $vals['user'] = $row->rc_user; } if ($this->fld_user) { $vals['user'] = $row->rc_user_text; } if (!$row->rc_user) { $vals['anon'] = ''; } } if ($this->fld_flags) { if ($row->rc_type == RC_NEW) { $vals['new'] = ''; } if ($row->rc_minor) { $vals['minor'] = ''; } if ($row->rc_bot) { $vals['bot'] = ''; } } if ($this->fld_patrol && isset($row->rc_patrolled)) { $vals['patrolled'] = ''; } if ($this->fld_timestamp) { $vals['timestamp'] = wfTimestamp(TS_ISO_8601, $row->rc_timestamp); } if ($this->fld_sizes) { $vals['oldlen'] = intval($row->rc_old_len); $vals['newlen'] = intval($row->rc_new_len); } if ($this->fld_notificationtimestamp) { $vals['notificationtimestamp'] = $row->wl_notificationtimestamp == null ? '' : wfTimestamp(TS_ISO_8601, $row->wl_notificationtimestamp); } if ($this->fld_comment && isset($row->rc_comment)) { $vals['comment'] = $row->rc_comment; } if ($this->fld_parsedcomment && isset($row->rc_comment)) { $vals['parsedcomment'] = Linker::formatComment($row->rc_comment, $title); } if ($this->fld_loginfo && $row->rc_type == RC_LOG) { $vals['logid'] = intval($row->rc_logid); $vals['logtype'] = $row->rc_log_type; $vals['logaction'] = $row->rc_log_action; $logEntry = DatabaseLogEntry::newFromRow((array) $row); ApiQueryLogEvents::addLogParams($this->getResult(), $vals, $logEntry->getParameters(), $logEntry->getType(), $logEntry->getSubtype(), $logEntry->getTimestamp()); } return $vals; }
private function extractRowInfo($row) { $logEntry = DatabaseLogEntry::newFromRow($row); $vals = array(); if ($this->fld_ids) { $vals['logid'] = intval($row->log_id); $vals['pageid'] = intval($row->page_id); } if ($this->fld_title || $this->fld_parsedcomment) { $title = Title::makeTitle($row->log_namespace, $row->log_title); } if ($this->fld_title) { if (LogEventsList::isDeleted($row, LogPage::DELETED_ACTION)) { $vals['actionhidden'] = ''; } else { ApiQueryBase::addTitleInfo($vals, $title); } } if ($this->fld_type || $this->fld_action) { $vals['type'] = $row->log_type; $vals['action'] = $row->log_action; } if ($this->fld_details && $row->log_params !== '') { if (LogEventsList::isDeleted($row, LogPage::DELETED_ACTION)) { $vals['actionhidden'] = ''; } else { self::addLogParams($this->getResult(), $vals, $logEntry->getParameters(), $logEntry->getType(), $logEntry->getSubtype(), $logEntry->getTimestamp(), $logEntry->isLegacy()); } } if ($this->fld_user || $this->fld_userid) { if (LogEventsList::isDeleted($row, LogPage::DELETED_USER)) { $vals['userhidden'] = ''; } else { if ($this->fld_user) { $vals['user'] = $row->user_name; } if ($this->fld_userid) { $vals['userid'] = $row->user_id; } if (!$row->log_user) { $vals['anon'] = ''; } } } if ($this->fld_timestamp) { $vals['timestamp'] = wfTimestamp(TS_ISO_8601, $row->log_timestamp); } if (($this->fld_comment || $this->fld_parsedcomment) && isset($row->log_comment)) { if (LogEventsList::isDeleted($row, LogPage::DELETED_COMMENT)) { $vals['commenthidden'] = ''; } else { if ($this->fld_comment) { $vals['comment'] = $row->log_comment; } if ($this->fld_parsedcomment) { $vals['parsedcomment'] = Linker::formatComment($row->log_comment, $title); } } } if ($this->fld_tags) { if ($row->ts_tags) { $tags = explode(',', $row->ts_tags); $this->getResult()->setIndexedTagName($tags, 'tag'); $vals['tags'] = $tags; } else { $vals['tags'] = array(); } } return $vals; }
/** * Constructs the most part of the query. Extra conditions are sprinkled in * all over this class. * @return array */ public function getQueryInfo() { $basic = DatabaseLogEntry::getSelectQueryData(); $tables = $basic['tables']; $fields = $basic['fields']; $conds = $basic['conds']; $options = $basic['options']; $joins = $basic['join_conds']; $index = array(); # Add log_search table if there are conditions on it. # This filters the results to only include log rows that have # log_search records with the specified ls_field and ls_value values. if (array_key_exists('ls_field', $this->mConds)) { $tables[] = 'log_search'; $index['log_search'] = 'ls_field_val'; $index['logging'] = 'PRIMARY'; if (!$this->hasEqualsClause('ls_field') || !$this->hasEqualsClause('ls_value')) { # Since (ls_field,ls_value,ls_logid) is unique, if the condition is # to match a specific (ls_field,ls_value) tuple, then there will be # no duplicate log rows. Otherwise, we need to remove the duplicates. $options[] = 'DISTINCT'; } } if (count($index)) { $options['USE INDEX'] = $index; } # Don't show duplicate rows when using log_search $joins['log_search'] = array('INNER JOIN', 'ls_log_id=log_id'); $info = array('tables' => $tables, 'fields' => $fields, 'conds' => array_merge($conds, $this->mConds), 'options' => $options, 'join_conds' => $joins); # Add ChangeTags filter query ChangeTags::modifyDisplayQuery($info['tables'], $info['fields'], $info['conds'], $info['join_conds'], $info['options'], $this->mTagFilter); return $info; }
/** * Extracts from a single sql row the data needed to describe one recent change. * * @param $row The row from which to extract the data. * @return array An array mapping strings (descriptors) to their respective string values. * @access public */ public function extractRowInfo($row) { /* If page was moved somewhere, get the title of the move target. */ $movedToTitle = false; if (isset($row->rc_moved_to_title) && $row->rc_moved_to_title !== '') { $movedToTitle = Title::makeTitle($row->rc_moved_to_ns, $row->rc_moved_to_title); } /* Determine the title of the page that has been changed. */ $title = Title::makeTitle($row->rc_namespace, $row->rc_title); /* Our output data. */ $vals = array(); $type = intval($row->rc_type); /* Determine what kind of change this was. */ switch ($type) { case RC_EDIT: $vals['type'] = 'edit'; break; case RC_NEW: $vals['type'] = 'new'; break; case RC_MOVE: $vals['type'] = 'move'; break; case RC_LOG: $vals['type'] = 'log'; break; case RC_MOVE_OVER_REDIRECT: $vals['type'] = 'move over redirect'; break; default: $vals['type'] = $type; } /* Create a new entry in the result for the title. */ if ($this->fld_title) { ApiQueryBase::addTitleInfo($vals, $title); if ($movedToTitle) { ApiQueryBase::addTitleInfo($vals, $movedToTitle, 'new_'); } } /* Add ids, such as rcid, pageid, revid, and oldid to the change's info. */ if ($this->fld_ids) { $vals['rcid'] = intval($row->rc_id); $vals['pageid'] = intval($row->rc_cur_id); $vals['revid'] = intval($row->rc_this_oldid); $vals['old_revid'] = intval($row->rc_last_oldid); } /* Add user data and 'anon' flag, if use is anonymous. */ if ($this->fld_user || $this->fld_userid) { if ($this->fld_user) { $vals['user'] = $row->rc_user_text; } if ($this->fld_userid) { $vals['userid'] = $row->rc_user; } if (!$row->rc_user) { $vals['anon'] = ''; } } /* Add flags, such as new, minor, bot. */ if ($this->fld_flags) { if ($row->rc_bot) { $vals['bot'] = ''; } if ($row->rc_type == RC_NEW) { $vals['new'] = ''; } if ($row->rc_minor) { $vals['minor'] = ''; } } /* Add sizes of each revision. (Only available on 1.10+) */ if ($this->fld_sizes) { $vals['oldlen'] = intval($row->rc_old_len); $vals['newlen'] = intval($row->rc_new_len); } /* Add the timestamp. */ if ($this->fld_timestamp) { $vals['timestamp'] = wfTimestamp(TS_ISO_8601, $row->rc_timestamp); } /* Add edit summary / log summary. */ if ($this->fld_comment && isset($row->rc_comment)) { $vals['comment'] = $row->rc_comment; } if ($this->fld_parsedcomment && isset($row->rc_comment)) { $vals['parsedcomment'] = Linker::formatComment($row->rc_comment, $title); } if ($this->fld_redirect) { if ($row->page_is_redirect) { $vals['redirect'] = ''; } } /* Add the patrolled flag */ if ($this->fld_patrolled && $row->rc_patrolled == 1) { $vals['patrolled'] = ''; } if ($this->fld_loginfo && $row->rc_type == RC_LOG) { $vals['logid'] = intval($row->rc_logid); $vals['logtype'] = $row->rc_log_type; $vals['logaction'] = $row->rc_log_action; $logEntry = DatabaseLogEntry::newFromRow((array) $row); ApiQueryLogEvents::addLogParams($this->getResult(), $vals, $logEntry->getParameters(), $logEntry->getType(), $logEntry->getSubtype(), $logEntry->getTimestamp()); } if ($this->fld_tags) { if ($row->ts_tags) { $tags = explode(',', $row->ts_tags); $this->getResult()->setIndexedTagName($tags, 'tag'); $vals['tags'] = $tags; } else { $vals['tags'] = array(); } } if (!is_null($this->token)) { $tokenFunctions = $this->getTokenFunctions(); foreach ($this->token as $t) { $val = call_user_func($tokenFunctions[$t], $row->rc_cur_id, $title, RecentChange::newFromRow($row)); if ($val === false) { $this->setWarning("Action '{$t}' is not allowed for the current user"); } else { $vals[$t . 'token'] = $val; } } } return $vals; }