/**
  * When viewing a diff:
  * (a) Add the review form to the top of the page
  * (b) Mark off which versions are checked or not
  * (c) When comparing the stable revision to the current:
  *   (i)  Show a tag with some explanation for the diff
  *   (ii) List any template/file changes pending review
  */
 public function addToDiffView($diff, $oldRev, $newRev)
 {
     global $wgMemc, $wgParserCacheExpireTime;
     $request = $this->getRequest();
     $reqUser = $this->getUser();
     $this->load();
     # Exempt printer-friendly output
     if ($this->out->isPrintable()) {
         return true;
         # Multi-page diffs are useless and misbehave (bug 19327). Sanity check $newRev.
     } elseif ($this->isMultiPageDiff || !$newRev) {
         return true;
         # Page must be reviewable.
     } elseif (!$this->article->isReviewable()) {
         return true;
     }
     $srev = $this->article->getStableRev();
     if ($srev && $this->isReviewableDiff) {
         $this->reviewFormRev = $newRev;
     }
     # Check if this is a diff-to-stable. If so:
     # (a) prompt reviewers to review the changes
     # (b) list template/file changes if only includes are pending
     if ($srev && $this->isDiffFromStable && !$this->article->stableVersionIsSynced()) {
         $changeText = '';
         $changeList = array();
         # Page not synced only due to includes?
         if (!$this->article->revsArePending()) {
             # Add a list of links to each changed template...
             $changeList = self::fetchTemplateChanges($srev);
             # Add a list of links to each changed file...
             $changeList = array_merge($changeList, self::fetchFileChanges($srev));
             # Correct bad cache which said they were not synced...
             if (!count($changeList)) {
                 $key = wfMemcKey('flaggedrevs', 'includesSynced', $this->article->getId());
                 $data = FlaggedRevs::makeMemcObj("true");
                 $wgMemc->set($key, $data, $wgParserCacheExpireTime);
             }
             # Otherwise, check for includes pending on top of edits pending...
         } else {
             $incs = FRInclusionCache::getRevIncludes($this->article, $newRev, $reqUser);
             $this->oldRevIncludes = $incs;
             // process cache
             # Add a list of links to each changed template...
             $changeList = self::fetchTemplateChanges($srev, $incs[0]);
             # Add a list of links to each changed file...
             $changeList = array_merge($changeList, self::fetchFileChanges($srev, $incs[1]));
         }
         # If there are pending revs or templates/files changes, notify the user...
         if ($this->article->revsArePending() || count($changeList)) {
             # If the user can review then prompt them to review them...
             if ($reqUser->isAllowed('review')) {
                 // Reviewer just edited...
                 if ($request->getInt('shownotice') && $newRev->isCurrent() && $newRev->getRawUserText() == $reqUser->getName()) {
                     $title = $this->article->getTitle();
                     // convenience
                     // @TODO: make diff class cache this
                     $n = $title->countRevisionsBetween($oldRev, $newRev);
                     if ($n) {
                         $msg = 'revreview-update-edited-prev';
                         // previous pending edits
                     } else {
                         $msg = 'revreview-update-edited';
                         // just couldn't autoreview
                     }
                     // All other cases...
                 } else {
                     $msg = 'revreview-update';
                     // generic "please review" notice...
                 }
                 $this->diffNoticeBox = wfMsgExt($msg, 'parse');
                 // add as part of form
             }
             # Add include change list...
             if (count($changeList)) {
                 // just inclusion changes
                 $changeText .= "<p>" . wfMsgExt('revreview-update-includes', 'parseinline') . '&#160;' . implode(', ', $changeList) . "</p>\n";
             }
         }
         # template/file change list
         if ($changeText != '') {
             if ($reqUser->isAllowed('review')) {
                 $this->diffIncChangeBox = "<p>{$changeText}</p>";
             } else {
                 $css = 'flaggedrevs_diffnotice plainlinks';
                 $this->out->addHTML("<div id='mw-fr-difftostable' class='{$css}'>{$changeText}</div>\n");
             }
         }
     }
     # Add a link to diff from stable to current as needed.
     # Show review status of the diff revision(s). Uses a <table>.
     $this->out->addHTML('<div id="mw-fr-diff-headeritems">' . self::diffLinkAndMarkers($this->article, $oldRev, $newRev) . '</div>');
     return true;
 }
 /**
  * Set template and image versions from parsing a revision
  * @param Title $title
  * @param int $revId
  * @param ParserOutput $rev
  * @return void
  */
 public static function setRevIncludes(Title $title, $revId, ParserOutput $pOut)
 {
     global $wgMemc;
     $key = self::getCacheKey($title, $revId);
     # Get the template/file versions used...
     $versions = array($pOut->getTemplateIds(), $pOut->getFileSearchOptions());
     # Save to cache (check cache expiry for dynamic elements)...
     $data = FlaggedRevs::makeMemcObj($versions);
     $wgMemc->set($key, $data, $pOut->getCacheExpiry());
 }
 /**
  * Checks if the stable version is synced with the current revision
  * Note: slower than getPendingRevCount()
  * @return bool
  */
 public function stableVersionIsSynced()
 {
     global $wgMemc, $wgParserCacheExpireTime;
     $srev = $this->getStableRev();
     if (!$srev) {
         return true;
     }
     # Stable text revision must be the same as the current
     if ($this->revsArePending()) {
         return false;
         # Stable file revision must be the same as the current
     } elseif ($this->mTitle->getNamespace() == NS_FILE) {
         $file = $this->getFile();
         // current upload version
         if ($file && $file->getTimestamp() > $srev->getFileTimestamp()) {
             return false;
         }
     }
     # If using the current version of includes, there is nothing else to check.
     if (FlaggedRevs::inclusionSetting() == FR_INCLUDES_CURRENT) {
         return true;
         // short-circuit
     }
     # Try the cache...
     $key = wfMemcKey('flaggedrevs', 'includesSynced', $this->getId());
     $value = FlaggedRevs::getMemcValue($wgMemc->get($key), $this);
     if ($value === "true") {
         return true;
     } elseif ($value === "false") {
         return false;
     }
     # Since the stable and current revisions have the same text and only outputs,
     # the only other things to check for are template and file differences in the output.
     # (a) Check if the current output has a newer template/file used
     # (b) Check if the stable version has a file/template that was deleted
     $synced = !$srev->findPendingTemplateChanges() && !$srev->findPendingFileChanges('noForeign');
     # Save to cache. This will be updated whenever the page is touched.
     $data = FlaggedRevs::makeMemcObj($synced ? "true" : "false");
     $wgMemc->set($key, $data, $wgParserCacheExpireTime);
     return $synced;
 }
 public static function overrideRedirect(Title $title, WebRequest $request, &$ignoreRedirect, &$target, Article &$article)
 {
     global $wgMemc, $wgParserCacheExpireTime;
     $fa = FlaggableWikiPage::getTitleInstance($title);
     // on $wgTitle
     if (!$fa->isReviewable()) {
         return true;
         // nothing to do
     }
     # Viewing an old reviewed version...
     if ($request->getVal('stableid')) {
         $ignoreRedirect = true;
         // don't redirect (same as ?oldid=x)
         return true;
     }
     $srev = $fa->getStableRev();
     $view = FlaggablePageView::singleton();
     # Check if we are viewing an unsynced stable version...
     if ($srev && $view->showingStable() && $srev->getRevId() != $article->getLatest()) {
         # Check the stable redirect properties from the cache...
         $key = wfMemcKey('flaggedrevs', 'overrideRedirect', $article->getId());
         $tuple = FlaggedRevs::getMemcValue($wgMemc->get($key), $article);
         if (is_array($tuple)) {
             // cache hit
             list($ignoreRedirect, $target) = $tuple;
         } else {
             // cache miss; fetch the stable rev text...
             $text = $srev->getRevText();
             $redirect = $fa->getRedirectURL(Title::newFromRedirectRecurse($text));
             if ($redirect) {
                 $target = $redirect;
                 // use stable redirect
             } else {
                 $ignoreRedirect = true;
                 // make MW skip redirection
             }
             $data = FlaggedRevs::makeMemcObj(array($ignoreRedirect, $target));
             $wgMemc->set($key, $data, $wgParserCacheExpireTime);
             // cache results
         }
         $clearEnvironment = (bool) $target;
         # Check if the we are viewing a draft or synced stable version...
     } else {
         # In both cases, we can just let MW use followRedirect()
         # on the draft as normal, avoiding any page text hits.
         $clearEnvironment = $article->isRedirect();
     }
     # Environment (e.g. $wgTitle) will change in MediaWiki::initializeArticle
     if ($clearEnvironment) {
         $view->clear();
     }
     return true;
 }