private function makeRecentChange($attribs, $counter, $watchingUsers) { $change = new RecentChange(); $change->setAttribs($attribs); $change->counter = $counter; $change->numberofWatchingusers = $watchingUsers; return $change; }
/** * Generates a notification that can be easily interpreted by a machine. * @see RCFeedFormatter::getLine */ public function getLine(array $feed, RecentChange $rc, $actionComment) { global $wgCanonicalServer, $wgScriptPath; $attrib = $rc->getAttributes(); $packet = array('id' => $attrib['rc_id'], 'type' => $attrib['rc_type'], 'namespace' => $rc->getTitle()->getNamespace(), 'title' => $rc->getTitle()->getPrefixedText(), 'comment' => $attrib['rc_comment'], 'timestamp' => (int) wfTimestamp(TS_UNIX, $attrib['rc_timestamp']), 'user' => $attrib['rc_user_text'], 'bot' => (bool) $attrib['rc_bot']); if (isset($feed['channel'])) { $packet['channel'] = $feed['channel']; } $type = $attrib['rc_type']; if ($type == RC_EDIT || $type == RC_NEW) { global $wgUseRCPatrol, $wgUseNPPatrol; $packet['minor'] = $attrib['rc_minor']; if ($wgUseRCPatrol || $type == RC_NEW && $wgUseNPPatrol) { $packet['patrolled'] = $attrib['rc_patrolled']; } } switch ($type) { case RC_EDIT: $packet['length'] = array('old' => $attrib['rc_old_len'], 'new' => $attrib['rc_new_len']); $packet['revision'] = array('old' => $attrib['rc_last_oldid'], 'new' => $attrib['rc_this_oldid']); break; case RC_NEW: $packet['length'] = array('old' => null, 'new' => $attrib['rc_new_len']); $packet['revision'] = array('old' => null, 'new' => $attrib['rc_this_oldid']); break; case RC_LOG: $packet['log_type'] = $attrib['rc_log_type']; $packet['log_action'] = $attrib['rc_log_action']; if ($attrib['rc_params']) { wfSuppressWarnings(); $params = unserialize($attrib['rc_params']); wfRestoreWarnings(); if ($attrib['rc_params'] == serialize(false) || $params !== false) { // From ApiQueryLogEvents::addLogParams $logParams = array(); // Keys like "4::paramname" can't be used for output so we change them to "paramname" foreach ($params as $key => $value) { if (strpos($key, ':') === false) { $logParams[$key] = $value; continue; } $logParam = explode(':', $key, 3); $logParams[$logParam[2]] = $value; } $packet['log_params'] = $logParams; } else { $packet['log_params'] = explode("\n", $attrib['rc_params']); } } $packet['log_action_comment'] = $actionComment; break; } $packet['server_url'] = $wgCanonicalServer; $packet['server_script_path'] = $wgScriptPath ?: '/'; $packet['wiki'] = wfWikiID(); return $this->formatArray($packet); }
/** * @param RecentChange $rc * @param string[] &$classes * @param bool $watched * * @return string */ private function formatChangeLine(RecentChange $rc, array &$classes, $watched) { $html = ''; if ($rc->mAttribs['rc_log_type']) { $logtitle = SpecialPage::getTitleFor('Log', $rc->mAttribs['rc_log_type']); $this->insertLog($html, $logtitle, $rc->mAttribs['rc_log_type']); // Log entries (old format) or log targets, and special pages } elseif ($rc->mAttribs['rc_namespace'] == NS_SPECIAL) { list($name, $htmlubpage) = SpecialPageFactory::resolveAlias($rc->mAttribs['rc_title']); if ($name == 'Log') { $this->insertLog($html, $rc->getTitle(), $htmlubpage); } // Regular entries } else { $unpatrolled = $this->showAsUnpatrolled($rc); $this->insertDiffHist($html, $rc, $unpatrolled); # M, N, b and ! (minor, new, bot and unpatrolled) $html .= $this->recentChangesFlags(array('newpage' => $rc->mAttribs['rc_type'] == RC_NEW, 'minor' => $rc->mAttribs['rc_minor'], 'unpatrolled' => $unpatrolled, 'bot' => $rc->mAttribs['rc_bot']), ''); $this->insertArticleLink($html, $rc, $unpatrolled, $watched); } # Edit/log timestamp $this->insertTimestamp($html, $rc); # Bytes added or removed if ($this->getConfig()->get('RCShowChangedSize')) { $cd = $this->formatCharacterDifference($rc); if ($cd !== '') { $html .= $cd . ' <span class="mw-changeslist-separator">. .</span> '; } } if ($rc->mAttribs['rc_type'] == RC_LOG) { $html .= $this->insertLogEntry($rc); } elseif ($this->isCategorizationWithoutRevision($rc)) { $html .= $this->insertComment($rc); } else { # User tool links $this->insertUserRelatedLinks($html, $rc); # LTR/RTL direction mark $html .= $this->getLanguage()->getDirMark(); $html .= $this->insertComment($rc); } # Tags $this->insertTags($html, $rc, $classes); # Rollback $this->insertRollback($html, $rc); # For subclasses $this->insertExtra($html, $rc, $classes); # How many users watch this page if ($rc->numberofWatchingusers > 0) { $html .= ' ' . $this->numberofWatchingusers($rc->numberofWatchingusers); } return $html; }
protected function saveContent() { global $wgLogRestrictions; $dbw = wfGetDB(DB_MASTER); $log_id = $dbw->nextSequenceValue('logging_log_id_seq'); $this->timestamp = $now = wfTimestampNow(); $data = array('log_id' => $log_id, 'log_type' => $this->type, 'log_action' => $this->action, 'log_timestamp' => $dbw->timestamp($now), 'log_user' => $this->doer->getId(), 'log_user_text' => $this->doer->getName(), 'log_namespace' => $this->target->getNamespace(), 'log_title' => $this->target->getDBkey(), 'log_page' => $this->target->getArticleId(), 'log_comment' => $this->comment, 'log_params' => $this->params); $dbw->insert('logging', $data, __METHOD__); $newId = !is_null($log_id) ? $log_id : $dbw->insertId(); # And update recentchanges if ($this->updateRecentChanges) { $titleObj = SpecialPage::getTitleFor('Log', $this->type); RecentChange::notifyLog($now, $titleObj, $this->doer, $this->getRcComment(), '', $this->type, $this->action, $this->target, $this->comment, $this->params, $newId); } else { if ($this->sendToUDP) { # Don't send private logs to UDP if (isset($wgLogRestrictions[$this->type]) && $wgLogRestrictions[$this->type] != '*') { return true; } # Notify external application via UDP. # We send this to IRC but do not want to add it the RC table. $titleObj = SpecialPage::getTitleFor('Log', $this->type); $rc = RecentChange::newLogEntry($now, $titleObj, $this->doer, $this->getRcComment(), '', $this->type, $this->action, $this->target, $this->comment, $this->params, $newId); $rc->notifyRC2UDP(); } } return $newId; }
function saveContent() { if (wfReadOnly()) { return false; } global $wgUser; $fname = 'LogPage::saveContent'; $dbw =& wfGetDB(DB_MASTER); $uid = $wgUser->getID(); $this->timestamp = $now = wfTimestampNow(); $dbw->insert('logging', array('log_type' => $this->type, 'log_action' => $this->action, 'log_timestamp' => $dbw->timestamp($now), 'log_user' => $uid, 'log_namespace' => $this->target->getNamespace(), 'log_title' => $this->target->getDBkey(), 'log_comment' => $this->comment, 'log_params' => $this->params), $fname); # And update recentchanges if ($this->updateRecentChanges) { $titleObj = Title::makeTitle(NS_SPECIAL, 'Log/' . $this->type); $rcComment = $this->actionText; if ('' != $this->comment) { if ($rcComment == '') { $rcComment = $this->comment; } else { $rcComment .= ': ' . $this->comment; } } RecentChange::notifyLog($now, $titleObj, $wgUser, $rcComment, '', $this->type, $this->action, $this->target, $this->comment, $this->params); } return true; }
/** * Patrols the article or provides the reason the patrol failed. */ public function execute() { global $wgUser, $wgUseRCPatrol, $wgUseNPPatrol; $this->getMain()->requestWriteMode(); $params = $this->extractRequestParams(); if (!isset($params['token'])) { $this->dieUsageMsg(array('missingparam', 'token')); } if (!isset($params['rcid'])) { $this->dieUsageMsg(array('missingparam', 'rcid')); } if (!$wgUser->matchEditToken($params['token'])) { $this->dieUsageMsg(array('sessionfailure')); } $rc = RecentChange::newFromID($params['rcid']); if (!$rc instanceof RecentChange) { $this->dieUsageMsg(array('nosuchrcid', $params['rcid'])); } $retval = RecentChange::markPatrolled($params['rcid']); if ($retval) { $this->dieUsageMsg(current($retval)); } $result = array('rcid' => $rc->getAttribute('rc_id')); ApiQueryBase::addTitleInfo($result, $rc->getTitle()); $this->getResult()->addValue(null, $this->getModuleName(), $result); }
/** * Record a log event for a change being patrolled * * @param $rc Mixed: change identifier or RecentChange object * @param $auto Boolean: was this patrol event automatic? * @param $user User: user performing the action or null to use $wgUser * * @return bool */ public static function record( $rc, $auto = false, User $user = null ) { global $wgLogAutopatrol; // do not log autopatrolled edits if setting disables it if ( $auto && !$wgLogAutopatrol ) { return false; } if ( !$rc instanceof RecentChange ) { $rc = RecentChange::newFromId( $rc ); if ( !is_object( $rc ) ) { return false; } } if ( !$user ) { global $wgUser; $user = $wgUser; } $entry = new ManualLogEntry( 'patrol', 'patrol' ); $entry->setTarget( $rc->getTitle() ); $entry->setParameters( self::buildParams( $rc, $auto ) ); $entry->setPerformer( $user ); $logid = $entry->insert(); if ( !$auto ) { $entry->publish( $logid, 'udp' ); } return true; }
/** * Patrols the article or provides the reason the patrol failed. */ public function execute() { $params = $this->extractRequestParams(); $this->requireOnlyOneParameter($params, 'rcid', 'revid'); if (isset($params['rcid'])) { $rc = RecentChange::newFromID($params['rcid']); if (!$rc) { $this->dieUsageMsg(array('nosuchrcid', $params['rcid'])); } } else { $rev = Revision::newFromId($params['revid']); if (!$rev) { $this->dieUsageMsg(array('nosuchrevid', $params['revid'])); } $rc = $rev->getRecentChange(); if (!$rc) { $this->dieUsage('The revision ' . $params['revid'] . " can't be patrolled as it's too old", 'notpatrollable'); } } $retval = $rc->doMarkPatrolled($this->getUser()); if ($retval) { $this->dieUsageMsg(reset($retval)); } $result = array('rcid' => intval($rc->getAttribute('rc_id'))); ApiQueryBase::addTitleInfo($result, $rc->getTitle()); $this->getResult()->addValue(null, $this->getModuleName(), $result); }
function saveContent() { if (wfReadOnly()) { return false; } global $wgUser; $fname = 'LogPage::saveContent'; $dbw = wfGetDB(DB_MASTER); $uid = $wgUser->getID(); $log_id = $dbw->nextSequenceValue('log_log_id_seq'); $this->timestamp = $now = wfTimestampNow(); $data = array('log_type' => $this->type, 'log_action' => $this->action, 'log_timestamp' => $dbw->timestamp($now), 'log_user' => $uid, 'log_namespace' => $this->target->getNamespace(), 'log_title' => $this->target->getDBkey(), 'log_comment' => $this->comment, 'log_params' => $this->params); # log_id doesn't exist on Wikimedia servers yet, and it's a tricky # schema update to do. Hack it for now to ignore the field on MySQL. if (!is_null($log_id)) { $data['log_id'] = $log_id; } $dbw->insert('logging', $data, $fname); # And update recentchanges if ($this->updateRecentChanges) { $titleObj = SpecialPage::getTitleFor('Log', $this->type); $rcComment = $this->getRcComment(); RecentChange::notifyLog($now, $titleObj, $wgUser, $rcComment, '', $this->type, $this->action, $this->target, $this->comment, $this->params); } return true; }
public function onView() { $rc = RecentChange::newFromId($this->getRequest()->getInt('rcid')); if (is_null($rc)) { throw new ErrorPageError('markedaspatrollederror', 'markedaspatrollederrortext'); } $errors = $rc->doMarkPatrolled($this->getUser()); if (in_array(array('rcpatroldisabled'), $errors)) { throw new ErrorPageError('rcpatroldisabled', 'rcpatroldisabledtext'); } if (in_array(array('hookaborted'), $errors)) { // The hook itself has handled any output return; } # It would be nice to see where the user had actually come from, but for now just guess $returnto = $rc->getAttribute('rc_type') == RC_NEW ? 'Newpages' : 'Recentchanges'; $return = SpecialPage::getTitleFor($returnto); if (in_array(array('markedaspatrollederror-noautopatrol'), $errors)) { $this->getOutput()->setPageTitle(wfMsg('markedaspatrollederror')); $this->getOutput()->addWikiMsg('markedaspatrollederror-noautopatrol'); $this->getOutput()->returnToMain(null, $return); return; } if (!empty($errors)) { $this->getOutput()->showPermissionsErrorPage($errors); return; } # Inform the user $this->getOutput()->setPageTitle(wfMsg('markedaspatrolled')); $this->getOutput()->addWikiMsg('markedaspatrolledtext', $rc->getTitle()->getPrefixedText()); $this->getOutput()->returnToMain(null, $return); }
/** * @see RCFeedFormatter::getLine */ public function getLine(array $feed, RecentChange $rc, $actionComment) { global $wgWWRCFeedHideLogs, $wgWWRCFeedHideNamespaces; $attribs = $rc->getAttributes(); if ($attribs['rc_type'] == RC_LOG) { $title = Title::newFromText('Log/' . $attribs['rc_log_type'], NS_SPECIAL); } else { $title =& $rc->getTitle(); } if ($attribs['rc_type'] == RC_LOG && in_array($attribs['rc_log_type'], $wgWWRCFeedHideLogs)) { return null; } elseif (in_array($title->getNamespace(), $wgWWRCFeedHideNamespaces)) { return null; } // if we aren't hiding it, let the core class do all the heavy lifting return parent::getLine($feed, $rc, $actionComment); }
function wfMarkUndoneEditAsPatrolled() { global $wgRequest; if ($wgRequest->getVal('wpUndoEdit', null) != null) { $oldid = $wgRequest->getVal('wpUndoEdit'); // using db master to avoid db replication lag $dbr = wfGetDB(DB_MASTER); $rcid = $dbr->selectField('recentchanges', 'rc_id', array('rc_this_oldid' => $oldid)); RecentChange::markPatrolled($rcid); PatrolLog::record($rcid, false); } return true; }
function doTest() { // Quick syntax check. $out = $this->getOutput(); $result = AbuseFilter::checkSyntax($this->mFilter); if ($result !== true) { $out->addWikiMsg('abusefilter-test-syntaxerr'); return; } $dbr = wfGetDB(DB_SLAVE); $conds = array('rc_user_text' => $this->mTestUser, 'rc_type != ' . RC_EXTERNAL); if ($this->mTestPeriodStart) { $conds[] = 'rc_timestamp >= ' . $dbr->addQuotes($dbr->timestamp(strtotime($this->mTestPeriodStart))); } if ($this->mTestPeriodEnd) { $conds[] = 'rc_timestamp <= ' . $dbr->addQuotes($dbr->timestamp(strtotime($this->mTestPeriodEnd))); } if ($this->mTestPage) { $title = Title::newFromText($this->mTestPage); if ($title instanceof Title) { $conds['rc_namespace'] = $title->getNamespace(); $conds['rc_title'] = $title->getDBkey(); } else { $out->addWikiMsg('abusefilter-test-badtitle'); return; } } // Get our ChangesList $changesList = new AbuseFilterChangesList($this->getSkin()); $output = $changesList->beginRecentChangesList(); $res = $dbr->select('recentchanges', '*', array_filter($conds), __METHOD__, array('LIMIT' => self::$mChangeLimit, 'ORDER BY' => 'rc_timestamp desc')); $counter = 1; foreach ($res as $row) { $vars = AbuseFilter::getVarsFromRCRow($row); if (!$vars) { continue; } $result = AbuseFilter::checkConditions($this->mFilter, $vars); if ($result || $this->mShowNegative) { // Stash result in RC item $rc = RecentChange::newFromRow($row); $rc->examineParams['testfilter'] = $this->mFilter; $rc->filterResult = $result; $rc->counter = $counter++; $output .= $changesList->recentChangesLine($rc, false); } } $output .= $changesList->endRecentChangesList(); $out->addHTML($output); }
/** * Patrols the article or provides the reason the patrol failed. */ public function execute() { $params = $this->extractRequestParams(); $rc = RecentChange::newFromID($params['rcid']); if (!$rc instanceof RecentChange) { $this->dieUsageMsg(array('nosuchrcid', $params['rcid'])); } $retval = $rc->doMarkPatrolled($this->getUser()); if ($retval) { $this->dieUsageMsg(reset($retval)); } $result = array('rcid' => intval($rc->getAttribute('rc_id'))); ApiQueryBase::addTitleInfo($result, $rc->getTitle()); $this->getResult()->addValue(null, $this->getModuleName(), $result); }
function doEdit($edit) { // create "fake" EditPage $editor = (object) array('textbox1' => isset($edit['text']) ? $edit['text'] : ''); // try to get section name MyHome::getSectionName($editor, '', !empty($edit['section']) ? $edit['section'] : false, $errno); // create "fake" RecentChange object $row = (object) array('rev_timestamp' => time(), 'rev_user' => 1, 'rev_user_text' => 'test', 'page_namespace' => NS_MAIN, 'page_title' => 'Test', 'rev_comment' => isset($edit['comment']) ? $edit['comment'] : '', 'rev_minor_edit' => true, 'page_is_new' => !empty($edit['is_new']), 'page_id' => 1, 'rev_id' => 1, 'rc_id' => 1, 'rc_patrolled' => 1, 'rc_old_len' => 1, 'rc_new_len' => 1, 'rc_deleted' => 1, 'rc_timestamp' => time()); $rc = RecentChange::newFromCurRow($row); // call MyHome to add its data to rc object and Wikia vars MyHome::storeInRecentChanges($rc); $data = Wikia::getVar('rc_data'); unset($data['articleComment']); return $data; }
/** * Record a log event for a change being patrolled * * @param $rc Mixed: change identifier or RecentChange object * @param $auto Boolean: was this patrol event automatic? */ public static function record($rc, $auto = false) { if (!$rc instanceof RecentChange) { $rc = RecentChange::newFromId($rc); if (!is_object($rc)) { return false; } } $title = Title::makeTitleSafe($rc->getAttribute('rc_namespace'), $rc->getAttribute('rc_title')); if (is_object($title)) { $params = self::buildParams($rc, $auto); $log = new LogPage('patrol', false, $auto ? "skipUDP" : "UDP"); # False suppresses RC entries $log->addEntry('patrol', $title, '', $params); return true; } return false; }
protected function processIndividual($type, $params, $id) { $idResult = array($type => $id); // validate the ID $valid = false; switch ($type) { case 'rcid': $valid = RecentChange::newFromId($id); break; case 'revid': $valid = Revision::newFromId($id); break; case 'logid': $valid = self::validateLogId($id); break; } if (!$valid) { $idResult['status'] = 'error'; $idResult += $this->parseMsg(array("nosuch{$type}", $id)); return $idResult; } $status = ChangeTags::updateTagsWithChecks($params['add'], $params['remove'], $type === 'rcid' ? $id : null, $type === 'revid' ? $id : null, $type === 'logid' ? $id : null, null, $params['reason'], $this->getUser()); if (!$status->isOK()) { if ($status->hasMessage('actionthrottledtext')) { $idResult['status'] = 'skipped'; } else { $idResult['status'] = 'failure'; $idResult['errors'] = $this->getErrorFormatter()->arrayFromStatus($status, 'error'); } } else { $idResult['status'] = 'success'; if (is_null($status->value->logId)) { $idResult['noop'] = ''; } else { $idResult['actionlogid'] = $status->value->logId; $idResult['added'] = $status->value->addedTags; ApiResult::setIndexedTagName($idResult['added'], 't'); $idResult['removed'] = $status->value->removedTags; ApiResult::setIndexedTagName($idResult['removed'], 't'); } } return $idResult; }
public function onView() { $request = $this->getRequest(); $rcId = $request->getInt('rcid'); $rc = RecentChange::newFromId($rcId); if (is_null($rc)) { throw new ErrorPageError('markedaspatrollederror', 'markedaspatrollederrortext'); } $user = $this->getUser(); if (!$user->matchEditToken($request->getVal('token'), $rcId)) { throw new ErrorPageError('sessionfailure-title', 'sessionfailure'); } $errors = $rc->doMarkPatrolled($user); if (in_array(['rcpatroldisabled'], $errors)) { throw new ErrorPageError('rcpatroldisabled', 'rcpatroldisabledtext'); } if (in_array(['hookaborted'], $errors)) { // The hook itself has handled any output return; } # It would be nice to see where the user had actually come from, but for now just guess if ($rc->getAttribute('rc_type') == RC_NEW) { $returnTo = 'Newpages'; } elseif ($rc->getAttribute('rc_log_type') == 'upload') { $returnTo = 'Newfiles'; } else { $returnTo = 'Recentchanges'; } $return = SpecialPage::getTitleFor($returnTo); if (in_array(['markedaspatrollederror-noautopatrol'], $errors)) { $this->getOutput()->setPageTitle($this->msg('markedaspatrollederror')); $this->getOutput()->addWikiMsg('markedaspatrollederror-noautopatrol'); $this->getOutput()->returnToMain(null, $return); return; } if (count($errors)) { throw new PermissionsError('patrol', $errors); } # Inform the user $this->getOutput()->setPageTitle($this->msg('markedaspatrolled')); $this->getOutput()->addWikiMsg('markedaspatrolledtext', $rc->getTitle()->getPrefixedText()); $this->getOutput()->returnToMain(null, $return); }
/** * Record a log event for a change being patrolled * * @param $rc Mixed: change identifier or RecentChange object * @param $auto Boolean: was this patrol event automatic? * * @return bool */ public static function record($rc, $auto = false) { if (!$rc instanceof RecentChange) { $rc = RecentChange::newFromId($rc); if (!is_object($rc)) { return false; } } $title = Title::makeTitleSafe($rc->getAttribute('rc_namespace'), $rc->getAttribute('rc_title')); if ($title) { $entry = new ManualLogEntry('patrol', 'patrol'); $entry->setTarget($title); $entry->setParameters(self::buildParams($rc, $auto)); $entry->setPerformer(User::newFromName($rc->getAttribute('rc_user_text'), false)); $logid = $entry->insert(); if (!$auto) { $entry->publish($logid, 'udp'); } return true; } return false; }
protected function saveContent() { global $wgUser, $wgLogRestrictions; $fname = 'LogPage::saveContent'; $dbw = wfGetDB(DB_MASTER); $log_id = $dbw->nextSequenceValue('log_log_id_seq'); $this->timestamp = $now = wfTimestampNow(); $data = array('log_id' => $log_id, 'log_type' => $this->type, 'log_action' => $this->action, 'log_timestamp' => $dbw->timestamp($now), 'log_user' => $this->doer->getId(), 'log_namespace' => $this->target->getNamespace(), 'log_title' => $this->target->getDBkey(), 'log_comment' => $this->comment, 'log_params' => $this->params); $dbw->insert('logging', $data, $fname); $newId = !is_null($log_id) ? $log_id : $dbw->insertId(); if (!($dbw->affectedRows() > 0)) { wfDebugLog("logging", "LogPage::saveContent failed to insert row - Error {$dbw->lastErrno()}: {$dbw->lastError()}"); } # And update recentchanges if ($this->updateRecentChanges) { # Don't add private logs to RC! if (!isset($wgLogRestrictions[$this->type]) || $wgLogRestrictions[$this->type] == '*') { $titleObj = SpecialPage::getTitleFor('Log', $this->type); $rcComment = $this->getRcComment(); RecentChange::notifyLog($now, $titleObj, $this->doer, $rcComment, '', $this->type, $this->action, $this->target, $this->comment, $this->params, $newId); } } return true; }
/** * Patrols the article or provides the reason the patrol failed. */ public function execute() { $params = $this->extractRequestParams(); $this->requireOnlyOneParameter($params, 'rcid', 'revid'); if (isset($params['rcid'])) { $rc = RecentChange::newFromId($params['rcid']); if (!$rc) { $this->dieUsageMsg(['nosuchrcid', $params['rcid']]); } } else { $rev = Revision::newFromId($params['revid']); if (!$rev) { $this->dieUsageMsg(['nosuchrevid', $params['revid']]); } $rc = $rev->getRecentChange(); if (!$rc) { $this->dieUsage('The revision ' . $params['revid'] . " can't be patrolled as it's too old", 'notpatrollable'); } } $user = $this->getUser(); $tags = $params['tags']; // Check if user can add tags if (!is_null($tags)) { $ableToTag = ChangeTags::canAddTagsAccompanyingChange($tags, $user); if (!$ableToTag->isOK()) { $this->dieStatus($ableToTag); } } $retval = $rc->doMarkPatrolled($user, false, $tags); if ($retval) { $this->dieUsageMsg(reset($retval)); } $result = ['rcid' => intval($rc->getAttribute('rc_id'))]; ApiQueryBase::addTitleInfo($result, $rc->getTitle()); $this->getResult()->addValue(null, $this->getModuleName(), $result); }
/** * RecentChange_save hook handler that tags mobile changes * @see https://www.mediawiki.org/wiki/Manual:Hooks/RecentChange_save * * @param RecentChange $rc * @return bool */ public static function onRecentChange_save(RecentChange $rc) { $context = MobileContext::singleton(); $userAgent = $context->getRequest()->getHeader("User-agent"); $logType = $rc->getAttribute('rc_log_type'); // Only log edits and uploads if ($context->shouldDisplayMobileView() && ($logType === 'upload' || is_null($logType))) { $rcId = $rc->getAttribute('rc_id'); $revId = $rc->getAttribute('rc_this_oldid'); $logId = $rc->getAttribute('rc_logid'); ChangeTags::addTags('mobile edit', $rcId, $revId, $logId); // Tag as mobile web edit specifically, if it isn't coming from the apps if (strpos($userAgent, 'WikipediaApp/') !== 0) { ChangeTags::addTags('mobile web edit', $rcId, $revId, $logId); } } return true; }
/** * Extracts from a single sql row the data needed to describe one recent change. * * @param stdClass $row The row from which to extract the data. * @return array An array mapping strings (descriptors) to their respective string values. * @access public */ public function extractRowInfo($row) { /* Determine the title of the page that has been changed. */ $title = Title::makeTitle($row->rc_namespace, $row->rc_title); $user = $this->getUser(); /* Our output data. */ $vals = array(); $type = intval($row->rc_type); $vals['type'] = RecentChange::parseFromRCType($type); $anyHidden = false; /* Create a new entry in the result for the title. */ if ($this->fld_title || $this->fld_ids) { if ($type === RC_LOG && $row->rc_deleted & LogPage::DELETED_ACTION) { $vals['actionhidden'] = true; $anyHidden = true; } if ($type !== RC_LOG || LogEventsList::userCanBitfield($row->rc_deleted, LogPage::DELETED_ACTION, $user)) { if ($this->fld_title) { ApiQueryBase::addTitleInfo($vals, $title); } if ($this->fld_ids) { $vals['pageid'] = intval($row->rc_cur_id); $vals['revid'] = intval($row->rc_this_oldid); $vals['old_revid'] = intval($row->rc_last_oldid); } } } if ($this->fld_ids) { $vals['rcid'] = intval($row->rc_id); } /* Add user data and 'anon' flag, if user is anonymous. */ if ($this->fld_user || $this->fld_userid) { if ($row->rc_deleted & Revision::DELETED_USER) { $vals['userhidden'] = true; $anyHidden = true; } if (Revision::userCanBitfield($row->rc_deleted, Revision::DELETED_USER, $user)) { if ($this->fld_user) { $vals['user'] = $row->rc_user_text; } if ($this->fld_userid) { $vals['userid'] = $row->rc_user; } if (!$row->rc_user) { $vals['anon'] = true; } } } /* Add flags, such as new, minor, bot. */ if ($this->fld_flags) { $vals['bot'] = (bool) $row->rc_bot; $vals['new'] = $row->rc_type == RC_NEW; $vals['minor'] = (bool) $row->rc_minor; } /* Add sizes of each revision. (Only available on 1.10+) */ if ($this->fld_sizes) { $vals['oldlen'] = intval($row->rc_old_len); $vals['newlen'] = intval($row->rc_new_len); } /* Add the timestamp. */ if ($this->fld_timestamp) { $vals['timestamp'] = wfTimestamp(TS_ISO_8601, $row->rc_timestamp); } /* Add edit summary / log summary. */ if ($this->fld_comment || $this->fld_parsedcomment) { if ($row->rc_deleted & Revision::DELETED_COMMENT) { $vals['commenthidden'] = true; $anyHidden = true; } if (Revision::userCanBitfield($row->rc_deleted, Revision::DELETED_COMMENT, $user)) { if ($this->fld_comment && isset($row->rc_comment)) { $vals['comment'] = $row->rc_comment; } if ($this->fld_parsedcomment && isset($row->rc_comment)) { $vals['parsedcomment'] = Linker::formatComment($row->rc_comment, $title); } } } if ($this->fld_redirect) { $vals['redirect'] = (bool) $row->page_is_redirect; } /* Add the patrolled flag */ if ($this->fld_patrolled) { $vals['patrolled'] = $row->rc_patrolled == 1; $vals['unpatrolled'] = ChangesList::isUnpatrolled($row, $user); } if ($this->fld_loginfo && $row->rc_type == RC_LOG) { if ($row->rc_deleted & LogPage::DELETED_ACTION) { $vals['actionhidden'] = true; $anyHidden = true; } if (LogEventsList::userCanBitfield($row->rc_deleted, LogPage::DELETED_ACTION, $user)) { $vals['logid'] = intval($row->rc_logid); $vals['logtype'] = $row->rc_log_type; $vals['logaction'] = $row->rc_log_action; $vals['logparams'] = LogFormatter::newFromRow($row)->formatParametersForApi(); } } if ($this->fld_tags) { if ($row->ts_tags) { $tags = explode(',', $row->ts_tags); ApiResult::setIndexedTagName($tags, 'tag'); $vals['tags'] = $tags; } else { $vals['tags'] = array(); } } if ($this->fld_sha1 && $row->rev_sha1 !== null) { if ($row->rev_deleted & Revision::DELETED_TEXT) { $vals['sha1hidden'] = true; $anyHidden = true; } if (Revision::userCanBitfield($row->rev_deleted, Revision::DELETED_TEXT, $user)) { if ($row->rev_sha1 !== '') { $vals['sha1'] = wfBaseConvert($row->rev_sha1, 36, 16, 40); } else { $vals['sha1'] = ''; } } } if (!is_null($this->token)) { $tokenFunctions = $this->getTokenFunctions(); foreach ($this->token as $t) { $val = call_user_func($tokenFunctions[$t], $row->rc_cur_id, $title, RecentChange::newFromRow($row)); if ($val === false) { $this->setWarning("Action '{$t}' is not allowed for the current user"); } else { $vals[$t . 'token'] = $val; } } } if ($anyHidden && $row->rc_deleted & Revision::DELETED_RESTRICTED) { $vals['suppressed'] = true; } return $vals; }
/** * Makes an entry in the database corresponding to page creation * Note: the title object must be loaded with the new id using resetArticleID() * * @param string $timestamp * @param Title $title * @param bool $minor * @param User $user * @param string $comment * @param bool $bot * @param string $ip * @param int $size * @param int $newId * @param int $patrol * @return RecentChange */ public static function notifyNew($timestamp, &$title, $minor, &$user, $comment, $bot, $ip = '', $size = 0, $newId = 0, $patrol = 0) { $rc = new RecentChange(); $rc->mTitle = $title; $rc->mPerformer = $user; $rc->mAttribs = array('rc_timestamp' => $timestamp, 'rc_namespace' => $title->getNamespace(), 'rc_title' => $title->getDBkey(), 'rc_type' => RC_NEW, 'rc_source' => self::SRC_NEW, 'rc_minor' => $minor ? 1 : 0, 'rc_cur_id' => $title->getArticleID(), 'rc_user' => $user->getId(), 'rc_user_text' => $user->getName(), 'rc_comment' => $comment, 'rc_this_oldid' => $newId, 'rc_last_oldid' => 0, 'rc_bot' => $bot ? 1 : 0, 'rc_ip' => self::checkIPAddress($ip), 'rc_patrolled' => intval($patrol), 'rc_new' => 1, 'rc_old_len' => 0, 'rc_new_len' => $size, 'rc_deleted' => 0, 'rc_logid' => 0, 'rc_log_type' => null, 'rc_log_action' => '', 'rc_params' => ''); $rc->mExtra = array('prefixedDBkey' => $title->getPrefixedDBkey(), 'lastTimestamp' => 0, 'oldSize' => 0, 'newSize' => $size, 'pageStatus' => 'created'); DeferredUpdates::addCallableUpdate(function () use($rc) { $rc->save(); if ($rc->mAttribs['rc_patrolled']) { PatrolLog::record($rc, true, $rc->getPerformer()); } }); return $rc; }
public static function notifyMoveOverRedirect($timestamp, &$oldTitle, &$newTitle, &$user, $comment, $ip = '') { RecentChange::notifyMove($timestamp, $oldTitle, $newTitle, $user, $comment, $ip, true); }
/** * Build and output the actual changes list. * * @param ResultWrapper $rows Database rows * @param FormOptions $opts */ public function outputChangesList($rows, $opts) { $dbr = $this->getDB(); $user = $this->getUser(); $output = $this->getOutput(); # Show a message about slave lag, if applicable $lag = wfGetLB()->safeGetLag($dbr); if ($lag > 0) { $output->showLagWarning($lag); } # If no rows to display, show message before try to render the list if ($rows->numRows() == 0) { $output->wrapWikiMsg("<div class='mw-changeslist-empty'>\n\$1\n</div>", 'recentchanges-noresult'); return; } $dbr->dataSeek($rows, 0); $list = ChangesList::newFromContext($this->getContext()); $list->setWatchlistDivs(); $list->initChangesListRows($rows); $dbr->dataSeek($rows, 0); $s = $list->beginRecentChangesList(); $counter = 1; foreach ($rows as $obj) { # Make RC entry $rc = RecentChange::newFromRow($obj); $rc->counter = $counter++; if ($this->getConfig()->get('ShowUpdatedMarker')) { $updated = $obj->wl_notificationtimestamp; } else { $updated = false; } if ($this->getConfig()->get('RCShowWatchingUsers') && $user->getOption('shownumberswatching')) { $rc->numberofWatchingusers = $dbr->selectField('watchlist', 'COUNT(*)', array('wl_namespace' => $obj->rc_namespace, 'wl_title' => $obj->rc_title), __METHOD__); } else { $rc->numberofWatchingusers = 0; } $changeLine = $list->recentChangesLine($rc, $updated, $counter); if ($changeLine !== false) { $s .= $changeLine; } } $s .= $list->endRecentChangesList(); $output->addHTML($s); }
function showDiffPage($diffOnly = false) { global $wgUser, $wgOut, $wgUseExternalEditor, $wgUseRCPatrol; wfProfileIn(__METHOD__); # Allow frames except in certain special cases $wgOut->allowClickjacking(); # If external diffs are enabled both globally and for the user, # we'll use the application/x-external-editor interface to call # an external diff tool like kompare, kdiff3, etc. if ($wgUseExternalEditor && $wgUser->getOption('externaldiff')) { global $wgCanonicalServer, $wgScript, $wgLang; $wgOut->disable(); header("Content-type: application/x-external-editor; charset=UTF-8"); $url1 = $this->mTitle->getCanonical(array('action' => 'raw', 'oldid' => $this->mOldid)); $url2 = $this->mTitle->getCanonical(array('action' => 'raw', 'oldid' => $this->mNewid)); $special = $wgLang->getNsText(NS_SPECIAL); $control = <<<CONTROL \t\t\t[Process] \t\t\tType=Diff text \t\t\tEngine=MediaWiki \t\t\tScript={$wgCanonicalServer}{$wgScript} \t\t\tSpecial namespace={$special} \t\t\t[File] \t\t\tExtension=wiki \t\t\tURL={$url1} \t\t\t[File 2] \t\t\tExtension=wiki \t\t\tURL={$url2} CONTROL; echo $control; wfProfileOut(__METHOD__); return; } $wgOut->setArticleFlag(false); if (!$this->loadRevisionData()) { // Sounds like a deleted revision... Let's see what we can do. $t = $this->mTitle->getPrefixedText(); $d = wfMsgExt('missingarticle-diff', array('escape'), $this->deletedIdMarker($this->mOldid), $this->deletedIdMarker($this->mNewid)); $wgOut->setPagetitle(wfMsg('errorpagetitle')); $wgOut->addWikiMsg('missing-article', "<nowiki>{$t}</nowiki>", "<span class='plainlinks'>{$d}</span>"); wfProfileOut(__METHOD__); return; } wfRunHooks('DiffViewHeader', array($this, $this->mOldRev, $this->mNewRev)); if ($this->mNewRev->isCurrent()) { $wgOut->setArticleFlag(true); } # mOldid is false if the difference engine is called with a "vague" query for # a diff between a version V and its previous version V' AND the version V # is the first version of that article. In that case, V' does not exist. if ($this->mOldid === false) { $this->showFirstRevision(); $this->renderNewRevision(); // should we respect $diffOnly here or not? wfProfileOut(__METHOD__); return; } $oldTitle = $this->mOldPage->getPrefixedText(); $newTitle = $this->mNewPage->getPrefixedText(); if ($oldTitle == $newTitle) { $wgOut->setPageTitle($newTitle); } else { $wgOut->setPageTitle($oldTitle . ', ' . $newTitle); } if ($this->mNewPage->equals($this->mOldPage)) { $wgOut->setSubtitle(wfMsgExt('difference', array('parseinline'))); } else { $wgOut->setSubtitle(wfMsgExt('difference-multipage', array('parseinline'))); } $wgOut->setRobotPolicy('noindex,nofollow'); if (!$this->mOldPage->userCanRead() || !$this->mNewPage->userCanRead()) { $wgOut->loginToUse(); $wgOut->output(); $wgOut->disable(); wfProfileOut(__METHOD__); return; } $sk = $wgUser->getSkin(); if (method_exists($sk, 'suppressQuickbar')) { $sk->suppressQuickbar(); } // Check if page is editable $editable = $this->mNewRev->getTitle()->userCan('edit'); if ($editable && $this->mNewRev->isCurrent() && $wgUser->isAllowed('rollback')) { $wgOut->preventClickjacking(); $rollback = '   ' . $sk->generateRollback($this->mNewRev); } else { $rollback = ''; } // Prepare a change patrol link, if applicable if ($wgUseRCPatrol && $this->mTitle->userCan('patrol')) { // If we've been given an explicit change identifier, use it; saves time if ($this->mRcidMarkPatrolled) { $rcid = $this->mRcidMarkPatrolled; $rc = RecentChange::newFromId($rcid); // Already patrolled? $rcid = is_object($rc) && !$rc->getAttribute('rc_patrolled') ? $rcid : 0; } else { // Look for an unpatrolled change corresponding to this diff $db = wfGetDB(DB_SLAVE); $change = RecentChange::newFromConds(array('rc_user_text' => $this->mNewRev->getRawUserText(), 'rc_timestamp' => $db->timestamp($this->mNewRev->getTimestamp()), 'rc_this_oldid' => $this->mNewid, 'rc_last_oldid' => $this->mOldid, 'rc_patrolled' => 0), __METHOD__); if ($change instanceof RecentChange) { $rcid = $change->mAttribs['rc_id']; $this->mRcidMarkPatrolled = $rcid; } else { // None found $rcid = 0; } } // Build the link if ($rcid) { $wgOut->preventClickjacking(); $token = $wgUser->editToken($rcid); $patrol = ' <span class="patrollink">[' . $sk->link($this->mTitle, wfMsgHtml('markaspatrolleddiff'), array(), array('action' => 'markpatrolled', 'rcid' => $rcid, 'token' => $token), array('known', 'noclasses')) . ']</span>'; } else { $patrol = ''; } } else { $patrol = ''; } # Carry over 'diffonly' param via navigation links if ($diffOnly != $wgUser->getBoolOption('diffonly')) { $query['diffonly'] = $diffOnly; } # Make "previous revision link" $query['diff'] = 'prev'; $query['oldid'] = $this->mOldid; # Cascade unhide param in links for easy deletion browsing if ($this->unhide) { $query['unhide'] = 1; } if (!$this->mOldRev->getPrevious()) { $prevlink = ' '; } else { $prevlink = $sk->link($this->mTitle, wfMsgHtml('previousdiff'), array('id' => 'differences-prevlink'), $query, array('known', 'noclasses')); } # Make "next revision link" $query['diff'] = 'next'; $query['oldid'] = $this->mNewid; # Skip next link on the top revision if ($this->mNewRev->isCurrent()) { $nextlink = ' '; } else { $nextlink = $sk->link($this->mTitle, wfMsgHtml('nextdiff'), array('id' => 'differences-nextlink'), $query, array('known', 'noclasses')); } $oldminor = ''; $newminor = ''; if ($this->mOldRev->isMinor()) { $oldminor = ChangesList::flag('minor'); } if ($this->mNewRev->isMinor()) { $newminor = ChangesList::flag('minor'); } # Handle RevisionDelete links... $ldel = $this->revisionDeleteLink($this->mOldRev); $rdel = $this->revisionDeleteLink($this->mNewRev); $oldHeader = '<div id="mw-diff-otitle1"><strong>' . $this->mOldtitle . '</strong></div>' . '<div id="mw-diff-otitle2">' . $sk->revUserTools($this->mOldRev, !$this->unhide) . '</div>' . '<div id="mw-diff-otitle3">' . $oldminor . $sk->revComment($this->mOldRev, !$diffOnly, !$this->unhide) . $ldel . '</div>' . '<div id="mw-diff-otitle4">' . $prevlink . '</div>'; $newHeader = '<div id="mw-diff-ntitle1"><strong>' . $this->mNewtitle . '</strong></div>' . '<div id="mw-diff-ntitle2">' . $sk->revUserTools($this->mNewRev, !$this->unhide) . " {$rollback}</div>" . '<div id="mw-diff-ntitle3">' . $newminor . $sk->revComment($this->mNewRev, !$diffOnly, !$this->unhide) . $rdel . '</div>' . '<div id="mw-diff-ntitle4">' . $nextlink . $patrol . '</div>'; # Check if this user can see the revisions $allowed = $this->mOldRev->userCan(Revision::DELETED_TEXT) && $this->mNewRev->userCan(Revision::DELETED_TEXT); # Check if one of the revisions is deleted/suppressed $deleted = $suppressed = false; if ($this->mOldRev->isDeleted(Revision::DELETED_TEXT)) { $deleted = true; // old revisions text is hidden if ($this->mOldRev->isDeleted(Revision::DELETED_RESTRICTED)) { $suppressed = true; } // also suppressed } if ($this->mNewRev->isDeleted(Revision::DELETED_TEXT)) { $deleted = true; // new revisions text is hidden if ($this->mNewRev->isDeleted(Revision::DELETED_RESTRICTED)) { $suppressed = true; } // also suppressed } # If the diff cannot be shown due to a deleted revision, then output # the diff header and links to unhide (if available)... if ($deleted && (!$this->unhide || !$allowed)) { $this->showDiffStyle(); $multi = $this->getMultiNotice(); $wgOut->addHTML($this->addHeader('', $oldHeader, $newHeader, $multi)); if (!$allowed) { $msg = $suppressed ? 'rev-suppressed-no-diff' : 'rev-deleted-no-diff'; # Give explanation for why revision is not visible $wgOut->wrapWikiMsg("<div id='mw-{$msg}' class='mw-warning plainlinks'>\n\$1\n</div>\n", array($msg)); } else { # Give explanation and add a link to view the diff... $link = $this->mTitle->getFullUrl(array('diff' => $this->mNewid, 'oldid' => $this->mOldid, 'unhide' => 1)); $msg = $suppressed ? 'rev-suppressed-unhide-diff' : 'rev-deleted-unhide-diff'; $wgOut->wrapWikiMsg("<div id='mw-{$msg}' class='mw-warning plainlinks'>\n\$1\n</div>\n", array($msg, $link)); } # Otherwise, output a regular diff... } else { # Add deletion notice if the user is viewing deleted content $notice = ''; if ($deleted) { $msg = $suppressed ? 'rev-suppressed-diff-view' : 'rev-deleted-diff-view'; $notice = "<div id='mw-{$msg}' class='mw-warning plainlinks'>\n" . wfMsgExt($msg, 'parseinline') . "</div>\n"; } $this->showDiff($oldHeader, $newHeader, $notice); if (!$diffOnly) { $this->renderNewRevision(); } } wfProfileOut(__METHOD__); }
/** * Do standard deferred updates after page edit. * Update links tables, site stats, search index and message cache. * Purges pages that include this page if the text was changed here. * Every 100th edit, prune the recent changes table. * * @param $revision Revision object * @param $user User object that did the revision * @param array $options of options, following indexes are used: * - changed: boolean, whether the revision changed the content (default true) * - created: boolean, whether the revision created the page (default false) * - oldcountable: boolean or null (default null): * - boolean: whether the page was counted as an article before that * revision, only used in changed is true and created is false * - null: don't change the article count */ public function doEditUpdates( Revision $revision, User $user, array $options = array() ) { global $wgEnableParserCache; wfProfileIn( __METHOD__ ); $options += array( 'changed' => true, 'created' => false, 'oldcountable' => null ); $content = $revision->getContent(); // Parse the text // Be careful not to do pre-save transform twice: $text is usually // already pre-save transformed once. if ( !$this->mPreparedEdit || $this->mPreparedEdit->output->getFlag( 'vary-revision' ) ) { wfDebug( __METHOD__ . ": No prepared edit or vary-revision is set...\n" ); $editInfo = $this->prepareContentForEdit( $content, $revision->getId(), $user ); } else { wfDebug( __METHOD__ . ": No vary-revision, using prepared edit...\n" ); $editInfo = $this->mPreparedEdit; } // Save it to the parser cache if ( $wgEnableParserCache ) { $parserCache = ParserCache::singleton(); $parserCache->save( $editInfo->output, $this, $editInfo->popts ); } // Update the links tables and other secondary data if ( $content ) { $recursive = $options['changed']; // bug 50785 $updates = $content->getSecondaryDataUpdates( $this->getTitle(), null, $recursive, $editInfo->output ); DataUpdate::runUpdates( $updates ); } wfRunHooks( 'ArticleEditUpdates', array( &$this, &$editInfo, $options['changed'] ) ); if ( wfRunHooks( 'ArticleEditUpdatesDeleteFromRecentchanges', array( &$this ) ) ) { if ( 0 == mt_rand( 0, 99 ) ) { // Flush old entries from the `recentchanges` table; we do this on // random requests so as to avoid an increase in writes for no good reason RecentChange::purgeExpiredChanges(); } } if ( !$this->exists() ) { wfProfileOut( __METHOD__ ); return; } $id = $this->getId(); $title = $this->mTitle->getPrefixedDBkey(); $shortTitle = $this->mTitle->getDBkey(); if ( !$options['changed'] ) { $good = 0; $total = 0; } elseif ( $options['created'] ) { $good = (int)$this->isCountable( $editInfo ); $total = 1; } elseif ( $options['oldcountable'] !== null ) { $good = (int)$this->isCountable( $editInfo ) - (int)$options['oldcountable']; $total = 0; } else { $good = 0; $total = 0; } DeferredUpdates::addUpdate( new SiteStatsUpdate( 0, 1, $good, $total ) ); DeferredUpdates::addUpdate( new SearchUpdate( $id, $title, $content ) ); // If this is another user's talk page, update newtalk. // Don't do this if $options['changed'] = false (null-edits) nor if // it's a minor edit and the user doesn't want notifications for those. if ( $options['changed'] && $this->mTitle->getNamespace() == NS_USER_TALK && $shortTitle != $user->getTitleKey() && !( $revision->isMinor() && $user->isAllowed( 'nominornewtalk' ) ) ) { $recipient = User::newFromName( $shortTitle, false ); if ( !$recipient ) { wfDebug( __METHOD__ . ": invalid username\n" ); } else { // Allow extensions to prevent user notification when a new message is added to their talk page if ( wfRunHooks( 'ArticleEditUpdateNewTalk', array( &$this, $recipient ) ) ) { if ( User::isIP( $shortTitle ) ) { // An anonymous user $recipient->setNewtalk( true, $revision ); } elseif ( $recipient->isLoggedIn() ) { $recipient->setNewtalk( true, $revision ); } else { wfDebug( __METHOD__ . ": don't need to notify a nonexistent user\n" ); } } } } if ( $this->mTitle->getNamespace() == NS_MEDIAWIKI ) { // XXX: could skip pseudo-messages like js/css here, based on content model. $msgtext = $content ? $content->getWikitextForTransclusion() : null; if ( $msgtext === false || $msgtext === null ) { $msgtext = ''; } MessageCache::singleton()->replace( $shortTitle, $msgtext ); } if ( $options['created'] ) { self::onArticleCreate( $this->mTitle ); } else { self::onArticleEdit( $this->mTitle ); } wfProfileOut( __METHOD__ ); }
/** * Returns an array of meta data needed to build a "mark as patrolled" link and * adds the mediawiki.page.patrol.ajax to the output. * * @return array|false An array of meta data for a patrol link (rcid & token) * or false if no link is needed */ protected function getMarkPatrolledLinkInfo() { global $wgUseRCPatrol, $wgEnableAPI, $wgEnableWriteAPI; $user = $this->getUser(); // Prepare a change patrol link, if applicable if ($wgUseRCPatrol && $this->mNewPage->quickUserCan('patrol', $user) && RecentChange::isInRCLifespan($this->mNewRev->getTimestamp(), 21600)) { // Look for an unpatrolled change corresponding to this diff $db = wfGetDB(DB_SLAVE); $change = RecentChange::newFromConds(array('rc_timestamp' => $db->timestamp($this->mNewRev->getTimestamp()), 'rc_this_oldid' => $this->mNewid, 'rc_patrolled' => 0), __METHOD__); if ($change && !$change->getPerformer()->equals($user)) { $rcid = $change->getAttribute('rc_id'); } else { // None found or the page has been created by the current user. // If the user could patrol this it already would be patrolled $rcid = 0; } // Build the link if ($rcid) { $this->getOutput()->preventClickjacking(); if ($wgEnableAPI && $wgEnableWriteAPI && $user->isAllowed('writeapi')) { $this->getOutput()->addModules('mediawiki.page.patrol.ajax'); } $token = $user->getEditToken($rcid); return array('rcid' => $rcid, 'token' => $token); } } // No mark as patrolled link applicable return false; }
/** * Process the query * * @param array $conds * @param FormOptions $opts * @return bool|ResultWrapper Result or false */ public function doMainQuery($conds, $opts) { $tables = ['recentchanges']; $fields = RecentChange::selectFields(); $query_options = []; $join_conds = []; ChangeTags::modifyDisplayQuery($tables, $fields, $conds, $join_conds, $query_options, ''); if (!$this->runMainQueryHook($tables, $fields, $conds, $query_options, $join_conds, $opts)) { return false; } $dbr = $this->getDB(); return $dbr->select($tables, $fields, $conds, __METHOD__, $query_options, $join_conds); }