Index: trunk/extensions/FlaggedRevs/FlaggedArticle.php |
— | — | @@ -9,6 +9,7 @@ |
10 | 10 | protected $stableRev = null; |
11 | 11 | protected $pendingRevs = null; |
12 | 12 | protected $pageConfig = null; |
| 13 | + protected $file = null; |
13 | 14 | |
14 | 15 | /** |
15 | 16 | * Get a FlaggedArticle for a given title |
— | — | @@ -40,9 +41,26 @@ |
41 | 42 | $this->stableRev = null; |
42 | 43 | $this->pendingRevs = null; |
43 | 44 | $this->pageConfig = null; |
| 45 | + $this->file = null; |
44 | 46 | parent::clear(); |
45 | 47 | } |
46 | 48 | |
| 49 | + /** |
| 50 | + * Get the current file version of this file page |
| 51 | + * @TODO: kind of hacky |
| 52 | + * @return mixed (File/false) |
| 53 | + */ |
| 54 | + public function getFile() { |
| 55 | + if ( $this->getTitle()->getNamespace() != NS_FILE ) { |
| 56 | + return false; // not an file page |
| 57 | + } |
| 58 | + if ( is_null( $this->file ) ) { |
| 59 | + $imagePage = new ImagePage( $this->getTitle() ); |
| 60 | + $this->file = $imagePage->getFile(); |
| 61 | + } |
| 62 | + return $this->file; |
| 63 | + } |
| 64 | + |
47 | 65 | /** |
48 | 66 | * Is the stable version shown by default for this page? |
49 | 67 | * @param int $flags, FR_MASTER |
— | — | @@ -132,6 +150,100 @@ |
133 | 151 | } |
134 | 152 | |
135 | 153 | /** |
| 154 | + * Check if the stable version is synced with the current revision. |
| 155 | + * Note: This function can be pretty expensive... |
| 156 | + * @param ParserOutput $stableOutput, will fetch if not given |
| 157 | + * @param ParserOutput $currentOutput, will fetch if not given |
| 158 | + * @return bool |
| 159 | + */ |
| 160 | + public function stableVersionIsSynced( |
| 161 | + ParserOutput $stableOutput = null, ParserOutput $currentOutput = null |
| 162 | + ) { |
| 163 | + global $wgUser, $wgMemc, $wgEnableParserCache, $wgParserCacheExpireTime; |
| 164 | + $srev = $this->getStableRev(); |
| 165 | + if ( !$srev ) { |
| 166 | + return true; |
| 167 | + } |
| 168 | + # Stable text revision must be the same as the current |
| 169 | + if ( $this->revsArePending() ) { |
| 170 | + return false; |
| 171 | + # Stable file revision must be the same as the current |
| 172 | + } elseif ( $this->getTitle()->getNamespace() == NS_FILE ) { |
| 173 | + $file = $this->getFile(); // current upload version |
| 174 | + if ( $file && $file->getTimestamp() > $srev->getFileTimestamp() ) { |
| 175 | + return false; |
| 176 | + } |
| 177 | + } |
| 178 | + # If using the current version of includes, there is nothing else to check. |
| 179 | + if ( FlaggedRevs::inclusionSetting() == FR_INCLUDES_CURRENT ) { |
| 180 | + return true; // short-circuit |
| 181 | + } |
| 182 | + # Try the cache... |
| 183 | + $key = wfMemcKey( 'flaggedrevs', 'includesSynced', $this->getId() ); |
| 184 | + $value = FlaggedRevs::getMemcValue( $wgMemc->get( $key ), $this ); |
| 185 | + if ( $value === "true" ) { |
| 186 | + return true; |
| 187 | + } elseif ( $value === "false" ) { |
| 188 | + return false; |
| 189 | + } |
| 190 | + # If parseroutputs not given, fetch them... |
| 191 | + if ( is_null( $stableOutput ) || !isset( $stableOutput->fr_newestTemplateID ) ) { |
| 192 | + # Get parsed stable version |
| 193 | + $anon = new User(); // anon cache most likely to exist |
| 194 | + $stableOutput = FlaggedRevs::getPageCache( $this, $anon ); |
| 195 | + if ( $stableOutput == false && $wgUser->getId() ) { |
| 196 | + $stableOutput = FlaggedRevs::getPageCache( $this, $wgUser ); |
| 197 | + } |
| 198 | + # Regenerate the parser output as needed... |
| 199 | + if ( $stableOutput == false ) { |
| 200 | + $text = $srev->getRevText(); |
| 201 | + $stableOutput = FlaggedRevs::parseStableText( $this, $text, $srev->getRevId() ); |
| 202 | + # Update the stable version cache |
| 203 | + FlaggedRevs::updatePageCache( $this, $anon, $stableOutput ); |
| 204 | + } |
| 205 | + } |
| 206 | + if ( is_null( $currentOutput ) || !isset( $currentOutput->fr_newestTemplateID ) ) { |
| 207 | + # Get parsed current version |
| 208 | + $parserCache = ParserCache::singleton(); |
| 209 | + $currentOutput = false; |
| 210 | + $anon = new User(); // anon cache most likely to exist |
| 211 | + # If $text is set, then the stableOutput is new. In that case, |
| 212 | + # the current must also be new to avoid sync goofs. |
| 213 | + if ( !isset( $text ) ) { |
| 214 | + $currentOutput = $parserCache->get( $this, $anon ); |
| 215 | + if ( $currentOutput == false && $wgUser->getId() ) { |
| 216 | + $currentOutput = $parserCache->get( $this, $wgUser ); |
| 217 | + } |
| 218 | + } |
| 219 | + # Regenerate the parser output as needed... |
| 220 | + if ( $currentOutput == false ) { |
| 221 | + global $wgParser; |
| 222 | + $source = $this->getContent(); |
| 223 | + $options = FlaggedRevs::makeParserOptions( $anon ); |
| 224 | + $currentOutput = $wgParser->parse( $source, $this->getTitle(), |
| 225 | + $options, /*$lineStart*/true, /*$clearState*/true, $this->getLatest() ); |
| 226 | + # Might as well save the cache while we're at it |
| 227 | + if ( $wgEnableParserCache ) { |
| 228 | + $parserCache->save( $currentOutput, $this, $anon ); |
| 229 | + } |
| 230 | + } |
| 231 | + } |
| 232 | + # Since the stable and current revisions have the same text and only outputs, |
| 233 | + # the only other things to check for are template and file differences in the output. |
| 234 | + # (a) Check if the current output has a newer template/file used |
| 235 | + # (b) Check if the stable version has a file/template that was deleted |
| 236 | + $synced = ( |
| 237 | + !$stableOutput->fr_includeErrors && // deleted since |
| 238 | + FlaggedRevs::includesAreSynced( $stableOutput, $currentOutput ) |
| 239 | + ); |
| 240 | + # Save to cache. This will be updated whenever the page is touched. |
| 241 | + $data = FlaggedRevs::makeMemcObj( $synced ? "true" : "false" ); |
| 242 | + $wgMemc->set( $key, $data, $wgParserCacheExpireTime ); |
| 243 | + |
| 244 | + return $synced; |
| 245 | + } |
| 246 | + |
| 247 | + /** |
136 | 248 | * Is this page less open than the site defaults? |
137 | 249 | * @return bool |
138 | 250 | */ |
Index: trunk/extensions/FlaggedRevs/FlaggedRevs.class.php |
— | — | @@ -735,102 +735,31 @@ |
736 | 736 | # ################ Synchronization and link update functions ################# |
737 | 737 | |
738 | 738 | /** |
739 | | - * @param FlaggedRevision $srev, the stable revision |
740 | | - * @param Article $article |
741 | | - * @param ParserOutput $stableOutput, will fetch if not given |
742 | | - * @param ParserOutput $currentOutput, will fetch if not given |
743 | | - * @return bool |
744 | | - * See if a flagged revision is synced with the current. |
745 | | - * This function is pretty expensive... |
746 | | - */ |
747 | | - public static function stableVersionIsSynced( |
748 | | - FlaggedRevision $srev, |
749 | | - Article $article, |
750 | | - ParserOutput $stableOutput = null, |
751 | | - ParserOutput $currentOutput = null |
| 739 | + * Check if all includes in $stableOutput are the same as those in $currentOutput |
| 740 | + * @param ParserOutput $stableOutput |
| 741 | + * @param ParserOutput $currentOutput |
| 742 | + * @return bool |
| 743 | + */ |
| 744 | + public static function includesAreSynced( |
| 745 | + ParserOutput $stableOutput, ParserOutput $currentOutput |
752 | 746 | ) { |
753 | | - global $wgMemc, $wgEnableParserCache, $wgUser; |
754 | | - # Stable text revision must be the same as the current |
755 | | - if ( $srev->getRevId() < $article->getTitle()->getLatestRevID() ) { |
756 | | - return false; |
757 | | - } |
758 | | - # Stable file revision must be the same as the current |
759 | | - if ( $article instanceof ImagePage && $article->getFile() ) { |
760 | | - if ( $srev->getFileTimestamp() < $article->getFile()->getTimestamp() ) { |
761 | | - return false; |
| 747 | + $sTmpls = $stableOutput->mTemplateIds; |
| 748 | + $cTmpls = $currentOutput->mTemplateIds; |
| 749 | + foreach ( $sTmpls as $name => $revId ) { |
| 750 | + if ( isset( $cTmpls[$name] ) && $cTmpls[$name] != $revId ) { |
| 751 | + return false; // updated/created |
762 | 752 | } |
763 | 753 | } |
764 | | - # If using the current version of includes, there is nothing else to check. |
765 | | - if ( self::inclusionSetting() == FR_INCLUDES_CURRENT ) { |
766 | | - return true; |
767 | | - } |
768 | | - # Try the cache... |
769 | | - $key = wfMemcKey( 'flaggedrevs', 'includesSynced', $article->getId() ); |
770 | | - $value = self::getMemcValue( $wgMemc->get( $key ), $article ); |
771 | | - if ( $value === "true" ) { |
772 | | - return true; |
773 | | - } elseif ( $value === "false" ) { |
774 | | - return false; |
775 | | - } |
776 | | - # If parseroutputs not given, fetch them... |
777 | | - if ( is_null( $stableOutput ) || !isset( $stableOutput->fr_newestTemplateID ) ) { |
778 | | - # Get parsed stable version |
779 | | - $anon = new User(); // anon cache most likely to exist |
780 | | - $stableOutput = self::getPageCache( $article, $anon ); |
781 | | - if ( $stableOutput == false && $wgUser->getId() ) |
782 | | - $stableOutput = self::getPageCache( $article, $wgUser ); |
783 | | - # Regenerate the parser output as needed... |
784 | | - if ( $stableOutput == false ) { |
785 | | - $text = $srev->getRevText(); |
786 | | - $stableOutput = self::parseStableText( $article, $text, $srev->getRevId() ); |
787 | | - # Update the stable version cache |
788 | | - self::updatePageCache( $article, $anon, $stableOutput ); |
789 | | - } |
790 | | - } |
791 | | - if ( is_null( $currentOutput ) || !isset( $currentOutput->fr_newestTemplateID ) ) { |
792 | | - # Get parsed current version |
793 | | - $parserCache = ParserCache::singleton(); |
794 | | - $currentOutput = false; |
795 | | - $anon = new User(); // anon cache most likely to exist |
796 | | - # If $text is set, then the stableOutput is new. In that case, |
797 | | - # the current must also be new to avoid sync goofs. |
798 | | - if ( !isset( $text ) ) { |
799 | | - $currentOutput = $parserCache->get( $article, $anon ); |
800 | | - if ( $currentOutput == false && $wgUser->getId() ) |
801 | | - $currentOutput = $parserCache->get( $article, $wgUser ); |
| 754 | + $sFiles = $stableOutput->fr_ImageSHA1Keys; |
| 755 | + $cFiles = $currentOutput->fr_ImageSHA1Keys; |
| 756 | + foreach ( $sFiles as $name => $timeKey ) { |
| 757 | + foreach ( $timeKey as $sTs => $sSha1 ) { |
| 758 | + if ( isset( $cFiles[$name] ) && !isset( $cFiles[$name][$sTs] ) ) { |
| 759 | + return false; // updated/created |
| 760 | + } |
802 | 761 | } |
803 | | - # Regenerate the parser output as needed... |
804 | | - if ( $currentOutput == false ) { |
805 | | - global $wgParser; |
806 | | - $rev = Revision::newFromTitle( $article->getTitle() ); |
807 | | - $text = $rev ? $rev->getText() : false; |
808 | | - $id = $rev ? $rev->getId() : null; |
809 | | - $title = $article->getTitle(); |
810 | | - $options = self::makeParserOptions( $anon ); |
811 | | - $currentOutput = $wgParser->parse( $text, $title, $options, |
812 | | - /*$lineStart*/true, /*$clearState*/true, $id ); |
813 | | - # Might as well save the cache while we're at it |
814 | | - if ( $wgEnableParserCache ) |
815 | | - $parserCache->save( $currentOutput, $article, $anon ); |
816 | | - } |
817 | 762 | } |
818 | | - # Only current of revisions of inclusions can be reviewed. Since the stable and current revisions |
819 | | - # have the same text, the only thing that can make them different is updating a template or image. |
820 | | - # If this is the case, the current revision will have a newer template or image version used somewhere. |
821 | | - if ( $currentOutput->fr_newestImageTime > $stableOutput->fr_newestImageTime ) { |
822 | | - $synced = false; |
823 | | - } elseif ( $currentOutput->fr_newestTemplateID > $stableOutput->fr_newestTemplateID ) { |
824 | | - $synced = false; |
825 | | - } else { |
826 | | - $synced = true; |
827 | | - } |
828 | | - # Save to cache. This will be updated whenever the page is re-parsed as well. This means |
829 | | - # that MW can check a light-weight key first. |
830 | | - global $wgParserCacheExpireTime; |
831 | | - $data = self::makeMemcObj( $synced ? "true" : "false" ); |
832 | | - $wgMemc->set( $key, $data, $wgParserCacheExpireTime ); |
833 | | - |
834 | | - return $synced; |
| 763 | + return true; |
835 | 764 | } |
836 | 765 | |
837 | 766 | /** |
— | — | @@ -1588,6 +1517,8 @@ |
1589 | 1518 | $editInfo = $article->prepareTextForEdit( $text ); // Parse the revision HTML output |
1590 | 1519 | $poutput = $editInfo->output; |
1591 | 1520 | |
| 1521 | + $dbw = wfGetDB( DB_MASTER ); |
| 1522 | + |
1592 | 1523 | # NS:title -> rev ID mapping |
1593 | 1524 | foreach ( $poutput->mTemplateIds as $namespace => $titleAndID ) { |
1594 | 1525 | foreach ( $titleAndID as $dbkey => $id ) { |
— | — | @@ -1602,12 +1533,15 @@ |
1603 | 1534 | # Image -> timestamp mapping |
1604 | 1535 | foreach ( $poutput->fr_ImageSHA1Keys as $dbkey => $timeAndSHA1 ) { |
1605 | 1536 | foreach ( $timeAndSHA1 as $time => $sha1 ) { |
1606 | | - $imgset[] = array( |
| 1537 | + $fileIncludeData = array( |
1607 | 1538 | 'fi_rev_id' => $rev->getId(), |
1608 | 1539 | 'fi_name' => $dbkey, |
1609 | | - 'fi_img_timestamp' => $time, |
1610 | 1540 | 'fi_img_sha1' => $sha1 |
1611 | 1541 | ); |
| 1542 | + if ( $time ) { // b/c for bad <char(14) NOT NULL default ''> def |
| 1543 | + $fileIncludeData['fi_img_timestamp'] = $dbw->timestamp( $time ); |
| 1544 | + } |
| 1545 | + $imgset[] = $fileIncludeData; |
1612 | 1546 | } |
1613 | 1547 | } |
1614 | 1548 | |
Index: trunk/extensions/FlaggedRevs/forms/RevisionReviewForm.php |
— | — | @@ -323,7 +323,8 @@ |
324 | 324 | private function approveRevision( $rev ) { |
325 | 325 | global $wgUser, $wgMemc, $wgParser, $wgEnableParserCache; |
326 | 326 | wfProfileIn( __METHOD__ ); |
327 | | - |
| 327 | + |
| 328 | + $dbw = wfGetDB( DB_MASTER ); |
328 | 329 | $article = new Article( $this->page ); |
329 | 330 | |
330 | 331 | $quality = 0; |
— | — | @@ -386,12 +387,16 @@ |
387 | 388 | if ( $timestamp > $lastImgTime ) |
388 | 389 | $lastImgTime = $timestamp; |
389 | 390 | |
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 |
| 391 | + $fileIncludeData = array( |
| 392 | + 'fi_rev_id' => $rev->getId(), |
| 393 | + 'fi_name' => $img_title->getDBkey(), |
| 394 | + 'fi_img_sha1' => $key |
395 | 395 | ); |
| 396 | + if ( $time ) { // b/c for bad <char(14) NOT NULL default ''> def |
| 397 | + $fileIncludeData['fi_img_timestamp'] = $dbw->timestamp( $timestamp ); |
| 398 | + } |
| 399 | + $imgset[] = $fileIncludeData; |
| 400 | + |
396 | 401 | if ( !isset( $imgParams[$img_title->getDBkey()] ) ) { |
397 | 402 | $imgParams[$img_title->getDBkey()] = array(); |
398 | 403 | } |
— | — | @@ -445,19 +450,14 @@ |
446 | 451 | |
447 | 452 | # Is this a duplicate review? |
448 | 453 | 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; |
| 454 | + $fileSha1 = $fileData ? |
| 455 | + $fileData['sha1'] : null; // stable upload version for file pages |
| 456 | + $synced = ( |
| 457 | + $oldfrev->getTags() == $flags && // tags => quality |
| 458 | + $oldfrev->getFileSha1() == $fileSha1 && |
| 459 | + $oldfrev->getComment() == $this->notes && |
| 460 | + FlaggedRevs::includesAreSynced( $stableOutput, $flaggedOutput ) |
| 461 | + ); |
462 | 462 | # Don't review if the same |
463 | 463 | if ( $synced ) { |
464 | 464 | wfProfileOut( __METHOD__ ); |
— | — | @@ -465,7 +465,6 @@ |
466 | 466 | } |
467 | 467 | } |
468 | 468 | |
469 | | - $dbw = wfGetDB( DB_MASTER ); |
470 | 469 | # Our review entry |
471 | 470 | $flaggedRevision = new FlaggedRevision( array( |
472 | 471 | 'fr_rev_id' => $rev->getId(), |
— | — | @@ -498,8 +497,10 @@ |
499 | 498 | || !isset( $poutput->fr_newestTemplateID ) |
500 | 499 | || !isset( $poutput->fr_newestImageTime ) ) |
501 | 500 | { |
| 501 | + $source = $article->getContent(); |
502 | 502 | $options = FlaggedRevs::makeParserOptions(); |
503 | | - $poutput = $wgParser->parse( $article->getContent(), $article->mTitle, $options ); |
| 503 | + $poutput = $wgParser->parse( $source, $article->getTitle(), $options, |
| 504 | + /*$lineStart*/true, /*$clearState*/true, $article->getLatest() ); |
504 | 505 | } |
505 | 506 | # Prepare for a link tracking update |
506 | 507 | $u = new LinksUpdate( $this->page, $poutput ); |
— | — | @@ -659,7 +660,7 @@ |
660 | 661 | * @return mixed (string/false) |
661 | 662 | */ |
662 | 663 | public static function buildQuickReview( |
663 | | - $article, $rev, $templateIDs, $imageSHA1Keys, $stableDiff = false |
| 664 | + FlaggedArticle $article, $rev, $templateIDs, $imageSHA1Keys, $stableDiff = false |
664 | 665 | ) { |
665 | 666 | global $wgUser, $wgRequest; |
666 | 667 | # The revision must be valid and public |
— | — | @@ -688,8 +689,7 @@ |
689 | 690 | } |
690 | 691 | $reviewNotes = $srev->getComment(); |
691 | 692 | # Re-review button is need for template/file only review case |
692 | | - $allowRereview = ( $srev->getRevId() == $id ) |
693 | | - && !FlaggedRevs::stableVersionIsSynced( $srev, $article ); |
| 693 | + $allowRereview = ( $srev->getRevId() == $id && !$article->stableVersionIsSynced() ); |
694 | 694 | } else { |
695 | 695 | $flags = $oldFlags; |
696 | 696 | // Get existing notes to pre-fill field |
Index: trunk/extensions/FlaggedRevs/FlaggedRevs.hooks.php |
— | — | @@ -397,7 +397,7 @@ |
398 | 398 | } |
399 | 399 | return true; |
400 | 400 | } |
401 | | - |
| 401 | + |
402 | 402 | protected static function addLink( array &$links, $ns, $dbKey ) { |
403 | 403 | if ( !isset( $links[$ns] ) ) { |
404 | 404 | $links[$ns] = array(); |
— | — | @@ -593,9 +593,10 @@ |
594 | 594 | array( 'fi_rev_id' => $parser->getRevisionId(), 'fi_name' => $title->getDBkey() ), |
595 | 595 | __METHOD__ |
596 | 596 | ); |
| 597 | + $reviewedTS = trim( $row->fi_img_timestamp ); // remove garbage |
597 | 598 | # Only the one picked at review time exists OR it is the newest...use it! |
598 | | - if ( $row && ( $time === false || $row->fi_img_timestamp > $time ) ) { |
599 | | - $time = $row->fi_img_timestamp; |
| 599 | + if ( $row && ( $time === false || $reviewedTS > $time ) ) { |
| 600 | + $time = $reviewedTS; |
600 | 601 | $sha1 = $row->fi_img_sha1; |
601 | 602 | $isKnownLocal = false; // up in the air...possibly a commons image |
602 | 603 | } |
— | — | @@ -685,9 +686,10 @@ |
686 | 687 | array( 'fi_rev_id' => $ig->mRevisionId, 'fi_name' => $nt->getDBkey() ), |
687 | 688 | __METHOD__ |
688 | 689 | ); |
| 690 | + $reviewedTS = trim( $row->fi_img_timestamp ); // remove garbage |
689 | 691 | # Only the one picked at review time exists OR it is the newest...use it! |
690 | | - if ( $row && ( $time === false || $row->fi_img_timestamp > $time ) ) { |
691 | | - $time = $row->fi_img_timestamp; |
| 692 | + if ( $row && ( $time === false || $reviewedTS > $time ) ) { |
| 693 | + $time = $reviewedTS; |
692 | 694 | $sha1 = $row->fi_img_sha1; |
693 | 695 | $isKnownLocal = false; // up in the air...possibly a commons image |
694 | 696 | } |
Index: trunk/extensions/FlaggedRevs/FlaggedArticleView.php |
— | — | @@ -36,7 +36,7 @@ |
37 | 37 | $this->loaded = true; |
38 | 38 | $this->article = self::globalArticleInstance(); |
39 | 39 | if ( $this->article == null ) { |
40 | | - throw new MWException( 'FlaggedArticleViewer has no context article!' ); |
| 40 | + throw new MWException( 'FlaggedArticleView has no context article!' ); |
41 | 41 | } |
42 | 42 | } |
43 | 43 | } |
— | — | @@ -354,7 +354,7 @@ |
355 | 355 | $quality = FlaggedRevs::isQuality( $flags ); |
356 | 356 | $pristine = FlaggedRevs::isPristine( $flags ); |
357 | 357 | # Get stable version sync status |
358 | | - $synced = FlaggedRevs::stableVersionIsSynced( $srev, $this->article ); |
| 358 | + $synced = $this->article->stableVersionIsSynced(); |
359 | 359 | if ( $synced ) { |
360 | 360 | $this->setReviewNotes( $srev ); // Still the same |
361 | 361 | } else { |
— | — | @@ -549,7 +549,7 @@ |
550 | 550 | $parserOut = null; |
551 | 551 | } |
552 | 552 | } |
553 | | - $synced = FlaggedRevs::stableVersionIsSynced( $srev, $this->article, $parserOut, null ); |
| 553 | + $synced = $this->article->stableVersionIsSynced( $parserOut, null ); |
554 | 554 | # Construct some tagging |
555 | 555 | if ( !$wgOut->isPrintable() && !( $this->article->lowProfileUI() && $synced ) ) { |
556 | 556 | $revsSince = $this->article->getPendingRevCount(); |
— | — | @@ -1093,7 +1093,7 @@ |
1094 | 1094 | if ( !$srev ) { |
1095 | 1095 | return true; // No stable revision exists |
1096 | 1096 | } |
1097 | | - $synced = FlaggedRevs::stableVersionIsSynced( $srev, $fa ); |
| 1097 | + $synced = $this->article->stableVersionIsSynced(); |
1098 | 1098 | $pendingEdits = !$synced && $fa->isStableShownByDefault(); |
1099 | 1099 | // Set the edit tab names as needed... |
1100 | 1100 | if ( $pendingEdits ) { |
— | — | @@ -1134,7 +1134,8 @@ |
1135 | 1135 | $tabs['read']['class'] = 'selected'; |
1136 | 1136 | } elseif ( self::isViewAction( $action ) ) { |
1137 | 1137 | // Are we looking at a draft/current revision? |
1138 | | - if ( $wgOut->getRevisionId() > $srev->getRevId() ) { |
| 1138 | + // Note: there may *just* be template/file changes. |
| 1139 | + if ( $wgOut->getRevisionId() >= $srev->getRevId() ) { |
1139 | 1140 | $tabs['draft']['class'] = 'selected'; |
1140 | 1141 | // Otherwise, fallback to regular tab behavior |
1141 | 1142 | } else { |
— | — | @@ -1294,11 +1295,14 @@ |
1295 | 1296 | * Add a link to diff-to-stable for reviewable pages |
1296 | 1297 | */ |
1297 | 1298 | protected function diffToStableLink( FlaggedRevision $frev, Revision $newRev ) { |
1298 | | - global $wgUser, $wgOut; |
| 1299 | + global $wgUser; |
1299 | 1300 | $this->load(); |
1300 | 1301 | $review = ''; |
1301 | | - # Make a link to the full diff-to-stable as needed |
1302 | | - if ( !$this->isDiffFromStable || !$newRev->isCurrent() ) { |
| 1302 | + # Make a link to the full diff-to-stable if: |
| 1303 | + # (a) Actual revs are pending and (b) We are not viewing the stable diff |
| 1304 | + if ( $this->article->revsArePending() && |
| 1305 | + !( $this->isDiffFromStable && $newRev->isCurrent() ) ) |
| 1306 | + { |
1303 | 1307 | $review = $wgUser->getSkin()->makeKnownLinkObj( |
1304 | 1308 | $this->article->getTitle(), |
1305 | 1309 | wfMsgHtml( 'review-diff2stable' ), |
— | — | @@ -1310,7 +1314,9 @@ |
1311 | 1315 | return $review; |
1312 | 1316 | } |
1313 | 1317 | |
1314 | | - // add [checked version] and such to left and right side of diff |
| 1318 | + /** |
| 1319 | + * Add [checked version] and such to left and right side of diff |
| 1320 | + */ |
1315 | 1321 | protected function diffReviewMarkers( $oldRev, $newRev ) { |
1316 | 1322 | $form = ''; |
1317 | 1323 | $oldRevQ = $newRevQ = false; |
— | — | @@ -1374,41 +1380,44 @@ |
1375 | 1381 | global $wgUser; |
1376 | 1382 | $skin = $wgUser->getSkin(); |
1377 | 1383 | $dbr = wfGetDB( DB_SLAVE ); |
1378 | | - // Get templates where the current and stable are not the same revision |
| 1384 | + # Get templates where the current and stable are not the same revision |
1379 | 1385 | $ret = $dbr->select( array( 'flaggedtemplates', 'page', 'flaggedpages' ), |
1380 | | - array( 'ft_namespace', 'ft_title', 'fp_stable', |
1381 | | - 'ft_tmp_rev_id', 'page_latest' ), |
1382 | | - array( 'ft_rev_id' => $frev->getRevId(), |
1383 | | - 'page_namespace = ft_namespace', |
1384 | | - 'page_title = ft_title' ), |
| 1386 | + array( 'ft_namespace', 'ft_title', 'fp_stable', 'ft_tmp_rev_id', 'page_latest' ), |
| 1387 | + array( 'ft_rev_id' => $frev->getRevId() ), |
1385 | 1388 | __METHOD__, |
1386 | 1389 | array(), /* OPTIONS */ |
1387 | | - array( 'flaggedpages' => array( 'LEFT JOIN', 'fp_page_id = page_id' ) ) |
| 1390 | + array( |
| 1391 | + 'page' => array( 'LEFT JOIN', |
| 1392 | + 'page_namespace = ft_namespace AND page_title = ft_title' ), |
| 1393 | + 'flaggedpages' => array( 'LEFT JOIN', 'fp_page_id = page_id' ) ) |
1388 | 1394 | ); |
1389 | 1395 | $tmpChanges = array(); |
1390 | 1396 | while ( $row = $dbr->fetchObject( $ret ) ) { |
1391 | 1397 | $title = Title::makeTitleSafe( $row->ft_namespace, $row->ft_title ); |
1392 | | - $revIdDraft = $row->page_latest; |
1393 | | - // stable time -> time when reviewed (unless the other is newer) |
1394 | | - $revIdStable = isset( $row->fp_stable ) && $row->fp_stable >= $row->ft_tmp_rev_id ? |
1395 | | - $row->fp_stable : $row->ft_tmp_rev_id; |
1396 | | - // compare to current |
1397 | | - if ( $revIdDraft > $revIdStable ) { |
1398 | | - $tmpChanges[] = $skin->makeKnownLinkObj( $title, |
| 1398 | + $revIdDraft = $row->page_latest; // may be NULL |
| 1399 | + # Stable time -> time when reviewed (unless the other is newer) |
| 1400 | + $revIdStable = $row->fp_stable && $row->fp_stable >= $row->ft_tmp_rev_id |
| 1401 | + ? $row->fp_stable |
| 1402 | + : $row->ft_tmp_rev_id; |
| 1403 | + # Compare to current... |
| 1404 | + $deleted = ( !$revIdDraft && $revIdStable ); // later deleted |
| 1405 | + $updated = ( $revIdDraft && $revIdDraft > $revIdStable ); // updated/created |
| 1406 | + if ( $deleted || $updated ) { |
| 1407 | + $tmpChanges[] = $skin->makeLinkObj( $title, |
1399 | 1408 | $title->getPrefixedText(), |
1400 | | - 'diff=cur&oldid=' . intval( $revIdStable ) ); |
| 1409 | + 'diff=cur&oldid=' . (int)$revIdStable ); |
1401 | 1410 | } |
1402 | 1411 | } |
1403 | 1412 | return $tmpChanges; |
1404 | 1413 | } |
1405 | | - |
| 1414 | + |
1406 | 1415 | // Fetch file changes for a reviewed revision since review |
1407 | 1416 | // @returns array |
1408 | 1417 | protected function fetchFileChanges( FlaggedRevision $frev ) { |
1409 | 1418 | global $wgUser; |
1410 | 1419 | $skin = $wgUser->getSkin(); |
1411 | 1420 | $dbr = wfGetDB( DB_SLAVE ); |
1412 | | - // Get images where the current and stable are not the same revision |
| 1421 | + # Get images where the current and stable are not the same revision |
1413 | 1422 | $ret = $dbr->select( |
1414 | 1423 | array( 'flaggedimages', 'page', 'image', 'flaggedpages', 'flaggedrevs' ), |
1415 | 1424 | array( 'fi_name', 'fi_img_timestamp', 'fr_img_timestamp' ), |
— | — | @@ -1426,13 +1435,18 @@ |
1427 | 1436 | $imgChanges = array(); |
1428 | 1437 | while ( $row = $dbr->fetchObject( $ret ) ) { |
1429 | 1438 | $title = Title::makeTitleSafe( NS_FILE, $row->fi_name ); |
1430 | | - // stable time -> time when reviewed (unless the other is newer) |
1431 | | - $timestamp = isset( $row->fr_img_timestamp ) && $row->fr_img_timestamp >= $row->fi_img_timestamp ? |
1432 | | - $row->fr_img_timestamp : $row->fi_img_timestamp; |
1433 | | - // compare to current |
| 1439 | + $reviewedTS = trim( $row->fi_img_timestamp ); // may be ''/NULL |
| 1440 | + # Stable time -> time when reviewed (unless the other is newer) |
| 1441 | + $tsStable = $row->fr_img_timestamp && $row->fr_img_timestamp >= $reviewedTS |
| 1442 | + ? $row->fr_img_timestamp |
| 1443 | + : $reviewedTS; |
| 1444 | + # Compare to current... |
1434 | 1445 | $file = wfFindFile( $title ); |
1435 | | - if ( $file && $file->getTimestamp() > $timestamp ) { |
1436 | | - $imgChanges[] = $skin->makeKnownLinkObj( $title, $title->getPrefixedText() ); |
| 1446 | + $deleted = ( !$file && $tsStable ); // later deleted |
| 1447 | + $updated = ( $file && $file->getTimestamp() > $tsStable ); // updated/created |
| 1448 | + if ( $deleted || $updated ) { |
| 1449 | + // @TODO: change when MW has file diffs |
| 1450 | + $imgChanges[] = $skin->makeLinkObj( $title, $title->getPrefixedText() ); |
1437 | 1451 | } |
1438 | 1452 | } |
1439 | 1453 | return $imgChanges; |