/** * This function does essentially the same as RevisionReview::AjaxReview, * except that it generates the template and image parameters itself. */ public function execute() { global $wgUser; $params = $this->extractRequestParams(); // Check basic permissions if (!$wgUser->isAllowed('review')) { $this->dieUsage("You don't have the right to review revisions.", 'permissiondenied'); } elseif ($wgUser->isBlocked(false)) { $this->dieUsageMsg(array('blockedtext')); } $newRev = Revision::newFromId($params['oldid']); if (!$newRev || !$newRev->getTitle()) { $this->dieUsage("Cannot find a revision with the specified ID.", 'notarget'); } $title = $newRev->getTitle(); $fa = FlaggableWikiPage::getTitleInstance($title); if (!$fa->isReviewable()) { $this->dieUsage("Provided page is not reviewable.", 'notreviewable'); } $status = false; if ($params['previd']) { // changes $oldRev = Revision::newFromId($params['previd']); if (!$oldRev || $oldRev->getPage() != $newRev->getPage()) { $this->dieUsage("Revisions do not belong to the same page.", 'notarget'); } // Mark as reviewing... if ($params['reviewing']) { $status = FRUserActivity::setUserReviewingDiff($wgUser, $params['previd'], $params['oldid']); // Unmark as reviewing... } else { $status = FRUserActivity::clearUserReviewingDiff($wgUser, $params['previd'], $params['oldid']); } } else { // Mark as reviewing... if ($params['reviewing']) { $status = FRUserActivity::setUserReviewingPage($wgUser, $newRev->getPage()); // Unmark as reviewing... } else { $status = FRUserActivity::clearUserReviewingPage($wgUser, $newRev->getPage()); } } # Success in setting flag... if ($status === true) { $this->getResult()->addValue(null, $this->getModuleName(), array('result' => 'Success')); # Failure... } else { $this->getResult()->addValue(null, $this->getModuleName(), array('result' => 'Failure')); } }
private function run($resultPageSet = null) { global $wgMemc; $params = $this->extractRequestParams(); // Construct SQL Query $this->addTables(array('page', 'flaggedpages')); $this->addWhereFld('page_namespace', $params['namespace']); if ($params['filterredir'] == 'redirects') { $this->addWhereFld('page_is_redirect', 1); } if ($params['filterredir'] == 'nonredirects') { $this->addWhereFld('page_is_redirect', 0); } $dir = $params['dir'] == 'descending' ? 'older' : 'newer'; $this->addWhereRange('page_title', $dir, $params['start'], $params['end']); $this->addJoinConds(array('flaggedpages' => array('LEFT JOIN', 'fp_page_id=page_id'))); $this->addWhere('fp_page_id IS NULL OR fp_quality < ' . intval($params['filterlevel'])); $this->addOption('USE INDEX', array('page' => 'name_title', 'flaggedpages' => 'PRIMARY')); if (is_null($resultPageSet)) { $this->addFields(array('page_id', 'page_namespace', 'page_title', 'page_len', 'page_latest')); } else { $this->addFields($resultPageSet->getPageTableFields()); } $limit = $params['limit']; $this->addOption('LIMIT', $limit + 1); $res = $this->select(__METHOD__); $data = array(); $count = 0; foreach ($res as $row) { if (++$count > $limit) { // We've reached the one extra which shows that there are // additional pages to be had. Stop here... $this->setContinueEnumParameter('start', $row->page_title); break; } if (is_null($resultPageSet)) { $title = Title::newFromRow($row); $data[] = array('pageid' => intval($row->page_id), 'ns' => intval($title->getNamespace()), 'title' => $title->getPrefixedText(), 'revid' => intval($row->page_latest), 'under_review' => FRUserActivity::pageIsUnderReview($row->page_id)); } else { $resultPageSet->processDbRow($row); } } if (is_null($resultPageSet)) { $result = $this->getResult(); $result->setIndexedTagName($data, 'p'); $result->addValue('query', $this->getModuleName(), $data); } }
private function run($resultPageSet = null) { global $wgUser, $wgMemc; $params = $this->extractRequestParams(); // Construct SQL Query $this->addTables(array('page', 'flaggedpages', 'revision')); $this->addWhereFld('page_namespace', $params['namespace']); $useIndex = array('flaggedpages' => 'fp_pending_since'); if ($params['filterredir'] == 'redirects') { $this->addWhereFld('page_is_redirect', 1); } if ($params['filterredir'] == 'nonredirects') { $this->addWhereFld('page_is_redirect', 0); } if ($params['maxsize'] !== null) { # Get absolute difference for comparison. ABS(x-y) # is broken due to mysql unsigned int design. $this->addWhere('GREATEST(page_len,rev_len)-LEAST(page_len,rev_len) <= ' . intval($params['maxsize'])); } if ($params['filterwatched'] == 'watched') { if (!($uid = $wgUser->getId())) { $this->dieUsage('You must be logged-in to have a watchlist', 'notloggedin'); } $this->addTables('watchlist'); $this->addWhereFld('wl_user', $uid); $this->addWhere('page_namespace = wl_namespace'); $this->addWhere('page_title = wl_title'); } if ($params['category'] != '') { $this->addTables('categorylinks'); $this->addWhere('cl_from = fp_page_id'); $this->addWhereFld('cl_to', $params['category']); $useIndex['categorylinks'] = 'cl_from'; } $this->addWhereRange('fp_pending_since', $params['dir'], $params['start'], $params['end']); $this->addWhere('page_id=fp_page_id'); $this->addWhere('rev_id=fp_stable'); if (!isset($params['start']) && !isset($params['end'])) { $this->addWhere('fp_pending_since IS NOT NULL'); } $this->addOption('USE INDEX', $useIndex); if (is_null($resultPageSet)) { $this->addFields(array('page_id', 'page_namespace', 'page_title', 'page_latest', 'page_len', 'rev_len', 'fp_stable', 'fp_pending_since', 'fp_quality')); } else { $this->addFields($resultPageSet->getPageTableFields()); $this->addFields('fp_pending_since'); } $limit = $params['limit']; $this->addOption('LIMIT', $limit + 1); $res = $this->select(__METHOD__); $data = array(); $count = 0; foreach ($res as $row) { if (++$count > $limit) { // We've reached the one extra which shows that there are // additional pages to be had. Stop here... $this->setContinueEnumParameter('start', wfTimestamp(TS_ISO_8601, $row->fp_pending_since)); break; } if (is_null($resultPageSet)) { $title = Title::newFromRow($row); $underReview = FRUserActivity::diffIsUnderReview($row->fp_stable, $row->page_latest); $data[] = array('pageid' => intval($row->page_id), 'ns' => intval($row->page_namespace), 'title' => $title->getPrefixedText(), 'revid' => intval($row->page_latest), 'stable_revid' => intval($row->fp_stable), 'pending_since' => wfTimestamp(TS_ISO_8601, $row->fp_pending_since), 'flagged_level' => intval($row->fp_quality), 'flagged_level_text' => FlaggedRevs::getQualityLevelText($row->fp_quality), 'diff_size' => (int) $row->page_len - (int) $row->rev_len, 'under_review' => $underReview); } else { $resultPageSet->processDbRow($row); } } if (is_null($resultPageSet)) { $result = $this->getResult(); $result->setIndexedTagName($data, 'p'); $result->addValue('query', $this->getModuleName(), $data); } }
public function formatRow($row) { $css = $quality = $underReview = ''; $title = Title::newFromRow($row); $stxt = ChangesList::showCharacterDifference($row->rev_len, $row->page_len); # Page links... $link = Linker::link($title); $hist = Linker::linkKnown($title, wfMsgHtml('hist'), array(), 'action=history'); $review = Linker::linkKnown($title, wfMsg('pendingchanges-diff'), array(), array('diff' => 'cur', 'oldid' => $row->stable) + FlaggedRevs::diffOnlyCGI()); # Show quality level if there are several if (FlaggedRevs::qualityVersions()) { $quality = $row->quality ? wfMsgHtml('revreview-lev-quality') : wfMsgHtml('revreview-lev-basic'); $quality = " <b>[{$quality}]</b>"; } # Is anybody watching? if (!$this->including() && $this->getUser()->isAllowed('unreviewedpages')) { $uw = FRUserActivity::numUsersWatchingPage($title); $watching = $uw ? wfMsgExt('pendingchanges-watched', 'parsemag', $this->getLang()->formatNum($uw)) : wfMsgHtml('pendingchanges-unwatched'); $watching = " {$watching}"; } else { $uw = -1; $watching = ''; // leave out data } # Get how long the first unreviewed edit has been waiting... if ($row->pending_since) { $firstPendingTime = wfTimestamp(TS_UNIX, $row->pending_since); $hours = ($this->currentUnixTS - $firstPendingTime) / 3600; // After three days, just use days if ($hours > 3 * 24) { $days = round($hours / 24, 0); $age = wfMsgExt('pendingchanges-days', 'parsemag', $this->getLang()->formatNum($days)); // If one or more hours, use hours } elseif ($hours >= 1) { $hours = round($hours, 0); $age = wfMsgExt('pendingchanges-hours', 'parsemag', $this->getLang()->formatNum($hours)); } else { $age = wfMsg('pendingchanges-recent'); // hot off the press :) } // Oh-noes! $css = self::getLineClass($hours, $uw); $css = $css ? " class='{$css}'" : ""; } else { $age = ""; // wtf? } # Show if a user is looking at this page list($u, $ts) = FRUserActivity::getUserReviewingDiff($row->stable, $row->page_latest); if ($u !== null) { $underReview = ' <span class="fr-under-review">' . wfMsgHtml('pendingchanges-viewing') . '</span>'; } return "<li{$css}>{$link} ({$hist}) {$stxt} ({$review}) <i>{$age}</i>" . "{$quality}{$watching}{$underReview}</li>"; }
public function formatRow($row) { $title = Title::newFromRow($row); $stxt = $underReview = $watching = ''; $link = Linker::link($title, null, array(), 'redirect=no'); $dirmark = $this->getLanguage()->getDirMark(); $hist = Linker::linkKnown($title, $this->msg('hist')->escaped(), array(), array('action' => 'history')); if (!is_null($size = $row->page_len)) { $stxt = $size == 0 ? $this->msg('historyempty')->escaped() : $this->msg('historysize')->numParams($size)->escaped(); $stxt = " <small>{$stxt}</small>"; } # Get how long the first unreviewed edit has been waiting... $firstPendingTime = wfTimestamp(TS_UNIX, $row->creation); $hours = ($this->currentUnixTS - $firstPendingTime) / 3600; // After three days, just use days if ($hours > 3 * 24) { $days = round($hours / 24, 0); $age = ' ' . $this->msg('unreviewedpages-days')->numParams($days)->escaped(); // If one or more hours, use hours } elseif ($hours >= 1) { $hours = round($hours, 0); $age = ' ' . $this->msg('unreviewedpages-hours')->numParams($hours)->escaped(); } else { $age = ' ' . $this->msg('unreviewedpages-recent')->escaped(); // hot off the press :) } if ($this->getUser()->isAllowed('unwatchedpages')) { $uw = FRUserActivity::numUsersWatchingPage($title); $watching = $uw ? $this->msg('unreviewedpages-watched')->numParams($uw)->escaped() : $this->msg('unreviewedpages-unwatched')->escaped(); $watching = " {$watching}"; // Oh-noes! } else { $uw = -1; } $css = self::getLineClass($hours, $uw); $css = $css ? " class='{$css}'" : ""; # Show if a user is looking at this page list($u, $ts) = FRUserActivity::getUserReviewingPage($row->page_id); if ($u !== null) { $underReview = " <span class='fr-under-review'>" . $this->msg('unreviewedpages-viewing')->escaped() . '</span>'; } return "<li{$css}>{$link} {$dirmark} {$stxt} ({$hist})" . "{$age}{$watching}{$underReview}</li>"; }
/** * Generates a brief review form for a page * @return array (html string, error string or true) */ public function getHtml() { global $wgLang; $revId = $this->rev->getId(); if ($this->rev->isDeleted(Revision::DELETED_TEXT)) { return array('', 'review_bad_oldid'); # The revision must be valid and public } $article = $this->article; // convenience $srev = $article->getStableRev(); # See if the version being displayed is flagged... if ($revId == $article->getStable()) { $frev = $srev; // avoid query } else { $frev = FlaggedRevision::newFromTitle($article->getTitle(), $revId); } $oldFlags = $frev ? $frev->getTags() : FlaggedRevs::quickTags(FR_CHECKED); // basic tags $reviewTime = $frev ? $frev->getTimestamp() : ''; // last review of rev $priorRevId = $this->refRev ? $this->refRev->getId() : 0; # If we are reviewing updates to a page, start off with the stable revision's # flags. Otherwise, we just fill them in with the selected revision's flags. # @TODO: do we want to carry over info for other diffs? if ($srev && $srev->getRevId() == $priorRevId) { // diff-to-stable $flags = $srev->getTags(); # Check if user is allowed to renew the stable version. # If not, then get the flags for the new revision itself. if (!FlaggedRevs::userCanSetFlags($this->user, $oldFlags)) { $flags = $oldFlags; } # Re-review button is need for template/file only review case $reviewIncludes = $srev->getRevId() == $revId && !$article->stableVersionIsSynced(); } else { // views $flags = $oldFlags; $reviewIncludes = false; // re-review button not needed } # Disable form for unprivileged users $disabled = array(); if (!$article->getTitle()->quickUserCan('review') || !FlaggedRevs::userCanSetFlags($this->user, $flags)) { $disabled = array('disabled' => 'disabled'); } # Begin form... $reviewTitle = SpecialPage::getTitleFor('RevisionReview'); $action = $reviewTitle->getLocalUrl('action=submit'); $params = array('method' => 'post', 'action' => $action, 'id' => 'mw-fr-reviewform'); $form = Xml::openElement('form', $params) . "\n"; $form .= Xml::openElement('fieldset', array('class' => 'flaggedrevs_reviewform noprint')) . "\n"; # Add appropriate legend text $legendMsg = $frev ? 'revreview-reflag' : 'revreview-flag'; $form .= Xml::openElement('legend', array('id' => 'mw-fr-reviewformlegend')); $form .= "<strong>" . wfMessage($legendMsg)->escaped() . "</strong>"; $form .= Xml::closeElement('legend') . "\n"; # Show explanatory text $form .= $this->topNotice; # Check if anyone is reviewing this already and # show a conflict warning message as needed... if ($priorRevId) { list($u, $ts) = FRUserActivity::getUserReviewingDiff($priorRevId, $this->rev->getId()); } else { list($u, $ts) = FRUserActivity::getUserReviewingPage($this->rev->getPage()); } $form .= Xml::openElement('p'); // Page under review (and not by this user)... if ($u !== null && $u != $this->user->getName()) { $form .= '<span class="fr-under-review">'; $msg = $priorRevId ? 'revreview-poss-conflict-c' : 'revreview-poss-conflict-p'; $form .= wfMessage($msg, $u, $wgLang->date($ts, true), $wgLang->time($ts, true))->parse(); $form .= "</span>"; // Page not under review or under review by this user... } elseif (!$frev) { // rev not already reviewed $form .= '<span id="mw-fr-reviewing-status" style="display:none;"></span>'; // JS widget } $form .= Xml::closeElement('p') . "\n"; # Start rating controls $css = $disabled ? 'fr-rating-controls-disabled' : 'fr-rating-controls'; $form .= Xml::openElement('p', array('class' => $css, 'id' => 'fr-rating-controls')) . "\n"; # Add main checkboxes/selects $form .= Xml::openElement('span', array('id' => 'mw-fr-ratingselects', 'class' => 'fr-rating-options')) . "\n"; $form .= self::ratingInputs($this->user, $flags, (bool) $disabled, (bool) $frev) . "\n"; $form .= Xml::closeElement('span') . "\n"; # Don't put buttons & comment field on the same line as tag inputs. if (!$disabled && !FlaggedRevs::binaryFlagging()) { // $disabled => no comment/buttons $form .= "<br />"; } # Start comment & buttons $form .= Xml::openElement('span', array('id' => 'mw-fr-confirmreview')) . "\n"; # Hide comment input if needed if (!$disabled) { $form .= Xml::inputLabel(wfMessage('revreview-log')->text(), 'wpReason', 'mw-fr-commentbox', 40, '', array('maxlength' => 255, 'class' => 'fr-comment-box')); } # Add the submit buttons... $rejectId = $this->rejectRefRevId(); // determine if there will be reject button $form .= self::submitButtons($rejectId, $frev, (bool) $disabled, $reviewIncludes); # Show stability log if there is anything interesting... if ($article->isPageLocked()) { $form .= ' ' . FlaggedRevsXML::logToggle('revreview-log-toggle-show'); } # End comment & buttons $form .= Xml::closeElement('span') . "\n"; # ..add the actual stability log body here if ($article->isPageLocked()) { $form .= FlaggedRevsXML::stabilityLogExcerpt($article); } # End rating controls $form .= Xml::closeElement('p') . "\n"; # Show explanatory text $form .= $this->bottomNotice; # Get the file version used for File: pages as needed $fileKey = $this->getFileVersion(); # Get template/file version info as needed list($templateIDs, $imageSHA1Keys) = $this->getIncludeVersions(); # Convert these into flat string params list($templateParams, $imageParams, $fileVersion) = RevisionReviewForm::getIncludeParams($templateIDs, $imageSHA1Keys, $fileKey); # Hidden params $form .= Html::hidden('title', $reviewTitle->getPrefixedText()) . "\n"; $form .= Html::hidden('target', $article->getTitle()->getPrefixedDBKey()) . "\n"; $form .= Html::hidden('refid', $priorRevId, array('id' => 'mw-fr-input-refid')) . "\n"; $form .= Html::hidden('oldid', $revId, array('id' => 'mw-fr-input-oldid')) . "\n"; $form .= Html::hidden('wpEditToken', $this->user->getEditToken()) . "\n"; $form .= Html::hidden('changetime', $reviewTime, array('id' => 'mw-fr-input-changetime')) . "\n"; // id for JS $form .= Html::hidden('userreviewing', (int) ($u === $this->user->getName()), array('id' => 'mw-fr-user-reviewing')) . "\n"; // id for JS # Add review parameters $form .= Html::hidden('templateParams', $templateParams) . "\n"; $form .= Html::hidden('imageParams', $imageParams) . "\n"; $form .= Html::hidden('fileVersion', $fileVersion) . "\n"; # Special token to discourage fiddling... $key = $this->request->getSessionData('wsFlaggedRevsKey'); $checkCode = RevisionReviewForm::validationKey($templateParams, $imageParams, $fileVersion, $revId, $key); $form .= Html::hidden('validatedParams', $checkCode) . "\n"; $form .= Xml::closeElement('fieldset') . "\n"; $form .= Xml::closeElement('form') . "\n"; return array($form, true); }
public function testUserReviewingDiff() { $oldid = 12910; $newid = 15910; FRUserActivity::clearAllReviewingDiff($oldid, $newid); // clear $this->assertEquals(true, FRUserActivity::setUserReviewingDiff($this->user, $oldid, $newid), "Set reviewing page succeeds"); $this->assertEquals(true, FRUserActivity::clearUserReviewingDiff($this->user, $oldid, $newid), "Unset reviewing page"); $this->assertEquals(false, FRUserActivity::clearUserReviewingDiff($this->user, $oldid, $newid), "Extra unset reviewing page"); // set two instances... $this->assertEquals(true, FRUserActivity::setUserReviewingDiff($this->user, $oldid, $newid), "Set reviewing page (1)"); $this->assertEquals(true, FRUserActivity::setUserReviewingDiff($this->user, $oldid, $newid), "Set reviewing page (2)"); // clear both... $this->assertEquals(true, FRUserActivity::clearUserReviewingDiff($this->user, $oldid, $newid), "Unset reviewing page (1)"); $this->assertEquals(true, FRUserActivity::clearUserReviewingDiff($this->user, $oldid, $newid), "Unset reviewing page (2)"); // extra clears... $this->assertEquals(false, FRUserActivity::clearUserReviewingDiff($this->user, $oldid, $newid), "Extra unset reviewing page"); }