function showDiffPage($diffOnly = false) { global $wgUser, $wgOut, $wgUseExternalEditor, $wgUseRCPatrol, $wgRequest, $wgTitle, $wgLanguageCode; $fname = 'DifferenceEngine::showDiffPage'; wfProfileIn($fname); # If external diffs are enabled both globally and for the user, # we'll use the application/x-external-editor interface to call # an external diff tool like kompare, kdiff3, etc. if ($wgUseExternalEditor && $wgUser->getOption('externaldiff')) { global $wgInputEncoding, $wgServer, $wgScript, $wgLang; $wgOut->disable(); header("Content-type: application/x-external-editor; charset=" . $wgInputEncoding); $url1 = $this->mTitle->getFullURL("action=raw&oldid=" . $this->mOldid); $url2 = $this->mTitle->getFullURL("action=raw&oldid=" . $this->mNewid); $special = $wgLang->getNsText(NS_SPECIAL); $control = <<<CONTROL [Process] Type=Diff text Engine=MediaWiki Script={$wgServer}{$wgScript} Special namespace={$special} [File] Extension=wiki URL={$url1} [File 2] Extension=wiki URL={$url2} CONTROL; echo $control; return; } $wgOut->setArticleFlag(false); if (!$this->loadRevisionData()) { $t = $this->mTitle->getPrefixedText() . " (Diff: {$this->mOldid}, {$this->mNewid})"; $wgOut->setPagetitle(wfMsg('errorpagetitle')); $wgOut->addWikiMsg('missingarticle', "<nowiki>{$t}</nowiki>"); wfProfileOut($fname); return; } wfRunHooks('DiffViewHeader', array($this, $this->mOldRev, $this->mNewRev)); if ($this->mNewRev->isCurrent()) { $wgOut->setArticleFlag(true); } # mOldid is false if the difference engine is called with a "vague" query for # a diff between a version V and its previous version V' AND the version V # is the first version of that article. In that case, V' does not exist. if ($this->mOldid === false && false) { $this->showFirstRevision(); $this->renderNewRevision(); // should we respect $diffOnly here or not? wfProfileOut($fname); return; } $wgOut->suppressQuickbar(); if (!$this->mOldPage) { $this->mOldPage = $this->mNewPage; } $oldTitle = $this->mOldPage->getPrefixedText(); $newTitle = $this->mNewPage->getPrefixedText(); if ($oldTitle == $newTitle) { $wgOut->setPageTitle($newTitle); } else { $wgOut->setPageTitle($oldTitle . ', ' . $newTitle); } $wgOut->setSubtitle(wfMsg('difference')); $wgOut->setRobotpolicy('noindex,nofollow'); if (!($this->mOldPage->userCanRead() && $this->mNewPage->userCanRead())) { $wgOut->loginToUse(); $wgOut->output(); wfProfileOut($fname); exit; } $sk = $wgUser->getSkin(); if ($this->mNewRev->isCurrent() && $wgUser->isAllowed('rollback') && $this->mTitle->userCanEdit()) { $rollback = $sk->generateRollback($this->mNewRev); } else { $rollback = ''; } // Prepare a change patrol link, if applicable if ($wgUseRCPatrol && $wgUser->isAllowed('patrol')) { // If we've been given an explicit change identifier, use it; saves time if ($this->mRcidMarkPatrolled) { $rcid = $this->mRcidMarkPatrolled; } else { // Look for an unpatrolled change corresponding to this diff $db = wfGetDB(DB_SLAVE); $change = RecentChange::newFromConds(array('rc_user_text' => $this->mNewRev->getRawUserText(), 'rc_timestamp' => $db->timestamp($this->mNewRev->getTimestamp()), 'rc_this_oldid' => $this->mNewid, 'rc_last_oldid' => $this->mOldid, 'rc_patrolled' => 0), __METHOD__); if ($change instanceof RecentChange) { $rcid = $change->mAttribs['rc_id']; } else { // None found $rcid = 0; } } // Build the link if ($rcid) { //XXCHANGED for recent changes patrolling $show_namespace = $wgRequest->getVal('show_namespace'); $invert = $wgRequest->getVal('invert'); $featured = $wgRequest->getVal('featured'); $reverse = $wgRequest->getVal('reverse'); //XXCHANGED $fromrc = ""; if ($wgRequest->getVal('fromrc', null) != null) { $fromrc = "&fromrc=1"; } if ($this->mRcidMarkPatrolledCount > 1) { $msg = wfMsg('markaspatrolleddiff_multiple', $this->mRcidMarkPatrolledCount); $patrol = '[' . $sk->makeKnownLinkObj($this->mTitle, $msg, "action=markpatrolled&rcid={$this->mRcidMarkPatrolled}&show_namespace={$show_namespace}" . "&invert={$invert}&reverse={$reverse}&featured={$featured}" . "&rchi={$this->mRcidMarkPatrolledMax}&rclow={$this->mRcidMarkPatrolledMin}{$fromrc}", '', '', "accesskey='p'") . ']'; $patrol .= '[' . $sk->makeKnownLinkObj($this->mTitle, wfMsg('skip'), "action=markpatrolled&rcid={$this->mRcidMarkPatrolled}&show_namespace={$show_namespace}" . "&invert={$invert}&reverse={$reverse}&featured={$featured}" . "&rchi={$this->mRcidMarkPatrolledMax}&rclow={$this->mRcidMarkPatrolledMin}{$fromrc}&skip=1", '', '', "") . ']'; } else { $patrol = '[' . $sk->makeKnownLinkObj($this->mTitle, wfMsg('markaspatrolleddiff'), "action=markpatrolled&rcid={$rcid}&show_namespace={$show_namespace}&invert={$invert}&reverse={$reverse}&featured={$featured}{$fromrc}", '', '', "accesskey='p'") . ']'; $patrol .= ' [' . $sk->makeKnownLinkObj($this->mTitle, wfMsg('skip'), "action=markpatrolled&rcid={$this->mRcidMarkPatrolled}&show_namespace={$show_namespace}&invert={$invert}&reverse={$reverse}&featured={$featured}&skip=1{$fromrc}") . ']'; } $patrol = "<span id='markaspatrolledlinks'>{$patrol}</span>"; //XXADDED } else { $patrol = ''; } } else { $patrol = ''; } //XXADDED if ($wgUser->isAllowed('rollback') && $this->mTitle->userCanEdit()) { //$rollback .= '<br/> <strong>' . SpamDiffTool::getDiffLink($this->mTitle) . '</strong>'; } $prevlink = $sk->makeKnownLinkObj($this->mTitle, wfMsgHtml('previousdiff'), 'diff=prev&oldid=' . $this->mOldid, '', '', 'id="differences-prevlink"'); if ($this->mNewRev->isCurrent()) { $nextlink = ''; } else { $nextlink = $sk->makeKnownLinkObj($this->mTitle, wfMsgHtml('nextdiff'), 'diff=next&oldid=' . $this->mNewid, '', '', 'id="differences-nextlink"'); } $oldminor = ''; $newminor = ''; if ($this->mOldRev->mMinorEdit == 1) { $oldminor = wfElement('span', array('class' => 'minor'), wfMsg('minoreditletter')) . ' '; } if ($this->mNewRev->mMinorEdit == 1) { $newminor = wfElement('span', array('class' => 'minor'), wfMsg('minoreditletter')) . ' '; } $rdel = ''; $ldel = ''; if ($wgUser->isAllowed('deleterevision')) { $revdel = SpecialPage::getTitleFor('Revisiondelete'); if (!$this->mOldRev->userCan(Revision::DELETED_RESTRICTED)) { // If revision was hidden from sysops $ldel = wfMsgHtml('rev-delundel'); } else { $ldel = $sk->makeKnownLinkObj($revdel, wfMsgHtml('rev-delundel'), 'target=' . urlencode($this->mOldRev->mTitle->getPrefixedDbkey()) . '&oldid=' . urlencode($this->mOldRev->getId())); // Bolden oversighted content if ($this->mOldRev->isDeleted(Revision::DELETED_RESTRICTED)) { $ldel = "<strong>{$ldel}</strong>"; } } $ldel = " <tt>(<small>{$ldel}</small>)</tt> "; // We don't currently handle well changing the top revision's settings if ($this->mNewRev->isCurrent()) { // If revision was hidden from sysops $rdel = wfMsgHtml('rev-delundel'); } else { if (!$this->mNewRev->userCan(Revision::DELETED_RESTRICTED)) { // If revision was hidden from sysops $rdel = wfMsgHtml('rev-delundel'); } else { $rdel = $sk->makeKnownLinkObj($revdel, wfMsgHtml('rev-delundel'), 'target=' . urlencode($this->mNewRev->mTitle->getPrefixedDbkey()) . '&oldid=' . urlencode($this->mNewRev->getId())); // Bolden oversighted content if ($this->mNewRev->isDeleted(Revision::DELETED_RESTRICTED)) { $rdel = "<strong>{$rdel}</strong>"; } } } $rdel = " <tt>(<small>{$rdel}</small>)</tt> "; } if ($this->mOldRev) { /*$oldHeader = '<div id="mw-diff-otitle1"><strong>'.$this->mOldtitle.'</strong></div>' . '<div id="mw-diff-otitle2">' . $sk->revUserTools( $this->mOldRev, true ) . "</div>" . '<div id="mw-diff-otitle3">' . $oldminor . $sk->revComment( $this->mOldRev, !$diffOnly, true ) . $ldel . "</div>" . '<div id="mw-diff-otitle4">' . $prevlink .'</div>';*/ $comment = $oldminor . $sk->revComment($this->mOldRev, !$diffOnly, true) . $ldel; //INTL: Avatar database data doesn't exist for sites other than English if ($wgLanguageCode == 'en') { $av = '<img src="' . Avatar::getAvatarURL($this->mOldRev->mUserText) . '" class="diff_avatar" />'; } //$userToolsString = $sk->revUserTools( $this->mOldRev, true ); //$userParts = explode("(", $userToolsString, 2); //$userName = $userParts[0]; //$userTools = "(" . $userParts[1]; $userName = $sk->userLink($this->mOldRev->getUser(), $this->mOldRev->getUserText()); $userTools = $sk->userToolLinks($this->mOldRev->getUser(), $this->mOldRev->getUserText()); $oldHeader = '<div id="mw-diff-otitle1"><h4>' . $prevlink . $this->mOldtitle . '</h4></div>' . '<div class="diff_details">' . $av . '<div id="mw-diff-otitle1a">' . wfMsg('diff_by') . ' ' . $userName . '</div>' . '<div id="mw-diff-otitle2">' . $this->mOldDate . "</div>" . '<div id="mw-diff-otitle2b">' . $userTools . "</div>"; if ($comment != "") { $oldHeader .= '<div id="mw-diff-otitle3" class="rccomment"><div class="">' . $comment . '</div></div>'; } $oldHeader .= '</div>'; } else { $oldHeader = wfMsg('diff_noprev'); } /*$newHeader = '<div id="mw-diff-ntitle1"><strong>'.$this->mNewtitle.'</strong></div>' . '<div id="mw-diff-ntitle2">' . $sk->revUserTools( $this->mNewRev, true ) . "</div>" . '<div id="mw-diff-ntitle2a">' . $rollback . "</div>" . '<div id="mw-diff-ntitle3">' . $newminor . $sk->revComment( $this->mNewRev, !$diffOnly, true ) . $rdel . "</div>" . '<div id="mw-diff-ntitle4">' . $nextlink . $patrol . '</div>';*/ $comment = $newminor . $sk->revComment($this->mNewRev, !$diffOnly, true) . $rdel; //INTL: Avatar database data doesn't exist for sites other than English if ($wgLanguageCode == 'en') { $av = '<img src="' . Avatar::getAvatarURL($this->mNewRev->mUserText) . '" class="diff_avatar" />'; } //$userToolsString = $sk->revUserTools( $this->mNewRev, true ); //$userParts = explode("(", $userToolsString, 2); //$userName = $userParts[0]; //$userTools = "(" . $userParts[1]; $userName = $sk->userLink($this->mNewRev->getUser(), $this->mNewRev->getUserText()); $userTools = $sk->userToolLinks($this->mNewRev->getUser(), $this->mNewRev->getUserText()); $thumbsHtml = ""; $thumbHeader = ""; $th_diff_div = ""; if ($wgUser->getId() != 0 && $wgTitle->getText() != "RCPatrol" && $wgTitle->getText() != "RCPatrolGuts" && $this->mNewRev->getTitle()->getNamespace() == NS_MAIN) { $oldId = $this->mNewRev->getPrevious(); $oldId = $oldId ? $oldId->getId() : -1; // Only show thumbs up for diffs that look back one revision if (class_exists('ThumbsUp')) { if ($oldId == -1 || $this->mOldRev && $oldId == $this->mOldRev->getId()) { $params = array('title' => $this->mNewRev->getTitle(), 'new' => $this->mNewid, 'old' => $oldId, 'vandal' => 0); $thumbsHtml = ThumbsUp::getThumbsUpButton($params, true); //$thumbHeader = 'class="th_diff_h4"'; $th_diff_div = 'class="th_diff_div"'; } } } $newHeader = '<div id="mw-diff-ntitle1" ' . $th_diff_div . '><h4 ' . $thumbHeader . '>' . $this->mNewtitle . ' ' . $nextlink . '</h4></div>' . '<div class="diff_details">' . $av . $thumbsHtml . '<div id="mw-diff-ntitle1a">' . wfMsg('diff_by') . ' ' . $userName . '</div>' . '<div id="mw-diff-ntitle2">' . $this->mNewDate . "</div>" . '<div id="mw-diff-ntitle2b">' . $userTools . "</div>" . '<div id="mw-diff-ntitle4" style="text-align:left">' . $rollback . $nextlink . $patrol . '</div>'; if ($comment != "") { $newHeader .= '<div id="mw-diff-ntitle3" class="rccomment"><div class="">' . $comment . '</div></div>'; } $newHeader .= '</div>'; $this->showDiff($oldHeader, $newHeader); if (!$diffOnly) { $this->renderNewRevision(); } wfProfileOut($fname); }
function showDiffPage($diffOnly = false) { global $wgUser, $wgOut, $wgUseExternalEditor, $wgUseRCPatrol; wfProfileIn(__METHOD__); # Allow frames except in certain special cases $wgOut->allowClickjacking(); # If external diffs are enabled both globally and for the user, # we'll use the application/x-external-editor interface to call # an external diff tool like kompare, kdiff3, etc. if ($wgUseExternalEditor && $wgUser->getOption('externaldiff')) { global $wgCanonicalServer, $wgScript, $wgLang; $wgOut->disable(); header("Content-type: application/x-external-editor; charset=UTF-8"); $url1 = $this->mTitle->getCanonical(array('action' => 'raw', 'oldid' => $this->mOldid)); $url2 = $this->mTitle->getCanonical(array('action' => 'raw', 'oldid' => $this->mNewid)); $special = $wgLang->getNsText(NS_SPECIAL); $control = <<<CONTROL \t\t\t[Process] \t\t\tType=Diff text \t\t\tEngine=MediaWiki \t\t\tScript={$wgCanonicalServer}{$wgScript} \t\t\tSpecial namespace={$special} \t\t\t[File] \t\t\tExtension=wiki \t\t\tURL={$url1} \t\t\t[File 2] \t\t\tExtension=wiki \t\t\tURL={$url2} CONTROL; echo $control; wfProfileOut(__METHOD__); return; } $wgOut->setArticleFlag(false); if (!$this->loadRevisionData()) { // Sounds like a deleted revision... Let's see what we can do. $t = $this->mTitle->getPrefixedText(); $d = wfMsgExt('missingarticle-diff', array('escape'), $this->deletedIdMarker($this->mOldid), $this->deletedIdMarker($this->mNewid)); $wgOut->setPagetitle(wfMsg('errorpagetitle')); $wgOut->addWikiMsg('missing-article', "<nowiki>{$t}</nowiki>", "<span class='plainlinks'>{$d}</span>"); wfProfileOut(__METHOD__); return; } wfRunHooks('DiffViewHeader', array($this, $this->mOldRev, $this->mNewRev)); if ($this->mNewRev->isCurrent()) { $wgOut->setArticleFlag(true); } # mOldid is false if the difference engine is called with a "vague" query for # a diff between a version V and its previous version V' AND the version V # is the first version of that article. In that case, V' does not exist. if ($this->mOldid === false) { $this->showFirstRevision(); $this->renderNewRevision(); // should we respect $diffOnly here or not? wfProfileOut(__METHOD__); return; } $oldTitle = $this->mOldPage->getPrefixedText(); $newTitle = $this->mNewPage->getPrefixedText(); if ($oldTitle == $newTitle) { $wgOut->setPageTitle($newTitle); } else { $wgOut->setPageTitle($oldTitle . ', ' . $newTitle); } if ($this->mNewPage->equals($this->mOldPage)) { $wgOut->setSubtitle(wfMsgExt('difference', array('parseinline'))); } else { $wgOut->setSubtitle(wfMsgExt('difference-multipage', array('parseinline'))); } $wgOut->setRobotPolicy('noindex,nofollow'); if (!$this->mOldPage->userCanRead() || !$this->mNewPage->userCanRead()) { $wgOut->loginToUse(); $wgOut->output(); $wgOut->disable(); wfProfileOut(__METHOD__); return; } $sk = $wgUser->getSkin(); if (method_exists($sk, 'suppressQuickbar')) { $sk->suppressQuickbar(); } // Check if page is editable $editable = $this->mNewRev->getTitle()->userCan('edit'); if ($editable && $this->mNewRev->isCurrent() && $wgUser->isAllowed('rollback')) { $wgOut->preventClickjacking(); $rollback = '   ' . $sk->generateRollback($this->mNewRev); } else { $rollback = ''; } // Prepare a change patrol link, if applicable if ($wgUseRCPatrol && $this->mTitle->userCan('patrol')) { // If we've been given an explicit change identifier, use it; saves time if ($this->mRcidMarkPatrolled) { $rcid = $this->mRcidMarkPatrolled; $rc = RecentChange::newFromId($rcid); // Already patrolled? $rcid = is_object($rc) && !$rc->getAttribute('rc_patrolled') ? $rcid : 0; } else { // Look for an unpatrolled change corresponding to this diff $db = wfGetDB(DB_SLAVE); $change = RecentChange::newFromConds(array('rc_user_text' => $this->mNewRev->getRawUserText(), 'rc_timestamp' => $db->timestamp($this->mNewRev->getTimestamp()), 'rc_this_oldid' => $this->mNewid, 'rc_last_oldid' => $this->mOldid, 'rc_patrolled' => 0), __METHOD__); if ($change instanceof RecentChange) { $rcid = $change->mAttribs['rc_id']; $this->mRcidMarkPatrolled = $rcid; } else { // None found $rcid = 0; } } // Build the link if ($rcid) { $wgOut->preventClickjacking(); $token = $wgUser->editToken($rcid); $patrol = ' <span class="patrollink">[' . $sk->link($this->mTitle, wfMsgHtml('markaspatrolleddiff'), array(), array('action' => 'markpatrolled', 'rcid' => $rcid, 'token' => $token), array('known', 'noclasses')) . ']</span>'; } else { $patrol = ''; } } else { $patrol = ''; } # Carry over 'diffonly' param via navigation links if ($diffOnly != $wgUser->getBoolOption('diffonly')) { $query['diffonly'] = $diffOnly; } # Make "previous revision link" $query['diff'] = 'prev'; $query['oldid'] = $this->mOldid; # Cascade unhide param in links for easy deletion browsing if ($this->unhide) { $query['unhide'] = 1; } if (!$this->mOldRev->getPrevious()) { $prevlink = ' '; } else { $prevlink = $sk->link($this->mTitle, wfMsgHtml('previousdiff'), array('id' => 'differences-prevlink'), $query, array('known', 'noclasses')); } # Make "next revision link" $query['diff'] = 'next'; $query['oldid'] = $this->mNewid; # Skip next link on the top revision if ($this->mNewRev->isCurrent()) { $nextlink = ' '; } else { $nextlink = $sk->link($this->mTitle, wfMsgHtml('nextdiff'), array('id' => 'differences-nextlink'), $query, array('known', 'noclasses')); } $oldminor = ''; $newminor = ''; if ($this->mOldRev->isMinor()) { $oldminor = ChangesList::flag('minor'); } if ($this->mNewRev->isMinor()) { $newminor = ChangesList::flag('minor'); } # Handle RevisionDelete links... $ldel = $this->revisionDeleteLink($this->mOldRev); $rdel = $this->revisionDeleteLink($this->mNewRev); $oldHeader = '<div id="mw-diff-otitle1"><strong>' . $this->mOldtitle . '</strong></div>' . '<div id="mw-diff-otitle2">' . $sk->revUserTools($this->mOldRev, !$this->unhide) . '</div>' . '<div id="mw-diff-otitle3">' . $oldminor . $sk->revComment($this->mOldRev, !$diffOnly, !$this->unhide) . $ldel . '</div>' . '<div id="mw-diff-otitle4">' . $prevlink . '</div>'; $newHeader = '<div id="mw-diff-ntitle1"><strong>' . $this->mNewtitle . '</strong></div>' . '<div id="mw-diff-ntitle2">' . $sk->revUserTools($this->mNewRev, !$this->unhide) . " {$rollback}</div>" . '<div id="mw-diff-ntitle3">' . $newminor . $sk->revComment($this->mNewRev, !$diffOnly, !$this->unhide) . $rdel . '</div>' . '<div id="mw-diff-ntitle4">' . $nextlink . $patrol . '</div>'; # Check if this user can see the revisions $allowed = $this->mOldRev->userCan(Revision::DELETED_TEXT) && $this->mNewRev->userCan(Revision::DELETED_TEXT); # Check if one of the revisions is deleted/suppressed $deleted = $suppressed = false; if ($this->mOldRev->isDeleted(Revision::DELETED_TEXT)) { $deleted = true; // old revisions text is hidden if ($this->mOldRev->isDeleted(Revision::DELETED_RESTRICTED)) { $suppressed = true; } // also suppressed } if ($this->mNewRev->isDeleted(Revision::DELETED_TEXT)) { $deleted = true; // new revisions text is hidden if ($this->mNewRev->isDeleted(Revision::DELETED_RESTRICTED)) { $suppressed = true; } // also suppressed } # If the diff cannot be shown due to a deleted revision, then output # the diff header and links to unhide (if available)... if ($deleted && (!$this->unhide || !$allowed)) { $this->showDiffStyle(); $multi = $this->getMultiNotice(); $wgOut->addHTML($this->addHeader('', $oldHeader, $newHeader, $multi)); if (!$allowed) { $msg = $suppressed ? 'rev-suppressed-no-diff' : 'rev-deleted-no-diff'; # Give explanation for why revision is not visible $wgOut->wrapWikiMsg("<div id='mw-{$msg}' class='mw-warning plainlinks'>\n\$1\n</div>\n", array($msg)); } else { # Give explanation and add a link to view the diff... $link = $this->mTitle->getFullUrl(array('diff' => $this->mNewid, 'oldid' => $this->mOldid, 'unhide' => 1)); $msg = $suppressed ? 'rev-suppressed-unhide-diff' : 'rev-deleted-unhide-diff'; $wgOut->wrapWikiMsg("<div id='mw-{$msg}' class='mw-warning plainlinks'>\n\$1\n</div>\n", array($msg, $link)); } # Otherwise, output a regular diff... } else { # Add deletion notice if the user is viewing deleted content $notice = ''; if ($deleted) { $msg = $suppressed ? 'rev-suppressed-diff-view' : 'rev-deleted-diff-view'; $notice = "<div id='mw-{$msg}' class='mw-warning plainlinks'>\n" . wfMsgExt($msg, 'parseinline') . "</div>\n"; } $this->showDiff($oldHeader, $newHeader, $notice); if (!$diffOnly) { $this->renderNewRevision(); } } wfProfileOut(__METHOD__); }
/** * Returns an array of meta data needed to build a "mark as patrolled" link and * adds the mediawiki.page.patrol.ajax to the output. * * @return array|false An array of meta data for a patrol link (rcid & token) * or false if no link is needed */ protected function getMarkPatrolledLinkInfo() { global $wgUseRCPatrol, $wgEnableAPI, $wgEnableWriteAPI; $user = $this->getUser(); // Prepare a change patrol link, if applicable if ($wgUseRCPatrol && $this->mNewPage->quickUserCan('patrol', $user) && RecentChange::isInRCLifespan($this->mNewRev->getTimestamp(), 21600)) { // Look for an unpatrolled change corresponding to this diff $db = wfGetDB(DB_SLAVE); $change = RecentChange::newFromConds(array('rc_timestamp' => $db->timestamp($this->mNewRev->getTimestamp()), 'rc_this_oldid' => $this->mNewid, 'rc_patrolled' => 0), __METHOD__); if ($change && !$change->getPerformer()->equals($user)) { $rcid = $change->getAttribute('rc_id'); } else { // None found or the page has been created by the current user. // If the user could patrol this it already would be patrolled $rcid = 0; } // Build the link if ($rcid) { $this->getOutput()->preventClickjacking(); if ($wgEnableAPI && $wgEnableWriteAPI && $user->isAllowed('writeapi')) { $this->getOutput()->addModules('mediawiki.page.patrol.ajax'); } $token = $user->getEditToken($rcid); return array('rcid' => $rcid, 'token' => $token); } } // No mark as patrolled link applicable return false; }
/** * Get a link to mark the change as patrolled, or '' if there's either no * revision to patrol or the user is not allowed to to it. * Side effect: this method will call OutputPage::preventClickjacking() * when a link is builded. * * @return String */ protected function markPatrolledLink() { global $wgUseRCPatrol; if ($this->mMarkPatrolledLink === null) { // Prepare a change patrol link, if applicable if ($wgUseRCPatrol && $this->mNewPage->quickUserCan('patrol', $this->getUser())) { // If we've been given an explicit change identifier, use it; saves time if ($this->mRcidMarkPatrolled) { $rcid = $this->mRcidMarkPatrolled; $rc = RecentChange::newFromId($rcid); // Already patrolled? $rcid = is_object($rc) && !$rc->getAttribute('rc_patrolled') ? $rcid : 0; } else { // Look for an unpatrolled change corresponding to this diff $db = wfGetDB(DB_SLAVE); $change = RecentChange::newFromConds(array('rc_user_text' => $this->mNewRev->getRawUserText(), 'rc_timestamp' => $db->timestamp($this->mNewRev->getTimestamp()), 'rc_this_oldid' => $this->mNewid, 'rc_last_oldid' => $this->mOldid, 'rc_patrolled' => 0), __METHOD__); if ($change instanceof RecentChange) { $rcid = $change->mAttribs['rc_id']; $this->mRcidMarkPatrolled = $rcid; } else { // None found $rcid = 0; } } // Build the link if ($rcid) { $this->getOutput()->preventClickjacking(); $token = $this->getUser()->getEditToken($rcid); $this->mMarkPatrolledLink = ' <span class="patrollink">[' . Linker::linkKnown($this->mNewPage, $this->msg('markaspatrolleddiff')->escaped(), array(), array('action' => 'markpatrolled', 'rcid' => $rcid, 'token' => $token)) . ']</span>'; } else { $this->mMarkPatrolledLink = ''; } } else { $this->mMarkPatrolledLink = ''; } } return $this->mMarkPatrolledLink; }
/** * If patrol is possible, output a patrol UI box. This is called from the * footer section of ordinary page views. If patrol is not possible or not * desired, does nothing. * Side effect: When the patrol link is build, this method will call * OutputPage::preventClickjacking() and load mediawiki.page.patrol.ajax. * * @return bool */ public function showPatrolFooter() { global $wgUseNPPatrol, $wgUseRCPatrol, $wgEnableAPI, $wgEnableWriteAPI; $outputPage = $this->getContext()->getOutput(); $user = $this->getContext()->getUser(); $cache = wfGetMainCache(); $rc = false; if (!$this->getTitle()->quickUserCan('patrol', $user) || !($wgUseRCPatrol || $wgUseNPPatrol)) { // Patrolling is disabled or the user isn't allowed to return false; } // New page patrol: Get the timestamp of the oldest revison which // the revision table holds for the given page. Then we look // whether it's within the RC lifespan and if it is, we try // to get the recentchanges row belonging to that entry // (with rc_new = 1). if ($this->mRevision && !RecentChange::isInRCLifespan($this->mRevision->getTimestamp(), 21600)) { // The current revision is already older than what could be in the RC table // 6h tolerance because the RC might not be cleaned out regularly return false; } // Check for cached results $key = wfMemcKey('NotPatrollablePage', $this->getTitle()->getArticleID()); if ($cache->get($key)) { return false; } $dbr = wfGetDB(DB_SLAVE); $oldestRevisionTimestamp = $dbr->selectField('revision', 'MIN( rev_timestamp )', array('rev_page' => $this->getTitle()->getArticleID()), __METHOD__); if ($oldestRevisionTimestamp && RecentChange::isInRCLifespan($oldestRevisionTimestamp, 21600)) { // 6h tolerance because the RC might not be cleaned out regularly $rc = RecentChange::newFromConds(array('rc_new' => 1, 'rc_timestamp' => $oldestRevisionTimestamp, 'rc_namespace' => $this->getTitle()->getNamespace(), 'rc_cur_id' => $this->getTitle()->getArticleID()), __METHOD__, array('USE INDEX' => 'new_name_timestamp')); } else { // Cache the information we gathered above in case we can't patrol // Don't cache in case we can patrol as this could change $cache->set($key, '1'); } if (!$rc) { // Don't cache: This can be hit if the page gets accessed very fast after // its creation or in case we have high slave lag. In case the revision is // too old, we will already return above. return false; } if ($rc->getAttribute('rc_patrolled')) { // Patrolled RC entry around // Cache the information we gathered above in case we can't patrol // Don't cache in case we can patrol as this could change $cache->set($key, '1'); return false; } if ($rc->getPerformer()->equals($user)) { // Don't show a patrol link for own creations. If the user could // patrol them, they already would be patrolled return false; } $rcid = $rc->getAttribute('rc_id'); $token = $user->getEditToken($rcid); $outputPage->preventClickjacking(); if ($wgEnableAPI && $wgEnableWriteAPI && $user->isAllowed('writeapi')) { $outputPage->addModules('mediawiki.page.patrol.ajax'); } $link = Linker::linkKnown($this->getTitle(), wfMessage('markaspatrolledtext')->escaped(), array(), array('action' => 'markpatrolled', 'rcid' => $rcid, 'token' => $token)); $outputPage->addHTML("<div class='patrollink'>" . wfMessage('markaspatrolledlink')->rawParams($link)->escaped() . '</div>'); return true; }
function showDiffPage($diffOnly = false) { global $wgUser, $wgOut, $wgUseExternalEditor, $wgUseRCPatrol, $wgEnableHtmlDiff; wfProfileIn(__METHOD__); # If external diffs are enabled both globally and for the user, # we'll use the application/x-external-editor interface to call # an external diff tool like kompare, kdiff3, etc. if ($wgUseExternalEditor && $wgUser->getOption('externaldiff')) { global $wgInputEncoding, $wgServer, $wgScript, $wgLang; $wgOut->disable(); header("Content-type: application/x-external-editor; charset=" . $wgInputEncoding); $url1 = $this->mTitle->getFullURL("action=raw&oldid=" . $this->mOldid); $url2 = $this->mTitle->getFullURL("action=raw&oldid=" . $this->mNewid); $special = $wgLang->getNsText(NS_SPECIAL); $control = <<<CONTROL \t\t\t[Process] \t\t\tType=Diff text \t\t\tEngine=MediaWiki \t\t\tScript={$wgServer}{$wgScript} \t\t\tSpecial namespace={$special} \t\t\t[File] \t\t\tExtension=wiki \t\t\tURL={$url1} \t\t\t[File 2] \t\t\tExtension=wiki \t\t\tURL={$url2} CONTROL; echo $control; return; } $wgOut->setArticleFlag(false); if (!$this->loadRevisionData()) { $t = $this->mTitle->getPrefixedText(); $d = wfMsgExt('missingarticle-diff', array('escape'), $this->mOldid, $this->mNewid); $wgOut->setPagetitle(wfMsg('errorpagetitle')); $wgOut->addWikiMsg('missing-article', "<nowiki>{$t}</nowiki>", $d); wfProfileOut(__METHOD__); return; } wfRunHooks('DiffViewHeader', array($this, $this->mOldRev, $this->mNewRev)); if ($this->mNewRev->isCurrent()) { $wgOut->setArticleFlag(true); } # mOldid is false if the difference engine is called with a "vague" query for # a diff between a version V and its previous version V' AND the version V # is the first version of that article. In that case, V' does not exist. if ($this->mOldid === false) { $this->showFirstRevision(); $this->renderNewRevision(); // should we respect $diffOnly here or not? wfProfileOut(__METHOD__); return; } $wgOut->suppressQuickbar(); $oldTitle = $this->mOldPage->getPrefixedText(); $newTitle = $this->mNewPage->getPrefixedText(); if ($oldTitle == $newTitle) { $wgOut->setPageTitle($newTitle); } else { $wgOut->setPageTitle($oldTitle . ', ' . $newTitle); } $wgOut->setSubtitle(wfMsgExt('difference', array('parseinline'))); $wgOut->setRobotPolicy('noindex,nofollow'); if (!$this->mOldPage->userCanRead() || !$this->mNewPage->userCanRead()) { $wgOut->loginToUse(); $wgOut->output(); $wgOut->disable(); wfProfileOut(__METHOD__); return; } $sk = $wgUser->getSkin(); // Check if page is editable $editable = $this->mNewRev->getTitle()->userCan('edit'); if ($editable && $this->mNewRev->isCurrent() && $wgUser->isAllowed('rollback')) { $rollback = ' ' . $sk->generateRollback($this->mNewRev); } else { $rollback = ''; } // Prepare a change patrol link, if applicable if ($wgUseRCPatrol && $this->mTitle->userCan('patrol')) { // If we've been given an explicit change identifier, use it; saves time if ($this->mRcidMarkPatrolled) { $rcid = $this->mRcidMarkPatrolled; $rc = RecentChange::newFromId($rcid); // Already patrolled? $rcid = is_object($rc) && !$rc->getAttribute('rc_patrolled') ? $rcid : 0; } else { // Look for an unpatrolled change corresponding to this diff $db = wfGetDB(DB_SLAVE); $change = RecentChange::newFromConds(array('rc_user_text' => $this->mNewRev->getRawUserText(), 'rc_timestamp' => $db->timestamp($this->mNewRev->getTimestamp()), 'rc_this_oldid' => $this->mNewid, 'rc_last_oldid' => $this->mOldid, 'rc_patrolled' => 0), __METHOD__); if ($change instanceof RecentChange) { $rcid = $change->mAttribs['rc_id']; $this->mRcidMarkPatrolled = $rcid; } else { // None found $rcid = 0; } } // Build the link if ($rcid) { $patrol = ' <span class="patrollink">[' . $sk->makeKnownLinkObj($this->mTitle, wfMsgHtml('markaspatrolleddiff'), "action=markpatrolled&rcid={$rcid}") . ']</span>'; } else { $patrol = ''; } } else { $patrol = ''; } $diffOnlyArg = ''; # Carry over 'diffonly' param via navigation links if ($diffOnly != $wgUser->getBoolOption('diffonly')) { $diffOnlyArg = '&diffonly=' . $diffOnly; } $htmldiffarg = $this->htmlDiffArgument(); # Make "previous revision link" $prevlink = $sk->makeKnownLinkObj($this->mTitle, wfMsgHtml('previousdiff'), "diff=prev&oldid={$this->mOldid}{$htmldiffarg}{$diffOnlyArg}", '', '', 'id="differences-prevlink"'); # Make "next revision link" if ($this->mNewRev->isCurrent()) { $nextlink = ' '; } else { $nextlink = $sk->makeKnownLinkObj($this->mTitle, wfMsgHtml('nextdiff'), "diff=next&oldid={$this->mNewid}{$htmldiffarg}{$diffOnlyArg}", '', '', 'id="differences-nextlink"'); } $oldminor = ''; $newminor = ''; if ($this->mOldRev->isMinor()) { $oldminor = Xml::span(wfMsg('minoreditletter'), 'minor') . ' '; } if ($this->mNewRev->isMinor()) { $newminor = Xml::span(wfMsg('minoreditletter'), 'minor') . ' '; } $rdel = ''; $ldel = ''; if ($wgUser->isAllowed('deleterevision')) { if (!$this->mOldRev->userCan(Revision::DELETED_RESTRICTED)) { // If revision was hidden from sysops $ldel = Xml::tags('span', array('class' => 'mw-revdelundel-link'), '(' . wfMsgHtml('rev-delundel') . ')'); } else { $query = array('target' => $this->mOldRev->mTitle->getPrefixedDbkey(), 'oldid' => $this->mOldRev->getId()); $ldel = $sk->revDeleteLink($query, $this->mOldRev->isDeleted(Revision::DELETED_RESTRICTED)); } $ldel = " {$ldel} "; // We don't currently handle well changing the top revision's settings if ($this->mNewRev->isCurrent()) { $rdel = Xml::tags('span', array('class' => 'mw-revdelundel-link'), '(' . wfMsgHtml('rev-delundel') . ')'); } else { if (!$this->mNewRev->userCan(Revision::DELETED_RESTRICTED)) { // If revision was hidden from sysops $rdel = Xml::tags('span', array('class' => 'mw-revdelundel-link'), '(' . wfMsgHtml('rev-delundel') . ')'); } else { $query = array('target' => $this->mNewRev->mTitle->getPrefixedDbkey(), 'oldid' => $this->mNewRev->getId()); $rdel = $sk->revDeleteLink($query, $this->mNewRev->isDeleted(Revision::DELETED_RESTRICTED)); } } $rdel = " {$rdel} "; } $oldHeader = '<div id="mw-diff-otitle1"><strong>' . $this->mOldtitle . '</strong></div>' . '<div id="mw-diff-otitle2">' . $sk->revUserTools($this->mOldRev, !$this->unhide) . "</div>" . '<div id="mw-diff-otitle3">' . $oldminor . $sk->revComment($this->mOldRev, !$diffOnly, !$this->unhide) . $ldel . "</div>" . '<div id="mw-diff-otitle4">' . $prevlink . '</div>'; $newHeader = '<div id="mw-diff-ntitle1"><strong>' . $this->mNewtitle . '</strong></div>' . '<div id="mw-diff-ntitle2">' . $sk->revUserTools($this->mNewRev, !$this->unhide) . " {$rollback}</div>" . '<div id="mw-diff-ntitle3">' . $newminor . $sk->revComment($this->mNewRev, !$diffOnly, !$this->unhide) . $rdel . "</div>" . '<div id="mw-diff-ntitle4">' . $nextlink . $patrol . '</div>'; # Check if this user can see the revisions $allowed = $this->mOldRev->userCan(Revision::DELETED_TEXT) && $this->mNewRev->userCan(Revision::DELETED_TEXT); $deleted = $this->mOldRev->isDeleted(Revision::DELETED_TEXT) || $this->mNewRev->isDeleted(Revision::DELETED_TEXT); # Output the diff if allowed... if ($deleted && (!$this->unhide || !$allowed)) { $this->showDiffStyle(); $multi = $this->getMultiNotice(); $wgOut->addHTML($this->addHeader('', $oldHeader, $newHeader, $multi)); if (!$allowed) { # Give explanation for why revision is not visible $wgOut->wrapWikiMsg("<div class='mw-warning plainlinks'>\n\$1</div>\n", array('rev-deleted-no-diff')); } else { # Give explanation and add a link to view the diff... $link = $this->mTitle->getFullUrl("diff={$this->mNewid}&oldid={$this->mOldid}" . '&unhide=1&token=' . urlencode($wgUser->editToken($this->mNewid))); $wgOut->wrapWikiMsg("<div class='mw-warning plainlinks'>\n\$1</div>\n", array('rev-deleted-unhide-diff', $link)); } } else { if ($wgEnableHtmlDiff && $this->htmldiff) { $multi = $this->getMultiNotice(); $wgOut->addHTML('<div class="diff-switchtype">' . $sk->makeKnownLinkObj($this->mTitle, wfMsgHtml('wikicodecomparison'), 'diff=' . $this->mNewid . '&oldid=' . $this->mOldid . '&htmldiff=0', '', '', 'id="differences-switchtype"') . '</div>'); $wgOut->addHTML($this->addHeader('', $oldHeader, $newHeader, $multi)); $this->renderHtmlDiff(); } else { if ($wgEnableHtmlDiff) { $wgOut->addHTML('<div class="diff-switchtype">' . $sk->makeKnownLinkObj($this->mTitle, wfMsgHtml('visualcomparison'), 'diff=' . $this->mNewid . '&oldid=' . $this->mOldid . '&htmldiff=1', '', '', 'id="differences-switchtype"') . '</div>'); } $this->showDiff($oldHeader, $newHeader); if (!$diffOnly) { $this->renderNewRevision(); } } } wfProfileOut(__METHOD__); }
/** * Get the RC object belonging to the current revision, if there's one * * @param int $flags (optional) $flags include: * Revision::READ_LATEST : Select the data from the master * * @since 1.22 * @return RecentChange|null */ public function getRecentChange($flags = 0) { $dbr = wfGetDB(DB_SLAVE); list($dbType, ) = DBAccessObjectUtils::getDBOptions($flags); return RecentChange::newFromConds(array('rc_user_text' => $this->getUserText(Revision::RAW), 'rc_timestamp' => $dbr->timestamp($this->getTimestamp()), 'rc_this_oldid' => $this->getId()), __METHOD__, $dbType); }
function showDiffPage($diffOnly = false) { global $wgUser, $wgOut, $wgUseExternalEditor, $wgUseRCPatrol; $fname = 'DifferenceEngine::showDiffPage'; wfProfileIn($fname); # If external diffs are enabled both globally and for the user, # we'll use the application/x-external-editor interface to call # an external diff tool like kompare, kdiff3, etc. if ($wgUseExternalEditor && $wgUser->getOption('externaldiff')) { global $wgInputEncoding, $wgServer, $wgScript, $wgLang; $wgOut->disable(); header("Content-type: application/x-external-editor; charset=" . $wgInputEncoding); $url1 = $this->mTitle->getFullURL("action=raw&oldid=" . $this->mOldid); $url2 = $this->mTitle->getFullURL("action=raw&oldid=" . $this->mNewid); $special = $wgLang->getNsText(NS_SPECIAL); $control = <<<CONTROL [Process] Type=Diff text Engine=MediaWiki Script={$wgServer}{$wgScript} Special namespace={$special} [File] Extension=wiki URL={$url1} [File 2] Extension=wiki URL={$url2} CONTROL; echo $control; return; } $wgOut->setArticleFlag(false); if (!$this->loadRevisionData()) { $t = $this->mTitle->getPrefixedText() . " (Diff: {$this->mOldid}, {$this->mNewid})"; $wgOut->setPagetitle(wfMsg('errorpagetitle')); $wgOut->addWikiMsg('missingarticle', "<nowiki>{$t}</nowiki>"); wfProfileOut($fname); return; } wfRunHooks('DiffViewHeader', array($this, $this->mOldRev, $this->mNewRev)); if ($this->mNewRev->isCurrent()) { $wgOut->setArticleFlag(true); } # mOldid is false if the difference engine is called with a "vague" query for # a diff between a version V and its previous version V' AND the version V # is the first version of that article. In that case, V' does not exist. if ($this->mOldid === false) { $this->showFirstRevision(); $this->renderNewRevision(); // should we respect $diffOnly here or not? wfProfileOut($fname); return; } $wgOut->suppressQuickbar(); $oldTitle = $this->mOldPage->getPrefixedText(); $newTitle = $this->mNewPage->getPrefixedText(); if ($oldTitle == $newTitle) { $wgOut->setPageTitle($newTitle); } else { $wgOut->setPageTitle($oldTitle . ', ' . $newTitle); } $wgOut->setSubtitle(wfMsg('difference')); $wgOut->setRobotpolicy('noindex,nofollow'); if (!($this->mOldPage->userCanRead() && $this->mNewPage->userCanRead())) { $wgOut->loginToUse(); $wgOut->output(); wfProfileOut($fname); exit; } $sk = $wgUser->getSkin(); if ($this->mNewRev->isCurrent() && $wgUser->isAllowed('rollback')) { $rollback = ' ' . $sk->generateRollback($this->mNewRev); } else { $rollback = ''; } // Prepare a change patrol link, if applicable if ($wgUseRCPatrol && $wgUser->isAllowed('patrol')) { // If we've been given an explicit change identifier, use it; saves time if ($this->mRcidMarkPatrolled) { $rcid = $this->mRcidMarkPatrolled; } else { // Look for an unpatrolled change corresponding to this diff $db = wfGetDB(DB_SLAVE); $change = RecentChange::newFromConds(array('rc_user_text' => $this->mNewRev->getRawUserText(), 'rc_timestamp' => $db->timestamp($this->mNewRev->getTimestamp()), 'rc_this_oldid' => $this->mNewid, 'rc_last_oldid' => $this->mOldid, 'rc_patrolled' => 0), __METHOD__); if ($change instanceof RecentChange) { $rcid = $change->mAttribs['rc_id']; } else { // None found $rcid = 0; } } // Build the link if ($rcid) { $patrol = ' [' . $sk->makeKnownLinkObj($this->mTitle, wfMsgHtml('markaspatrolleddiff'), "action=markpatrolled&rcid={$rcid}") . ']'; } else { $patrol = ''; } } else { $patrol = ''; } $prevlink = $sk->makeKnownLinkObj($this->mTitle, wfMsgHtml('previousdiff'), 'diff=prev&oldid=' . $this->mOldid, '', '', 'id="differences-prevlink"'); if ($this->mNewRev->isCurrent()) { $nextlink = ' '; } else { $nextlink = $sk->makeKnownLinkObj($this->mTitle, wfMsgHtml('nextdiff'), 'diff=next&oldid=' . $this->mNewid, '', '', 'id="differences-nextlink"'); } $oldminor = ''; $newminor = ''; if ($this->mOldRev->mMinorEdit == 1) { $oldminor = wfElement('span', array('class' => 'minor'), wfMsg('minoreditletter')) . ' '; } if ($this->mNewRev->mMinorEdit == 1) { $newminor = wfElement('span', array('class' => 'minor'), wfMsg('minoreditletter')) . ' '; } $rdel = ''; $ldel = ''; if ($wgUser->isAllowed('deleterevision')) { $revdel = SpecialPage::getTitleFor('Revisiondelete'); if (!$this->mOldRev->userCan(Revision::DELETED_RESTRICTED)) { // If revision was hidden from sysops $ldel = wfMsgHtml('rev-delundel'); } else { $ldel = $sk->makeKnownLinkObj($revdel, wfMsgHtml('rev-delundel'), 'target=' . urlencode($this->mOldRev->mTitle->getPrefixedDbkey()) . '&oldid=' . urlencode($this->mOldRev->getId())); // Bolden oversighted content if ($this->mOldRev->isDeleted(Revision::DELETED_RESTRICTED)) { $ldel = "<strong>{$ldel}</strong>"; } } $ldel = " <tt>(<small>{$ldel}</small>)</tt> "; // We don't currently handle well changing the top revision's settings if ($this->mNewRev->isCurrent()) { // If revision was hidden from sysops $rdel = wfMsgHtml('rev-delundel'); } else { if (!$this->mNewRev->userCan(Revision::DELETED_RESTRICTED)) { // If revision was hidden from sysops $rdel = wfMsgHtml('rev-delundel'); } else { $rdel = $sk->makeKnownLinkObj($revdel, wfMsgHtml('rev-delundel'), 'target=' . urlencode($this->mNewRev->mTitle->getPrefixedDbkey()) . '&oldid=' . urlencode($this->mNewRev->getId())); // Bolden oversighted content if ($this->mNewRev->isDeleted(Revision::DELETED_RESTRICTED)) { $rdel = "<strong>{$rdel}</strong>"; } } } $rdel = " <tt>(<small>{$rdel}</small>)</tt> "; } $oldHeader = '<div id="mw-diff-otitle1"><strong>' . $this->mOldtitle . '</strong></div>' . '<div id="mw-diff-otitle2">' . $sk->revUserTools($this->mOldRev, true) . "</div>" . '<div id="mw-diff-otitle3">' . $oldminor . $sk->revComment($this->mOldRev, !$diffOnly, true) . $ldel . "</div>" . '<div id="mw-diff-otitle4">' . $prevlink . '</div>'; $newHeader = '<div id="mw-diff-ntitle1"><strong>' . $this->mNewtitle . '</strong></div>' . '<div id="mw-diff-ntitle2">' . $sk->revUserTools($this->mNewRev, true) . " {$rollback}</div>" . '<div id="mw-diff-ntitle3">' . $newminor . $sk->revComment($this->mNewRev, !$diffOnly, true) . $rdel . "</div>" . '<div id="mw-diff-ntitle4">' . $nextlink . $patrol . '</div>'; $this->showDiff($oldHeader, $newHeader); if (!$diffOnly) { $this->renderNewRevision(); } wfProfileOut($fname); }
/** * Get the RC object belonging to the current revision, if there's one * * @since 1.22 * @return RecentChange|null */ public function getRecentChange() { $dbr = wfGetDB(DB_SLAVE); return RecentChange::newFromConds(array('rc_user_text' => $this->getUserText(Revision::RAW), 'rc_timestamp' => $dbr->timestamp($this->getTimestamp()), 'rc_this_oldid' => $this->getId()), __METHOD__); }
/** * Get a link to mark the change as patrolled, or '' if there's either no * revision to patrol or the user is not allowed to to it. * Side effect: When the patrol link is build, this method will call * OutputPage::preventClickjacking() and load mediawiki.page.patrol.ajax. * * @return string */ protected function markPatrolledLink() { global $wgUseRCPatrol, $wgEnableAPI, $wgEnableWriteAPI; $user = $this->getUser(); if ($this->mMarkPatrolledLink === null) { // Prepare a change patrol link, if applicable if ($wgUseRCPatrol && $this->mNewPage->quickUserCan('patrol', $user) && RecentChange::isInRCLifespan($this->mNewRev->getTimestamp(), 21600)) { // Look for an unpatrolled change corresponding to this diff $db = wfGetDB(DB_SLAVE); $change = RecentChange::newFromConds(array('rc_timestamp' => $db->timestamp($this->mNewRev->getTimestamp()), 'rc_this_oldid' => $this->mNewid, 'rc_patrolled' => 0), __METHOD__, array('USE INDEX' => 'rc_timestamp')); if ($change && $change->getPerformer()->getName() !== $user->getName()) { $rcid = $change->getAttribute('rc_id'); } else { // None found or the page has been created by the current user. // If the user could patrol this it already would be patrolled $rcid = 0; } // Build the link if ($rcid) { $this->getOutput()->preventClickjacking(); if ($wgEnableAPI && $wgEnableWriteAPI && $user->isAllowed('writeapi')) { $this->getOutput()->addModules('mediawiki.page.patrol.ajax'); } $token = $user->getEditToken($rcid); $this->mMarkPatrolledLink = ' <span class="patrollink">[' . Linker::linkKnown($this->mNewPage, $this->msg('markaspatrolleddiff')->escaped(), array(), array('action' => 'markpatrolled', 'rcid' => $rcid, 'token' => $token)) . ']</span>'; } else { $this->mMarkPatrolledLink = ''; } } else { $this->mMarkPatrolledLink = ''; } } return $this->mMarkPatrolledLink; }
/** * If patrol is possible, output a patrol UI box. This is called from the * footer section of ordinary page views. If patrol is not possible or not * desired, does nothing. * Side effect: When the patrol link is build, this method will call * OutputPage::preventClickjacking() and load mediawiki.page.patrol.ajax. * * @return bool */ public function showPatrolFooter() { global $wgUseNPPatrol, $wgUseRCPatrol, $wgUseFilePatrol, $wgEnableAPI, $wgEnableWriteAPI; $outputPage = $this->getContext()->getOutput(); $user = $this->getContext()->getUser(); $title = $this->getTitle(); $rc = false; if (!$title->quickUserCan('patrol', $user) || !($wgUseRCPatrol || $wgUseNPPatrol || $wgUseFilePatrol && $title->inNamespace(NS_FILE))) { // Patrolling is disabled or the user isn't allowed to return false; } if ($this->mRevision && !RecentChange::isInRCLifespan($this->mRevision->getTimestamp(), 21600)) { // The current revision is already older than what could be in the RC table // 6h tolerance because the RC might not be cleaned out regularly return false; } // Check for cached results $key = wfMemcKey('unpatrollable-page', $title->getArticleID()); $cache = ObjectCache::getMainWANInstance(); if ($cache->get($key)) { return false; } $dbr = wfGetDB(DB_SLAVE); $oldestRevisionTimestamp = $dbr->selectField('revision', 'MIN( rev_timestamp )', ['rev_page' => $title->getArticleID()], __METHOD__); // New page patrol: Get the timestamp of the oldest revison which // the revision table holds for the given page. Then we look // whether it's within the RC lifespan and if it is, we try // to get the recentchanges row belonging to that entry // (with rc_new = 1). $recentPageCreation = false; if ($oldestRevisionTimestamp && RecentChange::isInRCLifespan($oldestRevisionTimestamp, 21600)) { // 6h tolerance because the RC might not be cleaned out regularly $recentPageCreation = true; $rc = RecentChange::newFromConds(['rc_new' => 1, 'rc_timestamp' => $oldestRevisionTimestamp, 'rc_namespace' => $title->getNamespace(), 'rc_cur_id' => $title->getArticleID()], __METHOD__); if ($rc) { // Use generic patrol message for new pages $markPatrolledMsg = wfMessage('markaspatrolledtext'); } } // File patrol: Get the timestamp of the latest upload for this page, // check whether it is within the RC lifespan and if it is, we try // to get the recentchanges row belonging to that entry // (with rc_type = RC_LOG, rc_log_type = upload). $recentFileUpload = false; if ((!$rc || $rc->getAttribute('rc_patrolled')) && $wgUseFilePatrol && $title->getNamespace() === NS_FILE) { // Retrieve timestamp of most recent upload $newestUploadTimestamp = $dbr->selectField('image', 'MAX( img_timestamp )', ['img_name' => $title->getDBkey()], __METHOD__); if ($newestUploadTimestamp && RecentChange::isInRCLifespan($newestUploadTimestamp, 21600)) { // 6h tolerance because the RC might not be cleaned out regularly $recentFileUpload = true; $rc = RecentChange::newFromConds(['rc_type' => RC_LOG, 'rc_log_type' => 'upload', 'rc_timestamp' => $newestUploadTimestamp, 'rc_namespace' => NS_FILE, 'rc_cur_id' => $title->getArticleID()], __METHOD__, ['USE INDEX' => 'rc_timestamp']); if ($rc) { // Use patrol message specific to files $markPatrolledMsg = wfMessage('markaspatrolledtext-file'); } } } if (!$recentPageCreation && !$recentFileUpload) { // Page creation and latest upload (for files) is too old to be in RC // We definitely can't patrol so cache the information // When a new file version is uploaded, the cache is cleared $cache->set($key, '1'); return false; } if (!$rc) { // Don't cache: This can be hit if the page gets accessed very fast after // its creation / latest upload or in case we have high slave lag. In case // the revision is too old, we will already return above. return false; } if ($rc->getAttribute('rc_patrolled')) { // Patrolled RC entry around // Cache the information we gathered above in case we can't patrol // Don't cache in case we can patrol as this could change $cache->set($key, '1'); return false; } if ($rc->getPerformer()->equals($user)) { // Don't show a patrol link for own creations/uploads. If the user could // patrol them, they already would be patrolled return false; } $rcid = $rc->getAttribute('rc_id'); $token = $user->getEditToken($rcid); $outputPage->preventClickjacking(); if ($wgEnableAPI && $wgEnableWriteAPI && $user->isAllowed('writeapi')) { $outputPage->addModules('mediawiki.page.patrol.ajax'); } $link = Linker::linkKnown($title, $markPatrolledMsg->escaped(), [], ['action' => 'markpatrolled', 'rcid' => $rcid, 'token' => $token]); $outputPage->addHTML("<div class='patrollink' data-mw='interface'>" . wfMessage('markaspatrolledlink')->rawParams($link)->escaped() . '</div>'); return true; }
/** * Returns an array of meta data needed to build a "mark as patrolled" link and * adds the mediawiki.page.patrol.ajax to the output. * * @return array|false An array of meta data for a patrol link (rcid & token) * or false if no link is needed */ protected function getMarkPatrolledLinkInfo() { global $wgUseRCPatrol, $wgEnableAPI, $wgEnableWriteAPI; $user = $this->getUser(); // Prepare a change patrol link, if applicable if ($wgUseRCPatrol && $this->mNewPage->quickUserCan('patrol', $user) && RecentChange::isInRCLifespan($this->mNewRev->getTimestamp(), 21600)) { // Look for an unpatrolled change corresponding to this diff $db = wfGetDB(DB_REPLICA); $change = RecentChange::newFromConds(['rc_timestamp' => $db->timestamp($this->mNewRev->getTimestamp()), 'rc_this_oldid' => $this->mNewid, 'rc_patrolled' => 0], __METHOD__); if ($change && !$change->getPerformer()->equals($user)) { $rcid = $change->getAttribute('rc_id'); } else { // None found or the page has been created by the current user. // If the user could patrol this it already would be patrolled $rcid = 0; } // Allow extensions to possibly change the rcid here // For example the rcid might be set to zero due to the user // being the same as the performer of the change but an extension // might still want to show it under certain conditions Hooks::run('DifferenceEngineMarkPatrolledRCID', [&$rcid, $this, $change, $user]); // Build the link if ($rcid) { $this->getOutput()->preventClickjacking(); if ($wgEnableAPI && $wgEnableWriteAPI && $user->isAllowed('writeapi')) { $this->getOutput()->addModules('mediawiki.page.patrol.ajax'); } $token = $user->getEditToken($rcid); return ['rcid' => $rcid, 'token' => $token]; } } // No mark as patrolled link applicable return false; }
public function markPatrolledLink() { global $wgUseRCPatrol, $wgEnableAPI, $wgEnableWriteAPI; $user = $this->getUser(); if ($this->mMarkPatrolledLink === null) { // Prepare a change patrol link, if applicable if ($wgUseRCPatrol && $this->mNewPage->quickUserCan('patrol', $user) && RecentChange::isInRCLifespan($this->mNewRev->getTimestamp(), 21600)) { // Look for an unpatrolled change corresponding to this diff $db = wfGetDB(DB_SLAVE); $change = RecentChange::newFromConds(array('rc_timestamp' => $db->timestamp($this->mNewRev->getTimestamp()), 'rc_this_oldid' => $this->mNewid, 'rc_patrolled' => 0), __METHOD__, array('USE INDEX' => 'rc_timestamp')); if ($change && $change->getPerformer()->getName() !== $user->getName()) { $rcid = $change->getAttribute('rc_id'); } else { // None found or the page has been created by the current user. // If the user could patrol this it already would be patrolled $rcid = 0; } // WIKIHOW - we might want to change the rcid here // for example the rcid might be set to zero due to the user being the same // as the performer of the change but on wikihow we still want to show it // under certain conditions wfRunHooks('DifferenceEngineMarkPatrolledRCID', array(&$rcid, $this, $change, $user)); // Build the link if ($rcid) { $this->getOutput()->preventClickjacking(); if ($wgEnableAPI && $wgEnableWriteAPI && $user->isAllowed('writeapi')) { $this->getOutput()->addModules('mediawiki.page.patrol.ajax'); } $token = $user->getEditToken($rcid); $this->mMarkPatrolledLink = ' <span class="patrollink">[' . Linker::linkKnown($this->mNewPage, $this->msg('markaspatrolleddiff')->escaped(), array(), array('action' => 'markpatrolled', 'rcid' => $rcid, 'token' => $token)) . ']</span>'; // WIKIHOW - added this hook to change the markpatrolled link wfRunHooks('DifferenceEngineMarkPatrolledLink', array($this, &$this->mMarkPatrolledLink, $rcid, $token)); } else { $this->mMarkPatrolledLink = ''; } } else { $this->mMarkPatrolledLink = ''; } } return $this->mMarkPatrolledLink; }
/** * @param int $revId * * @return RecentChange|null */ private function getCategorizeRecentChangeForRevId($revId) { return RecentChange::newFromConds(['rc_type' => RC_CATEGORIZE, 'rc_this_oldid' => $revId], __METHOD__); }