r66652 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r66651‎ | r66652 | r66653 >
Date:19:53, 19 May 2010
Author:aaron
Status:deferred (Comments)
Tags:
Comment:
* Refactored review form class
* Fixed session check in ajaxreview
* Fixed reviewability check for review
* Cleaned up API review description
* Fixed autoreview check from r66633
Modified paths:
  • /trunk/extensions/FlaggedRevs/FlaggedRevs.class.php (modified) (history)
  • /trunk/extensions/FlaggedRevs/FlaggedRevs.php (modified) (history)
  • /trunk/extensions/FlaggedRevs/FlaggedRevsXML.php (modified) (history)
  • /trunk/extensions/FlaggedRevs/api/ApiReview.php (modified) (history)
  • /trunk/extensions/FlaggedRevs/forms/PageStabilityForm.php (modified) (history)
  • /trunk/extensions/FlaggedRevs/forms/RevisionReviewForm.php (added) (history)
  • /trunk/extensions/FlaggedRevs/language/FlaggedRevs.i18n.php (modified) (history)
  • /trunk/extensions/FlaggedRevs/specialpages/RevisionReview_body.php (modified) (history)

Diff [purge]

Index: trunk/extensions/FlaggedRevs/FlaggedRevs.php
@@ -332,13 +332,15 @@
333333 # Load FlaggedRevision object class
334334 $wgAutoloadClasses['FlaggedRevision'] = $dir . 'FlaggedRevision.php';
335335
336 -# Load review UI
337 -$wgAutoloadClasses['RevisionReview'] = $dir . 'specialpages/RevisionReview_body.php';
338 -# Load protection/stability UI
 336+# Load review form
 337+$wgAutoloadClasses['RevisionReviewForm'] = $dir . 'forms/RevisionReviewForm.php';
 338+# Load protection/stability form
339339 $wgAutoloadClasses['PageStabilityForm'] = $dir . 'forms/PageStabilityForm.php';
340340 $wgAutoloadClasses['PageStabilityGeneralForm'] = $dir . 'forms/PageStabilityForm.php';
341341 $wgAutoloadClasses['PageStabilityProtectForm'] = $dir . 'forms/PageStabilityForm.php';
342342
 343+# Load revision review UI
 344+$wgAutoloadClasses['RevisionReview'] = $dir . 'specialpages/RevisionReview_body.php';
343345 # Load reviewed versions UI
344346 $wgAutoloadClasses['ReviewedVersions'] = $dir . 'specialpages/ReviewedVersions_body.php';
345347 $wgExtensionMessagesFiles['ReviewedVersions'] = $langDir . 'ReviewedVersions.i18n.php';
Index: trunk/extensions/FlaggedRevs/language/FlaggedRevs.i18n.php
@@ -91,6 +91,17 @@
9292 A template or file may have been requested when no specific version was specified.
9393 This can happen if a dynamic template transcludes another file or template depending on a variable that changed since you started reviewing this page.
9494 Refreshing the page and rereviewing can solve this problem.',
 95+
 96+ 'review_page_invalid' => 'The target page title is invalid.',
 97+ 'review_page_notexists' => 'The target page does not exist.',
 98+ 'review_page_unreviewable' => 'The target page is not reviewable.',
 99+ 'review_no_oldid' => 'No revision ID specified.',
 100+ 'review_bad_oldid' => 'There is no such target revision.',
 101+ 'review_too_low' => 'Revision cannot be reviewed with some fields left unapproved.',
 102+ 'review_bad_key' => 'Invalid inclusion parameter key.',
 103+ 'review_denied' => 'Permission denied.',
 104+ 'review_param_missing' => 'A parameter is missing or invalid.',
 105+
95106 'revreview-current' => 'Pending changes',
96107 'revreview-depth' => 'Depth',
97108 'revreview-depth-0' => 'Unapproved',
@@ -170,6 +181,7 @@
171182 'revreview-toggle-hide' => '(-)',
172183 'revreview-toggle-title' => 'show/hide details',
173184 'revreview-toolow' => '\'\'\'You must rate each of the attributes higher than "unapproved" in order for a revision to be considered reviewed.\'\'\'
 185+
174186 To remove the review status of a revision, set all fields to "unapproved".
175187
176188 Please hit the "back" button in your browser and try again.',
Index: trunk/extensions/FlaggedRevs/FlaggedRevs.class.php
@@ -1218,7 +1218,7 @@
12191219 $defaultConfig = self::getDefaultVisibilitySettings();
12201220 # Check if the page is not protected at all...
12211221 if ( $config['override'] == $defaultConfig['override']
1222 - && $config['autoreview'] == $defaultConfig['autoreview'] )
 1222+ && $config['autoreview'] == '' )
12231223 {
12241224 return "none"; // not protected
12251225 }
Index: trunk/extensions/FlaggedRevs/forms/RevisionReviewForm.php
@@ -0,0 +1,702 @@
 2+<?php
 3+# (c) Aaron Schulz 2010 GPL
 4+if ( !defined( 'MEDIAWIKI' ) ) {
 5+ echo "FlaggedRevs extension\n";
 6+ exit( 1 );
 7+}
 8+/**
 9+ * Class containing revision review form business logic
 10+ * Note: edit tokens are the responsibility of caller
 11+ * Usage: (a) set ALL form params before doing anything else
 12+ * (b) call ready() when all params are set
 13+ * (c) call submit() as needed
 14+ */
 15+class RevisionReviewForm
 16+{
 17+ /* Form parameters which can be user given */
 18+ protected $page = null;
 19+ protected $rcid = 0;
 20+ protected $approve = false;
 21+ protected $unapprove = false;
 22+ protected $oldid = 0;
 23+ protected $templateParams = '';
 24+ protected $imageParams = '';
 25+ protected $fileVersion = '';
 26+ protected $validatedParams = '';
 27+ protected $notes = '';
 28+ protected $comment = '';
 29+ protected $dims = array();
 30+
 31+ protected $unapprovedTags = 0;
 32+ protected $oflags = array();
 33+ protected $inputLock = 0; # Disallow bad submissions
 34+
 35+ protected $skin = null;
 36+
 37+ public function __construct() {
 38+ global $wgUser;
 39+ $this->skin = $wgUser->getSkin();
 40+ foreach ( FlaggedRevs::getTags() as $tag ) {
 41+ $this->dims[$tag] = 0;
 42+ }
 43+ }
 44+
 45+ public function getPage() {
 46+ return $this->page;
 47+ }
 48+
 49+ public function setPage( Title $value ) {
 50+ $this->trySet( $this->page, $value );
 51+ }
 52+
 53+ public function getRCId() {
 54+ return $this->page;
 55+ }
 56+
 57+ public function setRCId( $value ) {
 58+ $this->trySet( $this->rcid, (int)$value );
 59+ }
 60+
 61+ public function setApprove( $value ) {
 62+ $this->trySet( $this->approve, $value );
 63+ }
 64+
 65+ public function setUnapprove( $value ) {
 66+ $this->trySet( $this->unapprove, $value );
 67+ }
 68+
 69+ public function getOldId() {
 70+ return $this->oldid;
 71+ }
 72+
 73+ public function setOldId( $value ) {
 74+ $this->trySet( $this->oldid, (int)$value );
 75+ }
 76+
 77+ public function getTemplateParams() {
 78+ return $this->templateParams;
 79+ }
 80+
 81+ public function setTemplateParams( $value ) {
 82+ $this->trySet( $this->templateParams, $value );
 83+ }
 84+
 85+ public function getFileParams() {
 86+ return $this->imageParams;
 87+ }
 88+
 89+ public function setFileParams( $value ) {
 90+ $this->trySet( $this->imageParams, $value );
 91+ }
 92+
 93+ public function getFileVersion() {
 94+ return $this->fileVersion;
 95+ }
 96+
 97+ public function setFileVersion( $value ) {
 98+ $this->trySet( $this->fileVersion, $value );
 99+ }
 100+
 101+ public function getValidatedParams() {
 102+ return $this->validatedParams;
 103+ }
 104+
 105+ public function setValidatedParams( $value ) {
 106+ $this->trySet( $this->validatedParams, $value );
 107+ }
 108+
 109+ public function getComment() {
 110+ return $this->comment;
 111+ }
 112+
 113+ public function setComment( $value ) {
 114+ $this->trySet( $this->comment, $value );
 115+ }
 116+
 117+ public function getNotes() {
 118+ return $this->notes;
 119+ }
 120+
 121+ public function setNotes( $value ) {
 122+ global $wgUser;
 123+ if ( !FlaggedRevs::allowComments() || !$wgUser->isAllowed( 'validate' ) ) {
 124+ $value = '';
 125+ }
 126+ $this->trySet( $this->notes, $value );
 127+ }
 128+
 129+ public function getDims() {
 130+ return $this->dims;
 131+ }
 132+
 133+ public function setDim( $tag, $value ) {
 134+ if ( !in_array( $tag, FlaggedRevs::getTags() ) ) {
 135+ throw new MWException( "FlaggedRevs tag $tag does not exist.\n" );
 136+ }
 137+ $this->trySet( $this->dims[$tag], (int)$value );
 138+ }
 139+
 140+ /**
 141+ * Set a member field to a value if the fields are unlocked
 142+ */
 143+ protected function trySet( &$field, $value ) {
 144+ if ( $this->inputLock ) {
 145+ throw new MWException( __CLASS__ . " fields cannot be set anymore.\n");
 146+ } else {
 147+ $field = $value; // still allowing input
 148+ }
 149+ }
 150+
 151+ /**
 152+ * Signal that inputs are starting
 153+ */
 154+ public function start() {
 155+ $this->inputLock = 0;
 156+ }
 157+
 158+ /**
 159+ * Signal that inputs are done and load old config
 160+ * @return mixed (true on success, error string on target failure)
 161+ */
 162+ public function ready() {
 163+ $this->inputLock = 1;
 164+ $status = $this->checkTarget();
 165+ if ( $status !== true ) {
 166+ return $status; // bad target
 167+ }
 168+ # Get the revision's current flags, if any
 169+ $this->oflags = FlaggedRevs::getRevisionTags( $this->page, $this->oldid );
 170+ return $status;
 171+ }
 172+
 173+ /*
 174+ * Check that the target page is valid
 175+ * @return mixed (true on success, error string on failure)
 176+ */
 177+ protected function checkTarget() {
 178+ if ( is_null( $this->page ) ) {
 179+ return 'review_page_invalid';
 180+ } elseif ( !$this->page->exists() ) {
 181+ return 'review_page_notexists';
 182+ }
 183+ $fa = FlaggedArticle::getTitleInstance( $this->page );
 184+ if ( !$fa->isReviewable() ) {
 185+ return 'review_page_unreviewable';
 186+ }
 187+ return true;
 188+ }
 189+
 190+ /*
 191+ * Verify and clean up parameters (e.g. from POST request).
 192+ * @return mixed (true on success, error string on failure)
 193+ */
 194+ protected function checkSettings() {
 195+ $status = $this->checkTarget();
 196+ if ( $status !== true ) {
 197+ return $status; // bad target
 198+ }
 199+ if ( !$this->oldid ) {
 200+ return 'review_no_oldid';
 201+ }
 202+ # Check that this is an approval or de-approval
 203+ if ( $this->isApproval() === null ) {
 204+ return 'review_param_missing'; // user didn't say
 205+ }
 206+ # Fill in implicit tag data for binary flag case
 207+ if ( $iDims = $this->implicitDims() ) {
 208+ $this->dims = $iDims;
 209+ } else {
 210+ foreach ( FlaggedRevs::getDimensions() as $tag => $levels ) {
 211+ if ( $this->dims[$tag] === 0 ) {
 212+ $this->unapprovedTags++;
 213+ }
 214+ }
 215+ }
 216+ # We must at least rate each category as 1, the minimum
 217+ # Exception: we can rate ALL as unapproved to depreciate a revision
 218+ if ( $this->unapprovedTags
 219+ && $this->unapprovedTags < count( FlaggedRevs::getDimensions() ) )
 220+ {
 221+ return 'review_too_low';
 222+ }
 223+ # Special token to discourage fiddling...
 224+ $k = self::validationKey(
 225+ $this->templateParams, $this->imageParams, $this->fileVersion, $this->oldid );
 226+ if ( $this->validatedParams !== $k ) {
 227+ return 'review_bad_key';
 228+ }
 229+ # Check permissions and validate
 230+ # FIXME: invalid vs denied
 231+ if ( !FlaggedRevs::userCanSetFlags( $this->dims, $this->oflags ) ) {
 232+ return 'review_denied';
 233+ }
 234+ return true;
 235+ }
 236+
 237+ public function isAllowed() {
 238+ // Basic permission check
 239+ return ( $this->page
 240+ && $this->page->userCan( 'review' )
 241+ && $this->page->userCan( 'edit' )
 242+ );
 243+ }
 244+
 245+ // implicit dims for binary flag case
 246+ private function implicitDims() {
 247+ $tag = FlaggedRevs::binaryTagName();
 248+ if ( $tag ) {
 249+ if ( $this->approve ) {
 250+ return array( $tag => 1 );
 251+ } else if ( $this->unapprove ) {
 252+ return array( $tag => 0 );
 253+ }
 254+ }
 255+ return null;
 256+ }
 257+
 258+ public function isApproval() {
 259+ # If all values are set to zero, this has been unapproved
 260+ if ( FlaggedRevs::dimensionsEmpty() ) {
 261+ if ( $this->approve && !$this->unapprove ) {
 262+ return true; // no tags & approve param given
 263+ } elseif ( $this->unapprove && !$this->approve ) {
 264+ return false;
 265+ }
 266+ return null; // nothing valid asserted
 267+ } else {
 268+ foreach ( $this->dims as $quality => $value ) {
 269+ if ( $value ) return true;
 270+ }
 271+ return false;
 272+ }
 273+ }
 274+
 275+ /**
 276+ * Submit the form parameters for the page config to the DB.
 277+ *
 278+ * @return mixed (true on success, error string on failure)
 279+ */
 280+ public function submit() {
 281+ global $wgUser;
 282+ if ( !$this->inputLock ) {
 283+ throw new MWException( __CLASS__ . " input fields not set yet.\n");
 284+ }
 285+ $status = $this->checkSettings();
 286+ if ( $status !== true ) {
 287+ return $status; // cannot submit - broken params
 288+ }
 289+ # Double-check permissions
 290+ if ( !$this->isAllowed() ) {
 291+ return 'review_denied';
 292+ }
 293+ # We can only approve actual revisions...
 294+ if ( $this->isApproval() ) {
 295+ $rev = Revision::newFromTitle( $this->page, $this->oldid );
 296+ # Do not mess with archived/deleted revisions
 297+ if ( is_null( $rev ) || $rev->mDeleted ) {
 298+ return 'review_bad_oldid';
 299+ }
 300+ $status = $this->approveRevision( $rev );
 301+ # We can only unapprove approved revisions...
 302+ } else {
 303+ $frev = FlaggedRevision::newFromTitle( $this->page, $this->oldid );
 304+ # If we can't find this flagged rev, return to page???
 305+ if ( is_null( $frev ) ) {
 306+ return 'review_bad_oldid';
 307+ }
 308+ $status = $this->unapproveRevision( $frev );
 309+ }
 310+ # Watch page if set to do so
 311+ if ( $status === true ) {
 312+ if ( $wgUser->getOption( 'flaggedrevswatch' ) && !$this->page->userIsWatching() ) {
 313+ $wgUser->addWatch( $this->page );
 314+ }
 315+ }
 316+ return $status;
 317+ }
 318+
 319+ /**
 320+ * Adds or updates the flagged revision table for this page/id set
 321+ * @param Revision $rev
 322+ * @returns true on success, array of errors on failure
 323+ */
 324+ private function approveRevision( $rev ) {
 325+ global $wgUser, $wgMemc, $wgParser, $wgEnableParserCache;
 326+ wfProfileIn( __METHOD__ );
 327+
 328+ $article = new Article( $this->page );
 329+
 330+ $quality = 0;
 331+ if ( FlaggedRevs::isQuality( $this->dims ) ) {
 332+ $quality = FlaggedRevs::isPristine( $this->dims ) ? 2 : 1;
 333+ }
 334+ # Our flags
 335+ $flags = $this->dims;
 336+ # Some validation vars to make sure nothing changed during
 337+ $lastTempId = 0;
 338+ $lastImgTime = "0";
 339+ # Our template version pointers
 340+ $tmpset = $tmpParams = array();
 341+ $templateMap = explode( '#', trim( $this->templateParams ) );
 342+ foreach ( $templateMap as $template ) {
 343+ if ( !$template )
 344+ continue;
 345+
 346+ $m = explode( '|', $template, 2 );
 347+ if ( !isset( $m[0] ) || !isset( $m[1] ) || !$m[0] )
 348+ continue;
 349+
 350+ list( $prefixed_text, $rev_id ) = $m;
 351+
 352+ $tmp_title = Title::newFromText( $prefixed_text ); // Normalize this to be sure...
 353+ if ( is_null( $tmp_title ) )
 354+ continue; // Page must be valid!
 355+
 356+ if ( $rev_id > $lastTempId )
 357+ $lastTempId = $rev_id;
 358+
 359+ $tmpset[] = array(
 360+ 'ft_rev_id' => $rev->getId(),
 361+ 'ft_namespace' => $tmp_title->getNamespace(),
 362+ 'ft_title' => $tmp_title->getDBkey(),
 363+ 'ft_tmp_rev_id' => $rev_id
 364+ );
 365+ if ( !isset( $tmpParams[$tmp_title->getNamespace()] ) ) {
 366+ $tmpParams[$tmp_title->getNamespace()] = array();
 367+ }
 368+ $tmpParams[$tmp_title->getNamespace()][$tmp_title->getDBkey()] = $rev_id;
 369+ }
 370+ # Our image version pointers
 371+ $imgset = $imgParams = array();
 372+ $imageMap = explode( '#', trim( $this->imageParams ) );
 373+ foreach ( $imageMap as $image ) {
 374+ if ( !$image )
 375+ continue;
 376+ $m = explode( '|', $image, 3 );
 377+ # Expand our parameters ... <name>#<timestamp>#<key>
 378+ if ( !isset( $m[0] ) || !isset( $m[1] ) || !isset( $m[2] ) || !$m[0] )
 379+ continue;
 380+
 381+ list( $dbkey, $timestamp, $key ) = $m;
 382+
 383+ $img_title = Title::makeTitle( NS_IMAGE, $dbkey ); // Normalize
 384+ if ( is_null( $img_title ) )
 385+ continue; // Page must be valid!
 386+
 387+ if ( $timestamp > $lastImgTime )
 388+ $lastImgTime = $timestamp;
 389+
 390+ $imgset[] = array(
 391+ 'fi_rev_id' => $rev->getId(),
 392+ 'fi_name' => $img_title->getDBkey(),
 393+ 'fi_img_timestamp' => $timestamp,
 394+ 'fi_img_sha1' => $key
 395+ );
 396+ if ( !isset( $imgParams[$img_title->getDBkey()] ) ) {
 397+ $imgParams[$img_title->getDBkey()] = array();
 398+ }
 399+ $imgParams[$img_title->getDBkey()][$timestamp] = $key;
 400+ }
 401+ # If this is an image page, store corresponding file info
 402+ $fileData = array();
 403+ if ( $this->page->getNamespace() == NS_IMAGE && $this->fileVersion ) {
 404+ $data = explode( '#', $this->fileVersion, 2 );
 405+ if ( count( $data ) == 2 ) {
 406+ $fileData['name'] = $this->page->getDBkey();
 407+ $fileData['timestamp'] = $data[0];
 408+ $fileData['sha1'] = $data[1];
 409+ }
 410+ }
 411+
 412+ # Get current stable version ID (for logging)
 413+ $oldSv = FlaggedRevision::newFromStable( $this->page, FR_MASTER );
 414+ $oldSvId = $oldSv ? $oldSv->getRevId() : 0;
 415+
 416+ # Is this rev already flagged?
 417+ $flaggedOutput = false;
 418+ $oldfrev = FlaggedRevision::newFromTitle( $this->page, $rev->getId(), FR_MASTER );
 419+ if ( $oldfrev ) {
 420+ $flaggedOutput = FlaggedRevs::parseStableText( $article,
 421+ $oldfrev->getRevText(), $oldfrev->getRevId() );
 422+ }
 423+
 424+ # Be loose on templates that includes other files/templates dynamically.
 425+ # Strict checking breaks randomized images/metatemplates...(bug 14580)
 426+ global $wgUseCurrentTemplates, $wgUseCurrentImages;
 427+ $mustMatch = !( $wgUseCurrentTemplates && $wgUseCurrentImages );
 428+
 429+ # Set our versioning params cache
 430+ FlaggedRevs::setIncludeVersionCache( $rev->getId(), $tmpParams, $imgParams );
 431+ # Parse the text and check if all templates/files match up
 432+ $text = $rev->getText();
 433+ $stableOutput = FlaggedRevs::parseStableText( $article, $text, $rev->getId() );
 434+ $err =& $stableOutput->fr_includeErrors;
 435+ if ( $mustMatch ) { // if template/files must all be specified...
 436+ if ( !empty( $err )
 437+ || $stableOutput->fr_newestImageTime > $lastImgTime
 438+ || $stableOutput->fr_newestTemplateID > $lastTempId )
 439+ {
 440+ wfProfileOut( __METHOD__ );
 441+ return $err; // return templates/files with no version specified
 442+ }
 443+ }
 444+ # Clear our versioning params cache
 445+ FlaggedRevs::clearIncludeVersionCache( $rev->getId() );
 446+
 447+ # Is this a duplicate review?
 448+ if ( $oldfrev && $flaggedOutput ) {
 449+ $synced = true;
 450+ if ( $stableOutput->fr_newestImageTime != $flaggedOutput->fr_newestImageTime )
 451+ $synced = false;
 452+ elseif ( $stableOutput->fr_newestTemplateID != $flaggedOutput->fr_newestTemplateID )
 453+ $synced = false;
 454+ elseif ( $oldfrev->getTags() != $flags )
 455+ $synced = false;
 456+ elseif ( $oldfrev->getFileSha1() != @$fileData['sha1'] )
 457+ $synced = false;
 458+ elseif ( $oldfrev->getComment() != $this->notes )
 459+ $synced = false;
 460+ elseif ( $oldfrev->getQuality() != $quality )
 461+ $synced = false;
 462+ # Don't review if the same
 463+ if ( $synced ) {
 464+ wfProfileOut( __METHOD__ );
 465+ return true;
 466+ }
 467+ }
 468+
 469+ $dbw = wfGetDB( DB_MASTER );
 470+ # Our review entry
 471+ $flaggedRevision = new FlaggedRevision( array(
 472+ 'fr_rev_id' => $rev->getId(),
 473+ 'fr_page_id' => $rev->getPage(),
 474+ 'fr_user' => $wgUser->getId(),
 475+ 'fr_timestamp' => wfTimestampNow(),
 476+ 'fr_comment' => $this->notes,
 477+ 'fr_quality' => $quality,
 478+ 'fr_tags' => FlaggedRevision::flattenRevisionTags( $flags ),
 479+ 'fr_img_name' => $fileData ? $fileData['name'] : null,
 480+ 'fr_img_timestamp' => $fileData ? $fileData['timestamp'] : null,
 481+ 'fr_img_sha1' => $fileData ? $fileData['sha1'] : null
 482+ ) );
 483+
 484+ $dbw->begin();
 485+ $flaggedRevision->insertOn( $tmpset, $imgset );
 486+ # Avoid any lag issues
 487+ $this->page->resetArticleId( $rev->getPage() );
 488+ # Update recent changes
 489+ self::updateRecentChanges( $this->page, $rev->getId(), $this->rcid, true );
 490+ # Update the article review log
 491+ FlaggedRevsLogs::updateLog( $this->page, $this->dims, $this->oflags,
 492+ $this->comment, $this->oldid, $oldSvId, true );
 493+
 494+ # Update the links tables as the stable version may now be the default page.
 495+ # Try using the parser cache first since we didn't actually edit the current version.
 496+ $parserCache = ParserCache::singleton();
 497+ $poutput = $parserCache->get( $article, $wgUser );
 498+ if ( !$poutput
 499+ || !isset( $poutput->fr_newestTemplateID )
 500+ || !isset( $poutput->fr_newestImageTime ) )
 501+ {
 502+ $options = FlaggedRevs::makeParserOptions();
 503+ $poutput = $wgParser->parse( $article->getContent(), $article->mTitle, $options );
 504+ }
 505+ # Prepare for a link tracking update
 506+ $u = new LinksUpdate( $this->page, $poutput );
 507+ # If we know that this is now the new stable version
 508+ # (which it probably is), save it to the stable cache...
 509+ $sv = FlaggedRevision::newFromStable( $this->page, FR_MASTER/*consistent*/ );
 510+ if ( $sv && $sv->getRevId() == $rev->getId() ) {
 511+ global $wgParserCacheExpireTime;
 512+ $this->page->invalidateCache();
 513+ # Update stable cache with the revision we reviewed.
 514+ # Don't cache redirects; it would go unused and complicate things.
 515+ if ( !Title::newFromRedirect( $text ) ) {
 516+ FlaggedRevs::updatePageCache( $article, $wgUser, $stableOutput );
 517+ }
 518+ # We can set the sync cache key already
 519+ $includesSynced = true;
 520+ if ( $poutput->fr_newestImageTime > $stableOutput->fr_newestImageTime ) {
 521+ $includesSynced = false;
 522+ } elseif ( $poutput->fr_newestTemplateID > $stableOutput->fr_newestTemplateID ) {
 523+ $includesSynced = false;
 524+ }
 525+ $u->fr_stableRev = $sv; // no need to re-fetch this!
 526+ $u->fr_stableParserOut = $stableOutput; // no need to re-fetch this!
 527+ # We can set the sync cache key already.
 528+ $key = wfMemcKey( 'flaggedrevs', 'includesSynced', $article->getId() );
 529+ $data = FlaggedRevs::makeMemcObj( $includesSynced ? "true" : "false" );
 530+ $wgMemc->set( $key, $data, $wgParserCacheExpireTime );
 531+ } else {
 532+ # Get the old stable cache
 533+ $stableOutput = FlaggedRevs::getPageCache( $article, $wgUser );
 534+ # Clear the cache...(for page histories)
 535+ $this->page->invalidateCache();
 536+ if ( $stableOutput !== false ) {
 537+ # Reset stable cache if it existed, since we know it is the same.
 538+ FlaggedRevs::updatePageCache( $article, $wgUser, $stableOutput );
 539+ }
 540+ }
 541+ # Update link tracking. This will trigger extraLinksUpdate()...
 542+ $u->doUpdate();
 543+
 544+ $dbw->commit();
 545+ # Purge cache/squids for this page and any page that uses it
 546+ Article::onArticleEdit( $this->page );
 547+
 548+ wfProfileOut( __METHOD__ );
 549+ return true;
 550+ }
 551+
 552+ /**
 553+ * @param FlaggedRevision $frev
 554+ * Removes flagged revision data for this page/id set
 555+ */
 556+ private function unapproveRevision( $frev ) {
 557+ global $wgUser, $wgParser, $wgMemc;
 558+ wfProfileIn( __METHOD__ );
 559+
 560+ $dbw = wfGetDB( DB_MASTER );
 561+ $dbw->begin();
 562+ # Delete from flaggedrevs table
 563+ $dbw->delete( 'flaggedrevs',
 564+ array( 'fr_page_id' => $frev->getPage(), 'fr_rev_id' => $frev->getRevId() ) );
 565+ # Wipe versioning params
 566+ $dbw->delete( 'flaggedtemplates', array( 'ft_rev_id' => $frev->getRevId() ) );
 567+ $dbw->delete( 'flaggedimages', array( 'fi_rev_id' => $frev->getRevId() ) );
 568+ # Update recent changes
 569+ self::updateRecentChanges( $this->page, $frev->getRevId(), false, false );
 570+
 571+ # Get current stable version ID (for logging)
 572+ $oldSv = FlaggedRevision::newFromStable( $this->page, FR_MASTER );
 573+ $oldSvId = $oldSv ? $oldSv->getRevId() : 0;
 574+
 575+ # Update the article review log
 576+ FlaggedRevsLogs::updateLog( $this->page, $this->dims, $this->oflags,
 577+ $this->comment, $this->oldid, $oldSvId, false );
 578+
 579+ $article = new Article( $this->page );
 580+ # Update the links tables as a new stable version
 581+ # may now be the default page.
 582+ $parserCache = ParserCache::singleton();
 583+ $poutput = $parserCache->get( $article, $wgUser );
 584+ if ( $poutput == false ) {
 585+ $text = $article->getContent();
 586+ $options = FlaggedRevs::makeParserOptions();
 587+ $poutput = $wgParser->parse( $text, $article->mTitle, $options );
 588+ }
 589+ $u = new LinksUpdate( $this->page, $poutput );
 590+ $u->doUpdate();
 591+
 592+ # Clear the cache...
 593+ $this->page->invalidateCache();
 594+ # Purge cache/squids for this page and any page that uses it
 595+ $dbw->commit();
 596+ Article::onArticleEdit( $article->getTitle() );
 597+
 598+ wfProfileOut( __METHOD__ );
 599+ return true;
 600+ }
 601+
 602+ /**
 603+ * Get a validation key from versioning metadata
 604+ * @param string $tmpP
 605+ * @param string $imgP
 606+ * @param string $imgV
 607+ * @param integer $rid rev ID
 608+ * @return string
 609+ */
 610+ public static function validationKey( $tmpP, $imgP, $imgV, $rid ) {
 611+ global $wgReviewCodes;
 612+ # Fall back to $wgSecretKey/$wgProxyKey
 613+ if ( empty( $wgReviewCodes ) ) {
 614+ global $wgSecretKey, $wgProxyKey;
 615+ $key = $wgSecretKey ? $wgSecretKey : $wgProxyKey;
 616+ $p = md5( $key . $imgP . $tmpP . $rid . $imgV );
 617+ } else {
 618+ $p = md5( $wgReviewCodes[0] . $imgP . $rid . $tmpP . $imgV . $wgReviewCodes[1] );
 619+ }
 620+ return $p;
 621+ }
 622+
 623+ public static function updateRecentChanges( $title, $revId, $rcId = false, $patrol = true ) {
 624+ wfProfileIn( __METHOD__ );
 625+ $revId = intval( $revId );
 626+ $dbw = wfGetDB( DB_MASTER );
 627+ # Olders edits be marked as patrolled now...
 628+ $dbw->update( 'recentchanges',
 629+ array( 'rc_patrolled' => $patrol ? 1 : 0 ),
 630+ array( 'rc_cur_id' => $title->getArticleId(),
 631+ $patrol ? "rc_this_oldid <= $revId" : "rc_this_oldid = $revId" ),
 632+ __METHOD__,
 633+ // Performance
 634+ array( 'USE INDEX' => 'rc_cur_id', 'LIMIT' => 50 )
 635+ );
 636+ # New page patrol may be enabled. If so, the rc_id may be the first
 637+ # edit and not this one. If it is different, mark it too.
 638+ if ( $rcId && $rcId != $revId ) {
 639+ $dbw->update( 'recentchanges',
 640+ array( 'rc_patrolled' => 1 ),
 641+ array( 'rc_id' => $rcId,
 642+ 'rc_type' => RC_NEW ),
 643+ __METHOD__
 644+ );
 645+ }
 646+ wfProfileOut( __METHOD__ );
 647+ }
 648+
 649+ ########## Common form elements ##########
 650+
 651+ public function approvalSuccessHTML( $showlinks = false ) {
 652+ global $wgUser;
 653+ # Show success message
 654+ $form = "<div class='plainlinks'>";
 655+ $form .= wfMsgExt( 'revreview-successful', 'parse',
 656+ $this->page->getPrefixedText(), $this->page->getPrefixedUrl() );
 657+ $form .= wfMsgExt( 'revreview-stable1', 'parse',
 658+ $this->page->getPrefixedUrl(), $this->getOldId() );
 659+ $form .= "</div>";
 660+ # Handy links to special pages
 661+ if ( $showlinks && $wgUser->isAllowed( 'unreviewedpages' ) ) {
 662+ $form .= $this->getSpecialLinks();
 663+ }
 664+ return $form;
 665+ }
 666+
 667+ public function deapprovalSuccessHTML( $showlinks = false ) {
 668+ global $wgUser;
 669+ # Show success message
 670+ $form = "<div class='plainlinks'>";
 671+ $form .= wfMsgExt( 'revreview-successful2', 'parse',
 672+ $this->page->getPrefixedText(), $this->page->getPrefixedUrl() );
 673+ $form .= wfMsgExt( 'revreview-stable2', 'parse',
 674+ $this->page->getPrefixedUrl(), $this->getOldId() );
 675+ $form .= "</div>";
 676+ # Handy links to special pages
 677+ if ( $showlinks && $wgUser->isAllowed( 'unreviewedpages' ) ) {
 678+ $form .= $this->getSpecialLinks();
 679+ }
 680+ return $form;
 681+ }
 682+
 683+ public function syncFailureHTML( array $status, $showlinks = false ) {
 684+ $form = wfMsgExt( 'revreview-changed', 'parse', $this->page->getPrefixedText() );
 685+ $form .= "<ul>";
 686+ foreach ( $status as $n => $text ) {
 687+ $form .= "<li><i>$text</i></li>\n";
 688+ }
 689+ $form .= "</ul>";
 690+ if ( $showlinks ) {
 691+ $form .= wfMsg( 'returnto', $this->skin->makeLinkObj( $this->page ) );
 692+ }
 693+ return $form;
 694+ }
 695+
 696+ private function getSpecialLinks() {
 697+ $s = '<p>' . wfMsg( 'returnto',
 698+ $this->skin->makeLinkObj( SpecialPage::getTitleFor( 'UnreviewedPages' ) ) ) . '</p>';
 699+ $s .= '<p>' . wfMsg( 'returnto',
 700+ $this->skin->makeLinkObj( SpecialPage::getTitleFor( 'OldReviewedPages' ) ) ) . '</p>';
 701+ return $s;
 702+ }
 703+}
Property changes on: trunk/extensions/FlaggedRevs/forms/RevisionReviewForm.php
___________________________________________________________________
Added: svn:eol-style
1704 + native
Index: trunk/extensions/FlaggedRevs/forms/PageStabilityForm.php
@@ -6,7 +6,7 @@
77 }
88 /**
99 * Class containing stability settings form business logic
10 - *
 10+ * Note: edit tokens are the responsibility of caller
1111 * Usage: (a) set ALL form params before doing anything else
1212 * (b) call ready() when all params are set
1313 * (c) call preloadSettings() or submit() as needed
@@ -98,7 +98,7 @@
9999 if ( $this->inputLock ) {
100100 throw new MWException( __CLASS__ . " fields cannot be set anymore.\n");
101101 } else {
102 - $field = $value; // submission locked => still allowing input
 102+ $field = $value; // still allowing input
103103 }
104104 }
105105
@@ -453,7 +453,9 @@
454454 return 'stabilize_invalid_precedence'; // invalid precedence value
455455 }
456456 // Check autoreview restriction setting
457 - if ( !in_array( $this->autoreview, FlaggedRevs::getRestrictionLevels() ) ) {
 457+ if ( $this->autoreview != '' // restriction other than 'none'
 458+ && !in_array( $this->autoreview, FlaggedRevs::getRestrictionLevels() ) )
 459+ {
458460 return 'stabilize_invalid_autoreview'; // invalid value
459461 }
460462 if ( !FlaggedRevs::userCanSetAutoreviewLevel( $this->autoreview ) ) {
Index: trunk/extensions/FlaggedRevs/specialpages/RevisionReview_body.php
@@ -8,33 +8,18 @@
99
1010 class RevisionReview extends UnlistedSpecialPage
1111 {
12 - // Initialize vars in case of broken AJAX input
13 - var $page = null;
14 - var $rcid = 0;
15 - var $approve = false;
16 - var $unapprove = false;
17 - var $oldid = 0;
18 - var $templateParams = '';
19 - var $imageParams = '';
20 - var $fileVersion = '';
21 - var $validatedParams = '';
22 - var $notes = '';
23 - var $comment = '';
24 - var $dims = array();
25 - var $unapprovedTags = 0;
26 -
 12+ private $form;
 13+ private $page;
 14+
2715 public function __construct() {
28 - global $wgUser;
2916 parent::__construct( 'RevisionReview', 'review' );
30 - $this->skin = $wgUser->getSkin();
3117 }
3218
3319 public function execute( $par ) {
3420 global $wgRequest, $wgUser, $wgOut;
35 - $confirm = $wgRequest->wasPosted()
36 - && $wgUser->matchEditToken( $wgRequest->getVal( 'wpEditToken' ) );
 21+ $confirmed = $wgUser->matchEditToken( $wgRequest->getVal( 'wpEditToken' ) );
3722 if ( $wgUser->isAllowed( 'review' ) ) {
38 - if ( $wgUser->isBlocked( !$confirm ) ) {
 23+ if ( $wgUser->isBlocked( !$confirmed ) ) {
3924 $wgOut->blockedPage();
4025 return;
4126 }
@@ -47,141 +32,114 @@
4833 return;
4934 }
5035 $this->setHeaders();
 36+
 37+ $this->form = new RevisionReviewForm();
 38+ $form = $this->form; // convenience
5139 # Our target page
5240 $this->page = Title::newFromURL( $wgRequest->getVal( 'target' ) );
53 - if ( is_null( $this->page ) ) {
 41+ if ( !$this->page ) {
5442 $wgOut->showErrorPage( 'notargettitle', 'notargettext' );
5543 return;
5644 }
 45+ $form->setPage( $this->page );
5746 # Param for sites with binary flagging
58 - $this->approve = $wgRequest->getCheck( 'wpApprove' );
59 - $this->unapprove = $wgRequest->getCheck( 'wpUnapprove' );
60 - # Review the edit if requested...
61 - $this->markReviewed();
62 - }
63 -
64 - // implicit dims for binary flag case
65 - public function implicitDims() {
66 - $tag = FlaggedRevs::binaryTagName();
67 - if ( $tag ) {
68 - if ( $this->approve ) {
69 - return array( $tag => 1 );
70 - } else if ( $this->unapprove ) {
71 - return array( $tag => 0 );
72 - }
73 - }
74 - return null;
75 - }
76 -
77 - // non-JS submission code...
78 - private function markReviewed() {
79 - global $wgRequest, $wgOut, $wgUser;
80 - # Must be in reviewable namespace
81 - if ( !FlaggedRevs::inReviewNamespace( $this->page ) ) {
82 - $wgOut->addHTML( wfMsgExt( 'revreview-main', array( 'parse' ) ) );
83 - return;
84 - }
85 - # Get revision ID
86 - $this->oldid = $wgRequest->getIntOrNull( 'oldid' );
87 - if ( !$this->oldid ) {
88 - $wgOut->showErrorPage( 'internalerror', 'revreview-revnotfound' );
89 - return;
90 - }
91 - # Check if page is protected
92 - if ( !$this->page->quickUserCan( 'edit' ) ) {
93 - $wgOut->permissionRequired( 'badaccess-group0' );
94 - return;
95 - }
 47+ $form->setApprove( $wgRequest->getCheck( 'wpApprove' ) );
 48+ $form->setUnapprove( $wgRequest->getCheck( 'wpUnapprove' ) );
 49+ # Rev ID
 50+ $oldid = $wgRequest->getInt( 'oldid' );
 51+ $form->setOldId( $oldid );
9652 # Special parameter mapping
97 - $this->templateParams = $wgRequest->getVal( 'templateParams' );
98 - $this->imageParams = $wgRequest->getVal( 'imageParams' );
99 - $this->fileVersion = $wgRequest->getVal( 'fileVersion' );
100 - $this->validatedParams = $wgRequest->getVal( 'validatedParams' );
 53+ $form->setTemplateParams( $wgRequest->getVal( 'templateParams' ) );
 54+ $form->setFileParams( $wgRequest->getVal( 'imageParams' ) );
 55+ $form->setFileVersion( $wgRequest->getVal( 'fileVersion' ) );
10156 # Special token to discourage fiddling...
102 - $k = self::validationKey( $this->templateParams, $this->imageParams,
103 - $this->fileVersion, $this->oldid );
104 - if ( $this->validatedParams !== $k ) {
105 - $wgOut->permissionRequired( 'badaccess-group0' );
106 - return;
 57+ $form->setValidatedParams( $wgRequest->getVal( 'validatedParams' ) );
 58+ # Tag values
 59+ foreach ( FlaggedRevs::getDimensions() as $tag => $levels ) {
 60+ # This can be NULL if we uncheck a checkbox
 61+ $val = $wgRequest->getInt( "wp$tag" );
 62+ $form->setDim( $tag, $val );
10763 }
10864 # Log comment
109 - $this->comment = $wgRequest->getText( 'wpReason' );
 65+ $form->setComment( $wgRequest->getText( 'wpReason' ) );
11066 # Additional notes (displayed at bottom of page)
111 - $this->retrieveNotes( $wgRequest->getText( 'wpNotes' ) );
112 - # Get the revision's current flags, if any
113 - $this->oflags = FlaggedRevs::getRevisionTags( $this->page, $this->oldid );
114 - # Get our accuracy/quality dimensions
115 - $this->dims = array();
116 - $this->unapprovedTags = 0;
117 - # Fill in implicit tag data for binary flag case
118 - if ( $iDims = $this->implicitDims() ) {
119 - $this->dims = $iDims;
120 - } else {
121 - foreach ( FlaggedRevs::getDimensions() as $tag => $levels ) {
122 - $this->dims[$tag] = $wgRequest->getIntOrNull( "wp$tag" );
123 - if ( $this->dims[$tag] === 0 ) {
124 - $this->unapprovedTags++;
125 - } elseif ( is_null( $this->dims[$tag] ) ) {
126 - # This happens if we uncheck a checkbox
127 - $this->unapprovedTags++;
128 - $this->dims[$tag] = 0;
129 - }
130 - }
131 - }
132 - # Check permissions and validate
133 - if ( !FlaggedRevs::userCanSetFlags( $this->dims, $this->oflags ) ) {
134 - $wgOut->permissionRequired( 'badaccess-group0' );
 67+ $form->setNotes( $wgRequest->getText( 'wpNotes' ) );
 68+
 69+ $status = $form->ready();
 70+ # Page must exist and be in reviewable namespace
 71+ if ( $status === 'review_page_unreviewable' ) {
 72+ $wgOut->addWikiText( wfMsg( 'revreview-main' ) );
13573 return;
 74+ } elseif ( $status === 'review_page_notexists' ) {
 75+ $wgOut->showErrorPage( 'internalerror', 'nopagetext' );
 76+ return;
13677 }
137 - # We must at least rate each category as 1, the minimum
138 - # Exception: we can rate ALL as unapproved to depreciate a revision
139 - if ( $this->unapprovedTags && $this->unapprovedTags < count( FlaggedRevs::getDimensions() ) ) {
140 - $wgOut->addWikiText( wfMsg( 'revreview-toolow' ) );
141 - $wgOut->returnToMain( false, $this->page );
 78+ # Basic page permission checks...
 79+ $permErrors = $this->page->getUserPermissionsErrors( 'review', $wgUser, false );
 80+ if ( !$permErrors ) {
 81+ $permErrors = $this->page->getUserPermissionsErrors( 'edit', $wgUser, false );
 82+ }
 83+ if ( $permErrors ) {
 84+ $wgOut->showPermissionsErrorPage( $permErrors, 'review' );
14285 return;
143 - } elseif ( !$wgUser->matchEditToken( $wgRequest->getVal( 'wpEditToken' ) ) ) {
144 - $wgOut->addWikiText( wfMsg( 'sessionfailure' ) );
145 - $wgOut->returnToMain( false, $this->page );
146 - return;
14786 }
148 - # Submit or display info on failure
 87+
 88+ # Review the edit if requested (POST)...
14989 if ( $wgRequest->wasPosted() ) {
150 - list( $approved, $status ) = $this->submit();
 90+ // Check the edit token...
 91+ if ( !$confirmed ) {
 92+ $wgOut->addWikiText( wfMsg( 'sessionfailure' ) );
 93+ $wgOut->returnToMain( false, $this->page );
 94+ return;
 95+ }
 96+ $status = $form->submit();
15197 // Success for either flagging or unflagging
15298 if ( $status === true ) {
15399 $wgOut->setPageTitle( wfMsgHtml( 'actioncomplete' ) );
154 - $wgOut->addHTML( $this->showSuccess( $approved, true ) );
 100+ if ( $form->isApproval() ) {
 101+ $wgOut->addHTML( $form->approvalSuccessHTML( true ) );
 102+ } else {
 103+ $wgOut->addHTML( $form->deapprovalSuccessHTML( true ) );
 104+ }
 105+ // Failure for unflagging
 106+ } elseif ( !$form->isApproval() ) {
 107+ $wgOut->redirect( $this->page->getFullUrl() ); // already unflagged
155108 // Sync failure for flagging
156 - } elseif ( is_array( $status ) && $approved ) {
 109+ } elseif ( is_array( $status ) ) {
157110 $wgOut->setPageTitle( wfMsgHtml( 'internalerror' ) );
158 - $wgOut->addHTML( $this->showSyncFailure( $status, true ) );
159 - // Failure for unflagging
160 - } elseif ( $status === false && !$approved ) {
161 - $wgOut->redirect( $this->page->getFullUrl() );
162 - // Any other fail...
 111+ $wgOut->addHTML( $form->syncFailureHTML( $status, true ) );
 112+ // Any other fails for flagging...
163113 } else {
164 - $wgOut->setPageTitle( wfMsgHtml( 'internalerror' ) );
165 - $wgOut->showErrorPage( 'internalerror', 'revreview-revnotfound' );
 114+ if ( $status === 'review_denied' ) {
 115+ $wgOut->permissionRequired( 'badaccess-group0' ); // protected?
 116+ } elseif ( $status === 'review_bad_key' ) {
 117+ $wgOut->permissionRequired( 'badaccess-group0' ); // fiddling
 118+ } elseif ( $status === 'review_bad_oldid' ) {
 119+ $wgOut->showErrorPage( 'internalerror', 'revreview-revnotfound' );
 120+ } elseif ( $status === 'review_too_low' ) {
 121+ $wgOut->addWikiText( wfMsg( 'revreview-toolow' ) );
 122+ } else {
 123+ $wgOut->showErrorPage( 'internalerror', $status );
 124+ }
166125 $wgOut->returnToMain( false, $this->page );
167126 }
 127+ // No form to view (GET)
 128+ } else {
 129+ $wgOut->returnToMain( false, $this->page );
168130 }
169131 }
170 -
171 - private function retrieveNotes( $notes = '' ) {
172 - global $wgUser;
173 - $this->notes = ( FlaggedRevs::allowComments() && $wgUser->isAllowed( 'validate' ) ) ?
174 - $notes : '';
175 - }
176 -
 132+
177133 public static function AjaxReview( /*$args...*/ ) {
178 - global $wgUser;
 134+ global $wgUser, $wgOut;
179135 $args = func_get_args();
180136 if ( wfReadOnly() ) {
181137 return '<err#>' . wfMsgExt( 'revreview-failed', 'parseinline' );
182138 }
183139 $tags = FlaggedRevs::getDimensions();
184140 // Make review interface object
185 - $form = new RevisionReview();
 141+ $form = new RevisionReviewForm();
 142+ $title = null; // target page
 143+ $editToken = ''; // edit token
186144 // Each ajax url argument is of the form param|val.
187145 // This means that there is no ugly order dependance.
188146 foreach ( $args as $x => $arg ) {
@@ -193,535 +151,95 @@
194152 switch( $par )
195153 {
196154 case "target":
197 - $form->page = Title::newFromURL( $val );
198 - if ( is_null( $form->page ) || !FlaggedRevs::inReviewNamespace( $form->page ) ) {
199 - return '<err#>' . wfMsgExt( 'revreview-failed', 'parseinline' );
200 - }
 155+ $title = Title::newFromURL( $val );
201156 break;
202157 case "oldid":
203 - $form->oldid = intval( $val );
204 - if ( !$form->oldid ) {
205 - return '<err#>' . wfMsgExt( 'revreview-failed', 'parseinline' );
206 - }
 158+ $form->setOldId( $val );
207159 break;
208160 case "rcid":
209 - $form->rcid = intval( $val );
 161+ $form->setRCId( $val );
210162 break;
211163 case "validatedParams":
212 - $form->validatedParams = $val;
 164+ $form->setValidatedParams( $val );
213165 break;
214166 case "templateParams":
215 - $form->templateParams = $val;
 167+ $form->setTemplateParams( $val);
216168 break;
217169 case "imageParams":
218 - $form->imageParams = $val;
 170+ $form->setFileParams( $val );
219171 break;
220172 case "fileVersion":
221 - $form->fileVersion = $val;
 173+ $form->setFileVersion( $val );
222174 break;
223175 case "wpApprove":
224 - $form->approve = $val;
 176+ $form->setApprove( $val );
225177 break;
226178 case "wpUnapprove":
227 - $form->unapprove = $val;
 179+ $form->setUnapprove( $val );
228180 break;
229181 case "wpReason":
230 - $form->comment = $val;
 182+ $form->setComment( $val );
231183 break;
232184 case "wpNotes":
233 - $form->retrieveNotes( $val );
 185+ $form->setNotes( $val );
234186 break;
235187 case "wpEditToken":
236 - if ( !$wgUser->matchEditToken( $val ) ) {
237 - return '<err#>' . wfMsgExt( 'sessionfailure', 'parseinline' );
238 - }
 188+ $editToken = $val;
239189 break;
240190 default:
241191 $p = preg_replace( '/^wp/', '', $par ); // kill any "wp" prefix
242192 if ( array_key_exists( $p, $tags ) ) {
243 - $form->dims[$p] = intval( $val );
244 - if ( $form->dims[$p] === 0 ) {
245 - $form->unapprovedTags++;
246 - }
 193+ $form->setDim( $p, $val );
247194 }
248195 break;
249196 }
250197 }
251 - // No page?
252 - if ( !$form->page ) {
253 - return '<err#>' . wfMsgExt( 'revreview-failed', 'parseinline' );
 198+ # Valid target title?
 199+ if ( !$title ) {
 200+ return '<err#>' . wfMsgExt( 'notargettext', 'parseinline' );
254201 }
255 - // Basic permission check
256 - $permErrors = $form->page->getUserPermissionsErrors( 'review', $wgUser );
 202+ $form->setPage( $title );
 203+
 204+ $status = $form->ready(); // all params loaded
 205+ # Page must exist and be in reviewable namespace
 206+ if ( $status === 'review_page_unreviewable' ) {
 207+ return '<err#>' . wfMsgExt( 'revreview-main', 'parseinline' );
 208+ } elseif ( $status === 'review_page_notexists' ) {
 209+ return '<err#>' . wfMsgExt( 'nopagetext', 'parseinline' );
 210+ }
 211+ # Check session via user token
 212+ if ( !$wgUser->matchEditToken( $editToken ) ) {
 213+ return '<err#>' . wfMsgExt( 'sessionfailure', 'parseinline' );
 214+ }
 215+ # Basic permission checks...
 216+ $permErrors = $title->getUserPermissionsErrors( 'review', $wgUser, false );
257217 if ( !$permErrors ) {
258 - // User must be able to edit this page
259 - $permErrors = $form->page->getUserPermissionsErrors( 'edit', $wgUser );
 218+ $permErrors = $title->getUserPermissionsErrors( 'edit', $wgUser, false );
260219 }
261220 if ( $permErrors ) {
262 - global $wgOut;
263221 return '<err#>' . $wgOut->parse(
264222 $wgOut->formatPermissionsErrorMessage( $permErrors, 'review' )
265223 );
266224 }
267 - # Fill in implicit tag data for binary flag case
268 - if ( $iDims = $form->implicitDims() ) {
269 - $form->dims = $iDims;
270 - }
271 - // Missing params?
272 - if ( count( $form->dims ) != count( $tags ) ) {
273 - return '<err#>' . wfMsgExt( 'revreview-failed', 'parseinline' );
274 - }
275 - // Incomplete review?
276 - if ( !$form->oldid || is_null( $form->page ) ) {
277 - return '<err#>' . wfMsgExt( 'revreview-failed', 'parseinline' );
278 - }
279 - if ( $form->unapprovedTags
280 - && $form->unapprovedTags < count( FlaggedRevs::getDimensions() ) )
281 - {
282 - return '<err#>' . wfMsgExt( 'revreview-failed', 'parseinline' );
283 - }
284 - // Doesn't match up?
285 - $k = self::validationKey( $form->templateParams, $form->imageParams,
286 - $form->fileVersion, $form->oldid );
287 - if ( $form->validatedParams !== $k ) {
288 - return '<err#>' . wfMsgExt( 'revreview-failed', 'parseinline' );
289 - }
290 - # Get the revision's current flags, if any
291 - $form->oflags = FlaggedRevs::getRevisionTags( $form->page, $form->oldid );
292 - # Check tag permissions
293 - if ( !FlaggedRevs::userCanSetFlags( $form->dims, $form->oflags ) ) {
294 - return '<err#>' . wfMsgExt( 'revreview-failed', 'parseinline' );
295 - }
296 - list( $approved, $status ) = $form->submit();
 225+ # Try submission...
 226+ $status = $form->submit();
 227+ # Approve/de-approve success
297228 if ( $status === true ) {
298 - $tier = FlaggedRevs::getLevelTier( $form->dims ) + 1; // shift to 0-3
299 - return "<suc#><t#$tier>" . $form->showSuccess( $approved );
300 - } elseif ( $approved && is_array( $status ) ) {
301 - return '<err#>' . $form->showSyncFailure( $status );
302 - } elseif ( $approved ) {
303 - return '<err#>' . wfMsg( 'revreview-revnotfound' );
 229+ $tier = FlaggedRevs::getLevelTier( $form->getDims() ) + 1; // shift to 0-3
 230+ if ( $form->isApproval() ) {
 231+ return "<suc#><t#$tier>" . $form->approvalSuccessHTML( false );
 232+ } else {
 233+ return "<suc#><t#$tier>" . $form->deapprovalSuccessHTML( false );
 234+ }
 235+ # De-approve failure
 236+ } elseif ( !$form->isApproval() ) {
 237+ return "<suc#><t#0>"; // failure -> already unflagged
 238+ # Approve sync failure
 239+ } elseif ( is_array( $status ) ) {
 240+ return '<err#>' . $form->syncFailureHTML( $status, false );
 241+ # Other approval failures
304242 } else { // hmmm?
305243 return '<err#>' . wfMsgExt( 'revreview-failed', 'parseinline' );
306244 }
307245 }
308 -
309 - public function isApproval() {
310 - # If all values are set to zero, this has been unapproved
311 - if ( FlaggedRevs::dimensionsEmpty() ) {
312 - if ( $this->approve && !$this->unapprove )
313 - return true; // no tags & approve param given
314 - if ( $this->unapprove && !$this->approve )
315 - return false;
316 - else
317 - return null; // nothing valid asserted
318 - }
319 - foreach ( $this->dims as $quality => $value ) {
320 - if ( $value ) return true;
321 - }
322 - return false;
323 - }
324 -
325 - public function submit() {
326 - global $wgUser;
327 - # If all values are set to zero, this has been unapproved
328 - $approved = $this->isApproval();
329 - if ( $approved === null ) {
330 - return array( true, false ); // user didn't say
331 - }
332 - # Double-check permissions
333 - if ( !$this->page->quickUserCan( 'edit' )
334 - || !FlaggedRevs::userCanSetFlags( $this->dims, $this->oflags ) )
335 - {
336 - return array( $approved, false );
337 - }
338 - # We can only approve actual revisions...
339 - if ( $approved ) {
340 - $rev = Revision::newFromTitle( $this->page, $this->oldid );
341 - # Do not mess with archived/deleted revisions
342 - if ( is_null( $rev ) || $rev->mDeleted ) {
343 - return array( $approved, false );
344 - }
345 - $status = $this->approveRevision( $rev );
346 - # We can only unapprove approved revisions...
347 - } else {
348 - $frev = FlaggedRevision::newFromTitle( $this->page, $this->oldid );
349 - # If we can't find this flagged rev, return to page???
350 - if ( is_null( $frev ) ) {
351 - return array( $approved, true );
352 - }
353 - $status = $this->unapproveRevision( $frev );
354 - }
355 - # Watch page if set to do so
356 - if ( $status === true ) {
357 - if ( $wgUser->getOption( 'flaggedrevswatch' ) && !$this->page->userIsWatching() ) {
358 - $dbw = wfGetDB( DB_MASTER );
359 - $dbw->begin();
360 - $wgUser->addWatch( $this->page );
361 - $dbw->commit();
362 - }
363 - }
364 - return array( $approved, $status );
365 - }
366 -
367 - private function showSuccess( $approved, $showlinks = false ) {
368 - global $wgUser;
369 - # Show success message
370 - $msg = $approved ? 'revreview-successful' : 'revreview-successful2';
371 - $form = "<div class='plainlinks'>" . wfMsgExt( $msg, array( 'parseinline' ),
372 - $this->page->getPrefixedText(), $this->page->getPrefixedUrl() );
373 - $msg = $approved ? 'revreview-stable1' : 'revreview-stable2';
374 - $form .= wfMsgExt( $msg, array( 'parse' ), $this->page->getPrefixedUrl(), $this->oldid );
375 - $form .= "</div>";
376 - # Handy links to special pages
377 - if ( $showlinks && $wgUser->isAllowed( 'unreviewedpages' ) ) {
378 - $form .= '<p>' . wfMsg( 'returnto',
379 - $this->skin->makeLinkObj( SpecialPage::getTitleFor( 'UnreviewedPages' ) ) ) . '</p>';
380 - $form .= '<p>' . wfMsg( 'returnto',
381 - $this->skin->makeLinkObj( SpecialPage::getTitleFor( 'OldReviewedPages' ) ) ) . '</p>';
382 - }
383 - return $form;
384 - }
385 -
386 - private function showSyncFailure( $status, $showlinks = false ) {
387 - $form = wfMsgExt( 'revreview-changed', array( 'parse' ), $this->page->getPrefixedText() );
388 - $form .= "<ul>";
389 - foreach ( $status as $n => $text ) {
390 - $form .= "<li><i>$text</i></li>\n";
391 - }
392 - $form .= "</ul>";
393 - if ( $showlinks ) {
394 - $form .= wfMsg( 'returnto', $this->skin->makeLinkObj( $this->page ) );
395 - }
396 - return $form;
397 - }
398 -
399 - /**
400 - * Adds or updates the flagged revision table for this page/id set
401 - * @param Revision $rev
402 - * @returns true on success, array of errors on failure
403 - */
404 - private function approveRevision( $rev ) {
405 - global $wgUser, $wgMemc, $wgParser, $wgEnableParserCache;
406 - wfProfileIn( __METHOD__ );
407 -
408 - $article = new Article( $this->page );
409 -
410 - $quality = 0;
411 - if ( FlaggedRevs::isQuality( $this->dims ) ) {
412 - $quality = FlaggedRevs::isPristine( $this->dims ) ? 2 : 1;
413 - }
414 - # Our flags
415 - $flags = $this->dims;
416 - # Some validation vars to make sure nothing changed during
417 - $lastTempId = 0;
418 - $lastImgTime = "0";
419 - # Our template version pointers
420 - $tmpset = $tmpParams = array();
421 - $templateMap = explode( '#', trim( $this->templateParams ) );
422 - foreach ( $templateMap as $template ) {
423 - if ( !$template )
424 - continue;
425 -
426 - $m = explode( '|', $template, 2 );
427 - if ( !isset( $m[0] ) || !isset( $m[1] ) || !$m[0] )
428 - continue;
429 -
430 - list( $prefixed_text, $rev_id ) = $m;
431 -
432 - $tmp_title = Title::newFromText( $prefixed_text ); // Normalize this to be sure...
433 - if ( is_null( $tmp_title ) )
434 - continue; // Page must be valid!
435 -
436 - if ( $rev_id > $lastTempId )
437 - $lastTempId = $rev_id;
438 -
439 - $tmpset[] = array(
440 - 'ft_rev_id' => $rev->getId(),
441 - 'ft_namespace' => $tmp_title->getNamespace(),
442 - 'ft_title' => $tmp_title->getDBkey(),
443 - 'ft_tmp_rev_id' => $rev_id
444 - );
445 - if ( !isset( $tmpParams[$tmp_title->getNamespace()] ) ) {
446 - $tmpParams[$tmp_title->getNamespace()] = array();
447 - }
448 - $tmpParams[$tmp_title->getNamespace()][$tmp_title->getDBkey()] = $rev_id;
449 - }
450 - # Our image version pointers
451 - $imgset = $imgParams = array();
452 - $imageMap = explode( '#', trim( $this->imageParams ) );
453 - foreach ( $imageMap as $image ) {
454 - if ( !$image )
455 - continue;
456 - $m = explode( '|', $image, 3 );
457 - # Expand our parameters ... <name>#<timestamp>#<key>
458 - if ( !isset( $m[0] ) || !isset( $m[1] ) || !isset( $m[2] ) || !$m[0] )
459 - continue;
460 -
461 - list( $dbkey, $timestamp, $key ) = $m;
462 -
463 - $img_title = Title::makeTitle( NS_IMAGE, $dbkey ); // Normalize
464 - if ( is_null( $img_title ) )
465 - continue; // Page must be valid!
466 -
467 - if ( $timestamp > $lastImgTime )
468 - $lastImgTime = $timestamp;
469 -
470 - $imgset[] = array(
471 - 'fi_rev_id' => $rev->getId(),
472 - 'fi_name' => $img_title->getDBkey(),
473 - 'fi_img_timestamp' => $timestamp,
474 - 'fi_img_sha1' => $key
475 - );
476 - if ( !isset( $imgParams[$img_title->getDBkey()] ) ) {
477 - $imgParams[$img_title->getDBkey()] = array();
478 - }
479 - $imgParams[$img_title->getDBkey()][$timestamp] = $key;
480 - }
481 - # If this is an image page, store corresponding file info
482 - $fileData = array();
483 - if ( $this->page->getNamespace() == NS_IMAGE && $this->fileVersion ) {
484 - $data = explode( '#', $this->fileVersion, 2 );
485 - if ( count( $data ) == 2 ) {
486 - $fileData['name'] = $this->page->getDBkey();
487 - $fileData['timestamp'] = $data[0];
488 - $fileData['sha1'] = $data[1];
489 - }
490 - }
491 -
492 - # Get current stable version ID (for logging)
493 - $oldSv = FlaggedRevision::newFromStable( $this->page, FR_MASTER );
494 - $oldSvId = $oldSv ? $oldSv->getRevId() : 0;
495 -
496 - # Is this rev already flagged?
497 - $flaggedOutput = false;
498 - $oldfrev = FlaggedRevision::newFromTitle( $this->page, $rev->getId(), FR_MASTER );
499 - if ( $oldfrev ) {
500 - $flaggedOutput = FlaggedRevs::parseStableText( $article,
501 - $oldfrev->getRevText(), $oldfrev->getRevId() );
502 - }
503 -
504 - # Be loose on templates that includes other files/templates dynamically.
505 - # Strict checking breaks randomized images/metatemplates...(bug 14580)
506 - global $wgUseCurrentTemplates, $wgUseCurrentImages;
507 - $mustMatch = !( $wgUseCurrentTemplates && $wgUseCurrentImages );
508 -
509 - # Set our versioning params cache
510 - FlaggedRevs::setIncludeVersionCache( $rev->getId(), $tmpParams, $imgParams );
511 - # Parse the text and check if all templates/files match up
512 - $text = $rev->getText();
513 - $stableOutput = FlaggedRevs::parseStableText( $article, $text, $rev->getId() );
514 - $err =& $stableOutput->fr_includeErrors;
515 - if ( $mustMatch ) { // if template/files must all be specified...
516 - if ( !empty( $err )
517 - || $stableOutput->fr_newestImageTime > $lastImgTime
518 - || $stableOutput->fr_newestTemplateID > $lastTempId )
519 - {
520 - wfProfileOut( __METHOD__ );
521 - return $err; // return templates/files with no version specified
522 - }
523 - }
524 - # Clear our versioning params cache
525 - FlaggedRevs::clearIncludeVersionCache( $rev->getId() );
526 -
527 - # Is this a duplicate review?
528 - if ( $oldfrev && $flaggedOutput ) {
529 - $synced = true;
530 - if ( $stableOutput->fr_newestImageTime != $flaggedOutput->fr_newestImageTime )
531 - $synced = false;
532 - elseif ( $stableOutput->fr_newestTemplateID != $flaggedOutput->fr_newestTemplateID )
533 - $synced = false;
534 - elseif ( $oldfrev->getTags() != $flags )
535 - $synced = false;
536 - elseif ( $oldfrev->getFileSha1() != @$fileData['sha1'] )
537 - $synced = false;
538 - elseif ( $oldfrev->getComment() != $this->notes )
539 - $synced = false;
540 - elseif ( $oldfrev->getQuality() != $quality )
541 - $synced = false;
542 - # Don't review if the same
543 - if ( $synced ) {
544 - wfProfileOut( __METHOD__ );
545 - return true;
546 - }
547 - }
548 -
549 - $dbw = wfGetDB( DB_MASTER );
550 - # Our review entry
551 - $flaggedRevision = new FlaggedRevision( array(
552 - 'fr_rev_id' => $rev->getId(),
553 - 'fr_page_id' => $rev->getPage(),
554 - 'fr_user' => $wgUser->getId(),
555 - 'fr_timestamp' => wfTimestampNow(),
556 - 'fr_comment' => $this->notes,
557 - 'fr_quality' => $quality,
558 - 'fr_tags' => FlaggedRevision::flattenRevisionTags( $flags ),
559 - 'fr_img_name' => $fileData ? $fileData['name'] : null,
560 - 'fr_img_timestamp' => $fileData ? $fileData['timestamp'] : null,
561 - 'fr_img_sha1' => $fileData ? $fileData['sha1'] : null
562 - ) );
563 -
564 - $dbw->begin();
565 - $flaggedRevision->insertOn( $tmpset, $imgset );
566 - # Avoid any lag issues
567 - $this->page->resetArticleId( $rev->getPage() );
568 - # Update recent changes
569 - self::updateRecentChanges( $this->page, $rev->getId(), $this->rcid, true );
570 - # Update the article review log
571 - FlaggedRevsLogs::updateLog( $this->page, $this->dims, $this->oflags,
572 - $this->comment, $this->oldid, $oldSvId, true );
573 -
574 - # Update the links tables as the stable version may now be the default page.
575 - # Try using the parser cache first since we didn't actually edit the current version.
576 - $parserCache = ParserCache::singleton();
577 - $poutput = $parserCache->get( $article, $wgUser );
578 - if ( !$poutput
579 - || !isset( $poutput->fr_newestTemplateID )
580 - || !isset( $poutput->fr_newestImageTime ) )
581 - {
582 - $options = FlaggedRevs::makeParserOptions();
583 - $poutput = $wgParser->parse( $article->getContent(), $article->mTitle, $options );
584 - }
585 - # Prepare for a link tracking update
586 - $u = new LinksUpdate( $this->page, $poutput );
587 - # If we know that this is now the new stable version
588 - # (which it probably is), save it to the stable cache...
589 - $sv = FlaggedRevision::newFromStable( $this->page, FR_MASTER/*consistent*/ );
590 - if ( $sv && $sv->getRevId() == $rev->getId() ) {
591 - global $wgParserCacheExpireTime;
592 - $this->page->invalidateCache();
593 - # Update stable cache with the revision we reviewed.
594 - # Don't cache redirects; it would go unused and complicate things.
595 - if ( !Title::newFromRedirect( $text ) ) {
596 - FlaggedRevs::updatePageCache( $article, $wgUser, $stableOutput );
597 - }
598 - # We can set the sync cache key already
599 - $includesSynced = true;
600 - if ( $poutput->fr_newestImageTime > $stableOutput->fr_newestImageTime ) {
601 - $includesSynced = false;
602 - } elseif ( $poutput->fr_newestTemplateID > $stableOutput->fr_newestTemplateID ) {
603 - $includesSynced = false;
604 - }
605 - $u->fr_stableRev = $sv; // no need to re-fetch this!
606 - $u->fr_stableParserOut = $stableOutput; // no need to re-fetch this!
607 - # We can set the sync cache key already.
608 - $key = wfMemcKey( 'flaggedrevs', 'includesSynced', $article->getId() );
609 - $data = FlaggedRevs::makeMemcObj( $includesSynced ? "true" : "false" );
610 - $wgMemc->set( $key, $data, $wgParserCacheExpireTime );
611 - } else {
612 - # Get the old stable cache
613 - $stableOutput = FlaggedRevs::getPageCache( $article, $wgUser );
614 - # Clear the cache...(for page histories)
615 - $this->page->invalidateCache();
616 - if ( $stableOutput !== false ) {
617 - # Reset stable cache if it existed, since we know it is the same.
618 - FlaggedRevs::updatePageCache( $article, $wgUser, $stableOutput );
619 - }
620 - }
621 - # Update link tracking. This will trigger extraLinksUpdate()...
622 - $u->doUpdate();
623 -
624 - $dbw->commit();
625 - # Purge cache/squids for this page and any page that uses it
626 - Article::onArticleEdit( $this->page );
627 -
628 - wfProfileOut( __METHOD__ );
629 - return true;
630 - }
631 -
632 - /**
633 - * @param FlaggedRevision $frev
634 - * Removes flagged revision data for this page/id set
635 - */
636 - private function unapproveRevision( $frev ) {
637 - global $wgUser, $wgParser, $wgMemc;
638 - wfProfileIn( __METHOD__ );
639 -
640 - $dbw = wfGetDB( DB_MASTER );
641 - $dbw->begin();
642 - # Delete from flaggedrevs table
643 - $dbw->delete( 'flaggedrevs',
644 - array( 'fr_page_id' => $frev->getPage(), 'fr_rev_id' => $frev->getRevId() ) );
645 - # Wipe versioning params
646 - $dbw->delete( 'flaggedtemplates', array( 'ft_rev_id' => $frev->getRevId() ) );
647 - $dbw->delete( 'flaggedimages', array( 'fi_rev_id' => $frev->getRevId() ) );
648 - # Update recent changes
649 - self::updateRecentChanges( $this->page, $frev->getRevId(), false, false );
650 -
651 - # Get current stable version ID (for logging)
652 - $oldSv = FlaggedRevision::newFromStable( $this->page, FR_MASTER );
653 - $oldSvId = $oldSv ? $oldSv->getRevId() : 0;
654 -
655 - # Update the article review log
656 - FlaggedRevsLogs::updateLog( $this->page, $this->dims, $this->oflags,
657 - $this->comment, $this->oldid, $oldSvId, false );
658 -
659 - $article = new Article( $this->page );
660 - # Update the links tables as a new stable version
661 - # may now be the default page.
662 - $parserCache = ParserCache::singleton();
663 - $poutput = $parserCache->get( $article, $wgUser );
664 - if ( $poutput == false ) {
665 - $text = $article->getContent();
666 - $options = FlaggedRevs::makeParserOptions();
667 - $poutput = $wgParser->parse( $text, $article->mTitle, $options );
668 - }
669 - $u = new LinksUpdate( $this->page, $poutput );
670 - $u->doUpdate();
671 -
672 - # Clear the cache...
673 - $this->page->invalidateCache();
674 - # Purge cache/squids for this page and any page that uses it
675 - $dbw->commit();
676 - Article::onArticleEdit( $article->getTitle() );
677 -
678 - wfProfileOut( __METHOD__ );
679 - return true;
680 - }
681 -
682 - /**
683 - * Get a validation key from versioning metadata
684 - * @param string $tmpP
685 - * @param string $imgP
686 - * @param string $imgV
687 - * @param integer $rid rev ID
688 - * @return string
689 - */
690 - public static function validationKey( $tmpP, $imgP, $imgV, $rid ) {
691 - global $wgReviewCodes;
692 - # Fall back to $wgSecretKey/$wgProxyKey
693 - if ( empty( $wgReviewCodes ) ) {
694 - global $wgSecretKey, $wgProxyKey;
695 - $key = $wgSecretKey ? $wgSecretKey : $wgProxyKey;
696 - $p = md5( $key . $imgP . $tmpP . $rid . $imgV );
697 - } else {
698 - $p = md5( $wgReviewCodes[0] . $imgP . $rid . $tmpP . $imgV . $wgReviewCodes[1] );
699 - }
700 - return $p;
701 - }
702 -
703 - public static function updateRecentChanges( $title, $revId, $rcId = false, $patrol = true ) {
704 - wfProfileIn( __METHOD__ );
705 - $revId = intval( $revId );
706 - $dbw = wfGetDB( DB_MASTER );
707 - # Olders edits be marked as patrolled now...
708 - $dbw->update( 'recentchanges',
709 - array( 'rc_patrolled' => $patrol ? 1 : 0 ),
710 - array( 'rc_cur_id' => $title->getArticleId(),
711 - $patrol ? "rc_this_oldid <= $revId" : "rc_this_oldid = $revId" ),
712 - __METHOD__,
713 - // Performance
714 - array( 'USE INDEX' => 'rc_cur_id', 'LIMIT' => 50 )
715 - );
716 - # New page patrol may be enabled. If so, the rc_id may be the first
717 - # edit and not this one. If it is different, mark it too.
718 - if ( $rcId && $rcId != $revId ) {
719 - $dbw->update( 'recentchanges',
720 - array( 'rc_patrolled' => 1 ),
721 - array( 'rc_id' => $rcId,
722 - 'rc_type' => RC_NEW ),
723 - __METHOD__
724 - );
725 - }
726 - wfProfileOut( __METHOD__ );
727 - }
728246 }
Index: trunk/extensions/FlaggedRevs/FlaggedRevsXML.php
@@ -771,7 +771,7 @@
772772 # Pass this in if given; useful for new page patrol
773773 $form .= Xml::hidden( 'rcid', $wgRequest->getVal( 'rcid' ) ) . "\n";
774774 # Special token to discourage fiddling...
775 - $checkCode = RevisionReview::validationKey(
 775+ $checkCode = RevisionReviewForm::validationKey(
776776 $templateParams, $imageParams, $fileVersion, $id
777777 );
778778 $form .= Xml::hidden( 'validatedParams', $checkCode ) . "\n";
Index: trunk/extensions/FlaggedRevs/api/ApiReview.php
@@ -35,53 +35,36 @@
3636 public function execute() {
3737 global $wgUser;
3838 $params = $this->extractRequestParams();
39 -
40 - // Check permissions
41 - if ( !$wgUser->isAllowed( 'review' ) )
 39+ // Check basic permissions
 40+ if ( !$wgUser->isAllowed( 'review' ) ) {
 41+ // FIXME: better msg?
4242 $this->dieUsageMsg( array( 'badaccess-group0' ) );
43 - if ( $wgUser->isBlocked() )
 43+ } elseif ( $wgUser->isBlocked( false ) ) {
4444 $this->dieUsageMsg( array( 'blockedtext' ) );
45 -
 45+ }
4646 // Construct submit form
47 - $form = new RevisionReview();
48 - $revid = intval( $params['revid'] );
 47+ $form = new RevisionReviewForm();
 48+ $revid = (int)$params['revid'];
4949 $rev = Revision::newFromId( $revid );
50 - if ( !$rev )
 50+ if ( !$rev ) {
5151 $this->dieUsage( "Cannot find a revision with the specified ID.", 'notarget' );
52 - $form->oldid = $revid;
 52+ }
5353 $title = $rev->getTitle();
54 - $form->page = $title;
55 - if ( !FlaggedRevs::inReviewNamespace( $title ) )
56 - $this->dieUsage( "Provided revision or page can not be reviewed.", 'notreviewable' );
57 -
58 - if ( isset( $params['unapprove'] ) )
59 - $form->approve = !$params['unapprove'];
 54+ $form->setPage( $title );
 55+ $form->setOldId( $revid );
 56+ if ( FlaggedRevs::dimensionsEmpty() ) {
 57+ $form->setApprove( empty( $params['unapprove'] ) );
 58+ $form->setUnapprove( !empty( $params['unapprove'] ) );
 59+ }
6060 if ( isset( $params['comment'] ) )
61 - $form->comment = $params['comment'];
 61+ $form->setComment( $params['comment'] );
6262 if ( isset( $params['notes'] ) )
63 - $form->notes = $wgUser->isAllowed( 'validate' ) ? $params['notes'] : '';
64 -
 63+ $form->setNotes( $params['notes'] );
6564 // The flagging parameters have the form 'flag_$name'.
6665 // Extract them and put the values into $form->dims
67 - $flags = FlaggedRevs::getDimensions();
68 - foreach ( $flags as $name => $levels ) {
69 - if ( !( $form->dims[$name] = intval( $params['flag_' . $name] ) ) )
70 - $form->unapprovedTags++;
 66+ foreach ( FlaggedRevs::getDimensions() as $tag => $levels ) {
 67+ $form->setDim( $tag, intval( $params['flag_' . $tag] ) );
7168 }
72 -
73 - // Check if this is a valid approval/unapproval of the revision
74 - if ( $form->unapprovedTags && $form->unapprovedTags < count( $flags ) )
75 - $this->dieUsage( "Either all or none of the flags have to be set to zero.", 'mixedapproval' );
76 -
77 - // Check if user is even allowed to set the flags
78 - $form->oflags = FlaggedRevs::getRevisionTags( $title, $form->oldid );
79 -
80 - if ( !$title->quickUserCan( 'edit' )
81 - || !FlaggedRevs::userCanSetFlags( $form->dims, $form->oflags ) )
82 - {
83 - $this->dieUsage( "You don't have the necessary rights to set the specified flags.", 'permissiondenied' );
84 - }
85 -
8669 if ( $form->isApproval() ) {
8770 // Now get the template and image parameters needed
8871 // If it is the current revision, try the parser cache first
@@ -98,20 +81,51 @@
9982 $parserOutput = $wgParser->parse( $text, $title, $options );
10083 }
10184 // Set version parameters for review submission
102 - list( $form->templateParams, $form->imageParams, $form->fileVersion ) =
103 - FlaggedRevs::getIncludeParams( $article, $parserOutput->mTemplateIds, $parserOutput->fr_ImageSHA1Keys );
 85+ list( $templateParams, $imageParams, $fileVersion ) =
 86+ FlaggedRevs::getIncludeParams( $article,
 87+ $parserOutput->mTemplateIds, $parserOutput->fr_ImageSHA1Keys );
 88+ $form->setTemplateParams( $templateParams );
 89+ $form->setFileParams( $imageParams );
 90+ $form->setFileVersion( $fileVersion );
10491 }
105 -
106 - // Do the actual review
107 - list( $approved, $status ) = $form->submit();
 92+
 93+ $status = $form->ready(); // all params set
 94+ if ( $status === 'review_page_unreviewable' ) {
 95+ $this->dieUsage( "Provided revision or page can not be reviewed.",
 96+ 'notreviewable' );
 97+ // Check basic page permissions
 98+ } elseif ( !$title->quickUserCan( 'review' ) || !$title->quickUserCan( 'edit' ) ) {
 99+ $this->dieUsage( "You don't have the necessary rights to set the specified flags.",
 100+ 'permissiondenied' );
 101+ }
 102+
 103+ # Try to do the actual review
 104+ $status = $form->submit();
 105+ # Approve/de-approve success
108106 if ( $status === true ) {
109 - $this->getResult()->addValue( null, $this->getModuleName(), array( 'result' => 'Success' ) );
110 - } elseif ( $approved && is_array( $status ) ) {
111 - $this->dieUsage( "A sync failure has occured while reviewing. Please try again.", 'syncfailure' );
112 - } elseif ( $approved ) {
113 - $this->dieUsage( "Cannot find a revision with the specified ID.", 'notarget' );
 107+ $this->getResult()->addValue(
 108+ null, $this->getModuleName(), array( 'result' => 'Success' ) );
 109+ # De-approve failure
 110+ } elseif ( !$form->isApproval() ) {
 111+ $this->dieUsage( "Cannot find a flagged revision with the specified ID.", 'notarget' );
 112+ # Approval failures
114113 } else {
115 - $this->dieUsageMsg( array( 'unknownerror' ) );
 114+ if ( is_array( $status ) ) {
 115+ $this->dieUsage( "A sync failure has occured while reviewing. Please try again.",
 116+ 'syncfailure' );
 117+ } elseif ( $status === 'review_too_low' ) {
 118+ $this->dieUsage( "Either all or none of the flags have to be set to zero.",
 119+ 'mixedapproval' );
 120+ } elseif ( $status === 'review_denied' ) {
 121+ $this->dieUsage( "You don't have the necessary rights to set the specified flags.",
 122+ 'permissiondenied' );
 123+ } elseif ( $status === 'review_bad_key' ) {
 124+ $this->dieUsage( "You don't have the necessary rights to set the specified flags.",
 125+ 'permissiondenied' );
 126+ } else {
 127+ // FIXME: review_param_missing? better msg?
 128+ $this->dieUsage( array( 'unknownerror' ) );
 129+ }
116130 }
117131 }
118132
@@ -125,8 +139,8 @@
126140
127141 public function getAllowedParams() {
128142 $pars = array(
129 - 'revid' => null,
130 - 'token' => null,
 143+ 'revid' => null,
 144+ 'token' => null,
131145 'comment' => null,
132146 );
133147 if ( FlaggedRevs::allowComments() )
@@ -146,16 +160,19 @@
147161
148162 public function getParamDescription() {
149163 $desc = array(
150 - 'revid' => 'The revision ID for which to set the flags',
151 - 'token' => 'An edit token retrieved through prop=info',
152 - 'comment' => 'Comment for the review (optional)',
153 - // Only if FlaggedRevs::allowComments() is true:
154 - 'notes' => "Additional notes for the review. The ``validate'' right is needed to set this parameter.",
155 - // Will only show if FlaggedRevs::dimensionsEmpty() is true:
156 - 'unapprove' => "If set, revision will be unapproved"
 164+ 'revid' => 'The revision ID for which to set the flags',
 165+ 'token' => 'An edit token retrieved through prop=info',
 166+ 'comment' => 'Comment for the review (optional)'
157167 );
158 - foreach ( FlaggedRevs::getDimensions() as $flagname => $levels )
159 - $desc['flag_' . $flagname] = "Set the flag ''{$flagname}'' to the specified value";
 168+ if ( FlaggedRevs::allowComments() )
 169+ $desc['notes'] = "Additional notes for the review. The ''validate'' right is needed to set this parameter.";
 170+ if ( FlaggedRevs::dimensionsEmpty() ) {
 171+ $desc['unapprove'] = "If set, revision will be unapproved rather than approved.";
 172+ } else {
 173+ foreach ( FlaggedRevs::getDimensions() as $flagname => $levels ) {
 174+ $desc['flag_' . $flagname] = "Set the flag ''{$flagname}'' to the specified value";
 175+ }
 176+ }
160177 return $desc;
161178 }
162179

Follow-up revisions

RevisionCommit summaryAuthorDate
r66894Follow-up r66652: misspelled class nameraymond20:58, 25 May 2010

Past revisions this follows-up on

RevisionCommit summaryAuthorDate
r66633* Stability form double-checks permissions...aaron23:44, 18 May 2010

Comments

#Comment by Siebrand (talk | contribs)   22:10, 20 May 2010

Can you please explain what 'Invalid inclusion parameter key.' means. I'm having trouble thinking of a translation.

#Comment by Aaron Schulz (talk | contribs)   01:32, 21 May 2010

When you review, you specify the template/file versions to use. The key given by the user must match a special hash salted with those parameters. This makes it so users can only use the template/file versions as shown on the form they submitted on, rather than sending their own arbitrary values.

#Comment by Siebrand (talk | contribs)   18:10, 21 May 2010

Thanks.

Status & tagging log