summaryrefslogtreecommitdiff
path: root/includes/actions
diff options
context:
space:
mode:
Diffstat (limited to 'includes/actions')
-rw-r--r--includes/actions/CreditsAction.php67
-rw-r--r--includes/actions/DeleteAction.php (renamed from includes/actions/DeletetrackbackAction.php)30
-rw-r--r--includes/actions/EditAction.php74
-rw-r--r--includes/actions/HistoryAction.php804
-rw-r--r--includes/actions/InfoAction.php44
-rw-r--r--includes/actions/MarkpatrolledAction.php32
-rw-r--r--includes/actions/ProtectAction.php56
-rw-r--r--includes/actions/PurgeAction.php12
-rw-r--r--includes/actions/RawAction.php239
-rw-r--r--includes/actions/RenderAction.php42
-rw-r--r--includes/actions/RevertAction.php22
-rw-r--r--includes/actions/RevisiondeleteAction.php4
-rw-r--r--includes/actions/RollbackAction.php14
-rw-r--r--includes/actions/ViewAction.php43
-rw-r--r--includes/actions/WatchAction.php16
15 files changed, 1356 insertions, 143 deletions
diff --git a/includes/actions/CreditsAction.php b/includes/actions/CreditsAction.php
index 1040085b..cd083c30 100644
--- a/includes/actions/CreditsAction.php
+++ b/includes/actions/CreditsAction.php
@@ -29,12 +29,8 @@ class CreditsAction extends FormlessAction {
return 'credits';
}
- public function getRestriction() {
- return null;
- }
-
protected function getDescription() {
- return wfMsg( 'creditspage' );
+ return wfMsgHtml( 'creditspage' );
}
/**
@@ -46,7 +42,7 @@ class CreditsAction extends FormlessAction {
wfProfileIn( __METHOD__ );
if ( $this->page->getID() == 0 ) {
- $s = wfMsg( 'nocredits' );
+ $s = $this->msg( 'nocredits' )->parse();
} else {
$s = $this->getCredits( -1 );
}
@@ -67,8 +63,8 @@ class CreditsAction extends FormlessAction {
wfProfileIn( __METHOD__ );
$s = '';
- if ( isset( $cnt ) && $cnt != 0 ) {
- $s = self::getAuthor( $this->page );
+ if ( $cnt != 0 ) {
+ $s = $this->getAuthor( $this->page );
if ( $cnt > 1 || $cnt < 0 ) {
$s .= ' ' . $this->getContributors( $cnt - 1, $showIfMax );
}
@@ -83,20 +79,20 @@ class CreditsAction extends FormlessAction {
* @param $article Article object
* @return String HTML
*/
- protected static function getAuthor( Page $article ) {
- global $wgLang;
-
- $user = User::newFromId( $article->getUser() );
+ protected function getAuthor( Page $article ) {
+ $user = User::newFromName( $article->getUserText(), false );
$timestamp = $article->getTimestamp();
if ( $timestamp ) {
- $d = $wgLang->date( $article->getTimestamp(), true );
- $t = $wgLang->time( $article->getTimestamp(), true );
+ $lang = $this->getLanguage();
+ $d = $lang->date( $article->getTimestamp(), true );
+ $t = $lang->time( $article->getTimestamp(), true );
} else {
$d = '';
$t = '';
}
- return wfMessage( 'lastmodifiedatby', $d, $t )->rawParams( self::userLink( $user ) )->params( $user->getName() )->escaped();
+ return $this->msg( 'lastmodifiedatby', $d, $t )->rawParams(
+ $this->userLink( $user ) )->params( $user->getName() )->escaped();
}
/**
@@ -106,7 +102,7 @@ class CreditsAction extends FormlessAction {
* @return String: html
*/
protected function getContributors( $cnt, $showIfMax ) {
- global $wgLang, $wgHiddenPrefs;
+ global $wgHiddenPrefs;
$contributors = $this->page->getContributors();
@@ -116,7 +112,8 @@ class CreditsAction extends FormlessAction {
if ( $cnt > 0 && $contributors->count() > $cnt ) {
$others_link = $this->othersLink();
if ( !$showIfMax )
- return wfMessage( 'othercontribs' )->rawParams( $others_link )->params( $contributors->count() )->escaped();
+ return $this->msg( 'othercontribs' )->rawParams(
+ $others_link )->params( $contributors->count() )->escaped();
}
$real_names = array();
@@ -127,14 +124,14 @@ class CreditsAction extends FormlessAction {
foreach ( $contributors as $user ) {
$cnt--;
if ( $user->isLoggedIn() ) {
- $link = self::link( $user );
+ $link = $this->link( $user );
if ( !in_array( 'realname', $wgHiddenPrefs ) && $user->getRealName() ) {
$real_names[] = $link;
} else {
$user_names[] = $link;
}
} else {
- $anon_ips[] = self::link( $user );
+ $anon_ips[] = $this->link( $user );
}
if ( $cnt == 0 ) {
@@ -142,22 +139,24 @@ class CreditsAction extends FormlessAction {
}
}
+ $lang = $this->getLanguage();
+
if ( count( $real_names ) ) {
- $real = $wgLang->listToText( $real_names );
+ $real = $lang->listToText( $real_names );
} else {
$real = false;
}
# "ThisSite user(s) A, B and C"
if ( count( $user_names ) ) {
- $user = wfMessage( 'siteusers' )->rawParams( $wgLang->listToText( $user_names ) )->params(
+ $user = $this->msg( 'siteusers' )->rawParams( $lang->listToText( $user_names ) )->params(
count( $user_names ) )->escaped();
} else {
$user = false;
}
if ( count( $anon_ips ) ) {
- $anon = wfMessage( 'anonusers' )->rawParams( $wgLang->listToText( $anon_ips ) )->params(
+ $anon = $this->msg( 'anonusers' )->rawParams( $lang->listToText( $anon_ips ) )->params(
count( $anon_ips ) )->escaped();
} else {
$anon = false;
@@ -174,8 +173,8 @@ class CreditsAction extends FormlessAction {
$count = count( $fulllist );
# "Based on work by ..."
return $count
- ? wfMessage( 'othercontribs' )->rawParams(
- $wgLang->listToText( $fulllist ) )->params( $count )->escaped()
+ ? $this->msg( 'othercontribs' )->rawParams(
+ $lang->listToText( $fulllist ) )->params( $count )->escaped()
: '';
}
@@ -184,7 +183,7 @@ class CreditsAction extends FormlessAction {
* @param $user User object
* @return String: html
*/
- protected static function link( User $user ) {
+ protected function link( User $user ) {
global $wgHiddenPrefs;
if ( !in_array( 'realname', $wgHiddenPrefs ) && !$user->isAnon() ) {
$real = $user->getRealName();
@@ -204,32 +203,30 @@ class CreditsAction extends FormlessAction {
* @param $user User object
* @return String: html
*/
- protected static function userLink( User $user ) {
- $link = self::link( $user );
+ protected function userLink( User $user ) {
+ $link = $this->link( $user );
if ( $user->isAnon() ) {
- return wfMsgExt( 'anonuser', array( 'parseinline', 'replaceafter' ), $link );
+ return $this->msg( 'anonuser' )->rawParams( $link )->parse();
} else {
global $wgHiddenPrefs;
if ( !in_array( 'realname', $wgHiddenPrefs ) && $user->getRealName() ) {
return $link;
} else {
- return wfMessage( 'siteuser' )->rawParams( $link )->params( $user->getName() )->escaped();
+ return $this->msg( 'siteuser' )->rawParams( $link )->params( $user->getName() )->escaped();
}
}
}
/**
* Get a link to action=credits of $article page
- * @param $article Article object
- * @return String: html
+ * @return String: HTML link
*/
protected function othersLink() {
- return Linker::link(
+ return Linker::linkKnown(
$this->getTitle(),
- wfMsgHtml( 'others' ),
+ $this->msg( 'others' )->escaped(),
array(),
- array( 'action' => 'credits' ),
- array( 'known' )
+ array( 'action' => 'credits' )
);
}
}
diff --git a/includes/actions/DeletetrackbackAction.php b/includes/actions/DeleteAction.php
index 0efebdf5..5a5a382b 100644
--- a/includes/actions/DeletetrackbackAction.php
+++ b/includes/actions/DeleteAction.php
@@ -1,8 +1,8 @@
<?php
/**
- * Delete a trackback on a page
+ * Handle page deletion
*
- * Copyright © 2011 Alexandre Emsenhuber
+ * Copyright © 2012 Timo Tijhof
*
* 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,35 +20,23 @@
*
* @file
* @ingroup Actions
+ * @author Timo Tijhof
*/
-class DeletetrackbackAction extends FormlessAction {
+class DeleteAction extends FormlessAction {
public function getName() {
- return 'deletetrackback';
- }
-
- public function getRestriction() {
return 'delete';
}
- protected function getDescription() {
- return '';
+ public function onView(){
+ return null;
}
- protected function checkCanExecute( User $user ) {
- if ( !$user->matchEditToken( $this->getRequest()->getVal( 'token' ) ) ) {
- throw new ErrorPageError( 'sessionfailure-title', 'sessionfailure' );
- }
+ public function show(){
- return parent::checkCanExecute( $user );
- }
+ $this->page->delete();
- public function onView() {
- $db = wfGetDB( DB_MASTER );
- $db->delete( 'trackbacks', array( 'tb_id' => $this->getRequest()->getInt( 'tbid' ) ) );
-
- $this->getOutput()->addWikiMsg( 'trackbackdeleteok' );
- $this->getTitle()->invalidateCache();
}
+
}
diff --git a/includes/actions/EditAction.php b/includes/actions/EditAction.php
new file mode 100644
index 00000000..08a33f4c
--- /dev/null
+++ b/includes/actions/EditAction.php
@@ -0,0 +1,74 @@
+<?php
+/**
+ * action=edit / action=submit handler
+ *
+ * Copyright © 2012 Timo Tijhof
+ *
+ * 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
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * @file
+ * @ingroup Actions
+ * @author Timo Tijhof
+ */
+
+class EditAction extends FormlessAction {
+
+ public function getName() {
+ return 'edit';
+ }
+
+ public function onView(){
+ return null;
+ }
+
+ public function show(){
+ $page = $this->page;
+ $request = $this->getRequest();
+ $user = $this->getUser();
+ $context = $this->getContext();
+
+ if ( wfRunHooks( 'CustomEditor', array( $page, $user ) ) ) {
+ if ( ExternalEdit::useExternalEngine( $context, 'edit' )
+ && $this->getName() == 'edit' && !$request->getVal( 'section' )
+ && !$request->getVal( 'oldid' ) )
+ {
+ $extedit = new ExternalEdit( $context );
+ $extedit->execute();
+ } else {
+ $editor = new EditPage( $page );
+ $editor->edit();
+ }
+ }
+
+ }
+
+}
+
+class SubmitAction extends EditAction {
+
+ public function getName() {
+ return 'submit';
+ }
+
+ public function show(){
+ if ( session_id() == '' ) {
+ // Send a cookie so anons get talk message notifications
+ wfSetupSession();
+ }
+
+ parent::show();
+ }
+
+}
diff --git a/includes/actions/HistoryAction.php b/includes/actions/HistoryAction.php
new file mode 100644
index 00000000..457f67ff
--- /dev/null
+++ b/includes/actions/HistoryAction.php
@@ -0,0 +1,804 @@
+<?php
+/**
+ * Page history
+ *
+ * Split off from Article.php and Skin.php, 2003-12-22
+ * @file
+ */
+
+/**
+ * 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.
+ *
+ */
+class HistoryAction extends FormlessAction {
+ const DIR_PREV = 0;
+ const DIR_NEXT = 1;
+
+ public function getName() {
+ return 'history';
+ }
+
+ public function requiresWrite() {
+ return false;
+ }
+
+ public function requiresUnblock() {
+ return false;
+ }
+
+ protected function getPageTitle() {
+ return $this->msg( 'history-title', $this->getTitle()->getPrefixedText() )->text();
+ }
+
+ protected function getDescription() {
+ // Creation of a subtitle link pointing to [[Special:Log]]
+ return Linker::linkKnown(
+ SpecialPage::getTitleFor( 'Log' ),
+ $this->msg( 'viewpagelogs' )->escaped(),
+ array(),
+ array( 'page' => $this->getTitle()->getPrefixedText() )
+ );
+ }
+
+ /**
+ * Get the Article object we are working on.
+ * @return Page
+ */
+ public function getArticle() {
+ return $this->page;
+ }
+
+ /**
+ * As we use the same small set of messages in various methods and that
+ * they are called often, we call them once and save them in $this->message
+ */
+ private function preCacheMessages() {
+ // Precache various messages
+ if ( !isset( $this->message ) ) {
+ $msgs = array( 'cur', 'last', 'pipe-separator' );
+ foreach ( $msgs as $msg ) {
+ $this->message[$msg] = $this->msg( $msg )->escaped();
+ }
+ }
+ }
+
+ /**
+ * Print the history page for an article.
+ * @return nothing
+ */
+ function onView() {
+ global $wgScript, $wgUseFileCache, $wgSquidMaxage;
+
+ $out = $this->getOutput();
+ $request = $this->getRequest();
+
+ /**
+ * Allow client caching.
+ */
+ if ( $out->checkLastModified( $this->page->getTouched() ) ) {
+ return; // Client cache fresh and headers sent, nothing more to do.
+ }
+
+ wfProfileIn( __METHOD__ );
+
+ if ( $request->getFullRequestURL() == $this->getTitle()->getInternalURL( 'action=history' ) ) {
+ $out->setSquidMaxage( $wgSquidMaxage );
+ }
+
+ $this->preCacheMessages();
+
+ # Fill in the file cache if not set already
+ if ( $wgUseFileCache && HTMLFileCache::useFileCache( $this->getContext() ) ) {
+ $cache = HTMLFileCache::newFromTitle( $this->getTitle(), 'history' );
+ if ( !$cache->isCacheGood( /* Assume up to date */ ) ) {
+ ob_start( array( &$cache, 'saveToFileCache' ) );
+ }
+ }
+
+ // Setup page variables.
+ $out->setFeedAppendQuery( 'action=history' );
+ $out->addModules( array( 'mediawiki.legacy.history', 'mediawiki.action.history' ) );
+
+ // Handle atom/RSS feeds.
+ $feedType = $request->getVal( 'feed' );
+ if ( $feedType ) {
+ wfProfileOut( __METHOD__ );
+ return $this->feed( $feedType );
+ }
+
+ // Fail nicely if article doesn't exist.
+ if ( !$this->page->exists() ) {
+ $out->addWikiMsg( 'nohistory' );
+ # show deletion/move log if there is an entry
+ LogEventsList::showLogExtract(
+ $out,
+ array( 'delete', 'move' ),
+ $this->getTitle(),
+ '',
+ array( 'lim' => 10,
+ 'conds' => array( "log_action != 'revision'" ),
+ 'showIfEmpty' => false,
+ 'msgKey' => array( 'moveddeleted-notice' )
+ )
+ );
+ wfProfileOut( __METHOD__ );
+ return;
+ }
+
+ /**
+ * Add date selector to quickly get to a certain time
+ */
+ $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'" );
+ } else {
+ $conds = array();
+ }
+ $checkDeleted = Xml::checkLabel( $this->msg( 'history-show-deleted' )->text(),
+ 'deleted', 'mw-show-deleted-only', $request->getBool( 'deleted' ) ) . "\n";
+
+ // Add the general form
+ $action = htmlspecialchars( $wgScript );
+ $out->addHTML(
+ "<form action=\"$action\" method=\"get\" id=\"mw-history-searchform\">" .
+ Xml::fieldset(
+ $this->msg( 'history-fieldset-title' )->text(),
+ false,
+ array( 'id' => 'mw-history-search' )
+ ) .
+ Html::hidden( 'title', $this->getTitle()->getPrefixedDBKey() ) . "\n" .
+ Html::hidden( 'action', 'history' ) . "\n" .
+ Xml::dateMenu( $year, $month ) . '&#160;' .
+ ( $tagSelector ? ( implode( '&#160;', $tagSelector ) . '&#160;' ) : '' ) .
+ $checkDeleted .
+ Xml::submitButton( $this->msg( 'allpagessubmit' )->text() ) . "\n" .
+ '</fieldset></form>'
+ );
+
+ wfRunHooks( 'PageHistoryBeforeList', array( &$this->page ) );
+
+ // Create and output the list.
+ $pager = new HistoryPager( $this, $year, $month, $tagFilter, $conds );
+ $out->addHTML(
+ $pager->getNavigationBar() .
+ $pager->getBody() .
+ $pager->getNavigationBar()
+ );
+ $out->preventClickjacking( $pager->getPreventClickjacking() );
+
+ wfProfileOut( __METHOD__ );
+ }
+
+ /**
+ * Fetch an array of revisions, specified by a given limit, offset and
+ * direction. This is now only used by the feeds. It was previously
+ * used by the main UI but that's now handled by the pager.
+ *
+ * @param $limit Integer: the limit number of revisions to get
+ * @param $offset Integer
+ * @param $direction Integer: either HistoryPage::DIR_PREV or HistoryPage::DIR_NEXT
+ * @return ResultWrapper
+ */
+ function fetchRevisions( $limit, $offset, $direction ) {
+ $dbr = wfGetDB( DB_SLAVE );
+
+ if ( $direction == HistoryPage::DIR_PREV ) {
+ list( $dirs, $oper ) = array( "ASC", ">=" );
+ } else { /* $direction == HistoryPage::DIR_NEXT */
+ list( $dirs, $oper ) = array( "DESC", "<=" );
+ }
+
+ if ( $offset ) {
+ $offsets = array( "rev_timestamp $oper '$offset'" );
+ } else {
+ $offsets = array();
+ }
+
+ $page_id = $this->page->getId();
+
+ return $dbr->select( 'revision',
+ Revision::selectFields(),
+ array_merge( array( "rev_page=$page_id" ), $offsets ),
+ __METHOD__,
+ array( 'ORDER BY' => "rev_timestamp $dirs",
+ 'USE INDEX' => 'page_timestamp', 'LIMIT' => $limit )
+ );
+ }
+
+ /**
+ * Output a subscription feed listing recent edits to this page.
+ *
+ * @param $type String: feed type
+ */
+ function feed( $type ) {
+ global $wgFeedClasses, $wgFeedLimit;
+ if ( !FeedUtils::checkFeedOutput( $type ) ) {
+ return;
+ }
+ $request = $this->getRequest();
+
+ $feed = new $wgFeedClasses[$type](
+ $this->getTitle()->getPrefixedText() . ' - ' .
+ wfMsgForContent( 'history-feed-title' ),
+ wfMsgForContent( 'history-feed-description' ),
+ $this->getTitle()->getFullUrl( 'action=history' )
+ );
+
+ // Get a limit on number of feed entries. Provide a sane default
+ // of 10 if none is defined (but limit to $wgFeedLimit max)
+ $limit = $request->getInt( 'limit', 10 );
+ if ( $limit > $wgFeedLimit || $limit < 1 ) {
+ $limit = 10;
+ }
+ $items = $this->fetchRevisions( $limit, 0, HistoryPage::DIR_NEXT );
+
+ // Generate feed elements enclosed between header and footer.
+ $feed->outHeader();
+ if ( $items->numRows() ) {
+ foreach ( $items as $row ) {
+ $feed->outItem( $this->feedItem( $row ) );
+ }
+ } else {
+ $feed->outItem( $this->feedEmpty() );
+ }
+ $feed->outFooter();
+ }
+
+ function feedEmpty() {
+ return new FeedItem(
+ wfMsgForContent( 'nohistory' ),
+ $this->getOutput()->parse( wfMsgForContent( 'history-feed-empty' ) ),
+ $this->getTitle()->getFullUrl(),
+ wfTimestamp( TS_MW ),
+ '',
+ $this->getTitle()->getTalkPage()->getFullUrl()
+ );
+ }
+
+ /**
+ * Generate a FeedItem object from a given revision table row
+ * Borrows Recent Changes' feed generation functions for formatting;
+ * includes a diff to the previous revision (if any).
+ *
+ * @param $row Object: database row
+ * @return FeedItem
+ */
+ function feedItem( $row ) {
+ $rev = new Revision( $row );
+ $rev->setTitle( $this->getTitle() );
+ $text = FeedUtils::formatDiffRow(
+ $this->getTitle(),
+ $this->getTitle()->getPreviousRevisionID( $rev->getId() ),
+ $rev->getId(),
+ $rev->getTimestamp(),
+ $rev->getComment()
+ );
+ if ( $rev->getComment() == '' ) {
+ global $wgContLang;
+ $title = wfMsgForContent( 'history-feed-item-nocomment',
+ $rev->getUserText(),
+ $wgContLang->timeanddate( $rev->getTimestamp() ),
+ $wgContLang->date( $rev->getTimestamp() ),
+ $wgContLang->time( $rev->getTimestamp() )
+ );
+ } else {
+ $title = $rev->getUserText() .
+ wfMsgForContent( 'colon-separator' ) .
+ FeedItem::stripComment( $rev->getComment() );
+ }
+ return new FeedItem(
+ $title,
+ $text,
+ $this->getTitle()->getFullUrl( 'diff=' . $rev->getId() . '&oldid=prev' ),
+ $rev->getTimestamp(),
+ $rev->getUserText(),
+ $this->getTitle()->getTalkPage()->getFullUrl()
+ );
+ }
+}
+
+/**
+ * @ingroup Pager
+ */
+class HistoryPager extends ReverseChronologicalPager {
+ public $lastRow = false, $counter, $historyPage, $buttons, $conds;
+ protected $oldIdChecked;
+ protected $preventClickjacking = false;
+
+ function __construct( $historyPage, $year = '', $month = '', $tagFilter = '', $conds = array() ) {
+ parent::__construct( $historyPage->getContext() );
+ $this->historyPage = $historyPage;
+ $this->tagFilter = $tagFilter;
+ $this->getDateCond( $year, $month );
+ $this->conds = $conds;
+ }
+
+ // For hook compatibility...
+ function getArticle() {
+ return $this->historyPage->getArticle();
+ }
+
+ function getSqlComment() {
+ if ( $this->conds ) {
+ return 'history page filtered'; // potentially slow, see CR r58153
+ } else {
+ return 'history page unfiltered';
+ }
+ }
+
+ function getQueryInfo() {
+ $queryInfo = array(
+ 'tables' => array( 'revision', 'user' ),
+ 'fields' => array_merge( Revision::selectFields(), Revision::selectUserFields() ),
+ 'conds' => array_merge(
+ array( 'rev_page' => $this->getWikiPage()->getId() ),
+ $this->conds ),
+ 'options' => array( 'USE INDEX' => array( 'revision' => 'page_timestamp' ) ),
+ 'join_conds' => array(
+ 'user' => Revision::userJoinCond(),
+ 'tag_summary' => array( 'LEFT JOIN', 'ts_rev_id=rev_id' ) ),
+ );
+ ChangeTags::modifyDisplayQuery(
+ $queryInfo['tables'],
+ $queryInfo['fields'],
+ $queryInfo['conds'],
+ $queryInfo['join_conds'],
+ $queryInfo['options'],
+ $this->tagFilter
+ );
+ wfRunHooks( 'PageHistoryPager::getQueryInfo', array( &$this, &$queryInfo ) );
+ return $queryInfo;
+ }
+
+ function getIndexField() {
+ return 'rev_timestamp';
+ }
+
+ function formatRow( $row ) {
+ if ( $this->lastRow ) {
+ $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 );
+ } else {
+ $s = '';
+ }
+ $this->lastRow = $row;
+ return $s;
+ }
+
+ function doBatchLookups() {
+ # Do a link batch query
+ $this->mResult->seek( 0 );
+ $batch = new LinkBatch();
+ foreach ( $this->mResult as $row ) {
+ if( !is_null( $row->user_name ) ) {
+ $batch->add( NS_USER, $row->user_name );
+ $batch->add( NS_USER_TALK, $row->user_name );
+ } else { # for anons or usernames of imported revisions
+ $batch->add( NS_USER, $row->rev_user_text );
+ $batch->add( NS_USER_TALK, $row->rev_user_text );
+ }
+ }
+ $batch->execute();
+ $this->mResult->seek( 0 );
+ }
+
+ /**
+ * Creates begin of history list with a submit button
+ *
+ * @return string HTML output
+ */
+ function getStartBody() {
+ global $wgScript;
+ $this->lastRow = false;
+ $this->counter = 1;
+ $this->oldIdChecked = 0;
+
+ $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( 'action', 'historysubmit' ) . "\n";
+
+ // Button container stored in $this->buttons for re-use in getEndBody()
+ $this->buttons = '<div>';
+ $this->buttons .= $this->submitButton( $this->msg( 'compareselectedversions' )->text(),
+ array( 'class' => 'historysubmit mw-history-compareselectedversions-button' )
+ + Linker::tooltipAndAccesskeyAttribs( 'compareselectedversions' )
+ ) . "\n";
+
+ if ( $this->getUser()->isAllowed( 'deleterevision' ) ) {
+ $this->buttons .= $this->getRevisionButton( 'revisiondelete', 'showhideselectedversions' );
+ }
+ $this->buttons .= '</div>';
+
+ $s .= $this->buttons;
+ $s .= '<ul id="pagehistory">' . "\n";
+ return $s;
+ }
+
+ private function getRevisionButton( $name, $msg ) {
+ $this->preventClickjacking();
+ # Note bug #20966, <button> is non-standard in IE<8
+ $element = Html::element( 'button',
+ array(
+ 'type' => 'submit',
+ 'name' => $name,
+ 'value' => '1',
+ 'class' => "historysubmit mw-history-$name-button",
+ ),
+ $this->msg( $msg )->text()
+ ) . "\n";
+ return $element;
+ }
+
+ function getEndBody() {
+ if ( $this->lastRow ) {
+ $latest = $this->counter == 1 && $this->mIsFirst;
+ $firstInList = $this->counter == 1;
+ if ( $this->mIsBackwards ) {
+ # Next row is unknown, but for UI reasons, probably exists if an offset has been specified
+ if ( $this->mOffset == '' ) {
+ $next = null;
+ } else {
+ $next = 'unknown';
+ }
+ } else {
+ # The next row is the past-the-end row
+ $next = $this->mPastTheEndRow;
+ }
+ $this->counter++;
+ $s = $this->historyLine( $this->lastRow, $next,
+ $this->getTitle()->getNotificationTimestamp( $this->getUser() ), $latest, $firstInList );
+ } else {
+ $s = '';
+ }
+ $s .= "</ul>\n";
+ # Add second buttons only if there is more than one rev
+ if ( $this->getNumRows() > 2 ) {
+ $s .= $this->buttons;
+ }
+ $s .= '</form>';
+ return $s;
+ }
+
+ /**
+ * Creates a submit button
+ *
+ * @param $message String: text of the submit button, will be escaped
+ * @param $attributes Array: 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 );
+ } else {
+ return '';
+ }
+ }
+
+ /**
+ * Returns a row from the history printout.
+ *
+ * @todo document some more, and maybe clean up the code (some params redundant?)
+ *
+ * @param $row Object: the database row corresponding to the previous line.
+ * @param $next Mixed: the database row corresponding to the next line. (chronologically previous)
+ * @param $notificationtimestamp
+ * @param $latest Boolean: whether this row corresponds to the page's latest revision.
+ * @param $firstInList Boolean: whether this row corresponds to the first displayed on this history page.
+ * @return String: HTML output for the row
+ */
+ function historyLine( $row, $next, $notificationtimestamp = false,
+ $latest = false, $firstInList = false )
+ {
+ $rev = new Revision( $row );
+ $rev->setTitle( $this->getTitle() );
+
+ if ( is_object( $next ) ) {
+ $prevRev = new Revision( $next );
+ $prevRev->setTitle( $this->getTitle() );
+ } else {
+ $prevRev = null;
+ }
+
+ $curlink = $this->curLink( $rev, $latest );
+ $lastlink = $this->lastLink( $rev, $next );
+ $diffButtons = $this->diffButtons( $rev, $firstInList );
+ $histLinks = Html::rawElement(
+ 'span',
+ array( 'class' => 'mw-history-histlinks' ),
+ '(' . $curlink . $this->historyPage->message['pipe-separator'] . $lastlink . ') '
+ );
+ $s = $histLinks . $diffButtons;
+
+ $link = $this->revLink( $rev );
+ $classes = array();
+
+ $del = '';
+ $user = $this->getUser();
+ // Show checkboxes for each revision
+ if ( $user->isAllowed( 'deleterevision' ) ) {
+ $this->preventClickjacking();
+ // If revision was hidden from sysops, disable the checkbox
+ if ( !$rev->userCan( Revision::DELETED_RESTRICTED, $user ) ) {
+ $del = Xml::check( 'deleterevisions', false, array( 'disabled' => 'disabled' ) );
+ // Otherwise, enable the checkbox...
+ } else {
+ $del = Xml::check( 'showhiderevisions', false,
+ array( 'name' => 'ids[' . $rev->getId() . ']' ) );
+ }
+ // User can only view deleted revisions...
+ } 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 );
+ // Otherwise, show the link...
+ } else {
+ $query = array( 'type' => 'revision',
+ 'target' => $this->getTitle()->getPrefixedDbkey(), 'ids' => $rev->getId() );
+ $del .= Linker::revDeleteLink( $query,
+ $rev->isDeleted( Revision::DELETED_RESTRICTED ), false );
+ }
+ }
+ if ( $del ) {
+ $s .= " $del ";
+ }
+
+ $lang = $this->getLanguage();
+ $dirmark = $lang->getDirMark();
+
+ $s .= " $link";
+ $s .= $dirmark;
+ $s .= " <span class='history-user'>" .
+ Linker::revUserTools( $rev, true ) . "</span>";
+ $s .= $dirmark;
+
+ if ( $rev->isMinor() ) {
+ $s .= ' ' . ChangesList::flag( 'minor' );
+ }
+
+ # Size is always public data
+ $prevSize = $prevRev ? $prevRev->getSize() : 0;
+ $sDiff = ChangesList::showCharacterDifference( $prevSize, $rev->getSize() );
+ $s .= ' . . ' . $sDiff . ' . . ';
+
+ $s .= Linker::revComment( $rev, false, true );
+
+ if ( $notificationtimestamp && ( $row->rev_timestamp >= $notificationtimestamp ) ) {
+ $s .= ' <span class="updatedmarker">' . $this->msg( 'updatedmarker' )->escaped() . '</span>';
+ }
+
+ $tools = array();
+
+ # Rollback and undo links
+ if ( $prevRev &&
+ !count( $this->getTitle()->getUserPermissionsErrors( 'edit', $this->getUser() ) ) )
+ {
+ if ( $latest && !count( $this->getTitle()->getUserPermissionsErrors( 'rollback', $this->getUser() ) ) ) {
+ $this->preventClickjacking();
+ $tools[] = '<span class="mw-rollback-link">' .
+ Linker::buildRollbackLink( $rev ) . '</span>';
+ }
+
+ if ( !$rev->isDeleted( Revision::DELETED_TEXT )
+ && !$prevRev->isDeleted( Revision::DELETED_TEXT ) )
+ {
+ # Create undo tooltip for the first (=latest) line only
+ $undoTooltip = $latest
+ ? array( 'title' => $this->msg( 'tooltip-undo' )->text() )
+ : array();
+ $undolink = Linker::linkKnown(
+ $this->getTitle(),
+ $this->msg( 'editundo' )->escaped(),
+ $undoTooltip,
+ array(
+ 'action' => 'edit',
+ 'undoafter' => $prevRev->getId(),
+ 'undo' => $rev->getId()
+ )
+ );
+ $tools[] = "<span class=\"mw-history-undo\">{$undolink}</span>";
+ }
+ }
+
+ if ( $tools ) {
+ $s .= ' (' . $lang->pipeList( $tools ) . ')';
+ }
+
+ # Tags
+ list( $tagSummary, $newClasses ) = ChangeTags::formatSummaryRow( $row->ts_tags, 'history' );
+ $classes = array_merge( $classes, $newClasses );
+ $s .= " $tagSummary";
+
+ wfRunHooks( 'PageHistoryLineEnding', array( $this, &$row , &$s, &$classes ) );
+
+ $attribs = array();
+ if ( $classes ) {
+ $attribs['class'] = implode( ' ', $classes );
+ }
+
+ return Xml::tags( 'li', $attribs, $s ) . "\n";
+ }
+
+ /**
+ * Create a link to view this revision of the page
+ *
+ * @param $rev Revision
+ * @return String
+ */
+ function revLink( $rev ) {
+ $date = $this->getLanguage()->userTimeAndDate( $rev->getTimestamp(), $this->getUser() );
+ $date = htmlspecialchars( $date );
+ if ( $rev->userCan( Revision::DELETED_TEXT, $this->getUser() ) ) {
+ $link = Linker::linkKnown(
+ $this->getTitle(),
+ $date,
+ array(),
+ array( 'oldid' => $rev->getId() )
+ );
+ } else {
+ $link = $date;
+ }
+ if ( $rev->isDeleted( Revision::DELETED_TEXT ) ) {
+ $link = "<span class=\"history-deleted\">$link</span>";
+ }
+ return $link;
+ }
+
+ /**
+ * Create a diff-to-current link for this revision for this page
+ *
+ * @param $rev Revision
+ * @param $latest Boolean: this is the latest revision of the page?
+ * @return String
+ */
+ function curLink( $rev, $latest ) {
+ $cur = $this->historyPage->message['cur'];
+ if ( $latest || !$rev->userCan( Revision::DELETED_TEXT, $this->getUser() ) ) {
+ return $cur;
+ } else {
+ return Linker::linkKnown(
+ $this->getTitle(),
+ $cur,
+ array(),
+ array(
+ 'diff' => $this->getWikiPage()->getLatest(),
+ 'oldid' => $rev->getId()
+ )
+ );
+ }
+ }
+
+ /**
+ * Create a diff-to-previous link for this revision for this page.
+ *
+ * @param $prevRev Revision: the previous revision
+ * @param $next Mixed: the newer revision
+ * @return String
+ */
+ function lastLink( $prevRev, $next ) {
+ $last = $this->historyPage->message['last'];
+ # $next may either be a Row, null, or "unkown"
+ $nextRev = is_object( $next ) ? new Revision( $next ) : $next;
+ if ( is_null( $next ) ) {
+ # Probably no next row
+ return $last;
+ } elseif ( $next === 'unknown' ) {
+ # Next row probably exists but is unknown, use an oldid=prev link
+ return Linker::linkKnown(
+ $this->getTitle(),
+ $last,
+ array(),
+ array(
+ 'diff' => $prevRev->getId(),
+ 'oldid' => 'prev'
+ )
+ );
+ } elseif ( !$prevRev->userCan( Revision::DELETED_TEXT, $this->getUser() )
+ || !$nextRev->userCan( Revision::DELETED_TEXT, $this->getUser() ) )
+ {
+ return $last;
+ } else {
+ return Linker::linkKnown(
+ $this->getTitle(),
+ $last,
+ array(),
+ array(
+ 'diff' => $prevRev->getId(),
+ 'oldid' => $next->rev_id
+ )
+ );
+ }
+ }
+
+ /**
+ * Create radio buttons for page history
+ *
+ * @param $rev Revision object
+ * @param $firstInList Boolean: is this version the first one?
+ *
+ * @return String: HTML output for the radio buttons
+ */
+ function diffButtons( $rev, $firstInList ) {
+ if ( $this->getNumRows() > 1 ) {
+ $id = $rev->getId();
+ $radio = array( 'type' => 'radio', 'value' => $id );
+ /** @todo: move title texts to javascript */
+ if ( $firstInList ) {
+ $first = Xml::element( 'input',
+ array_merge( $radio, array(
+ 'style' => 'visibility:hidden',
+ 'name' => 'oldid',
+ 'id' => 'mw-oldid-null' ) )
+ );
+ $checkmark = array( 'checked' => 'checked' );
+ } else {
+ # Check visibility of old revisions
+ if ( !$rev->userCan( Revision::DELETED_TEXT, $this->getUser() ) ) {
+ $radio['disabled'] = 'disabled';
+ $checkmark = array(); // We will check the next possible one
+ } elseif ( !$this->oldIdChecked ) {
+ $checkmark = array( 'checked' => 'checked' );
+ $this->oldIdChecked = $id;
+ } else {
+ $checkmark = array();
+ }
+ $first = Xml::element( 'input',
+ array_merge( $radio, $checkmark, array(
+ 'name' => 'oldid',
+ 'id' => "mw-oldid-$id" ) ) );
+ $checkmark = array();
+ }
+ $second = Xml::element( 'input',
+ array_merge( $radio, $checkmark, array(
+ 'name' => 'diff',
+ 'id' => "mw-diff-$id" ) ) );
+ return $first . $second;
+ } else {
+ return '';
+ }
+ }
+
+ /**
+ * This is called if a write operation is possible from the generated HTML
+ */
+ function preventClickjacking( $enable = true ) {
+ $this->preventClickjacking = $enable;
+ }
+
+ /**
+ * Get the "prevent clickjacking" flag
+ */
+ function getPreventClickjacking() {
+ return $this->preventClickjacking;
+ }
+}
+
+/**
+ * Backwards-compatibility alias
+ */
+class HistoryPage extends HistoryAction {
+ public function __construct( Page $article ) { # Just to make it public
+ parent::__construct( $article );
+ }
+
+ public function history() {
+ $this->onView();
+ }
+}
diff --git a/includes/actions/InfoAction.php b/includes/actions/InfoAction.php
index b0b5f259..70edabce 100644
--- a/includes/actions/InfoAction.php
+++ b/includes/actions/InfoAction.php
@@ -29,10 +29,6 @@ class InfoAction extends FormlessAction {
return 'info';
}
- public function getRestriction() {
- return 'read';
- }
-
protected function getDescription() {
return '';
}
@@ -46,7 +42,7 @@ class InfoAction extends FormlessAction {
}
protected function getPageTitle() {
- return wfMsg( 'pageinfo-title', $this->getTitle()->getSubjectPage()->getPrefixedText() );
+ return $this->msg( 'pageinfo-title', $this->getTitle()->getSubjectPage()->getPrefixedText() )->text();
}
public function onView() {
@@ -60,44 +56,44 @@ class InfoAction extends FormlessAction {
return Html::rawElement( 'table', array( 'class' => 'wikitable mw-page-info' ),
Html::rawElement( 'tr', array(),
Html::element( 'th', array(), '' ) .
- Html::element( 'th', array(), wfMsg( 'pageinfo-subjectpage' ) ) .
- Html::element( 'th', array(), wfMsg( 'pageinfo-talkpage' ) )
+ Html::element( 'th', array(), $this->msg( 'pageinfo-subjectpage' )->text() ) .
+ Html::element( 'th', array(), $this->msg( 'pageinfo-talkpage' )->text() )
) .
Html::rawElement( 'tr', array(),
- Html::element( 'th', array( 'colspan' => 3 ), wfMsg( 'pageinfo-header-edits' ) )
+ Html::element( 'th', array( 'colspan' => 3 ), $this->msg( 'pageinfo-header-edits' )->text() )
) .
Html::rawElement( 'tr', array(),
- Html::element( 'td', array(), wfMsg( 'pageinfo-edits' ) ) .
- Html::element( 'td', array(), $this->getLang()->formatNum( $pageInfo['edits'] ) ) .
- Html::element( 'td', array(), $this->getLang()->formatNum( $talkInfo['edits'] ) )
+ Html::element( 'td', array(), $this->msg( 'pageinfo-edits' )->text() ) .
+ Html::element( 'td', array(), $this->getLanguage()->formatNum( $pageInfo['edits'] ) ) .
+ Html::element( 'td', array(), $this->getLanguage()->formatNum( $talkInfo['edits'] ) )
) .
Html::rawElement( 'tr', array(),
- Html::element( 'td', array(), wfMsg( 'pageinfo-authors' ) ) .
- Html::element( 'td', array(), $this->getLang()->formatNum( $pageInfo['authors'] ) ) .
- Html::element( 'td', array(), $this->getLang()->formatNum( $talkInfo['authors'] ) )
+ Html::element( 'td', array(), $this->msg( 'pageinfo-authors' )->text() ) .
+ Html::element( 'td', array(), $this->getLanguage()->formatNum( $pageInfo['authors'] ) ) .
+ Html::element( 'td', array(), $this->getLanguage()->formatNum( $talkInfo['authors'] ) )
) .
( !$this->getUser()->isAllowed( 'unwatchedpages' ) ? '' :
Html::rawElement( 'tr', array(),
- Html::element( 'th', array( 'colspan' => 3 ), wfMsg( 'pageinfo-header-watchlist' ) )
+ Html::element( 'th', array( 'colspan' => 3 ), $this->msg( 'pageinfo-header-watchlist' )->text() )
) .
Html::rawElement( 'tr', array(),
- Html::element( 'td', array(), wfMsg( 'pageinfo-watchers' ) ) .
- Html::element( 'td', array( 'colspan' => 2 ), $this->getLang()->formatNum( $pageInfo['watchers'] ) )
+ Html::element( 'td', array(), $this->msg( 'pageinfo-watchers' )->text() ) .
+ Html::element( 'td', array( 'colspan' => 2 ), $this->getLanguage()->formatNum( $pageInfo['watchers'] ) )
)
).
( $wgDisableCounters ? '' :
Html::rawElement( 'tr', array(),
- Html::element( 'th', array( 'colspan' => 3 ), wfMsg( 'pageinfo-header-views' ) )
+ Html::element( 'th', array( 'colspan' => 3 ), $this->msg( 'pageinfo-header-views' )->text() )
) .
Html::rawElement( 'tr', array(),
- Html::element( 'td', array(), wfMsg( 'pageinfo-views' ) ) .
- Html::element( 'td', array(), $this->getLang()->formatNum( $pageInfo['views'] ) ) .
- Html::element( 'td', array(), $this->getLang()->formatNum( $talkInfo['views'] ) )
+ Html::element( 'td', array(), $this->msg( 'pageinfo-views' )->text() ) .
+ Html::element( 'td', array(), $this->getLanguage()->formatNum( $pageInfo['views'] ) ) .
+ Html::element( 'td', array(), $this->getLanguage()->formatNum( $talkInfo['views'] ) )
) .
Html::rawElement( 'tr', array(),
- Html::element( 'td', array(), wfMsg( 'pageinfo-viewsperedit' ) ) .
- Html::element( 'td', array(), $this->getLang()->formatNum( sprintf( '%.2f', $pageInfo['edits'] ? $pageInfo['views'] / $pageInfo['edits'] : 0 ) ) ) .
- Html::element( 'td', array(), $this->getLang()->formatNum( sprintf( '%.2f', $talkInfo['edits'] ? $talkInfo['views'] / $talkInfo['edits'] : 0 ) ) )
+ Html::element( 'td', array(), $this->msg( 'pageinfo-viewsperedit' )->text() ) .
+ Html::element( 'td', array(), $this->getLanguage()->formatNum( sprintf( '%.2f', $pageInfo['edits'] ? $pageInfo['views'] / $pageInfo['edits'] : 0 ) ) ) .
+ Html::element( 'td', array(), $this->getLanguage()->formatNum( sprintf( '%.2f', $talkInfo['edits'] ? $talkInfo['views'] / $talkInfo['edits'] : 0 ) ) )
)
)
);
diff --git a/includes/actions/MarkpatrolledAction.php b/includes/actions/MarkpatrolledAction.php
index a5d76627..ae9223f4 100644
--- a/includes/actions/MarkpatrolledAction.php
+++ b/includes/actions/MarkpatrolledAction.php
@@ -28,30 +28,25 @@ class MarkpatrolledAction extends FormlessAction {
return 'markpatrolled';
}
- public function getRestriction() {
- return 'read';
- }
-
protected function getDescription() {
return '';
}
- protected function checkCanExecute( User $user ) {
- if ( !$user->matchEditToken( $this->getRequest()->getVal( 'token' ), $this->getRequest()->getInt( 'rcid' ) ) ) {
- throw new ErrorPageError( 'sessionfailure-title', 'sessionfailure' );
- }
-
- return parent::checkCanExecute( $user );
- }
-
public function onView() {
- $rc = RecentChange::newFromId( $this->getRequest()->getInt( 'rcid' ) );
+ $request = $this->getRequest();
+ $rcId = $request->getInt( 'rcid' );
+ $rc = RecentChange::newFromId( $rcId );
if ( is_null( $rc ) ) {
throw new ErrorPageError( 'markedaspatrollederror', 'markedaspatrollederrortext' );
}
- $errors = $rc->doMarkPatrolled( $this->getUser() );
+ $user = $this->getUser();
+ if ( !$user->matchEditToken( $request->getVal( 'token' ), $rcId ) ) {
+ throw new ErrorPageError( 'sessionfailure-title', 'sessionfailure' );
+ }
+
+ $errors = $rc->doMarkPatrolled( $user );
if ( in_array( array( 'rcpatroldisabled' ), $errors ) ) {
throw new ErrorPageError( 'rcpatroldisabled', 'rcpatroldisabledtext' );
@@ -67,19 +62,18 @@ class MarkpatrolledAction extends FormlessAction {
$return = SpecialPage::getTitleFor( $returnto );
if ( in_array( array( 'markedaspatrollederror-noautopatrol' ), $errors ) ) {
- $this->getOutput()->setPageTitle( wfMsg( 'markedaspatrollederror' ) );
+ $this->getOutput()->setPageTitle( $this->msg( 'markedaspatrollederror' ) );
$this->getOutput()->addWikiMsg( 'markedaspatrollederror-noautopatrol' );
$this->getOutput()->returnToMain( null, $return );
return;
}
- if ( !empty( $errors ) ) {
- $this->getOutput()->showPermissionsErrorPage( $errors );
- return;
+ if ( count( $errors ) ) {
+ throw new PermissionsError( 'patrol', $errors );
}
# Inform the user
- $this->getOutput()->setPageTitle( wfMsg( 'markedaspatrolled' ) );
+ $this->getOutput()->setPageTitle( $this->msg( 'markedaspatrolled' ) );
$this->getOutput()->addWikiMsg( 'markedaspatrolledtext', $rc->getTitle()->getPrefixedText() );
$this->getOutput()->returnToMain( null, $return );
}
diff --git a/includes/actions/ProtectAction.php b/includes/actions/ProtectAction.php
new file mode 100644
index 00000000..f053ede7
--- /dev/null
+++ b/includes/actions/ProtectAction.php
@@ -0,0 +1,56 @@
+<?php
+/**
+ * action=protect handler
+ *
+ * Copyright © 2012 Timo Tijhof
+ *
+ * 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
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * @file
+ * @ingroup Actions
+ * @author Timo Tijhof
+ */
+
+class ProtectAction extends FormlessAction {
+
+ public function getName() {
+ return 'protect';
+ }
+
+ public function onView(){
+ return null;
+ }
+
+ public function show(){
+
+ $this->page->protect();
+
+ }
+
+}
+
+class UnprotectAction extends ProtectAction {
+
+ public function getName() {
+ return 'unprotect';
+ }
+
+ public function show(){
+
+ $this->page->unprotect();
+
+ }
+
+}
diff --git a/includes/actions/PurgeAction.php b/includes/actions/PurgeAction.php
index 29cbf3ae..21a6d904 100644
--- a/includes/actions/PurgeAction.php
+++ b/includes/actions/PurgeAction.php
@@ -31,10 +31,6 @@ class PurgeAction extends FormAction {
return 'purge';
}
- public function getRestriction() {
- return null;
- }
-
public function requiresUnblock() {
return false;
}
@@ -52,8 +48,7 @@ class PurgeAction extends FormAction {
}
public function onSubmit( $data ) {
- $this->page->doPurge();
- return true;
+ return $this->page->doPurge();
}
/**
@@ -71,8 +66,9 @@ class PurgeAction extends FormAction {
$this->getRequest()->getQueryValues(),
array( 'title' => null, 'action' => null )
) );
- $this->onSubmit( array() );
- $this->onSuccess();
+ if( $this->onSubmit( array() ) ) {
+ $this->onSuccess();
+ }
} else {
$this->redirectParams = $this->getRequest()->getVal( 'redirectparams', '' );
$form = $this->getForm();
diff --git a/includes/actions/RawAction.php b/includes/actions/RawAction.php
new file mode 100644
index 00000000..e4c6b3e0
--- /dev/null
+++ b/includes/actions/RawAction.php
@@ -0,0 +1,239 @@
+<?php
+/**
+ * Raw page text accessor
+ *
+ * Copyright © 2004 Gabriel Wicke <wicke@wikidev.net>
+ * http://wikidev.net/
+ *
+ * Based on HistoryPage and SpecialExport
+ *
+ * License: GPL (http://www.gnu.org/copyleft/gpl.html)
+ *
+ * @author Gabriel Wicke <wicke@wikidev.net>
+ * @file
+ */
+
+/**
+ * A simple method to retrieve the plain source of an article,
+ * using "action=raw" in the GET request string.
+ */
+class RawAction extends FormlessAction {
+ private $mGen;
+
+ public function getName() {
+ return 'raw';
+ }
+
+ public function requiresWrite() {
+ return false;
+ }
+
+ public function requiresUnblock() {
+ return false;
+ }
+
+ function onView() {
+ global $wgGroupPermissions, $wgSquidMaxage, $wgForcedRawSMaxage, $wgJsMimeType;
+
+ $this->getOutput()->disable();
+ $request = $this->getRequest();
+
+ if ( !$request->checkUrlExtension() ) {
+ return;
+ }
+
+ if ( $this->getOutput()->checkLastModified( $this->page->getTouched() ) ) {
+ 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->mGen = $gen;
+ if ( $smaxage === null ) {
+ $smaxage = $wgSquidMaxage;
+ }
+ } else {
+ $this->mGen = false;
+ }
+
+ $contentType = $this->getContentType();
+
+ # Force caching for CSS and JS raw content, default: 5 minutes
+ if ( $smaxage === null ) {
+ if ( $contentType == 'text/css' || $contentType == $wgJsMimeType ) {
+ $smaxage = intval( $wgForcedRawSMaxage );
+ } else {
+ $smaxage = 0;
+ }
+ }
+
+ $maxage = $request->getInt( 'maxage', $wgSquidMaxage );
+
+ $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
+ $privateCache = !$wgGroupPermissions['*']['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 );
+
+ $text = $this->getRawText();
+
+ 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' );
+ }
+
+ if ( !wfRunHooks( 'RawPageViewBeforeOutput', array( &$this, &$text ) ) ) {
+ wfDebug( __METHOD__ . ": RawPageViewBeforeOutput hook broke raw page output.\n" );
+ }
+
+ echo $text;
+ }
+
+ /**
+ * Get the text that should be returned, or false if the page or revision
+ * was not found.
+ *
+ * @return String|Bool
+ */
+ public function getRawText() {
+ global $wgParser;
+
+ # No longer used
+ if( $this->mGen ) {
+ return '';
+ }
+
+ $text = false;
+ $title = $this->getTitle();
+ $request = $this->getRequest();
+
+ // If it's a MediaWiki message we can just hit the message cache
+ if ( $request->getBool( 'usemsgcache' ) && $title->getNamespace() == NS_MEDIAWIKI ) {
+ $key = $title->getDBkey();
+ $msg = wfMessage( $key )->inContentLanguage();
+ # If the message doesn't exist, return a blank
+ $text = !$msg->exists() ? '' : $msg->plain();
+ } else {
+ // Get it from the DB
+ $rev = Revision::newFromTitle( $title, $this->getOldId() );
+ if ( $rev ) {
+ $lastmod = wfTimestamp( TS_RFC2822, $rev->getTimestamp() );
+ $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 );
+ }
+ }
+ }
+
+ if ( $text !== false && $text !== '' && $request->getVal( 'templates' ) === 'expand' ) {
+ $text = $wgParser->preprocess( $text, $title, ParserOptions::newFromContext( $this->getContext() ) );
+ }
+
+ return $text;
+ }
+
+ /**
+ * Get the ID of the revision that should used to get the text.
+ *
+ * @return Integer
+ */
+ public function getOldId() {
+ $oldid = $this->getRequest()->getInt( 'oldid' );
+ switch ( $this->getRequest()->getText( 'direction' ) ) {
+ case 'next':
+ # output next revision, or nothing if there isn't one
+ if( $oldid ) {
+ $oldid = $this->getTitle()->getNextRevisionId( $oldid );
+ }
+ $oldid = $oldid ? $oldid : -1;
+ break;
+ case 'prev':
+ # output previous revision, or nothing if there isn't one
+ if( !$oldid ) {
+ # get the current revision so we can get the penultimate one
+ $oldid = $this->page->getLatest();
+ }
+ $prev = $this->getTitle()->getPreviousRevisionId( $oldid );
+ $oldid = $prev ? $prev : -1 ;
+ break;
+ case 'cur':
+ $oldid = 0;
+ break;
+ }
+ return $oldid;
+ }
+
+ /**
+ * Get the content type to use for the response
+ *
+ * @return String
+ */
+ public function getContentType() {
+ global $wgJsMimeType;
+
+ $ctype = $this->getRequest()->getVal( 'ctype' );
+
+ if ( $ctype == '' ) {
+ $gen = $this->getRequest()->getVal( 'gen' );
+ if ( $gen == 'js' ) {
+ $ctype = $wgJsMimeType;
+ } elseif ( $gen == 'css' ) {
+ $ctype = 'text/css';
+ }
+ }
+
+ $allowedCTypes = array( 'text/x-wiki', $wgJsMimeType, 'text/css', 'application/x-zope-edit' );
+ if ( $ctype == '' || !in_array( $ctype, $allowedCTypes ) ) {
+ $ctype = 'text/x-wiki';
+ }
+
+ return $ctype;
+ }
+}
+
+/**
+ * Backward compatibility for extensions
+ *
+ * @deprecated in 1.19
+ */
+class RawPage extends RawAction {
+ public $mOldId;
+
+ function __construct( Page $page, $request = false ) {
+ wfDeprecated( __CLASS__, '1.19' );
+ parent::__construct( $page );
+
+ if ( $request !== false ) {
+ $context = new DerivativeContext( $this->getContext() );
+ $context->setRequest( $request );
+ $this->context = $context;
+ }
+ }
+
+ public function view() {
+ $this->onView();
+ }
+
+ public function getOldId() {
+ # Some extensions like to set $mOldId
+ if ( $this->mOldId !== null ) {
+ return $this->mOldId;
+ }
+ return parent::getOldId();
+ }
+}
diff --git a/includes/actions/RenderAction.php b/includes/actions/RenderAction.php
new file mode 100644
index 00000000..80af79cc
--- /dev/null
+++ b/includes/actions/RenderAction.php
@@ -0,0 +1,42 @@
+<?php
+/**
+ * Handle action=render
+ *
+ * Copyright © 2012 Timo Tijhof
+ *
+ * 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
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * @file
+ * @ingroup Actions
+ * @author Timo Tijhof
+ */
+
+class RenderAction extends FormlessAction {
+
+ public function getName() {
+ return 'render';
+ }
+
+ public function onView(){
+ return null;
+ }
+
+ public function show(){
+
+ $this->page->render();
+
+ }
+
+}
diff --git a/includes/actions/RevertAction.php b/includes/actions/RevertAction.php
index bcb8cd8b..f9497f4b 100644
--- a/includes/actions/RevertAction.php
+++ b/includes/actions/RevertAction.php
@@ -17,7 +17,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*
* @file
- * @ingroup Action
+ * @ingroup Actions
* @ingroup Media
* @author Alexandre Emsenhuber
* @author Rob Church <robchur@gmail.com>
@@ -26,7 +26,7 @@
/**
* Dummy class for pages not in NS_FILE
*
- * @ingroup Action
+ * @ingroup Actions
*/
class RevertAction extends Action {
@@ -34,10 +34,6 @@ class RevertAction extends Action {
return 'revert';
}
- public function getRestriction() {
- return 'read';
- }
-
public function show() {
$this->getOutput()->showErrorPage( 'nosuchaction', 'nosuchactiontext' );
}
@@ -48,7 +44,7 @@ class RevertAction extends Action {
/**
* Class for pages in NS_FILE
*
- * @ingroup Action
+ * @ingroup Actions
*/
class RevertFileAction extends FormAction {
protected $oldFile;
@@ -95,7 +91,7 @@ class RevertFileAction extends FormAction {
'vertical-label' => true,
'raw' => true,
'default' => wfMsgExt( 'filerevert-intro', 'parse', $this->getTitle()->getText(),
- $this->getLang()->date( $timestamp, true ), $this->getLang()->time( $timestamp, true ),
+ $this->getLanguage()->date( $timestamp, true ), $this->getLanguage()->time( $timestamp, true ),
wfExpandUrl( $this->page->getFile()->getArchiveUrl( $this->getRequest()->getText( 'oldimage' ) ),
PROTO_CURRENT
) )
@@ -119,8 +115,8 @@ class RevertFileAction extends FormAction {
public function onSuccess() {
$timestamp = $this->oldFile->getTimestamp();
$this->getOutput()->addHTML( wfMsgExt( 'filerevert-success', 'parse', $this->getTitle()->getText(),
- $this->getLang()->date( $timestamp, true ),
- $this->getLang()->time( $timestamp, true ),
+ $this->getLanguage()->date( $timestamp, true ),
+ $this->getLanguage()->time( $timestamp, true ),
wfExpandUrl( $this->page->getFile()->getArchiveUrl( $this->getRequest()->getText( 'oldimage' ) ),
PROTO_CURRENT
) ) );
@@ -132,9 +128,7 @@ class RevertFileAction extends FormAction {
}
protected function getDescription() {
- return wfMsg(
- 'filerevert-backlink',
- Linker::linkKnown( $this->getTitle() )
- );
+ $this->getOutput()->addBacklinkSubtitle( $this->getTitle() );
+ return '';
}
}
diff --git a/includes/actions/RevisiondeleteAction.php b/includes/actions/RevisiondeleteAction.php
index 2ac03d18..f07e493d 100644
--- a/includes/actions/RevisiondeleteAction.php
+++ b/includes/actions/RevisiondeleteAction.php
@@ -29,10 +29,6 @@ class RevisiondeleteAction extends FormlessAction {
return 'revisiondelete';
}
- public function getRestriction() {
- return null;
- }
-
public function requiresUnblock() {
return false;
}
diff --git a/includes/actions/RollbackAction.php b/includes/actions/RollbackAction.php
index 9036ebf5..ebb34c78 100644
--- a/includes/actions/RollbackAction.php
+++ b/includes/actions/RollbackAction.php
@@ -17,13 +17,13 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*
* @file
- * @ingroup Action
+ * @ingroup Actions
*/
/**
* User interface for the rollback action
*
- * @ingroup Action
+ * @ingroup Actions
*/
class RollbackAction extends FormlessAction {
@@ -54,7 +54,7 @@ class RollbackAction extends FormlessAction {
}
if ( isset( $result[0][0] ) && ( $result[0][0] == 'alreadyrolled' || $result[0][0] == 'cantrollback' ) ) {
- $this->getOutput()->setPageTitle( wfMsg( 'rollbackfailed' ) );
+ $this->getOutput()->setPageTitle( $this->msg( 'rollbackfailed' ) );
$errArray = $result[0];
$errMsg = array_shift( $errArray );
$this->getOutput()->addWikiMsgArray( $errMsg, $errArray );
@@ -83,9 +83,7 @@ class RollbackAction extends FormlessAction {
$out [] = $error;
}
}
- $this->getOutput()->showPermissionsErrorPage( $out );
-
- return;
+ throw new PermissionsError( 'rollback', $out );
}
if ( $result == array( array( 'readonlytext' ) ) ) {
@@ -95,7 +93,7 @@ class RollbackAction extends FormlessAction {
$current = $details['current'];
$target = $details['target'];
$newId = $details['newid'];
- $this->getOutput()->setPageTitle( wfMsg( 'actioncomplete' ) );
+ $this->getOutput()->setPageTitle( $this->msg( 'actioncomplete' ) );
$this->getOutput()->setRobotPolicy( 'noindex,nofollow' );
if ( $current->getUserText() === '' ) {
@@ -111,7 +109,7 @@ class RollbackAction extends FormlessAction {
$this->getOutput()->returnToMain( false, $this->getTitle() );
if ( !$request->getBool( 'hidediff', false ) && !$this->getUser()->getBoolOption( 'norollbackdiff', false ) ) {
- $de = new DifferenceEngine( $this->getTitle(), $current->getId(), $newId, false, true );
+ $de = new DifferenceEngine( $this->getContext(), $current->getId(), $newId, false, true );
$de->showDiff( '', '' );
}
}
diff --git a/includes/actions/ViewAction.php b/includes/actions/ViewAction.php
new file mode 100644
index 00000000..4e37381b
--- /dev/null
+++ b/includes/actions/ViewAction.php
@@ -0,0 +1,43 @@
+<?php
+/**
+ * An action that views article content
+ *
+ * Copyright © 2012 Timo Tijhof
+ *
+ * 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
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * @file
+ * @ingroup Actions
+ * @author Timo Tijhof
+ */
+
+class ViewAction extends FormlessAction {
+
+ public function getName() {
+ return 'view';
+ }
+
+ public function onView(){
+ return null;
+ }
+
+ public function show(){
+ global $wgSquidMaxage;
+
+ $this->getOutput()->setSquidMaxage( $wgSquidMaxage );
+ $this->page->view();
+ }
+
+}
diff --git a/includes/actions/WatchAction.php b/includes/actions/WatchAction.php
index 52e66754..63d9b151 100644
--- a/includes/actions/WatchAction.php
+++ b/includes/actions/WatchAction.php
@@ -26,16 +26,12 @@ class WatchAction extends FormAction {
return 'watch';
}
- public function getRestriction() {
- return 'read';
- }
-
public function requiresUnblock() {
return false;
}
protected function getDescription() {
- return wfMsg( 'addwatch' );
+ return wfMsgHtml( 'addwatch' );
}
/**
@@ -87,7 +83,7 @@ class WatchAction extends FormAction {
}
public static function doWatch( Title $title, User $user ) {
- $page = new Article( $title, 0 );
+ $page = WikiPage::factory( $title );
if ( wfRunHooks( 'WatchArticle', array( &$user, &$page ) ) ) {
$user->addWatch( $title );
@@ -97,7 +93,7 @@ class WatchAction extends FormAction {
}
public static function doUnwatch( Title $title, User $user ) {
- $page = new Article( $title, 0 );
+ $page = WikiPage::factory( $title );
if ( wfRunHooks( 'UnwatchArticle', array( &$user, &$page ) ) ) {
$user->removeWatch( $title );
@@ -110,7 +106,7 @@ class WatchAction extends FormAction {
* Get token to watch (or unwatch) a page for a user
*
* @param Title $title Title object of page to watch
- * @param User $title User for whom the action is going to be performed
+ * @param User $user User for whom the action is going to be performed
* @param string $action Optionally override the action to 'unwatch'
* @return string Token
* @since 1.18
@@ -123,14 +119,14 @@ class WatchAction extends FormAction {
// This token stronger salted and not compatible with ApiWatch
// It's title/action specific because index.php is GET and API is POST
- return $user->editToken( $salt );
+ return $user->getEditToken( $salt );
}
/**
* Get token to unwatch (or watch) a page for a user
*
* @param Title $title Title object of page to unwatch
- * @param User $title User for whom the action is going to be performed
+ * @param User $user User for whom the action is going to be performed
* @param string $action Optionally override the action to 'watch'
* @return string Token
* @since 1.18