protected function autoreview_current(User $user)
 {
     $this->output("Auto-reviewing all current page versions...\n");
     if (!$user->getID()) {
         $this->output("Invalid user specified.\n");
         return;
     } elseif (!$user->isAllowed('review')) {
         $this->output("User specified (id: {$user->getID()}) does not have \"review\" rights.\n");
         return;
     }
     $db = wfGetDB(DB_MASTER);
     $this->output("Reviewer username: "******"\n");
     $start = $db->selectField('page', 'MIN(page_id)', false, __METHOD__);
     $end = $db->selectField('page', 'MAX(page_id)', false, __METHOD__);
     if (is_null($start) || is_null($end)) {
         $this->output("...page table seems to be empty.\n");
         return;
     }
     # Do remaining chunk
     $end += $this->mBatchSize - 1;
     $blockStart = $start;
     $blockEnd = $start + $this->mBatchSize - 1;
     $count = 0;
     $changed = 0;
     $flags = FlaggedRevs::quickTags(FR_CHECKED);
     // Assume basic level
     while ($blockEnd <= $end) {
         $this->output("...doing page_id from {$blockStart} to {$blockEnd}\n");
         $res = $db->select(array('page', 'revision'), '*', array("page_id BETWEEN {$blockStart} AND {$blockEnd}", 'page_namespace' => FlaggedRevs::getReviewNamespaces(), 'rev_id = page_latest'), __METHOD__);
         # Go through and autoreview the current version of every page...
         foreach ($res as $row) {
             $title = Title::newFromRow($row);
             $rev = Revision::newFromRow($row);
             # Is it already reviewed?
             $frev = FlaggedRevision::newFromTitle($title, $row->page_latest, FR_MASTER);
             # Rev should exist, but to be safe...
             if (!$frev && $rev) {
                 $article = new Article($title);
                 $db->begin();
                 FlaggedRevs::autoReviewEdit($article, $user, $rev, $flags, true);
                 FlaggedRevs::HTMLCacheUpdates($article->getTitle());
                 $db->commit();
                 $changed++;
             }
             $count++;
         }
         $db->freeResult($res);
         $blockStart += $this->mBatchSize - 1;
         $blockEnd += $this->mBatchSize - 1;
         // XXX: Don't let deferred jobs array get absurdly large (bug 24375)
         DeferredUpdates::doUpdates('commit');
         wfWaitForSlaves(5);
     }
     $this->output("Auto-reviewing of all pages complete ..." . "{$count} rows [{$changed} changed]\n");
 }
 protected function feedItem($row)
 {
     $title = Title::makeTitle(intval($row->page_namespace), $row->page_title);
     if ($title && $title->userCan('read', $this->getUser())) {
         $date = $row->rev_timestamp;
         $comments = $title->getTalkPage()->getFullURL();
         $revision = Revision::newFromRow($row);
         return new FeedItem($title->getPrefixedText(), $this->feedItemDesc($revision), $title->getFullURL(), $date, $this->feedItemAuthor($revision), $comments);
     }
     return null;
 }
 public function run()
 {
     $page = WikiPage::newFromID($this->params['pageId'], WikiPage::READ_LATEST);
     if (!$page) {
         $this->setLastError("Could not find page #{$this->params['pageId']}");
         return false;
         // deleted?
     }
     $dbw = wfGetDB(DB_MASTER);
     // Use a named lock so that jobs for this page see each others' changes
     $fname = __METHOD__;
     $lockKey = "CategoryMembershipUpdates:{$page->getId()}";
     if (!$dbw->lock($lockKey, $fname, 10)) {
         $this->setLastError("Could not acquire lock '{$lockKey}'");
         return false;
     }
     $unlocker = new ScopedCallback(function () use($dbw, $lockKey, $fname) {
         $dbw->unlock($lockKey, $fname);
     });
     // Sanity: clear any DB transaction snapshot
     $dbw->commit(__METHOD__, 'flush');
     $cutoffUnix = wfTimestamp(TS_UNIX, $this->params['revTimestamp']);
     // Using ENQUEUE_FUDGE_SEC handles jobs inserted out of revision order due to the delay
     // between COMMIT and actual enqueueing of the CategoryMembershipChangeJob job.
     $cutoffUnix -= self::ENQUEUE_FUDGE_SEC;
     // Get the newest revision that has a SRC_CATEGORIZE row...
     $row = $dbw->selectRow(array('revision', 'recentchanges'), array('rev_timestamp', 'rev_id'), array('rev_page' => $page->getId(), 'rev_timestamp >= ' . $dbw->addQuotes($dbw->timestamp($cutoffUnix))), __METHOD__, array('ORDER BY' => 'rev_timestamp DESC, rev_id DESC'), array('recentchanges' => array('INNER JOIN', array('rc_this_oldid = rev_id', 'rc_source' => RecentChange::SRC_CATEGORIZE, 'rc_cur_id = rev_page', 'rc_timestamp >= rev_timestamp'))));
     // Only consider revisions newer than any such revision
     if ($row) {
         $cutoffUnix = wfTimestamp(TS_UNIX, $row->rev_timestamp);
         $lastRevId = (int) $row->rev_id;
     } else {
         $lastRevId = 0;
     }
     // Find revisions to this page made around and after this revision which lack category
     // notifications in recent changes. This lets jobs pick up were the last one left off.
     $encCutoff = $dbw->addQuotes($dbw->timestamp($cutoffUnix));
     $res = $dbw->select('revision', Revision::selectFields(), array('rev_page' => $page->getId(), "rev_timestamp > {$encCutoff}" . " OR (rev_timestamp = {$encCutoff} AND rev_id > {$lastRevId})"), __METHOD__, array('ORDER BY' => 'rev_timestamp ASC, rev_id ASC'));
     // Apply all category updates in revision timestamp order
     foreach ($res as $row) {
         $this->notifyUpdatesForRevision($page, Revision::newFromRow($row));
     }
     ScopedCallback::consume($unlocker);
     return true;
 }
Esempio n. 4
0
	/**
	 * Get the Revision object of the oldest revision
	 * @return Revision|null
	 */
	public function getOldestRevision() {
		wfProfileIn( __METHOD__ );

		// Try using the slave database first, then try the master
		$continue = 2;
		$db = wfGetDB( DB_SLAVE );
		$revSelectFields = Revision::selectFields();

		$row = null;
		while ( $continue ) {
			$row = $db->selectRow(
				array( 'page', 'revision' ),
				$revSelectFields,
				array(
					'page_namespace' => $this->mTitle->getNamespace(),
					'page_title' => $this->mTitle->getDBkey(),
					'rev_page = page_id'
				),
				__METHOD__,
				array(
					'ORDER BY' => 'rev_timestamp ASC'
				)
			);

			if ( $row ) {
				$continue = 0;
			} else {
				$db = wfGetDB( DB_MASTER );
				$continue--;
			}
		}

		wfProfileOut( __METHOD__ );
		return $row ? Revision::newFromRow( $row ) : null;
	}
 /**
  * @param ApiPageSet $resultPageSet
  * @return void
  */
 protected function run(ApiPageSet $resultPageSet = null)
 {
     $db = $this->getDB();
     $params = $this->extractRequestParams(false);
     $result = $this->getResult();
     $this->requireMaxOneParameter($params, 'user', 'excludeuser');
     // Namespace check is likely to be desired, but can't be done
     // efficiently in SQL.
     $miser_ns = null;
     $needPageTable = false;
     if ($params['namespace'] !== null) {
         $params['namespace'] = array_unique($params['namespace']);
         sort($params['namespace']);
         if ($params['namespace'] != MWNamespace::getValidNamespaces()) {
             $needPageTable = true;
             if ($this->getConfig()->get('MiserMode')) {
                 $miser_ns = $params['namespace'];
             } else {
                 $this->addWhere(array('page_namespace' => $params['namespace']));
             }
         }
     }
     $this->addTables('revision');
     if ($resultPageSet === null) {
         $this->parseParameters($params);
         $this->addTables('page');
         $this->addJoinConds(array('page' => array('INNER JOIN', array('rev_page = page_id'))));
         $this->addFields(Revision::selectFields());
         $this->addFields(Revision::selectPageFields());
         // Review this depeneding on the outcome of T113901
         $this->addOption('STRAIGHT_JOIN');
     } else {
         $this->limit = $this->getParameter('limit') ?: 10;
         $this->addFields(array('rev_timestamp', 'rev_id'));
         if ($params['generatetitles']) {
             $this->addFields(array('rev_page'));
         }
         if ($needPageTable) {
             $this->addTables('page');
             $this->addJoinConds(array('page' => array('INNER JOIN', array('rev_page = page_id'))));
             $this->addFieldsIf(array('page_namespace'), (bool) $miser_ns);
             // Review this depeneding on the outcome of T113901
             $this->addOption('STRAIGHT_JOIN');
         }
     }
     if ($this->fld_tags) {
         $this->addTables('tag_summary');
         $this->addJoinConds(array('tag_summary' => array('LEFT JOIN', array('rev_id=ts_rev_id'))));
         $this->addFields('ts_tags');
     }
     if ($this->fetchContent) {
         $this->addTables('text');
         $this->addJoinConds(array('text' => array('INNER JOIN', array('rev_text_id=old_id'))));
         $this->addFields('old_id');
         $this->addFields(Revision::selectTextFields());
     }
     if ($params['user'] !== null) {
         $id = User::idFromName($params['user']);
         if ($id) {
             $this->addWhereFld('rev_user', $id);
         } else {
             $this->addWhereFld('rev_user_text', $params['user']);
         }
     } elseif ($params['excludeuser'] !== null) {
         $id = User::idFromName($params['excludeuser']);
         if ($id) {
             $this->addWhere('rev_user != ' . $id);
         } else {
             $this->addWhere('rev_user_text != ' . $db->addQuotes($params['excludeuser']));
         }
     }
     if ($params['user'] !== null || $params['excludeuser'] !== null) {
         // Paranoia: avoid brute force searches (bug 17342)
         if (!$this->getUser()->isAllowed('deletedhistory')) {
             $bitmask = Revision::DELETED_USER;
         } elseif (!$this->getUser()->isAllowedAny('suppressrevision', 'viewsuppressed')) {
             $bitmask = Revision::DELETED_USER | Revision::DELETED_RESTRICTED;
         } else {
             $bitmask = 0;
         }
         if ($bitmask) {
             $this->addWhere($db->bitAnd('rev_deleted', $bitmask) . " != {$bitmask}");
         }
     }
     $dir = $params['dir'];
     if ($params['continue'] !== null) {
         $op = $dir == 'newer' ? '>' : '<';
         $cont = explode('|', $params['continue']);
         $this->dieContinueUsageIf(count($cont) != 2);
         $ts = $db->addQuotes($db->timestamp($cont[0]));
         $rev_id = (int) $cont[1];
         $this->dieContinueUsageIf(strval($rev_id) !== $cont[1]);
         $this->addWhere("rev_timestamp {$op} {$ts} OR " . "(rev_timestamp = {$ts} AND " . "rev_id {$op}= {$rev_id})");
     }
     $this->addOption('LIMIT', $this->limit + 1);
     $sort = $dir == 'newer' ? '' : ' DESC';
     $orderby = array();
     // Targeting index rev_timestamp, user_timestamp, or usertext_timestamp
     // But 'user' is always constant for the latter two, so it doesn't matter here.
     $orderby[] = "rev_timestamp {$sort}";
     $orderby[] = "rev_id {$sort}";
     $this->addOption('ORDER BY', $orderby);
     $res = $this->select(__METHOD__);
     $pageMap = array();
     // Maps rev_page to array index
     $count = 0;
     $nextIndex = 0;
     $generated = array();
     foreach ($res as $row) {
         if (++$count > $this->limit) {
             // We've had enough
             $this->setContinueEnumParameter('continue', "{$row->rev_timestamp}|{$row->rev_id}");
             break;
         }
         // Miser mode namespace check
         if ($miser_ns !== null && !in_array($row->page_namespace, $miser_ns)) {
             continue;
         }
         if ($resultPageSet !== null) {
             if ($params['generatetitles']) {
                 $generated[$row->rev_page] = $row->rev_page;
             } else {
                 $generated[] = $row->rev_id;
             }
         } else {
             $revision = Revision::newFromRow($row);
             $rev = $this->extractRevisionInfo($revision, $row);
             if (!isset($pageMap[$row->rev_page])) {
                 $index = $nextIndex++;
                 $pageMap[$row->rev_page] = $index;
                 $title = $revision->getTitle();
                 $a = array('pageid' => $title->getArticleID(), 'revisions' => array($rev));
                 ApiResult::setIndexedTagName($a['revisions'], 'rev');
                 ApiQueryBase::addTitleInfo($a, $title);
                 $fit = $result->addValue(array('query', $this->getModuleName()), $index, $a);
             } else {
                 $index = $pageMap[$row->rev_page];
                 $fit = $result->addValue(array('query', $this->getModuleName(), $index, 'revisions'), null, $rev);
             }
             if (!$fit) {
                 $this->setContinueEnumParameter('continue', "{$row->rev_timestamp}|{$row->rev_id}");
                 break;
             }
         }
     }
     if ($resultPageSet !== null) {
         if ($params['generatetitles']) {
             $resultPageSet->populateFromPageIDs($generated);
         } else {
             $resultPageSet->populateFromRevisionIDs($generated);
         }
     } else {
         $result->addIndexedTagName(array('query', $this->getModuleName()), 'page');
     }
 }
 protected function feedItem($row)
 {
     // This hook is the api contributions equivalent to the
     // ContributionsLineEnding hook. Hook implementers may cancel
     // the hook to signal the user is not allowed to read this item.
     $feedItem = null;
     $hookResult = Hooks::run('ApiFeedContributions::feedItem', array($row, $this->getContext(), &$feedItem));
     // Hook returned a valid feed item
     if ($feedItem instanceof FeedItem) {
         return $feedItem;
         // Hook was canceled and did not return a valid feed item
     } elseif (!$hookResult) {
         return null;
     }
     // Hook completed and did not return a valid feed item
     $title = Title::makeTitle(intval($row->page_namespace), $row->page_title);
     if ($title && $title->userCan('read', $this->getUser())) {
         $date = $row->rev_timestamp;
         $comments = $title->getTalkPage()->getFullURL();
         $revision = Revision::newFromRow($row);
         return new FeedItem($title->getPrefixedText(), $this->feedItemDesc($revision), $title->getFullURL(array('diff' => $revision->getId())), $date, $this->feedItemAuthor($revision), $comments);
     }
     return null;
 }
Esempio n. 7
0
 /**
  * Get the Revision object of the oldest revision
  * @return Revision|null
  */
 public function getOldestRevision()
 {
     // Try using the replica DB first, then try the master
     $continue = 2;
     $db = wfGetDB(DB_REPLICA);
     $revSelectFields = Revision::selectFields();
     $row = null;
     while ($continue) {
         $row = $db->selectRow(['page', 'revision'], $revSelectFields, ['page_namespace' => $this->mTitle->getNamespace(), 'page_title' => $this->mTitle->getDBkey(), 'rev_page = page_id'], __METHOD__, ['ORDER BY' => 'rev_timestamp ASC']);
         if ($row) {
             $continue = 0;
         } else {
             $db = wfGetDB(DB_MASTER);
             $continue--;
         }
     }
     return $row ? Revision::newFromRow($row) : null;
 }
 /**
  * @covers Revision::newFromRow
  */
 public function testNewFromRow()
 {
     $orig = $this->makeRevision();
     $dbr = wfGetDB(DB_SLAVE);
     $res = $dbr->select('revision', '*', ['rev_id' => $orig->getId()]);
     $this->assertTrue(is_object($res), 'query failed');
     $row = $res->fetchObject();
     $res->free();
     $rev = Revision::newFromRow($row);
     $this->assertRevEquals($orig, $rev);
 }
 public function run()
 {
     $page = WikiPage::newFromID($this->params['pageId'], WikiPage::READ_LATEST);
     if (!$page) {
         $this->setLastError("Could not find page #{$this->params['pageId']}");
         return false;
         // deleted?
     }
     $dbw = wfGetDB(DB_MASTER);
     // Use a named lock so that jobs for this page see each others' changes
     $lockKey = "CategoryMembershipUpdates:{$page->getId()}";
     $scopedLock = $dbw->getScopedLockAndFlush($lockKey, __METHOD__, 10);
     if (!$scopedLock) {
         $this->setLastError("Could not acquire lock '{$lockKey}'");
         return false;
     }
     $dbr = wfGetDB(DB_SLAVE, ['recentchanges']);
     // Wait till the slave is caught up so that jobs for this page see each others' changes
     if (!wfGetLB()->safeWaitForMasterPos($dbr)) {
         $this->setLastError("Timed out while waiting for slave to catch up");
         return false;
     }
     // Clear any stale REPEATABLE-READ snapshot
     $dbr->commit(__METHOD__, 'flush');
     $cutoffUnix = wfTimestamp(TS_UNIX, $this->params['revTimestamp']);
     // Using ENQUEUE_FUDGE_SEC handles jobs inserted out of revision order due to the delay
     // between COMMIT and actual enqueueing of the CategoryMembershipChangeJob job.
     $cutoffUnix -= self::ENQUEUE_FUDGE_SEC;
     // Get the newest revision that has a SRC_CATEGORIZE row...
     $row = $dbr->selectRow(['revision', 'recentchanges'], ['rev_timestamp', 'rev_id'], ['rev_page' => $page->getId(), 'rev_timestamp >= ' . $dbr->addQuotes($dbr->timestamp($cutoffUnix))], __METHOD__, ['ORDER BY' => 'rev_timestamp DESC, rev_id DESC'], ['recentchanges' => ['INNER JOIN', ['rc_this_oldid = rev_id', 'rc_source' => RecentChange::SRC_CATEGORIZE, 'rc_cur_id = rev_page', 'rc_timestamp >= rev_timestamp']]]);
     // Only consider revisions newer than any such revision
     if ($row) {
         $cutoffUnix = wfTimestamp(TS_UNIX, $row->rev_timestamp);
         $lastRevId = (int) $row->rev_id;
     } else {
         $lastRevId = 0;
     }
     // Find revisions to this page made around and after this revision which lack category
     // notifications in recent changes. This lets jobs pick up were the last one left off.
     $encCutoff = $dbr->addQuotes($dbr->timestamp($cutoffUnix));
     $res = $dbr->select('revision', Revision::selectFields(), ['rev_page' => $page->getId(), "rev_timestamp > {$encCutoff}" . " OR (rev_timestamp = {$encCutoff} AND rev_id > {$lastRevId})"], __METHOD__, ['ORDER BY' => 'rev_timestamp ASC, rev_id ASC']);
     // Apply all category updates in revision timestamp order
     foreach ($res as $row) {
         $this->notifyUpdatesForRevision($page, Revision::newFromRow($row));
     }
     return true;
 }
Esempio n. 10
0
 protected function loadWikiMessages()
 {
     $dbr = wfGetDB(DB_SLAVE, array());
     echo "Loading page list...\n";
     $res = $dbr->select('page', '*', array('page_namespace' => NS_MEDIAWIKI), 'evaluate_messaging.php');
     $rows = array();
     $byRev = array();
     foreach ($res as $row) {
         $rows[] = $row;
         $byRev[$row->page_latest] = false;
     }
     $res->free();
     echo "Loading revisions...\n";
     $res = $dbr->select('revision', '*', array('rev_id' => array_keys($byRev)), 'evaluate_messaging.php');
     foreach ($res as $row) {
         $byRev[$row->rev_id] = $row;
     }
     $res->free();
     echo "Loading contents...\n";
     $i = 0;
     $messages = array();
     foreach ($rows as $row) {
         list($key, $langcode) = MessageCache::singleton()->figureMessage($row->page_title);
         $revision = Revision::newFromRow($byRev[$row->page_latest]);
         $content = $revision->getRawText();
         $messages[$langcode][lcfirst($key)] = $content;
         if (++$i % 100 == 0) {
             echo ".";
             flush();
         }
     }
     echo "\n";
     $this->wikiMessages = $messages;
     $this->saveToFile(self::WIKI_MESSAGES_CACHE, $messages);
 }
 /**
  * Fetch an article from this or another local MediaWiki database.
  * This is probably *very* fragile, and shouldn't be used perhaps.
  *
  * @param string $wiki
  * @param string $article
  * @return string
  */
 function getArticleText($wiki, $article)
 {
     wfDebugLog('SpamBlacklist', "Fetching {$this->getBlacklistType()} blacklist from '{$article}' on '{$wiki}'...\n");
     $title = Title::newFromText($article);
     // Load all the relevant tables from the correct DB.
     // This assumes that old_text is the actual text or
     // that the external store system is at least unified.
     $row = wfGetDB(DB_SLAVE, array(), $wiki)->selectRow(array('page', 'revision', 'text'), array_merge(Revision::selectFields(), Revision::selectPageFields(), Revision::selectTextFields()), array('page_namespace' => $title->getNamespace(), 'page_title' => $title->getDBkey(), 'rev_id=page_latest', 'old_id=rev_text_id'), __METHOD__);
     return $row ? Revision::newFromRow($row)->getText() : false;
 }