diff options
Diffstat (limited to 'includes/actions')
-rw-r--r-- | includes/actions/Action.php | 10 | ||||
-rw-r--r-- | includes/actions/DeleteAction.php | 2 | ||||
-rw-r--r-- | includes/actions/EditAction.php | 2 | ||||
-rw-r--r-- | includes/actions/HistoryAction.php | 33 | ||||
-rw-r--r-- | includes/actions/InfoAction.php | 95 | ||||
-rw-r--r-- | includes/actions/RawAction.php | 52 | ||||
-rw-r--r-- | includes/actions/RevertAction.php | 2 | ||||
-rw-r--r-- | includes/actions/RollbackAction.php | 3 | ||||
-rw-r--r-- | includes/actions/UnprotectAction.php | 1 | ||||
-rw-r--r-- | includes/actions/WatchAction.php | 2 |
10 files changed, 146 insertions, 56 deletions
diff --git a/includes/actions/Action.php b/includes/actions/Action.php index bb6a4d5d..43f03c3a 100644 --- a/includes/actions/Action.php +++ b/includes/actions/Action.php @@ -407,4 +407,14 @@ abstract class Action { * @throws ErrorPageError */ abstract public function show(); + + /** + * Call wfTransactionalTimeLimit() if this request was POSTed + * @since 1.26 + */ + protected function useTransactionalTimeLimit() { + if ( $this->getRequest()->wasPosted() ) { + wfTransactionalTimeLimit(); + } + } } diff --git a/includes/actions/DeleteAction.php b/includes/actions/DeleteAction.php index be21a6f1..841a94df 100644 --- a/includes/actions/DeleteAction.php +++ b/includes/actions/DeleteAction.php @@ -41,6 +41,8 @@ class DeleteAction extends FormlessAction { } public function show() { + $this->useTransactionalTimeLimit(); + $out = $this->getOutput(); if ( $this->getContext()->getConfig()->get( 'UseMediaWikiUIEverywhere' ) ) { $out->addModuleStyles( array( diff --git a/includes/actions/EditAction.php b/includes/actions/EditAction.php index 6c8440ac..eb53f19a 100644 --- a/includes/actions/EditAction.php +++ b/includes/actions/EditAction.php @@ -41,6 +41,8 @@ class EditAction extends FormlessAction { } public function show() { + $this->useTransactionalTimeLimit(); + if ( $this->getContext()->getConfig()->get( 'UseMediaWikiUIEverywhere' ) ) { $out = $this->getOutput(); $out->addModuleStyles( array( diff --git a/includes/actions/HistoryAction.php b/includes/actions/HistoryAction.php index dcd77415..a81adf99 100644 --- a/includes/actions/HistoryAction.php +++ b/includes/actions/HistoryAction.php @@ -368,6 +368,9 @@ class HistoryPager extends ReverseChronologicalPager { */ protected $parentLens; + /** @var bool Whether to show the tag editing UI */ + protected $showTagEditUI; + /** * @param HistoryAction $historyPage * @param string $year @@ -381,6 +384,7 @@ class HistoryPager extends ReverseChronologicalPager { $this->tagFilter = $tagFilter; $this->getDateCond( $year, $month ); $this->conds = $conds; + $this->showTagEditUI = ChangeTags::showTagEditingUI( $this->getUser() ); } // For hook compatibility... @@ -432,8 +436,13 @@ class HistoryPager extends ReverseChronologicalPager { $latest = ( $this->counter == 1 && $this->mIsFirst ); $firstInList = $this->counter == 1; $this->counter++; - $s = $this->historyLine( $this->lastRow, $row, - $this->getTitle()->getNotificationTimestamp( $this->getUser() ), $latest, $firstInList ); + + $notifTimestamp = $this->getConfig()->get( 'ShowUpdatedMarker' ) + ? $this->getTitle()->getNotificationTimestamp( $this->getUser() ) + : false; + + $s = $this->historyLine( + $this->lastRow, $row, $notifTimestamp, $latest, $firstInList ); } else { $s = ''; } @@ -443,6 +452,10 @@ class HistoryPager extends ReverseChronologicalPager { } function doBatchLookups() { + if ( !Hooks::run( 'PageHistoryPager::doBatchLookups', array( $this, $this->mResult ) ) ) { + return; + } + # Do a link batch query $this->mResult->seek( 0 ); $batch = new LinkBatch(); @@ -495,7 +508,7 @@ class HistoryPager extends ReverseChronologicalPager { if ( $user->isAllowed( 'deleterevision' ) ) { $actionButtons .= $this->getRevisionButton( 'revisiondelete', 'showhideselectedversions' ); } - if ( ChangeTags::showTagEditingUI( $user ) ) { + if ( $this->showTagEditUI ) { $actionButtons .= $this->getRevisionButton( 'editchangetags', 'history-edit-tags' ); } if ( $actionButtons ) { @@ -542,8 +555,13 @@ class HistoryPager extends ReverseChronologicalPager { $next = $this->mPastTheEndRow; } $this->counter++; - $s = $this->historyLine( $this->lastRow, $next, - $this->getTitle()->getNotificationTimestamp( $this->getUser() ), $latest, $firstInList ); + + $notifTimestamp = $this->getConfig()->get( 'ShowUpdatedMarker' ) + ? $this->getTitle()->getNotificationTimestamp( $this->getUser() ) + : false; + + $s = $this->historyLine( + $this->lastRow, $next, $notifTimestamp, $latest, $firstInList ); } else { $s = ''; } @@ -617,14 +635,13 @@ class HistoryPager extends ReverseChronologicalPager { $del = ''; $user = $this->getUser(); $canRevDelete = $user->isAllowed( 'deleterevision' ); - $showTagEditUI = ChangeTags::showTagEditingUI( $user ); // Show checkboxes for each revision, to allow for revision deletion and // change tags - if ( $canRevDelete || $showTagEditUI ) { + if ( $canRevDelete || $this->showTagEditUI ) { $this->preventClickjacking(); // If revision was hidden from sysops and we don't need the checkbox // for anything else, disable it - if ( !$showTagEditUI && !$rev->userCan( Revision::DELETED_RESTRICTED, $user ) ) { + if ( !$this->showTagEditUI && !$rev->userCan( Revision::DELETED_RESTRICTED, $user ) ) { $del = Xml::check( 'deleterevisions', false, array( 'disabled' => 'disabled' ) ); // Otherwise, enable the checkbox... } else { diff --git a/includes/actions/InfoAction.php b/includes/actions/InfoAction.php index b5a73910..f3670a86 100644 --- a/includes/actions/InfoAction.php +++ b/includes/actions/InfoAction.php @@ -62,14 +62,18 @@ class InfoAction extends FormlessAction { * * @since 1.22 * @param Title $title Title to clear cache for + * @param int|null $revid Revision id to clear */ - public static function invalidateCache( Title $title ) { - global $wgMemc; + public static function invalidateCache( Title $title, $revid = null ) { + $cache = ObjectCache::getMainWANInstance(); - $revision = Revision::newFromTitle( $title, 0, Revision::READ_LATEST ); - if ( $revision !== null ) { - $key = wfMemcKey( 'infoaction', sha1( $title->getPrefixedText() ), $revision->getId() ); - $wgMemc->delete( $key ); + if ( !$revid ) { + $revision = Revision::newFromTitle( $title, 0, Revision::READ_LATEST ); + $revid = $revision ? $revision->getId() : null; + } + if ( $revid !== null ) { + $key = wfMemcKey( 'infoaction', sha1( $title->getPrefixedText() ), $revid ); + $cache->delete( $key ); } } @@ -193,7 +197,7 @@ class InfoAction extends FormlessAction { * @return array */ protected function pageInfo() { - global $wgContLang, $wgMemc; + global $wgContLang; $user = $this->getUser(); $lang = $this->getLanguage(); @@ -201,16 +205,17 @@ class InfoAction extends FormlessAction { $id = $title->getArticleID(); $config = $this->context->getConfig(); + $cache = ObjectCache::getMainWANInstance(); $memcKey = wfMemcKey( 'infoaction', sha1( $title->getPrefixedText() ), $this->page->getLatest() ); - $pageCounts = $wgMemc->get( $memcKey ); + $pageCounts = $cache->get( $memcKey ); $version = isset( $pageCounts['cacheversion'] ) ? $pageCounts['cacheversion'] : false; if ( $pageCounts === false || $version !== self::CACHE_VERSION ) { // Get page information that would be too "expensive" to retrieve by normal means $pageCounts = $this->pageCounts( $title ); $pageCounts['cacheversion'] = self::CACHE_VERSION; - $wgMemc->set( $memcKey, $pageCounts ); + $cache->set( $memcKey, $pageCounts ); } // Get page properties @@ -233,7 +238,7 @@ class InfoAction extends FormlessAction { // Display title $displayTitle = $title->getPrefixedText(); - if ( !empty( $pageProperties['displaytitle'] ) ) { + if ( isset( $pageProperties['displaytitle'] ) ) { $displayTitle = $pageProperties['displaytitle']; } @@ -258,7 +263,7 @@ class InfoAction extends FormlessAction { // Default sort key $sortKey = $title->getCategorySortkey(); - if ( !empty( $pageProperties['defaultsort'] ) ) { + if ( isset( $pageProperties['defaultsort'] ) ) { $sortKey = $pageProperties['defaultsort']; } @@ -324,8 +329,27 @@ class InfoAction extends FormlessAction { ) { // Number of page watchers $pageInfo['header-basic'][] = array( - $this->msg( 'pageinfo-watchers' ), $lang->formatNum( $pageCounts['watchers'] ) + $this->msg( 'pageinfo-watchers' ), + $lang->formatNum( $pageCounts['watchers'] ) ); + if ( + $config->get( 'ShowUpdatedMarker' ) && + isset( $pageCounts['visitingWatchers'] ) + ) { + $minToDisclose = $config->get( 'UnwatchedPageSecret' ); + if ( $pageCounts['visitingWatchers'] > $minToDisclose || + $user->isAllowed( 'unwatchedpages' ) ) { + $pageInfo['header-basic'][] = array( + $this->msg( 'pageinfo-visiting-watchers' ), + $lang->formatNum( $pageCounts['visitingWatchers'] ) + ); + } else { + $pageInfo['header-basic'][] = array( + $this->msg( 'pageinfo-visiting-watchers' ), + $this->msg( 'pageinfo-few-visiting-watchers' ) + ); + } + } } elseif ( $unwatchedPageThreshold !== false ) { $pageInfo['header-basic'][] = array( $this->msg( 'pageinfo-watchers' ), @@ -373,18 +397,30 @@ class InfoAction extends FormlessAction { if ( $title->inNamespace( NS_CATEGORY ) ) { $category = Category::newFromTitle( $title ); + + // $allCount is the total number of cat members, + // not the count of how many members are normal pages. + $allCount = (int)$category->getPageCount(); + $subcatCount = (int)$category->getSubcatCount(); + $fileCount = (int)$category->getFileCount(); + $pagesCount = $allCount - $subcatCount - $fileCount; + $pageInfo['category-info'] = array( array( + $this->msg( 'pageinfo-category-total' ), + $lang->formatNum( $allCount ) + ), + array( $this->msg( 'pageinfo-category-pages' ), - $lang->formatNum( $category->getPageCount() ) + $lang->formatNum( $pagesCount ) ), array( $this->msg( 'pageinfo-category-subcats' ), - $lang->formatNum( $category->getSubcatCount() ) + $lang->formatNum( $subcatCount ) ), array( $this->msg( 'pageinfo-category-files' ), - $lang->formatNum( $category->getFileCount() ) + $lang->formatNum( $fileCount ) ) ); } @@ -434,6 +470,10 @@ class InfoAction extends FormlessAction { $message = $message->escaped(); } } + $expiry = $title->getRestrictionExpiry( $restrictionType ); + $formattedexpiry = $this->msg( 'parentheses', + $this->getLanguage()->formatExpiry( $expiry ) )->escaped(); + $message .= $this->msg( 'word-separator' )->escaped() . $formattedexpiry; // Messages: restriction-edit, restriction-move, restriction-create, // restriction-upload @@ -639,11 +679,11 @@ class InfoAction extends FormlessAction { $id = $title->getArticleID(); $config = $this->context->getConfig(); - $dbr = wfGetDB( DB_SLAVE ); + $dbrWatchlist = wfGetDB( DB_SLAVE, 'watchlist' ); $result = array(); // Number of page watchers - $watchers = (int)$dbr->selectField( + $watchers = (int)$dbrWatchlist->selectField( 'watchlist', 'COUNT(*)', array( @@ -654,6 +694,27 @@ class InfoAction extends FormlessAction { ); $result['watchers'] = $watchers; + if ( $config->get( 'ShowUpdatedMarker' ) ) { + // Threshold: last visited about 26 weeks before latest edit + $updated = wfTimestamp( TS_UNIX, $this->page->getTimestamp() ); + $age = $config->get( 'WatchersMaxAge' ); + $threshold = $dbrWatchlist->timestamp( $updated - $age ); + // Number of page watchers who also visited a "recent" edit + $visitingWatchers = (int)$dbrWatchlist->selectField( + 'watchlist', + 'COUNT(*)', + array( + 'wl_namespace' => $title->getNamespace(), + 'wl_title' => $title->getDBkey(), + 'wl_notificationtimestamp >= ' . $dbrWatchlist->addQuotes( $threshold ) . + ' OR wl_notificationtimestamp IS NULL' + ), + __METHOD__ + ); + $result['visitingWatchers'] = $visitingWatchers; + } + + $dbr = wfGetDB( DB_SLAVE ); // Total number of edits $edits = (int)$dbr->selectField( 'revision', diff --git a/includes/actions/RawAction.php b/includes/actions/RawAction.php index 727bed20..b71b0e9e 100644 --- a/includes/actions/RawAction.php +++ b/includes/actions/RawAction.php @@ -34,10 +34,10 @@ */ class RawAction extends FormlessAction { /** - * @var bool Does the request include a gen=css|javascript parameter - * @deprecated This used to be a string for "css" or "javascript" but - * it is no longer used. Setting this parameter results in empty content - * being served + * Whether the request includes a 'gen' parameter + * @var bool + * @deprecated since 1.17 This used to be a string for "css" or "javascript" but + * it is no longer used. Setting this parameter results in an empty response. */ private $gen = false; @@ -56,6 +56,7 @@ class RawAction extends FormlessAction { function onView() { $this->getOutput()->disable(); $request = $this->getRequest(); + $response = $request->response(); $config = $this->context->getConfig(); if ( !$request->checkUrlExtension() ) { @@ -66,42 +67,35 @@ class RawAction extends FormlessAction { return; // Client cache fresh and headers sent, nothing more to do. } - # special case for 'generated' raw things: user css/js - # This is deprecated and will only return empty content $gen = $request->getVal( 'gen' ); - $smaxage = $request->getIntOrNull( 'smaxage' ); - if ( $gen == 'css' || $gen == 'js' ) { $this->gen = true; - if ( $smaxage === null ) { - $smaxage = $config->get( 'SquidMaxage' ); - } } $contentType = $this->getContentType(); - # Force caching for CSS and JS raw content, default: 5 minutes. - # Note: If using a canonical url for userpage css/js, we send an HTCP purge. + $maxage = $request->getInt( 'maxage', $config->get( 'SquidMaxage' ) ); + $smaxage = $request->getIntOrNull( 'smaxage' ); if ( $smaxage === null ) { - if ( $contentType == 'text/css' || $contentType == 'text/javascript' ) { + if ( $this->gen ) { + $smaxage = $config->get( 'SquidMaxage' ); + } elseif ( $contentType == 'text/css' || $contentType == 'text/javascript' ) { + // CSS/JS raw content has its own squid max age configuration. + // Note: Title::getSquidURLs() includes action=raw for css/js pages, + // so if using the canonical url, this will get HTCP purges. $smaxage = intval( $config->get( 'ForcedRawSMaxage' ) ); } else { + // No squid cache for anything else $smaxage = 0; } } - $maxage = $request->getInt( 'maxage', $config->get( 'SquidMaxage' ) ); - - $response = $request->response(); - $response->header( 'Content-type: ' . $contentType . '; charset=UTF-8' ); - # Output may contain user-specific data; - # vary generated content for open sessions on private wikis + // Output may contain user-specific data; + // vary generated content for open sessions on private wikis $privateCache = !User::isEveryoneAllowed( 'read' ) && ( $smaxage == 0 || session_id() != '' ); - // Bug 53032 - make this private if user is logged in, - // so we don't accidentally cache cookies - $privateCache = $privateCache ?: $this->getUser()->isLoggedIn(); - # allow the client to cache this for 24 hours + // Don't accidentally cache cookies if user is logged in (T55032) + $privateCache = $privateCache || $this->getUser()->isLoggedIn(); $mode = $privateCache ? 'private' : 'public'; $response->header( 'Cache-Control: ' . $mode . ', s-maxage=' . $smaxage . ', max-age=' . $maxage @@ -109,12 +103,12 @@ class RawAction extends FormlessAction { $text = $this->getRawText(); + // Don't return a 404 response for CSS or JavaScript; + // 404s aren't generally cached and it would create + // extra hits when user CSS/JS are on and the user doesn't + // have the pages. if ( $text === false && $contentType == 'text/x-wiki' ) { - # Don't return a 404 response for CSS or JavaScript; - # 404s aren't generally cached and it would create - # extra hits when user CSS/JS are on and the user doesn't - # have the pages. - $response->header( 'HTTP/1.x 404 Not Found' ); + $response->statusHeader( 404 ); } if ( !Hooks::run( 'RawPageViewBeforeOutput', array( &$this, &$text ) ) ) { diff --git a/includes/actions/RevertAction.php b/includes/actions/RevertAction.php index d0258784..c7f33463 100644 --- a/includes/actions/RevertAction.php +++ b/includes/actions/RevertAction.php @@ -107,6 +107,8 @@ class RevertAction extends FormAction { } public function onSubmit( $data ) { + $this->useTransactionalTimeLimit(); + $source = $this->page->getFile()->getArchiveVirtualUrl( $this->getRequest()->getText( 'oldimage' ) ); diff --git a/includes/actions/RollbackAction.php b/includes/actions/RollbackAction.php index 76d70d70..93669cf4 100644 --- a/includes/actions/RollbackAction.php +++ b/includes/actions/RollbackAction.php @@ -36,6 +36,9 @@ class RollbackAction extends FormlessAction { } public function onView() { + // TODO: use $this->useTransactionalTimeLimit(); when POST only + wfTransactionalTimeLimit(); + $details = null; $request = $this->getRequest(); diff --git a/includes/actions/UnprotectAction.php b/includes/actions/UnprotectAction.php index bc28c8ed..559cfaf7 100644 --- a/includes/actions/UnprotectAction.php +++ b/includes/actions/UnprotectAction.php @@ -37,7 +37,6 @@ class UnprotectAction extends ProtectAction { } public function show() { - $this->page->unprotect(); } } diff --git a/includes/actions/WatchAction.php b/includes/actions/WatchAction.php index 96473409..8b6e329d 100644 --- a/includes/actions/WatchAction.php +++ b/includes/actions/WatchAction.php @@ -64,7 +64,7 @@ class WatchAction extends FormAction { $this->checkCanExecute( $user ); // Must have valid token for this action/title - $salt = array( $this->getName(), $this->getTitle()->getDBkey() ); + $salt = array( $this->getName(), $this->getTitle()->getPrefixedDBkey() ); if ( $user->matchEditToken( $this->getRequest()->getVal( 'token' ), $salt ) ) { $this->onSubmit( array() ); |