summaryrefslogtreecommitdiff
path: root/includes/actions
diff options
context:
space:
mode:
Diffstat (limited to 'includes/actions')
-rw-r--r--includes/actions/CachedAction.php36
-rw-r--r--includes/actions/CreditsAction.php13
-rw-r--r--includes/actions/DeleteAction.php11
-rw-r--r--includes/actions/EditAction.php21
-rw-r--r--includes/actions/HistoryAction.php77
-rw-r--r--includes/actions/InfoAction.php320
-rw-r--r--includes/actions/MarkpatrolledAction.php5
-rw-r--r--includes/actions/ProtectAction.php20
-rw-r--r--includes/actions/PurgeAction.php15
-rw-r--r--includes/actions/RawAction.php35
-rw-r--r--includes/actions/RenderAction.php11
-rw-r--r--includes/actions/RevertAction.php6
-rw-r--r--includes/actions/RevisiondeleteAction.php5
-rw-r--r--includes/actions/RollbackAction.php35
-rw-r--r--includes/actions/ViewAction.php11
-rw-r--r--includes/actions/WatchAction.php10
16 files changed, 454 insertions, 177 deletions
diff --git a/includes/actions/CachedAction.php b/includes/actions/CachedAction.php
index d21f9aeb..bfdda7b9 100644
--- a/includes/actions/CachedAction.php
+++ b/includes/actions/CachedAction.php
@@ -1,22 +1,8 @@
<?php
-
/**
* Abstract action class with scaffolding for caching HTML and other values
* in a single blob.
*
- * Before using any of the caching functionality, call startCache.
- * After the last call to either getCachedValue or addCachedHTML, call saveCache.
- *
- * To get a cached value or compute it, use getCachedValue like this:
- * $this->getCachedValue( $callback );
- *
- * To add HTML that should be cached, use addCachedHTML like this:
- * $this->addCachedHTML( $callback );
- *
- * The callback function is only called when needed, so do all your expensive
- * computations here. This function should returns the HTML to be cached.
- * It should not add anything to the PageOutput object!
- *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -33,10 +19,30 @@
* http://www.gnu.org/copyleft/gpl.html
*
* @file
- * @ingroup Action
+ * @ingroup Actions
* @author Jeroen De Dauw < jeroendedauw@gmail.com >
* @since 1.20
*/
+
+/**
+ * Abstract action class with scaffolding for caching HTML and other values
+ * in a single blob.
+ *
+ * Before using any of the caching functionality, call startCache.
+ * After the last call to either getCachedValue or addCachedHTML, call saveCache.
+ *
+ * To get a cached value or compute it, use getCachedValue like this:
+ * $this->getCachedValue( $callback );
+ *
+ * To add HTML that should be cached, use addCachedHTML like this:
+ * $this->addCachedHTML( $callback );
+ *
+ * The callback function is only called when needed, so do all your expensive
+ * computations here. This function should returns the HTML to be cached.
+ * It should not add anything to the PageOutput object!
+ *
+ * @ingroup Actions
+ */
abstract class CachedAction extends FormlessAction implements ICacheHelper {
/**
diff --git a/includes/actions/CreditsAction.php b/includes/actions/CreditsAction.php
index f7152297..4d3c41be 100644
--- a/includes/actions/CreditsAction.php
+++ b/includes/actions/CreditsAction.php
@@ -23,6 +23,9 @@
* @author <evan@wikitravel.org>
*/
+/**
+ * @ingroup Actions
+ */
class CreditsAction extends FormlessAction {
public function getName() {
@@ -55,8 +58,8 @@ class CreditsAction extends FormlessAction {
/**
* Get a list of contributors
*
- * @param $cnt Int: maximum list of contributors to show
- * @param $showIfMax Bool: whether to contributors if there more than $cnt
+ * @param int $cnt maximum list of contributors to show
+ * @param bool $showIfMax whether to contributors if there more than $cnt
* @return String: html
*/
public function getCredits( $cnt, $showIfMax = true ) {
@@ -97,8 +100,8 @@ class CreditsAction extends FormlessAction {
/**
* Get a list of contributors of $article
- * @param $cnt Int: maximum list of contributors to show
- * @param $showIfMax Bool: whether to contributors if there more than $cnt
+ * @param int $cnt maximum list of contributors to show
+ * @param bool $showIfMax whether to contributors if there more than $cnt
* @return String: html
*/
protected function getContributors( $cnt, $showIfMax ) {
@@ -122,7 +125,7 @@ class CreditsAction extends FormlessAction {
# Sift for real versus user names
foreach ( $contributors as $user ) {
- $cnt--;
+ $cnt--;
if ( $user->isLoggedIn() ) {
$link = $this->link( $user );
if ( !in_array( 'realname', $wgHiddenPrefs ) && $user->getRealName() ) {
diff --git a/includes/actions/DeleteAction.php b/includes/actions/DeleteAction.php
index 5a5a382b..db7123db 100644
--- a/includes/actions/DeleteAction.php
+++ b/includes/actions/DeleteAction.php
@@ -23,17 +23,24 @@
* @author Timo Tijhof
*/
+/**
+ * Handle page deletion
+ *
+ * This is a wrapper that will call Article::delete().
+ *
+ * @ingroup Actions
+ */
class DeleteAction extends FormlessAction {
public function getName() {
return 'delete';
}
- public function onView(){
+ public function onView() {
return null;
}
- public function show(){
+ public function show() {
$this->page->delete();
diff --git a/includes/actions/EditAction.php b/includes/actions/EditAction.php
index 08a33f4c..dec3d841 100644
--- a/includes/actions/EditAction.php
+++ b/includes/actions/EditAction.php
@@ -23,17 +23,25 @@
* @author Timo Tijhof
*/
+/**
+ * Page edition handler
+ *
+ * This is a wrapper that will call the EditPage class, or ExternalEdit
+ * if $wgUseExternalEditor is set to true and requested by the user.
+ *
+ * @ingroup Actions
+ */
class EditAction extends FormlessAction {
public function getName() {
return 'edit';
}
- public function onView(){
+ public function onView() {
return null;
}
- public function show(){
+ public function show() {
$page = $this->page;
$request = $this->getRequest();
$user = $this->getUser();
@@ -56,13 +64,20 @@ class EditAction extends FormlessAction {
}
+/**
+ * Edit submission handler
+ *
+ * This is the same as EditAction; except that it sets the session cookie.
+ *
+ * @ingroup Actions
+ */
class SubmitAction extends EditAction {
public function getName() {
return 'submit';
}
- public function show(){
+ public function show() {
if ( session_id() == '' ) {
// Send a cookie so anons get talk message notifications
wfSetupSession();
diff --git a/includes/actions/HistoryAction.php b/includes/actions/HistoryAction.php
index dcd6fe55..245a5bdc 100644
--- a/includes/actions/HistoryAction.php
+++ b/includes/actions/HistoryAction.php
@@ -20,16 +20,18 @@
* http://www.gnu.org/copyleft/gpl.html
*
* @file
+ * @ingroup Actions
*/
/**
- * This class handles printing the history page for an article. In order to
+ * This class handles printing the history page for an article. In order to
* be efficient, it uses timestamps rather than offsets for paging, to avoid
* costly LIMIT,offset queries.
*
* Construct it by passing in an Article, and call $h->history() to print the
* history.
*
+ * @ingroup Actions
*/
class HistoryAction extends FormlessAction {
const DIR_PREV = 0;
@@ -132,7 +134,7 @@ class HistoryAction extends FormlessAction {
array( 'delete', 'move' ),
$this->getTitle(),
'',
- array( 'lim' => 10,
+ array( 'lim' => 10,
'conds' => array( "log_action != 'revision'" ),
'showIfEmpty' => false,
'msgKey' => array( 'moveddeleted-notice' )
@@ -145,21 +147,25 @@ class HistoryAction extends FormlessAction {
/**
* Add date selector to quickly get to a certain time
*/
- $year = $request->getInt( 'year' );
- $month = $request->getInt( 'month' );
- $tagFilter = $request->getVal( 'tagfilter' );
+ $year = $request->getInt( 'year' );
+ $month = $request->getInt( 'month' );
+ $tagFilter = $request->getVal( 'tagfilter' );
$tagSelector = ChangeTags::buildTagFilterSelector( $tagFilter );
/**
* Option to show only revisions that have been (partially) hidden via RevisionDelete
*/
if ( $request->getBool( 'deleted' ) ) {
- $conds = array( "rev_deleted != '0'" );
+ $conds = array( 'rev_deleted != 0' );
} else {
$conds = array();
}
- $checkDeleted = Xml::checkLabel( $this->msg( 'history-show-deleted' )->text(),
+ if ( $this->getUser()->isAllowed( 'deletedhistory' ) ) {
+ $checkDeleted = Xml::checkLabel( $this->msg( 'history-show-deleted' )->text(),
'deleted', 'mw-show-deleted-only', $request->getBool( 'deleted' ) ) . "\n";
+ } else {
+ $checkDeleted = '';
+ }
// Add the general form
$action = htmlspecialchars( $wgScript );
@@ -170,16 +176,16 @@ class HistoryAction extends FormlessAction {
false,
array( 'id' => 'mw-history-search' )
) .
- Html::hidden( 'title', $this->getTitle()->getPrefixedDBKey() ) . "\n" .
+ Html::hidden( 'title', $this->getTitle()->getPrefixedDBkey() ) . "\n" .
Html::hidden( 'action', 'history' ) . "\n" .
- Xml::dateMenu( $year, $month ) . '&#160;' .
+ Xml::dateMenu( ( $year == null ? date( "Y" ) : $year ), $month ) . '&#160;' .
( $tagSelector ? ( implode( '&#160;', $tagSelector ) . '&#160;' ) : '' ) .
$checkDeleted .
Xml::submitButton( $this->msg( 'allpagessubmit' )->text() ) . "\n" .
'</fieldset></form>'
);
- wfRunHooks( 'PageHistoryBeforeList', array( &$this->page ) );
+ wfRunHooks( 'PageHistoryBeforeList', array( &$this->page, $this->getContext() ) );
// Create and output the list.
$pager = new HistoryPager( $this, $year, $month, $tagFilter, $conds );
@@ -218,7 +224,7 @@ class HistoryAction extends FormlessAction {
}
if ( $offset ) {
- $offsets = array( "rev_timestamp $oper '$offset'" );
+ $offsets = array( "rev_timestamp $oper " . $dbr->addQuotes( $dbr->timestamp( $offset ) ) );
} else {
$offsets = array();
}
@@ -227,7 +233,7 @@ class HistoryAction extends FormlessAction {
return $dbr->select( 'revision',
Revision::selectFields(),
- array_merge( array( "rev_page=$page_id" ), $offsets ),
+ array_merge( array( 'rev_page' => $page_id ), $offsets ),
__METHOD__,
array( 'ORDER BY' => "rev_timestamp $dirs",
'USE INDEX' => 'page_timestamp', 'LIMIT' => $limit )
@@ -237,7 +243,7 @@ class HistoryAction extends FormlessAction {
/**
* Output a subscription feed listing recent edits to this page.
*
- * @param $type String: feed type
+ * @param string $type feed type
*/
function feed( $type ) {
global $wgFeedClasses, $wgFeedLimit;
@@ -327,6 +333,7 @@ class HistoryAction extends FormlessAction {
/**
* @ingroup Pager
+ * @ingroup Actions
*/
class HistoryPager extends ReverseChronologicalPager {
public $lastRow = false, $counter, $historyPage, $buttons, $conds;
@@ -436,7 +443,7 @@ class HistoryPager extends ReverseChronologicalPager {
$this->getOutput()->wrapWikiMsg( "<div class='mw-history-legend'>\n$1\n</div>", 'histlegend' );
$s = Html::openElement( 'form', array( 'action' => $wgScript,
'id' => 'mw-history-compare' ) ) . "\n";
- $s .= Html::hidden( 'title', $this->getTitle()->getPrefixedDbKey() ) . "\n";
+ $s .= Html::hidden( 'title', $this->getTitle()->getPrefixedDBkey() ) . "\n";
$s .= Html::hidden( 'action', 'historysubmit' ) . "\n";
// Button container stored in $this->buttons for re-use in getEndBody()
@@ -504,14 +511,14 @@ class HistoryPager extends ReverseChronologicalPager {
/**
* Creates a submit button
*
- * @param $message String: text of the submit button, will be escaped
- * @param $attributes Array: attributes
+ * @param string $message text of the submit button, will be escaped
+ * @param array $attributes attributes
* @return String: HTML output for the submit button
*/
function submitButton( $message, $attributes = array() ) {
# Disable submit button if history has 1 revision only
if ( $this->getNumRows() > 1 ) {
- return Xml::submitButton( $message , $attributes );
+ return Xml::submitButton( $message, $attributes );
} else {
return '';
}
@@ -572,11 +579,11 @@ class HistoryPager extends ReverseChronologicalPager {
} elseif ( $rev->getVisibility() && $user->isAllowed( 'deletedhistory' ) ) {
// If revision was hidden from sysops, disable the link
if ( !$rev->userCan( Revision::DELETED_RESTRICTED, $user ) ) {
- $cdel = Linker::revDeleteLinkDisabled( false );
+ $del = Linker::revDeleteLinkDisabled( false );
// Otherwise, show the link...
} else {
$query = array( 'type' => 'revision',
- 'target' => $this->getTitle()->getPrefixedDbkey(), 'ids' => $rev->getId() );
+ 'target' => $this->getTitle()->getPrefixedDBkey(), 'ids' => $rev->getId() );
$del .= Linker::revDeleteLink( $query,
$rev->isDeleted( Revision::DELETED_RESTRICTED ), false );
}
@@ -598,19 +605,22 @@ class HistoryPager extends ReverseChronologicalPager {
$s .= ' ' . ChangesList::flag( 'minor' );
}
- # Size is always public data
- $prevSize = isset( $this->parentLens[$row->rev_parent_id] )
- ? $this->parentLens[$row->rev_parent_id]
- : 0;
- $sDiff = ChangesList::showCharacterDifference( $prevSize, $rev->getSize() );
- $fSize = Linker::formatRevisionSize($rev->getSize());
- $s .= ' <span class="mw-changeslist-separator">. .</span> ' . "$fSize $sDiff";
+ # Sometimes rev_len isn't populated
+ if ( $rev->getSize() !== null ) {
+ # Size is always public data
+ $prevSize = isset( $this->parentLens[$row->rev_parent_id] )
+ ? $this->parentLens[$row->rev_parent_id]
+ : 0;
+ $sDiff = ChangesList::showCharacterDifference( $prevSize, $rev->getSize() );
+ $fSize = Linker::formatRevisionSize( $rev->getSize() );
+ $s .= ' <span class="mw-changeslist-separator">. .</span> ' . "$fSize $sDiff";
+ }
# Text following the character difference is added just before running hooks
$s2 = Linker::revComment( $rev, false, true );
if ( $notificationtimestamp && ( $row->rev_timestamp >= $notificationtimestamp ) ) {
- $s2 .= ' <span class="updatedmarker">' . $this->msg( 'updatedmarker' )->escaped() . '</span>';
+ $s2 .= ' <span class="updatedmarker">' . $this->msg( 'updatedmarker' )->escaped() . '</span>';
$classes[] = 'mw-history-line-updated';
}
@@ -619,9 +629,12 @@ class HistoryPager extends ReverseChronologicalPager {
# Rollback and undo links
if ( $prevRev && $this->getTitle()->quickUserCan( 'edit', $user ) ) {
if ( $latest && $this->getTitle()->quickUserCan( 'rollback', $user ) ) {
- $this->preventClickjacking();
- $tools[] = '<span class="mw-rollback-link">' .
- Linker::buildRollbackLink( $rev, $this->getContext() ) . '</span>';
+ // Get a rollback link without the brackets
+ $rollbackLink = Linker::generateRollback( $rev, $this->getContext(), array( 'verify', 'noBrackets' ) );
+ if ( $rollbackLink ) {
+ $this->preventClickjacking();
+ $tools[] = $rollbackLink;
+ }
}
if ( !$rev->isDeleted( Revision::DELETED_TEXT )
@@ -644,6 +657,8 @@ class HistoryPager extends ReverseChronologicalPager {
$tools[] = "<span class=\"mw-history-undo\">{$undolink}</span>";
}
}
+ // Allow extension to add their own links here
+ wfRunHooks( 'HistoryRevisionTools', array( $rev, &$tools ) );
if ( $tools ) {
$s2 .= ' '. $this->msg( 'parentheses' )->rawParams( $lang->pipeList( $tools ) )->escaped();
@@ -661,7 +676,7 @@ class HistoryPager extends ReverseChronologicalPager {
$s .= ' <span class="mw-changeslist-separator">. .</span> ' . $s2;
}
- wfRunHooks( 'PageHistoryLineEnding', array( $this, &$row , &$s, &$classes ) );
+ wfRunHooks( 'PageHistoryLineEnding', array( $this, &$row, &$s, &$classes ) );
$attribs = array();
if ( $classes ) {
diff --git a/includes/actions/InfoAction.php b/includes/actions/InfoAction.php
index ae550391..1e312d7a 100644
--- a/includes/actions/InfoAction.php
+++ b/includes/actions/InfoAction.php
@@ -22,6 +22,11 @@
* @ingroup Actions
*/
+/**
+ * Displays information about a page.
+ *
+ * @ingroup Actions
+ */
class InfoAction extends FormlessAction {
/**
* Returns the name of the action this object responds to.
@@ -81,11 +86,11 @@ class InfoAction extends FormlessAction {
// Hide "This page is a member of # hidden categories" explanation
$content .= Html::element( 'style', array(),
- '.mw-hiddenCategoriesExplanation { display: none; }' );
+ '.mw-hiddenCategoriesExplanation { display: none; }' ) . "\n";
// Hide "Templates used on this page" explanation
$content .= Html::element( 'style', array(),
- '.mw-templatesUsedExplanation { display: none; }' );
+ '.mw-templatesUsedExplanation { display: none; }' ) . "\n";
// Get page information
$pageInfo = $this->pageInfo();
@@ -95,14 +100,14 @@ class InfoAction extends FormlessAction {
// Render page information
foreach ( $pageInfo as $header => $infoTable ) {
- $content .= $this->makeHeader( $this->msg( "pageinfo-${header}" )->escaped() );
- $table = '';
+ $content .= $this->makeHeader( $this->msg( "pageinfo-${header}" )->escaped() ) . "\n";
+ $table = "\n";
foreach ( $infoTable as $infoRow ) {
$name = ( $infoRow[0] instanceof Message ) ? $infoRow[0]->escaped() : $infoRow[0];
$value = ( $infoRow[1] instanceof Message ) ? $infoRow[1]->escaped() : $infoRow[1];
- $table = $this->addRow( $table, $name, $value );
+ $table = $this->addRow( $table, $name, $value ) . "\n";
}
- $content = $this->addTable( $content, $table );
+ $content = $this->addTable( $content, $table ) . "\n";
}
// Page footer
@@ -125,17 +130,16 @@ class InfoAction extends FormlessAction {
* @return string The HTML.
*/
protected function makeHeader( $header ) {
- global $wgParser;
- $spanAttribs = array( 'class' => 'mw-headline', 'id' => $wgParser->guessSectionNameFromWikiText( $header ) );
+ $spanAttribs = array( 'class' => 'mw-headline', 'id' => Sanitizer::escapeId( $header ) );
return Html::rawElement( 'h2', array(), Html::element( 'span', $spanAttribs, $header ) );
}
/**
* Adds a row to a table that will be added to the content.
*
- * @param $table string The table that will be added to the content
- * @param $name string The name of the row
- * @param $value string The value of the row
+ * @param string $table The table that will be added to the content
+ * @param string $name The name of the row
+ * @param string $value The value of the row
* @return string The table with the row added
*/
protected function addRow( $table, $name, $value ) {
@@ -148,8 +152,8 @@ class InfoAction extends FormlessAction {
/**
* Adds a table to the content that will be added to the output.
*
- * @param $content string The content that will be added to the output
- * @param $table string The table
+ * @param string $content The content that will be added to the output
+ * @param string $table The table
* @return string The content with the table added
*/
protected function addTable( $content, $table ) {
@@ -161,17 +165,25 @@ class InfoAction extends FormlessAction {
* Returns page information in an easily-manipulated format. Array keys are used so extensions
* may add additional information in arbitrary positions. Array values are arrays with one
* element to be rendered as a header, arrays with two elements to be rendered as a table row.
+ *
+ * @return array
*/
protected function pageInfo() {
- global $wgContLang, $wgRCMaxAge;
+ global $wgContLang, $wgRCMaxAge, $wgMemc, $wgUnwatchedPageThreshold, $wgPageInfoTransclusionLimit;
$user = $this->getUser();
$lang = $this->getLanguage();
$title = $this->getTitle();
$id = $title->getArticleID();
- // Get page information that would be too "expensive" to retrieve by normal means
- $pageCounts = self::pageCounts( $title, $user );
+ $memcKey = wfMemcKey( 'infoaction', sha1( $title->getPrefixedText() ), $this->page->getLatest() );
+ $pageCounts = $wgMemc->get( $memcKey );
+ if ( $pageCounts === false ) {
+ // Get page information that would be too "expensive" to retrieve by normal means
+ $pageCounts = self::pageCounts( $title );
+
+ $wgMemc->set( $memcKey, $pageCounts );
+ }
// Get page properties
$dbr = wfGetDB( DB_SLAVE );
@@ -201,6 +213,21 @@ class InfoAction extends FormlessAction {
$this->msg( 'pageinfo-display-title' ), $displayTitle
);
+ // Is it a redirect? If so, where to?
+ if ( $title->isRedirect() ) {
+ $pageInfo['header-basic'][] = array(
+ $this->msg( 'pageinfo-redirectsto' ),
+ Linker::link( $this->page->getRedirectTarget() ) .
+ $this->msg( 'word-separator' )->text() .
+ $this->msg( 'parentheses', Linker::link(
+ $this->page->getRedirectTarget(),
+ $this->msg( 'pageinfo-redirectsto-info' )->escaped(),
+ array(),
+ array( 'action' => 'info' )
+ ) )->text()
+ );
+ }
+
// Default sort key
$sortKey = $title->getCategorySortKey();
if ( !empty( $pageProperties['defaultsort'] ) ) {
@@ -217,6 +244,12 @@ class InfoAction extends FormlessAction {
// Page ID (number not localised, as it's a database ID)
$pageInfo['header-basic'][] = array( $this->msg( 'pageinfo-article-id' ), $id );
+ // Language in which the page content is (supposed to be) written
+ $pageLang = $title->getPageLanguage()->getCode();
+ $pageInfo['header-basic'][] = array( $this->msg( 'pageinfo-language' ),
+ Language::fetchLanguageName( $pageLang, $lang->getCode() )
+ . ' ' . $this->msg( 'parentheses', $pageLang ) );
+
// Search engine status
$pOutput = new ParserOutput();
if ( isset( $pageProperties['noindex'] ) ) {
@@ -236,11 +269,20 @@ class InfoAction extends FormlessAction {
);
}
- if ( isset( $pageCounts['watchers'] ) ) {
+ if (
+ $user->isAllowed( 'unwatchedpages' ) ||
+ ( $wgUnwatchedPageThreshold !== false &&
+ $pageCounts['watchers'] >= $wgUnwatchedPageThreshold )
+ ) {
// Number of page watchers
$pageInfo['header-basic'][] = array(
$this->msg( 'pageinfo-watchers' ), $lang->formatNum( $pageCounts['watchers'] )
);
+ } elseif ( $wgUnwatchedPageThreshold !== false ) {
+ $pageInfo['header-basic'][] = array(
+ $this->msg( 'pageinfo-watchers' ),
+ $this->msg( 'pageinfo-few-watchers' )->numParams( $wgUnwatchedPageThreshold )
+ );
}
// Redirects to this page
@@ -256,6 +298,14 @@ class InfoAction extends FormlessAction {
->numParams( count( $title->getRedirectsHere() ) )
);
+ // Is it counted as a content page?
+ if ( $this->page->isCountable() ) {
+ $pageInfo['header-basic'][] = array(
+ $this->msg( 'pageinfo-contentpage' ),
+ $this->msg( 'pageinfo-contentpage-yes' )
+ );
+ }
+
// Subpages of this page, if subpages are enabled for the current NS
if ( MWNamespace::hasSubpages( $title->getNamespace() ) ) {
$prefixIndex = SpecialPage::getTitleFor( 'Prefixindex', $title->getPrefixedText() . '/' );
@@ -269,9 +319,51 @@ class InfoAction extends FormlessAction {
);
}
+ if ( $title->inNamespace( NS_CATEGORY ) ) {
+ $category = Category::newFromTitle( $title );
+ $pageInfo['category-info'] = array(
+ array(
+ $this->msg( 'pageinfo-category-pages' ),
+ $lang->formatNum( $category->getPageCount() )
+ ),
+ array(
+ $this->msg( 'pageinfo-category-subcats' ),
+ $lang->formatNum( $category->getSubcatCount() )
+ ),
+ array(
+ $this->msg( 'pageinfo-category-files' ),
+ $lang->formatNum( $category->getFileCount() )
+ )
+ );
+ }
+
// Page protection
$pageInfo['header-restrictions'] = array();
+ // Is this page effected by the cascading protection of something which includes it?
+ if ( $title->isCascadeProtected() ) {
+ $cascadingFrom = '';
+ $sources = $title->getCascadeProtectionSources(); // Array deferencing is in PHP 5.4 :(
+
+ foreach ( $sources[0] as $sourceTitle ) {
+ $cascadingFrom .= Html::rawElement( 'li', array(), Linker::linkKnown( $sourceTitle ) );
+ }
+
+ $cascadingFrom = Html::rawElement( 'ul', array(), $cascadingFrom );
+ $pageInfo['header-restrictions'][] = array(
+ $this->msg( 'pageinfo-protect-cascading-from' ),
+ $cascadingFrom
+ );
+ }
+
+ // Is out protection set to cascade to other pages?
+ if ( $title->areRestrictionsCascading() ) {
+ $pageInfo['header-restrictions'][] = array(
+ $this->msg( 'pageinfo-protect-cascading' ),
+ $this->msg( 'pageinfo-protect-cascading-yes' )
+ );
+ }
+
// Page protection
foreach ( $title->getRestrictionTypes() as $restrictionType ) {
$protectionLevel = implode( ', ', $title->getRestrictions( $restrictionType ) );
@@ -303,40 +395,64 @@ class InfoAction extends FormlessAction {
$pageInfo['header-edits'] = array();
$firstRev = $this->page->getOldestRevision();
+ $lastRev = $this->page->getRevision();
+ $batch = new LinkBatch;
+
+ if ( $firstRev ) {
+ $firstRevUser = $firstRev->getUserText( Revision::FOR_THIS_USER );
+ if ( $firstRevUser !== '' ) {
+ $batch->add( NS_USER, $firstRevUser );
+ $batch->add( NS_USER_TALK, $firstRevUser );
+ }
+ }
- // Page creator
- $pageInfo['header-edits'][] = array(
- $this->msg( 'pageinfo-firstuser' ),
- Linker::revUserTools( $firstRev )
- );
+ if ( $lastRev ) {
+ $lastRevUser = $lastRev->getUserText( Revision::FOR_THIS_USER );
+ if ( $lastRevUser !== '' ) {
+ $batch->add( NS_USER, $lastRevUser );
+ $batch->add( NS_USER_TALK, $lastRevUser );
+ }
+ }
- // Date of page creation
- $pageInfo['header-edits'][] = array(
- $this->msg( 'pageinfo-firsttime' ),
- Linker::linkKnown(
- $title,
- $lang->userTimeAndDate( $firstRev->getTimestamp(), $user ),
- array(),
- array( 'oldid' => $firstRev->getId() )
- )
- );
+ $batch->execute();
- // Latest editor
- $pageInfo['header-edits'][] = array(
- $this->msg( 'pageinfo-lastuser' ),
- Linker::revUserTools( $this->page->getRevision() )
- );
+ if ( $firstRev ) {
+ // Page creator
+ $pageInfo['header-edits'][] = array(
+ $this->msg( 'pageinfo-firstuser' ),
+ Linker::revUserTools( $firstRev )
+ );
- // Date of latest edit
- $pageInfo['header-edits'][] = array(
- $this->msg( 'pageinfo-lasttime' ),
- Linker::linkKnown(
- $title,
- $lang->userTimeAndDate( $this->page->getTimestamp(), $user ),
- array(),
- array( 'oldid' => $this->page->getLatest() )
- )
- );
+ // Date of page creation
+ $pageInfo['header-edits'][] = array(
+ $this->msg( 'pageinfo-firsttime' ),
+ Linker::linkKnown(
+ $title,
+ $lang->userTimeAndDate( $firstRev->getTimestamp(), $user ),
+ array(),
+ array( 'oldid' => $firstRev->getId() )
+ )
+ );
+ }
+
+ if ( $lastRev ) {
+ // Latest editor
+ $pageInfo['header-edits'][] = array(
+ $this->msg( 'pageinfo-lastuser' ),
+ Linker::revUserTools( $lastRev )
+ );
+
+ // Date of latest edit
+ $pageInfo['header-edits'][] = array(
+ $this->msg( 'pageinfo-lasttime' ),
+ Linker::linkKnown(
+ $title,
+ $lang->userTimeAndDate( $this->page->getTimestamp(), $user ),
+ array(),
+ array( 'oldid' => $this->page->getLatest() )
+ )
+ );
+ }
// Total number of edits
$pageInfo['header-edits'][] = array(
@@ -377,11 +493,17 @@ class InfoAction extends FormlessAction {
$localizedList = Html::rawElement( 'ul', array(), implode( '', $listItems ) );
$hiddenCategories = $this->page->getHiddenCategories();
- $transcludedTemplates = $title->getTemplateLinksFrom();
- if ( count( $listItems ) > 0
- || count( $hiddenCategories ) > 0
- || count( $transcludedTemplates ) > 0 ) {
+ if (
+ count( $listItems ) > 0 ||
+ count( $hiddenCategories ) > 0 ||
+ $pageCounts['transclusion']['from'] > 0 ||
+ $pageCounts['transclusion']['to'] > 0
+ ) {
+ $options = array( 'LIMIT' => $wgPageInfoTransclusionLimit );
+ $transcludedTemplates = $title->getTemplateLinksFrom( $options );
+ $transcludedTargets = $title->getTemplateLinksTo( $options );
+
// Page properties
$pageInfo['header-properties'] = array();
@@ -403,11 +525,44 @@ class InfoAction extends FormlessAction {
}
// Transcluded templates
- if ( count( $transcludedTemplates ) > 0 ) {
+ if ( $pageCounts['transclusion']['from'] > 0 ) {
+ if ( $pageCounts['transclusion']['from'] > count( $transcludedTemplates ) ) {
+ $more = $this->msg( 'morenotlisted' )->escaped();
+ } else {
+ $more = null;
+ }
+
$pageInfo['header-properties'][] = array(
$this->msg( 'pageinfo-templates' )
- ->numParams( count( $transcludedTemplates ) ),
- Linker::formatTemplates( $transcludedTemplates )
+ ->numParams( $pageCounts['transclusion']['from'] ),
+ Linker::formatTemplates(
+ $transcludedTemplates,
+ false,
+ false,
+ $more )
+ );
+ }
+
+ if ( $pageCounts['transclusion']['to'] > 0 ) {
+ if ( $pageCounts['transclusion']['to'] > count( $transcludedTargets ) ) {
+ $more = Linker::link(
+ $whatLinksHere,
+ $this->msg( 'moredotdotdot' )->escaped(),
+ array(),
+ array( 'hidelinks' => 1, 'hideredirs' => 1 )
+ );
+ } else {
+ $more = null;
+ }
+
+ $pageInfo['header-properties'][] = array(
+ $this->msg( 'pageinfo-transclusions' )
+ ->numParams( $pageCounts['transclusion']['to'] ),
+ Linker::formatTemplates(
+ $transcludedTargets,
+ false,
+ false,
+ $more )
);
}
}
@@ -418,11 +573,10 @@ class InfoAction extends FormlessAction {
/**
* Returns page counts that would be too "expensive" to retrieve by normal means.
*
- * @param $title Title object
- * @param $user User object
+ * @param Title $title Title to get counts for
* @return array
*/
- protected static function pageCounts( $title, $user ) {
+ protected static function pageCounts( Title $title ) {
global $wgRCMaxAge, $wgDisableCounters;
wfProfileIn( __METHOD__ );
@@ -442,19 +596,17 @@ class InfoAction extends FormlessAction {
$result['views'] = $views;
}
- if ( $user->isAllowed( 'unwatchedpages' ) ) {
- // Number of page watchers
- $watchers = (int) $dbr->selectField(
- 'watchlist',
- 'COUNT(*)',
- array(
- 'wl_namespace' => $title->getNamespace(),
- 'wl_title' => $title->getDBkey(),
- ),
- __METHOD__
- );
- $result['watchers'] = $watchers;
- }
+ // Number of page watchers
+ $watchers = (int) $dbr->selectField(
+ 'watchlist',
+ 'COUNT(*)',
+ array(
+ 'wl_namespace' => $title->getNamespace(),
+ 'wl_title' => $title->getDBkey(),
+ ),
+ __METHOD__
+ );
+ $result['watchers'] = $watchers;
// Total number of edits
$edits = (int) $dbr->selectField(
@@ -482,8 +634,8 @@ class InfoAction extends FormlessAction {
'revision',
'COUNT(rev_page)',
array(
- 'rev_page' => $id ,
- "rev_timestamp >= $threshold"
+ 'rev_page' => $id,
+ "rev_timestamp >= " . $dbr->addQuotes( $threshold )
),
__METHOD__
);
@@ -495,7 +647,7 @@ class InfoAction extends FormlessAction {
'COUNT(DISTINCT rev_user_text)',
array(
'rev_page' => $id,
- "rev_timestamp >= $threshold"
+ "rev_timestamp >= " . $dbr->addQuotes( $threshold )
),
__METHOD__
);
@@ -528,12 +680,30 @@ class InfoAction extends FormlessAction {
+ $result['subpages']['nonredirects'];
}
+ // Counts for the number of transclusion links (to/from)
+ $result['transclusion']['to'] = (int) $dbr->selectField(
+ 'templatelinks',
+ 'COUNT(tl_from)',
+ array(
+ 'tl_namespace' => $title->getNamespace(),
+ 'tl_title' => $title->getDBkey()
+ ),
+ __METHOD__
+ );
+
+ $result['transclusion']['from'] = (int) $dbr->selectField(
+ 'templatelinks',
+ 'COUNT(*)',
+ array( 'tl_from' => $title->getArticleID() ),
+ __METHOD__
+ );
+
wfProfileOut( __METHOD__ );
return $result;
}
/**
- * Returns the name that goes in the <h1> page title.
+ * Returns the name that goes in the "<h1>" page title.
*
* @return string
*/
@@ -604,7 +774,7 @@ class InfoAction extends FormlessAction {
}
/**
- * Returns the description that goes below the <h1> tag.
+ * Returns the description that goes below the "<h1>" tag.
*
* @return string
*/
diff --git a/includes/actions/MarkpatrolledAction.php b/includes/actions/MarkpatrolledAction.php
index ae9223f4..ff6cf13a 100644
--- a/includes/actions/MarkpatrolledAction.php
+++ b/includes/actions/MarkpatrolledAction.php
@@ -22,6 +22,11 @@
* @ingroup Actions
*/
+/**
+ * Mark a revision as patrolled on a page
+ *
+ * @ingroup Actions
+ */
class MarkpatrolledAction extends FormlessAction {
public function getName() {
diff --git a/includes/actions/ProtectAction.php b/includes/actions/ProtectAction.php
index f053ede7..ec6648e2 100644
--- a/includes/actions/ProtectAction.php
+++ b/includes/actions/ProtectAction.php
@@ -23,17 +23,24 @@
* @author Timo Tijhof
*/
+/**
+ * Handle page protection
+ *
+ * This is a wrapper that will call Article::protect().
+ *
+ * @ingroup Actions
+ */
class ProtectAction extends FormlessAction {
public function getName() {
return 'protect';
}
- public function onView(){
+ public function onView() {
return null;
}
- public function show(){
+ public function show() {
$this->page->protect();
@@ -41,13 +48,20 @@ class ProtectAction extends FormlessAction {
}
+/**
+ * Handle page unprotection
+ *
+ * This is a wrapper that will call Article::unprotect().
+ *
+ * @ingroup Actions
+ */
class UnprotectAction extends ProtectAction {
public function getName() {
return 'unprotect';
}
- public function show(){
+ public function show() {
$this->page->unprotect();
diff --git a/includes/actions/PurgeAction.php b/includes/actions/PurgeAction.php
index cd58889d..00bb961d 100644
--- a/includes/actions/PurgeAction.php
+++ b/includes/actions/PurgeAction.php
@@ -1,8 +1,6 @@
<?php
/**
- * Formats credits for articles
- *
- * Copyright 2004, Evan Prodromou <evan@wikitravel.org>.
+ * User-requested page cache purging.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -20,9 +18,16 @@
*
* @file
* @ingroup Actions
- * @author <evan@wikitravel.org>
*/
+/**
+ * User-requested page cache purging.
+ *
+ * For users with 'purge', this will directly trigger the cache purging and
+ * for users without that right, it will show a confirmation form.
+ *
+ * @ingroup Actions
+ */
class PurgeAction extends FormAction {
private $redirectParams;
@@ -62,7 +67,7 @@ class PurgeAction extends FormAction {
$this->checkCanExecute( $this->getUser() );
if ( $this->getUser()->isAllowed( 'purge' ) ) {
- $this->redirectParams = wfArrayToCGI( array_diff_key(
+ $this->redirectParams = wfArrayToCgi( array_diff_key(
$this->getRequest()->getQueryValues(),
array( 'title' => null, 'action' => null )
) );
diff --git a/includes/actions/RawAction.php b/includes/actions/RawAction.php
index 174ca3f8..d1d457c0 100644
--- a/includes/actions/RawAction.php
+++ b/includes/actions/RawAction.php
@@ -29,6 +29,8 @@
/**
* A simple method to retrieve the plain source of an article,
* using "action=raw" in the GET request string.
+ *
+ * @ingroup Actions
*/
class RawAction extends FormlessAction {
private $mGen;
@@ -46,7 +48,7 @@ class RawAction extends FormlessAction {
}
function onView() {
- global $wgGroupPermissions, $wgSquidMaxage, $wgForcedRawSMaxage, $wgJsMimeType;
+ global $wgSquidMaxage, $wgForcedRawSMaxage, $wgJsMimeType;
$this->getOutput()->disable();
$request = $this->getRequest();
@@ -91,7 +93,7 @@ class RawAction extends FormlessAction {
$response->header( 'Content-type: ' . $contentType . '; charset=UTF-8' );
# Output may contain user-specific data;
# vary generated content for open sessions on private wikis
- $privateCache = !$wgGroupPermissions['*']['read'] && ( $smaxage == 0 || session_id() != '' );
+ $privateCache = !User::groupHasPermission( '*', 'read' ) && ( $smaxage == 0 || session_id() != '' );
# allow the client to cache this for 24 hours
$mode = $privateCache ? 'private' : 'public';
$response->header( 'Cache-Control: ' . $mode . ', s-maxage=' . $smaxage . ', max-age=' . $maxage );
@@ -148,10 +150,29 @@ class RawAction extends FormlessAction {
$request->response()->header( "Last-modified: $lastmod" );
// Public-only due to cache headers
- $text = $rev->getText();
- $section = $request->getIntOrNull( 'section' );
- if ( $section !== null ) {
- $text = $wgParser->getSection( $text, $section );
+ $content = $rev->getContent();
+
+ if ( $content === null ) {
+ // revision not found (or suppressed)
+ $text = false;
+ } elseif ( !$content instanceof TextContent ) {
+ // non-text content
+ wfHttpError( 415, "Unsupported Media Type", "The requested page uses the content model `"
+ . $content->getModel() . "` which is not supported via this interface." );
+ die();
+ } else {
+ // want a section?
+ $section = $request->getIntOrNull( 'section' );
+ if ( $section !== null ) {
+ $content = $content->getSection( $section );
+ }
+
+ if ( $content === null || $content === false ) {
+ // section not found (or section not supported, e.g. for JS and CSS)
+ $text = false;
+ } else {
+ $text = $content->getNativeData();
+ }
}
}
}
@@ -185,7 +206,7 @@ class RawAction extends FormlessAction {
$oldid = $this->page->getLatest();
}
$prev = $this->getTitle()->getPreviousRevisionId( $oldid );
- $oldid = $prev ? $prev : -1 ;
+ $oldid = $prev ? $prev : -1;
break;
case 'cur':
$oldid = 0;
diff --git a/includes/actions/RenderAction.php b/includes/actions/RenderAction.php
index 80af79cc..3d244fb3 100644
--- a/includes/actions/RenderAction.php
+++ b/includes/actions/RenderAction.php
@@ -23,17 +23,24 @@
* @author Timo Tijhof
*/
+/**
+ * Handle action=render
+ *
+ * This is a wrapper that will call Article::render().
+ *
+ * @ingroup Actions
+ */
class RenderAction extends FormlessAction {
public function getName() {
return 'render';
}
- public function onView(){
+ public function onView() {
return null;
}
- public function show(){
+ public function show() {
$this->page->render();
diff --git a/includes/actions/RevertAction.php b/includes/actions/RevertAction.php
index 77434384..a5fc4e17 100644
--- a/includes/actions/RevertAction.php
+++ b/includes/actions/RevertAction.php
@@ -115,7 +115,7 @@ class RevertFileAction extends FormAction {
$source = $this->page->getFile()->getArchiveVirtualUrl( $this->getRequest()->getText( 'oldimage' ) );
$comment = $data['comment'];
// TODO: Preserve file properties from database instead of reloading from file
- return $this->page->getFile()->upload( $source, $comment, $comment );
+ return $this->page->getFile()->upload( $source, $comment, $comment, 0, false, false, $this->getUser() );
}
public function onSuccess() {
@@ -124,7 +124,7 @@ class RevertFileAction extends FormAction {
$lang = $this->getLanguage();
$userDate = $lang->userDate( $timestamp, $user );
$userTime = $lang->userTime( $timestamp, $user );
-
+
$this->getOutput()->addWikiMsg( 'filerevert-success', $this->getTitle()->getText(),
$userDate, $userTime,
wfExpandUrl( $this->page->getFile()->getArchiveUrl( $this->getRequest()->getText( 'oldimage' ) ),
@@ -136,7 +136,7 @@ class RevertFileAction extends FormAction {
protected function getPageTitle() {
return $this->msg( 'filerevert', $this->getTitle()->getText() );
}
-
+
protected function getDescription() {
$this->getOutput()->addBacklinkSubtitle( $this->getTitle() );
return '';
diff --git a/includes/actions/RevisiondeleteAction.php b/includes/actions/RevisiondeleteAction.php
index 14da2fcf..2949fa95 100644
--- a/includes/actions/RevisiondeleteAction.php
+++ b/includes/actions/RevisiondeleteAction.php
@@ -23,6 +23,11 @@
* @author Alexandre Emsenhuber
*/
+/**
+ * An action that just pass the request to Special:RevisionDelete
+ *
+ * @ingroup Actions
+ */
class RevisiondeleteAction extends FormlessAction {
public function getName() {
diff --git a/includes/actions/RollbackAction.php b/includes/actions/RollbackAction.php
index 0d9a9027..81bad9da 100644
--- a/includes/actions/RollbackAction.php
+++ b/includes/actions/RollbackAction.php
@@ -71,45 +71,32 @@ class RollbackAction extends FormlessAction {
return;
}
- # Display permissions errors before read-only message -- there's no
- # point in misleading the user into thinking the inability to rollback
- # is only temporary.
- if ( !empty( $result ) && $result !== array( array( 'readonlytext' ) ) ) {
- # array_diff is completely broken for arrays of arrays, sigh.
- # Remove any 'readonlytext' error manually.
- $out = array();
- foreach ( $result as $error ) {
- if ( $error != array( 'readonlytext' ) ) {
- $out [] = $error;
- }
- }
- throw new PermissionsError( 'rollback', $out );
- }
+ #NOTE: Permission errors already handled by Action::checkExecute.
if ( $result == array( array( 'readonlytext' ) ) ) {
throw new ReadOnlyError;
}
+ #XXX: Would be nice if ErrorPageError could take multiple errors, and/or a status object.
+ # Right now, we only show the first error
+ foreach ( $result as $error ) {
+ throw new ErrorPageError( 'rollbackfailed', $error[0], array_slice( $error, 1 ) );
+ }
+
$current = $details['current'];
$target = $details['target'];
$newId = $details['newid'];
$this->getOutput()->setPageTitle( $this->msg( 'actioncomplete' ) );
$this->getOutput()->setRobotPolicy( 'noindex,nofollow' );
- if ( $current->getUserText() === '' ) {
- $old = $this->msg( 'rev-deleted-user' )->escaped();
- } else {
- $old = Linker::userLink( $current->getUser(), $current->getUserText() )
- . Linker::userToolLinks( $current->getUser(), $current->getUserText() );
- }
-
- $new = Linker::userLink( $target->getUser(), $target->getUserText() )
- . Linker::userToolLinks( $target->getUser(), $target->getUserText() );
+ $old = Linker::revUserTools( $current );
+ $new = Linker::revUserTools( $target );
$this->getOutput()->addHTML( $this->msg( 'rollback-success' )->rawParams( $old, $new )->parseAsBlock() );
$this->getOutput()->returnToMain( false, $this->getTitle() );
if ( !$request->getBool( 'hidediff', false ) && !$this->getUser()->getBoolOption( 'norollbackdiff', false ) ) {
- $de = new DifferenceEngine( $this->getContext(), $current->getId(), $newId, false, true );
+ $contentHandler = $current->getContentHandler();
+ $de = $contentHandler->createDifferenceEngine( $this->getContext(), $current->getId(), $newId, false, true );
$de->showDiff( '', '' );
}
}
diff --git a/includes/actions/ViewAction.php b/includes/actions/ViewAction.php
index d57585ee..e227197d 100644
--- a/includes/actions/ViewAction.php
+++ b/includes/actions/ViewAction.php
@@ -23,17 +23,24 @@
* @author Timo Tijhof
*/
+/**
+ * An action that views article content
+ *
+ * This is a wrapper that will call Article::render().
+ *
+ * @ingroup Actions
+ */
class ViewAction extends FormlessAction {
public function getName() {
return 'view';
}
- public function onView(){
+ public function onView() {
return null;
}
- public function show(){
+ public function show() {
$this->page->view();
}
diff --git a/includes/actions/WatchAction.php b/includes/actions/WatchAction.php
index e2636452..ae5f76c6 100644
--- a/includes/actions/WatchAction.php
+++ b/includes/actions/WatchAction.php
@@ -20,6 +20,11 @@
* @ingroup Actions
*/
+/**
+ * Page addition to a user's watchlist
+ *
+ * @ingroup Actions
+ */
class WatchAction extends FormAction {
public function getName() {
@@ -148,6 +153,11 @@ class WatchAction extends FormAction {
}
}
+/**
+ * Page removal from a user's watchlist
+ *
+ * @ingroup Actions
+ */
class UnwatchAction extends WatchAction {
public function getName() {