summaryrefslogtreecommitdiff
path: root/includes/specials
diff options
context:
space:
mode:
authorPierre Schmitz <pierre@archlinux.de>2011-12-03 13:29:22 +0100
committerPierre Schmitz <pierre@archlinux.de>2011-12-03 13:29:22 +0100
commitca32f08966f1b51fcb19460f0996bb0c4048e6fe (patch)
treeec04cc15b867bc21eedca904cea9af0254531a11 /includes/specials
parenta22fbfc60f36f5f7ee10d5ae6fe347340c2ee67c (diff)
Update to MediaWiki 1.18.0
* also update ArchLinux skin to chagnes in MonoBook * Use only css to hide our menu bar when printing
Diffstat (limited to 'includes/specials')
-rw-r--r--includes/specials/SpecialActiveusers.php14
-rw-r--r--includes/specials/SpecialAllmessages.php214
-rw-r--r--includes/specials/SpecialAllpages.php80
-rw-r--r--includes/specials/SpecialAncientpages.php40
-rw-r--r--includes/specials/SpecialBlankpage.php3
-rw-r--r--includes/specials/SpecialBlock.php855
-rw-r--r--includes/specials/SpecialBlockList.php437
-rw-r--r--includes/specials/SpecialBlockip.php892
-rw-r--r--includes/specials/SpecialBlockme.php8
-rw-r--r--includes/specials/SpecialBooksources.php41
-rw-r--r--includes/specials/SpecialBrokenRedirects.php75
-rw-r--r--includes/specials/SpecialCategories.php19
-rw-r--r--includes/specials/SpecialChangePassword.php (renamed from includes/specials/SpecialResetpass.php)64
-rw-r--r--includes/specials/SpecialComparePages.php170
-rw-r--r--includes/specials/SpecialConfirmemail.php79
-rw-r--r--includes/specials/SpecialContributions.php322
-rw-r--r--includes/specials/SpecialDeadendpages.php58
-rw-r--r--includes/specials/SpecialDeletedContributions.php31
-rw-r--r--includes/specials/SpecialDisambiguations.php109
-rw-r--r--includes/specials/SpecialDoubleRedirects.php86
-rw-r--r--includes/specials/SpecialEditWatchlist.php596
-rw-r--r--includes/specials/SpecialEmailuser.php112
-rw-r--r--includes/specials/SpecialExport.php127
-rw-r--r--includes/specials/SpecialFewestrevisions.php41
-rw-r--r--includes/specials/SpecialFileDuplicateSearch.php226
-rw-r--r--includes/specials/SpecialFilepath.php11
-rw-r--r--includes/specials/SpecialImport.php50
-rw-r--r--includes/specials/SpecialIpblocklist.php581
-rw-r--r--includes/specials/SpecialLinkSearch.php202
-rw-r--r--includes/specials/SpecialListfiles.php148
-rw-r--r--includes/specials/SpecialListgrouprights.php62
-rw-r--r--includes/specials/SpecialListredirects.php96
-rw-r--r--includes/specials/SpecialListusers.php86
-rw-r--r--includes/specials/SpecialLockdb.php24
-rw-r--r--includes/specials/SpecialLog.php9
-rw-r--r--includes/specials/SpecialLonelypages.php64
-rw-r--r--includes/specials/SpecialLongpages.php15
-rw-r--r--includes/specials/SpecialMIMEsearch.php151
-rw-r--r--includes/specials/SpecialMergeHistory.php210
-rw-r--r--includes/specials/SpecialMostcategories.php49
-rw-r--r--includes/specials/SpecialMostimages.php39
-rw-r--r--includes/specials/SpecialMostlinked.php62
-rw-r--r--includes/specials/SpecialMostlinkedcategories.php57
-rw-r--r--includes/specials/SpecialMostlinkedtemplates.php50
-rw-r--r--includes/specials/SpecialMostrevisions.php62
-rw-r--r--includes/specials/SpecialMovepage.php36
-rw-r--r--includes/specials/SpecialNewimages.php308
-rw-r--r--includes/specials/SpecialNewpages.php286
-rw-r--r--includes/specials/SpecialPasswordReset.php273
-rw-r--r--includes/specials/SpecialPopularpages.php51
-rw-r--r--includes/specials/SpecialPreferences.php5
-rw-r--r--includes/specials/SpecialPrefixindex.php58
-rw-r--r--includes/specials/SpecialProtectedpages.php39
-rw-r--r--includes/specials/SpecialProtectedtitles.php26
-rw-r--r--includes/specials/SpecialRandompage.php90
-rw-r--r--includes/specials/SpecialRecentchanges.php417
-rw-r--r--includes/specials/SpecialRecentchangeslinked.php52
-rw-r--r--includes/specials/SpecialRevisiondelete.php238
-rw-r--r--includes/specials/SpecialSearch.php412
-rw-r--r--includes/specials/SpecialShortpages.php60
-rw-r--r--includes/specials/SpecialSpecialpages.php44
-rw-r--r--includes/specials/SpecialStatistics.php121
-rw-r--r--includes/specials/SpecialTags.php16
-rw-r--r--includes/specials/SpecialUnblock.php209
-rw-r--r--includes/specials/SpecialUncategorizedcategories.php18
-rw-r--r--includes/specials/SpecialUncategorizedimages.php32
-rw-r--r--includes/specials/SpecialUncategorizedpages.php54
-rw-r--r--includes/specials/SpecialUncategorizedtemplates.php18
-rw-r--r--includes/specials/SpecialUndelete.php703
-rw-r--r--includes/specials/SpecialUnlockdb.php16
-rw-r--r--includes/specials/SpecialUnusedcategories.php34
-rw-r--r--includes/specials/SpecialUnusedimages.php70
-rw-r--r--includes/specials/SpecialUnusedtemplates.php39
-rw-r--r--includes/specials/SpecialUnwatchedpages.php66
-rw-r--r--includes/specials/SpecialUpload.php150
-rw-r--r--includes/specials/SpecialUploadStash.php168
-rw-r--r--includes/specials/SpecialUserlogin.php405
-rw-r--r--includes/specials/SpecialUserrights.php29
-rw-r--r--includes/specials/SpecialVersion.php303
-rw-r--r--includes/specials/SpecialWantedcategories.php48
-rw-r--r--includes/specials/SpecialWantedfiles.php45
-rw-r--r--includes/specials/SpecialWantedpages.php102
-rw-r--r--includes/specials/SpecialWantedtemplates.php44
-rw-r--r--includes/specials/SpecialWatchlist.php825
-rw-r--r--includes/specials/SpecialWhatlinkshere.php86
-rw-r--r--includes/specials/SpecialWithoutinterwiki.php66
86 files changed, 7027 insertions, 5762 deletions
diff --git a/includes/specials/SpecialActiveusers.php b/includes/specials/SpecialActiveusers.php
index f016ab92..e4bf42d3 100644
--- a/includes/specials/SpecialActiveusers.php
+++ b/includes/specials/SpecialActiveusers.php
@@ -32,6 +32,16 @@
*/
class ActiveUsersPager extends UsersPager {
+ /**
+ * @var FormOptions
+ */
+ protected $opts;
+
+ /**
+ * @var Array
+ */
+ protected $groups;
+
function __construct( $group = null ) {
global $wgRequest, $wgActiveUserDays;
$this->RCMaxAge = $wgActiveUserDays;
@@ -49,6 +59,10 @@ class ActiveUsersPager extends UsersPager {
parent::__construct();
}
+ function getTitle() {
+ return SpecialPage::getTitleFor( 'Activeusers' );
+ }
+
public function setupOptions() {
global $wgRequest;
diff --git a/includes/specials/SpecialAllmessages.php b/includes/specials/SpecialAllmessages.php
index 296c6f50..2214b4ab 100644
--- a/includes/specials/SpecialAllmessages.php
+++ b/includes/specials/SpecialAllmessages.php
@@ -30,6 +30,11 @@
class SpecialAllmessages extends SpecialPage {
/**
+ * @var AllmessagesTablePager
+ */
+ protected $table;
+
+ /**
* Constructor
*/
public function __construct() {
@@ -42,37 +47,102 @@ class SpecialAllmessages extends SpecialPage {
* @param $par Mixed: parameter passed to the page or null
*/
public function execute( $par ) {
- global $wgOut, $wgRequest;
+ $request = $this->getRequest();
+ $out = $this->getOutput();
$this->setHeaders();
global $wgUseDatabaseMessages;
if( !$wgUseDatabaseMessages ) {
- $wgOut->addWikiMsg( 'allmessagesnotsupportedDB' );
+ $out->addWikiMsg( 'allmessagesnotsupportedDB' );
return;
} else {
$this->outputHeader( 'allmessagestext' );
}
- $this->filter = $wgRequest->getVal( 'filter', 'all' );
- $this->prefix = $wgRequest->getVal( 'prefix', '' );
+ $out->addModuleStyles( 'mediawiki.special' );
+
+ $this->filter = $request->getVal( 'filter', 'all' );
+ $this->prefix = $request->getVal( 'prefix', '' );
$this->table = new AllmessagesTablePager(
$this,
- $conds = array(),
- wfGetLangObj( $wgRequest->getVal( 'lang', $par ) )
+ array(),
+ wfGetLangObj( $request->getVal( 'lang', $par ) )
);
- $this->langCode = $this->table->lang->getCode();
+ $this->langcode = $this->table->lang->getCode();
- $wgOut->addHTML( $this->buildForm() .
+ $out->addHTML( $this->table->buildForm() .
$this->table->getNavigationBar() .
- $this->table->getLimitForm() .
$this->table->getBody() .
$this->table->getNavigationBar() );
}
+}
+
+/**
+ * Use TablePager for prettified output. We have to pretend that we're
+ * getting data from a table when in fact not all of it comes from the database.
+ */
+class AllmessagesTablePager extends TablePager {
+
+ protected $filter, $prefix, $langcode, $displayPrefix;
+
+ public $mLimitsShown;
+
+ /**
+ * @var Language
+ */
+ public $lang;
+
+ /**
+ * @var null|bool
+ */
+ public $custom;
+
+ function __construct( $page, $conds, $langObj = null ) {
+ parent::__construct();
+ $this->mIndexField = 'am_title';
+ $this->mPage = $page;
+ $this->mConds = $conds;
+ $this->mDefaultDirection = true; // always sort ascending
+ $this->mLimitsShown = array( 20, 50, 100, 250, 500, 5000 );
+
+ global $wgLang, $wgContLang, $wgRequest;
+
+ $this->talk = htmlspecialchars( wfMsg( 'talkpagelinktext' ) );
+
+ $this->lang = ( $langObj ? $langObj : $wgContLang );
+ $this->langcode = $this->lang->getCode();
+ $this->foreign = $this->langcode != $wgContLang->getCode();
+
+ if( $wgRequest->getVal( 'filter', 'all' ) === 'all' ){
+ $this->custom = null; // So won't match in either case
+ } else {
+ $this->custom = ($wgRequest->getVal( 'filter' ) == 'unmodified');
+ }
+
+ $prefix = $wgLang->ucfirst( $wgRequest->getVal( 'prefix', '' ) );
+ $prefix = $prefix != '' ? Title::makeTitleSafe( NS_MEDIAWIKI, $wgRequest->getVal( 'prefix', null ) ) : null;
+ if( $prefix !== null ){
+ $this->displayPrefix = $prefix->getDBkey();
+ $this->prefix = '/^' . preg_quote( $this->displayPrefix ) . '/i';
+ } else {
+ $this->displayPrefix = false;
+ $this->prefix = false;
+ }
+
+ // The suffix that may be needed for message names if we're in a
+ // different language (eg [[MediaWiki:Foo/fr]]: $suffix = '/fr'
+ if( $this->foreign ) {
+ $this->suffix = '/' . $this->langcode;
+ } else {
+ $this->suffix = '';
+ }
+ }
+
function buildForm() {
global $wgScript;
@@ -88,7 +158,7 @@ class SpecialAllmessages extends SpecialPage {
Xml::label( wfMsg( 'allmessages-prefix' ), 'mw-allmessages-form-prefix' ) .
"</td>\n
<td class=\"mw-input\">" .
- Xml::input( 'prefix', 20, str_replace( '_', ' ', $this->prefix ), array( 'id' => 'mw-allmessages-form-prefix' ) ) .
+ Xml::input( 'prefix', 20, str_replace( '_', ' ', $this->displayPrefix ), array( 'id' => 'mw-allmessages-form-prefix' ) ) .
"</td>\n
</tr>
<tr>\n
@@ -124,72 +194,33 @@ class SpecialAllmessages extends SpecialPage {
Xml::openElement( 'select', array( 'id' => 'mw-allmessages-form-lang', 'name' => 'lang' ) );
foreach( $languages as $lang => $name ) {
- $selected = $lang == $this->langCode;
+ $selected = $lang == $this->langcode;
$out .= Xml::option( $lang . ' - ' . $name, $lang, $selected ) . "\n";
}
$out .= Xml::closeElement( 'select' ) .
"</td>\n
- </tr>
- <tr>\n
+ </tr>" .
+
+ '<tr>
+ <td class="mw-label">' .
+ Xml::label( wfMsg( 'table_pager_limit_label'), 'mw-table_pager_limit_label' ) .
+ '</td>
+ <td class="mw-input">' .
+ $this->getLimitSelect() .
+ '</td>
+ <tr>
<td></td>
- <td>" .
+ <td>' .
Xml::submitButton( wfMsg( 'allmessages-filter-submit' ) ) .
"</td>\n
</tr>" .
+
Xml::closeElement( 'table' ) .
- $this->table->getHiddenFields( array( 'title', 'prefix', 'filter', 'lang' ) ) .
+ $this->getHiddenFields( array( 'title', 'prefix', 'filter', 'lang', 'limit' ) ) .
Xml::closeElement( 'fieldset' ) .
Xml::closeElement( 'form' );
return $out;
}
-}
-
-/* use TablePager for prettified output. We have to pretend that we're
- * getting data from a table when in fact not all of it comes from the database.
- */
-class AllmessagesTablePager extends TablePager {
-
- public $mLimitsShown;
-
- function __construct( $page, $conds, $langObj = null ) {
- parent::__construct();
- $this->mIndexField = 'am_title';
- $this->mPage = $page;
- $this->mConds = $conds;
- $this->mDefaultDirection = true; // always sort ascending
- $this->mLimitsShown = array( 20, 50, 100, 250, 500, 5000 );
-
- global $wgLang, $wgContLang, $wgRequest;
-
- $this->talk = htmlspecialchars( wfMsg( 'talkpagelinktext' ) );
-
- $this->lang = ( $langObj ? $langObj : $wgContLang );
- $this->langcode = $this->lang->getCode();
- $this->foreign = $this->langcode != $wgContLang->getCode();
-
- if( $wgRequest->getVal( 'filter', 'all' ) === 'all' ){
- $this->custom = null; // So won't match in either case
- } else {
- $this->custom = ($wgRequest->getVal( 'filter' ) == 'unmodified');
- }
-
- $prefix = $wgLang->ucfirst( $wgRequest->getVal( 'prefix', '' ) );
- $prefix = $prefix != '' ? Title::makeTitleSafe( NS_MEDIAWIKI, $wgRequest->getVal( 'prefix', null ) ) : null;
- if( $prefix !== null ){
- $this->prefix = '/^' . preg_quote( $prefix->getDBkey() ) . '/i';
- } else {
- $this->prefix = false;
- }
- $this->getSkin();
-
- // The suffix that may be needed for message names if we're in a
- // different language (eg [[MediaWiki:Foo/fr]]: $suffix = '/fr'
- if( $this->foreign ) {
- $this->suffix = '/' . $this->langcode;
- } else {
- $this->suffix = '';
- }
- }
function getAllMessages( $descending ) {
wfProfileIn( __METHOD__ );
@@ -208,12 +239,16 @@ class AllmessagesTablePager extends TablePager {
}
/**
- * Determine which of the MediaWiki and MediaWiki_talk namespace pages exist.
- * Returns array( 'pages' => ..., 'talks' => ... ), where the subarrays have
- * an entry for each existing page, with the key being the message name and
+ * Determine which of the MediaWiki and MediaWiki_talk namespace pages exist.
+ * Returns array( 'pages' => ..., 'talks' => ... ), where the subarrays have
+ * an entry for each existing page, with the key being the message name and
* value arbitrary.
+ *
+ * @param array $messageNames
+ * @param string $langcode What language code
+ * @param bool $foreign Whether the $langcode is not the content language
*/
- function getCustomisedStatuses( $messageNames ) {
+ public static function getCustomisedStatuses( $messageNames, $langcode = 'en', $foreign = false ) {
wfProfileIn( __METHOD__ . '-db' );
$dbr = wfGetDB( DB_SLAVE );
@@ -226,20 +261,19 @@ class AllmessagesTablePager extends TablePager {
$xNames = array_flip( $messageNames );
$pageFlags = $talkFlags = array();
-
+
foreach ( $res as $s ) {
if( $s->page_namespace == NS_MEDIAWIKI ) {
- if( $this->foreign ) {
+ if( $foreign ) {
$title = explode( '/', $s->page_title );
- if( count( $title ) === 2 && $this->langcode == $title[1]
- && isset( $xNames[$title[0]] ) )
- {
+ if( count( $title ) === 2 && $langcode == $title[1]
+ && isset( $xNames[$title[0]] ) ) {
$pageFlags["{$title[0]}"] = true;
}
} elseif( isset( $xNames[$s->page_title] ) ) {
$pageFlags[$s->page_title] = true;
}
- } else if( $s->page_namespace == NS_MEDIAWIKI_TALK ){
+ } elseif( $s->page_namespace == NS_MEDIAWIKI_TALK ){
$talkFlags[$s->page_title] = true;
}
}
@@ -249,14 +283,15 @@ class AllmessagesTablePager extends TablePager {
return array( 'pages' => $pageFlags, 'talks' => $talkFlags );
}
- /* This function normally does a database query to get the results; we need
+ /**
+ * This function normally does a database query to get the results; we need
* to make a pretend result using a FakeResultWrapper.
*/
function reallyDoQuery( $offset, $limit, $descending ) {
$result = new FakeResultWrapper( array() );
$messageNames = $this->getAllMessages( $descending );
- $statuses = $this->getCustomisedStatuses( $messageNames );
+ $statuses = self::getCustomisedStatuses( $messageNames, $this->langcode, $this->foreign );
$count = 0;
foreach( $messageNames as $key ) {
@@ -264,17 +299,21 @@ class AllmessagesTablePager extends TablePager {
if( $customised !== $this->custom &&
( $descending && ( $key < $offset || !$offset ) || !$descending && $key > $offset ) &&
( ( $this->prefix && preg_match( $this->prefix, $key ) ) || $this->prefix === false )
- ){
+ ) {
+ $actual = wfMessage( $key )->inLanguage( $this->langcode )->plain();
+ $default = wfMessage( $key )->inLanguage( $this->langcode )->useDatabase( false )->plain();
$result->result[] = array(
'am_title' => $key,
- 'am_actual' => wfMsgGetKey( $key, /*useDB*/true, $this->langcode, false ),
- 'am_default' => wfMsgGetKey( $key, /*useDB*/false, $this->langcode, false ),
+ 'am_actual' => $actual,
+ 'am_default' => $default,
'am_customised' => $customised,
'am_talk_exists' => isset( $statuses['talks'][$key] )
);
$count++;
}
- if( $count == $limit ) break;
+ if( $count == $limit ) {
+ break;
+ }
}
return $result;
}
@@ -306,9 +345,9 @@ class AllmessagesTablePager extends TablePager {
$talk = Title::makeTitle( NS_MEDIAWIKI_TALK, $value . $this->suffix );
if( $this->mCurrentRow->am_customised ){
- $title = $this->mSkin->linkKnown( $title, $wgLang->lcfirst( $value ) );
+ $title = Linker::linkKnown( $title, $wgLang->lcfirst( $value ) );
} else {
- $title = $this->mSkin->link(
+ $title = Linker::link(
$title,
$wgLang->lcfirst( $value ),
array(),
@@ -317,9 +356,9 @@ class AllmessagesTablePager extends TablePager {
);
}
if ( $this->mCurrentRow->am_talk_exists ) {
- $talk = $this->mSkin->linkKnown( $talk , $this->talk );
+ $talk = Linker::linkKnown( $talk , $this->talk );
} else {
- $talk = $this->mSkin->link(
+ $talk = Linker::link(
$talk,
$this->talk,
array(),
@@ -330,7 +369,6 @@ class AllmessagesTablePager extends TablePager {
return $title . ' (' . $talk . ')';
case 'am_default' :
- return Sanitizer::escapeHtmlAllowEntities( $value, ENT_QUOTES );
case 'am_actual' :
return Sanitizer::escapeHtmlAllowEntities( $value, ENT_QUOTES );
}
@@ -369,8 +407,10 @@ class AllmessagesTablePager extends TablePager {
function getCellAttrs( $field, $value ){
if( $this->mCurrentRow->am_customised && $field == 'am_title' ){
return array( 'rowspan' => '2', 'class' => $field );
- } else {
+ } else if( $field == 'am_title' ) {
return array( 'class' => $field );
+ } else {
+ return array( 'lang' => $this->langcode, 'dir' => $this->lang->getDir(), 'class' => $field );
}
}
@@ -381,15 +421,19 @@ class AllmessagesTablePager extends TablePager {
'am_default' => wfMsg( 'allmessagesdefault' )
);
}
+
function getTitle() {
return SpecialPage::getTitleFor( 'Allmessages', false );
}
+
function isFieldSortable( $x ){
return false;
}
+
function getDefaultSort(){
return '';
}
+
function getQueryInfo(){
return '';
}
diff --git a/includes/specials/SpecialAllpages.php b/includes/specials/SpecialAllpages.php
index 5fa1aa47..a9cbf3ab 100644
--- a/includes/specials/SpecialAllpages.php
+++ b/includes/specials/SpecialAllpages.php
@@ -20,7 +20,7 @@
* @file
* @ingroup SpecialPage
*/
-
+
/**
* Implements Special:Allpages
*
@@ -58,24 +58,27 @@ class SpecialAllpages extends IncludableSpecialPage {
* @param $par String: becomes "FOO" when called like Special:Allpages/FOO (default NULL)
*/
function execute( $par ) {
- global $wgRequest, $wgOut, $wgContLang;
+ global $wgContLang;
+ $request = $this->getRequest();
+ $out = $this->getOutput();
$this->setHeaders();
$this->outputHeader();
- $wgOut->allowClickjacking();
+ $out->allowClickjacking();
# GET values
- $from = $wgRequest->getVal( 'from', null );
- $to = $wgRequest->getVal( 'to', null );
- $namespace = $wgRequest->getInt( 'namespace' );
+ $from = $request->getVal( 'from', null );
+ $to = $request->getVal( 'to', null );
+ $namespace = $request->getInt( 'namespace' );
$namespaces = $wgContLang->getNamespaces();
- $wgOut->setPagetitle(
+ $out->setPagetitle(
( $namespace > 0 && in_array( $namespace, array_keys( $namespaces) ) ) ?
wfMsg( 'allinnamespace', str_replace( '_', ' ', $namespaces[$namespace] ) ) :
wfMsg( 'allarticles' )
);
+ $out->addModuleStyles( 'mediawiki.special' );
if( isset($par) ) {
$this->showChunk( $namespace, $par, $to );
@@ -96,7 +99,7 @@ class SpecialAllpages extends IncludableSpecialPage {
function namespaceForm( $namespace = NS_MAIN, $from = '', $to = '' ) {
global $wgScript;
$t = $this->getTitle();
-
+
$out = Xml::openElement( 'div', array( 'class' => 'namespaceoptions' ) );
$out .= Xml::openElement( 'form', array( 'method' => 'get', 'action' => $wgScript ) );
$out .= Html::hidden( 'title', $t->getPrefixedText() );
@@ -141,7 +144,7 @@ class SpecialAllpages extends IncludableSpecialPage {
* @param $to String: list all pages to this name
*/
function showToplevel( $namespace = NS_MAIN, $from = '', $to = '' ) {
- global $wgOut;
+ $output = $this->getOutput();
# TODO: Either make this *much* faster or cache the title index points
# in the querycache table.
@@ -220,7 +223,7 @@ class SpecialAllpages extends IncludableSpecialPage {
if( !empty($lines) ) {
$this->showChunk( $namespace, $from, $to );
} else {
- $wgOut->addHTML( $this->namespaceForm( $namespace, $from, $to ) );
+ $output->addHTML( $this->namespaceForm( $namespace, $from, $to ) );
}
return;
}
@@ -240,14 +243,13 @@ class SpecialAllpages extends IncludableSpecialPage {
$out2 = '';
} else {
if( isset($from) || isset($to) ) {
- global $wgUser;
$out2 = Xml::openElement( 'table', array( 'class' => 'mw-allpages-table-form' ) ).
'<tr>
<td>' .
$nsForm .
'</td>
<td class="mw-allpages-nav">' .
- $wgUser->getSkin()->link( $this->getTitle(), wfMsgHtml ( 'allpages' ),
+ $this->getSkin()->link( $this->getTitle(), wfMsgHtml ( 'allpages' ),
array(), array(), 'known' ) .
"</td>
</tr>" .
@@ -256,7 +258,7 @@ class SpecialAllpages extends IncludableSpecialPage {
$out2 = $nsForm;
}
}
- $wgOut->addHTML( $out2 . $out );
+ $output->addHTML( $out2 . $out );
}
/**
@@ -291,9 +293,9 @@ class SpecialAllpages extends IncludableSpecialPage {
* @param $to String: list all pages to this name (default FALSE)
*/
function showChunk( $namespace = NS_MAIN, $from = false, $to = false ) {
- global $wgOut, $wgUser, $wgContLang, $wgLang;
-
- $sk = $wgUser->getSkin();
+ global $wgContLang, $wgLang;
+ $output = $this->getOutput();
+ $sk = $this->getSkin();
$fromList = $this->getNamespaceKeyAndText($namespace, $from);
$toList = $this->getNamespaceKeyAndText( $namespace, $to );
@@ -301,7 +303,7 @@ class SpecialAllpages extends IncludableSpecialPage {
$n = 0;
if ( !$fromList || !$toList ) {
- $out = wfMsgWikiHtml( 'allpagesbadtitle' );
+ $out = wfMsgExt( 'allpagesbadtitle', 'parse' );
} elseif ( !in_array( $namespace, array_keys( $namespaces ) ) ) {
// Show errormessage and reset to NS_MAIN
$out = wfMsgExt( 'allpages-bad-ns', array( 'parseinline' ), $namespace );
@@ -320,7 +322,7 @@ class SpecialAllpages extends IncludableSpecialPage {
}
$res = $dbr->select( 'page',
- array( 'page_namespace', 'page_title', 'page_is_redirect' ),
+ array( 'page_namespace', 'page_title', 'page_is_redirect', 'page_id' ),
$conds,
__METHOD__,
array(
@@ -333,10 +335,10 @@ class SpecialAllpages extends IncludableSpecialPage {
if( $res->numRows() > 0 ) {
$out = Xml::openElement( 'table', array( 'class' => 'mw-allpages-table-chunk' ) );
while( ( $n < $this->maxPerPage ) && ( $s = $res->fetchObject() ) ) {
- $t = Title::makeTitle( $s->page_namespace, $s->page_title );
+ $t = Title::newFromRow( $s );
if( $t ) {
$link = ( $s->page_is_redirect ? '<div class="allpagesredirect">' : '' ) .
- $sk->linkKnown( $t, htmlspecialchars( $t->getText() ) ) .
+ $sk->link( $t ) .
($s->page_is_redirect ? '</div>' : '' );
} else {
$link = '[[' . htmlspecialchars( $s->page_title ) . ']]';
@@ -373,7 +375,7 @@ class SpecialAllpages extends IncludableSpecialPage {
'page_title',
array( 'page_namespace' => $namespace, 'page_title < '.$dbr->addQuotes($from) ),
__METHOD__,
- array( 'ORDER BY' => 'page_title DESC',
+ array( 'ORDER BY' => 'page_title DESC',
'LIMIT' => $this->maxPerPage, 'OFFSET' => ($this->maxPerPage - 1 )
)
);
@@ -409,7 +411,7 @@ class SpecialAllpages extends IncludableSpecialPage {
$nsForm .
'</td>
<td class="mw-allpages-nav">' .
- $sk->link( $self, wfMsgHtml ( 'allpages' ), array(), array(), 'known' );
+ $sk->link( $self, wfMsgHtml ( 'allpages' ) );
# Do we put a previous link ?
if( isset( $prevTitle ) && $pt = $prevTitle->getText() ) {
@@ -420,7 +422,7 @@ class SpecialAllpages extends IncludableSpecialPage {
$prevLink = $sk->linkKnown(
$self,
- htmlspecialchars( wfMsg( 'prevpage', $pt ) ),
+ wfMessage( 'prevpage', $pt )->escaped(),
array(),
$query
);
@@ -437,7 +439,7 @@ class SpecialAllpages extends IncludableSpecialPage {
$nextLink = $sk->linkKnown(
$self,
- htmlspecialchars( wfMsg( 'nextpage', $t->getText() ) ),
+ wfMessage( 'nextpage', $t->getText() )->escaped(),
array(),
$query
);
@@ -446,20 +448,18 @@ class SpecialAllpages extends IncludableSpecialPage {
$out2 .= "</td></tr></table>";
}
- $wgOut->addHTML( $out2 . $out );
- if( isset($prevLink) or isset($nextLink) ) {
- $wgOut->addHTML( '<hr /><p class="mw-allpages-nav">' );
- if( isset( $prevLink ) ) {
- $wgOut->addHTML( $prevLink );
- }
- if( isset( $prevLink ) && isset( $nextLink ) ) {
- $wgOut->addHTML( wfMsgExt( 'pipe-separator' , 'escapenoentities' ) );
- }
- if( isset( $nextLink ) ) {
- $wgOut->addHTML( $nextLink );
- }
- $wgOut->addHTML( '</p>' );
+ $output->addHTML( $out2 . $out );
+
+ $links = array();
+ if ( isset( $prevLink ) ) $links[] = $prevLink;
+ if ( isset( $nextLink ) ) $links[] = $nextLink;
+ if ( count( $links ) ) {
+ $output->addHTML(
+ Html::element( 'hr' ) .
+ Html::rawElement( 'div', array( 'class' => 'mw-allpages-nav' ),
+ $wgLang->pipeList( $links )
+ ) );
}
}
@@ -468,17 +468,15 @@ class SpecialAllpages extends IncludableSpecialPage {
* @param $ns Integer: the namespace of the article
* @param $text String: the name of the article
* @return array( int namespace, string dbkey, string pagename ) or NULL on error
- * @static (sort of)
- * @access private
*/
- function getNamespaceKeyAndText($ns, $text) {
+ protected function getNamespaceKeyAndText($ns, $text) {
if ( $text == '' )
return array( $ns, '', '' ); # shortcut for common case
$t = Title::makeTitleSafe($ns, $text);
if ( $t && $t->isLocal() ) {
return array( $t->getNamespace(), $t->getDBkey(), $t->getText() );
- } else if ( $t ) {
+ } elseif ( $t ) {
return null;
}
diff --git a/includes/specials/SpecialAncientpages.php b/includes/specials/SpecialAncientpages.php
index 2d5047d2..cbb5df80 100644
--- a/includes/specials/SpecialAncientpages.php
+++ b/includes/specials/SpecialAncientpages.php
@@ -28,8 +28,8 @@
*/
class AncientPagesPage extends QueryPage {
- function getName() {
- return "Ancientpages";
+ function __construct( $name = 'Ancientpages' ) {
+ parent::__construct( $name );
}
function isExpensive() {
@@ -38,20 +38,20 @@ class AncientPagesPage extends QueryPage {
function isSyndicated() { return false; }
- function getSQL() {
- $db = wfGetDB( DB_SLAVE );
- $page = $db->tableName( 'page' );
- $revision = $db->tableName( 'revision' );
- $epoch = $db->unixTimestamp( 'rev_timestamp' );
+ function getQueryInfo() {
+ return array(
+ 'tables' => array( 'page', 'revision' ),
+ 'fields' => array( 'page_namespace AS namespace',
+ 'page_title AS title',
+ 'rev_timestamp AS value' ),
+ 'conds' => array( 'page_namespace' => MWNamespace::getContentNamespaces(),
+ 'page_is_redirect' => 0,
+ 'page_latest=rev_id' )
+ );
+ }
- return
- "SELECT 'Ancientpages' as type,
- page_namespace as namespace,
- page_title as title,
- $epoch as value
- FROM $page, $revision
- WHERE page_namespace=".NS_MAIN." AND page_is_redirect=0
- AND page_latest=rev_id";
+ function usesTimestamps() {
+ return true;
}
function sortDescending() {
@@ -67,14 +67,6 @@ class AncientPagesPage extends QueryPage {
$title,
htmlspecialchars( $wgContLang->convert( $title->getPrefixedText() ) )
);
- return wfSpecialList($link, htmlspecialchars($d) );
+ return wfSpecialList( $link, htmlspecialchars($d) );
}
}
-
-function wfSpecialAncientpages() {
- list( $limit, $offset ) = wfCheckLimits();
-
- $app = new AncientPagesPage();
-
- $app->doQuery( $offset, $limit );
-}
diff --git a/includes/specials/SpecialBlankpage.php b/includes/specials/SpecialBlankpage.php
index aaa45a80..42d33779 100644
--- a/includes/specials/SpecialBlankpage.php
+++ b/includes/specials/SpecialBlankpage.php
@@ -32,8 +32,7 @@ class SpecialBlankpage extends UnlistedSpecialPage {
parent::__construct( 'Blankpage' );
}
public function execute( $par ) {
- global $wgOut;
$this->setHeaders();
- $wgOut->addWikiMsg('intentionallyblankpage');
+ $this->getOutput()->addWikiMsg('intentionallyblankpage');
}
}
diff --git a/includes/specials/SpecialBlock.php b/includes/specials/SpecialBlock.php
new file mode 100644
index 00000000..f1fe8386
--- /dev/null
+++ b/includes/specials/SpecialBlock.php
@@ -0,0 +1,855 @@
+<?php
+/**
+ * Implements Special:Block
+ *
+ * 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.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup SpecialPage
+ */
+
+/**
+ * A special page that allows users with 'block' right to block users from
+ * editing pages and other actions
+ *
+ * @ingroup SpecialPage
+ */
+class SpecialBlock extends SpecialPage {
+
+ /** The maximum number of edits a user can have and still be hidden
+ * TODO: config setting? */
+ const HIDEUSER_CONTRIBLIMIT = 1000;
+
+ /** @var User user to be blocked, as passed either by parameter (url?wpTarget=Foo)
+ * or as subpage (Special:Block/Foo) */
+ protected $target;
+
+ /// @var Block::TYPE_ constant
+ protected $type;
+
+ /// @var User|String the previous block target
+ protected $previousTarget;
+
+ /// @var Bool whether the previous submission of the form asked for HideUser
+ protected $requestedHideUser;
+
+ /// @var Bool
+ protected $alreadyBlocked;
+
+ /// @var Array
+ protected $preErrors = array();
+
+ public function __construct() {
+ parent::__construct( 'Block', 'block' );
+ }
+
+ public function execute( $par ) {
+ global $wgUser, $wgOut, $wgRequest;
+
+ # Permission check
+ if( !$this->userCanExecute( $wgUser ) ) {
+ $this->displayRestrictionError();
+ return;
+ }
+
+ # Can't block when the database is locked
+ if( wfReadOnly() ) {
+ throw new ReadOnlyError;
+ }
+
+ # Extract variables from the request. Try not to get into a situation where we
+ # need to extract *every* variable from the form just for processing here, but
+ # there are legitimate uses for some variables
+ list( $this->target, $this->type ) = self::getTargetAndType( $par, $wgRequest );
+ if ( $this->target instanceof User ) {
+ # Set the 'relevant user' in the skin, so it displays links like Contributions,
+ # User logs, UserRights, etc.
+ $this->getSkin()->setRelevantUser( $this->target );
+ }
+
+ list( $this->previousTarget, /*...*/ ) = Block::parseTarget( $wgRequest->getVal( 'wpPreviousTarget' ) );
+ $this->requestedHideUser = $wgRequest->getBool( 'wpHideUser' );
+
+ # bug 15810: blocked admins should have limited access here
+ $status = self::checkUnblockSelf( $this->target );
+ if ( $status !== true ) {
+ throw new ErrorPageError( 'badaccess', $status );
+ }
+
+ $wgOut->setPageTitle( wfMsg( 'blockip-title' ) );
+ $wgOut->addModules( 'mediawiki.special', 'mediawiki.special.block' );
+
+ $out = $this->getOutput();
+ $out->setPageTitle( wfMsg( 'blockip-title' ) );
+ $out->addModules( array( 'mediawiki.special', 'mediawiki.special.block' ) );
+
+ $fields = $this->getFormFields();
+ $this->maybeAlterFormDefaults( $fields );
+
+ $form = new HTMLForm( $fields, $this->getContext() );
+ $form->setWrapperLegend( wfMsg( 'blockip-legend' ) );
+ $form->setSubmitCallback( array( __CLASS__, 'processForm' ) );
+
+ $t = $this->alreadyBlocked
+ ? wfMsg( 'ipb-change-block' )
+ : wfMsg( 'ipbsubmit' );
+ $form->setSubmitText( $t );
+
+ $this->doPreText( $form );
+ $this->doHeadertext( $form );
+ $this->doPostText( $form );
+
+ if( $form->show() ){
+ $wgOut->setPageTitle( wfMsg( 'blockipsuccesssub' ) );
+ $wgOut->addWikiMsg( 'blockipsuccesstext', $this->target );
+ }
+ }
+
+ /**
+ * Get the HTMLForm descriptor array for the block form
+ * @return Array
+ */
+ protected static function getFormFields(){
+ global $wgUser, $wgBlockAllowsUTEdit;
+
+ $a = array(
+ 'Target' => array(
+ 'type' => 'text',
+ 'label-message' => 'ipadressorusername',
+ 'tabindex' => '1',
+ 'id' => 'mw-bi-target',
+ 'size' => '45',
+ 'required' => true,
+ 'validation-callback' => array( __CLASS__, 'validateTargetField' ),
+ ),
+ 'Expiry' => array(
+ 'type' => !count( self::getSuggestedDurations() ) ? 'text' : 'selectorother',
+ 'label-message' => 'ipbexpiry',
+ 'required' => true,
+ 'tabindex' => '2',
+ 'options' => self::getSuggestedDurations(),
+ 'other' => wfMsg( 'ipbother' ),
+ ),
+ 'Reason' => array(
+ 'type' => 'selectandother',
+ 'label-message' => 'ipbreason',
+ 'options-message' => 'ipbreason-dropdown',
+ ),
+ 'CreateAccount' => array(
+ 'type' => 'check',
+ 'label-message' => 'ipbcreateaccount',
+ 'default' => true,
+ ),
+ );
+
+ if( self::canBlockEmail( $wgUser ) ) {
+ $a['DisableEmail'] = array(
+ 'type' => 'check',
+ 'label-message' => 'ipbemailban',
+ );
+ }
+
+ if( $wgBlockAllowsUTEdit ){
+ $a['DisableUTEdit'] = array(
+ 'type' => 'check',
+ 'label-message' => 'ipb-disableusertalk',
+ 'default' => false,
+ );
+ }
+
+ $a['AutoBlock'] = array(
+ 'type' => 'check',
+ 'label-message' => 'ipbenableautoblock',
+ 'default' => true,
+ );
+
+ # Allow some users to hide name from block log, blocklist and listusers
+ if( $wgUser->isAllowed( 'hideuser' ) ) {
+ $a['HideUser'] = array(
+ 'type' => 'check',
+ 'label-message' => 'ipbhidename',
+ 'cssclass' => 'mw-block-hideuser',
+ );
+ }
+
+ # Watchlist their user page? (Only if user is logged in)
+ if( $wgUser->isLoggedIn() ) {
+ $a['Watch'] = array(
+ 'type' => 'check',
+ 'label-message' => 'ipbwatchuser',
+ );
+ }
+
+ $a['HardBlock'] = array(
+ 'type' => 'check',
+ 'label-message' => 'ipb-hardblock',
+ 'default' => false,
+ );
+
+ # This is basically a copy of the Target field, but the user can't change it, so we
+ # can see if the warnings we maybe showed to the user before still apply
+ $a['PreviousTarget'] = array(
+ 'type' => 'hidden',
+ 'default' => false,
+ );
+
+ # We'll turn this into a checkbox if we need to
+ $a['Confirm'] = array(
+ 'type' => 'hidden',
+ 'default' => '',
+ 'label-message' => 'ipb-confirm',
+ );
+
+ return $a;
+ }
+
+ /**
+ * If the user has already been blocked with similar settings, load that block
+ * and change the defaults for the form fields to match the existing settings.
+ * @param &$fields Array HTMLForm descriptor array
+ * @return Bool whether fields were altered (that is, whether the target is
+ * already blocked)
+ */
+ protected function maybeAlterFormDefaults( &$fields ){
+ global $wgRequest, $wgUser;
+
+ # This will be overwritten by request data
+ $fields['Target']['default'] = (string)$this->target;
+
+ # This won't be
+ $fields['PreviousTarget']['default'] = (string)$this->target;
+
+ $block = Block::newFromTarget( $this->target );
+
+ if( $block instanceof Block && !$block->mAuto # The block exists and isn't an autoblock
+ && ( $this->type != Block::TYPE_RANGE # The block isn't a rangeblock
+ || $block->getTarget() == $this->target ) # or if it is, the range is what we're about to block
+ )
+ {
+ $fields['HardBlock']['default'] = $block->isHardblock();
+ $fields['CreateAccount']['default'] = $block->prevents( 'createaccount' );
+ $fields['AutoBlock']['default'] = $block->isAutoblocking();
+ if( isset( $fields['DisableEmail'] ) ){
+ $fields['DisableEmail']['default'] = $block->prevents( 'sendemail' );
+ }
+ if( isset( $fields['HideUser'] ) ){
+ $fields['HideUser']['default'] = $block->mHideName;
+ }
+ if( isset( $fields['DisableUTEdit'] ) ){
+ $fields['DisableUTEdit']['default'] = $block->prevents( 'editownusertalk' );
+ }
+ $fields['Reason']['default'] = $block->mReason;
+
+ if( $wgRequest->wasPosted() ){
+ # Ok, so we got a POST submission asking us to reblock a user. So show the
+ # confirm checkbox; the user will only see it if they haven't previously
+ $fields['Confirm']['type'] = 'check';
+ } else {
+ # We got a target, but it wasn't a POST request, so the user must have gone
+ # to a link like [[Special:Block/User]]. We don't need to show the checkbox
+ # as long as they go ahead and block *that* user
+ $fields['Confirm']['default'] = 1;
+ }
+
+ if( $block->mExpiry == 'infinity' ) {
+ $fields['Expiry']['default'] = 'indefinite';
+ } else {
+ $fields['Expiry']['default'] = wfTimestamp( TS_RFC2822, $block->mExpiry );
+ }
+
+ $this->alreadyBlocked = true;
+ $this->preErrors[] = array( 'ipb-needreblock', (string)$block->getTarget() );
+ }
+
+ # We always need confirmation to do HideUser
+ if( $this->requestedHideUser ){
+ $fields['Confirm']['type'] = 'check';
+ unset( $fields['Confirm']['default'] );
+ $this->preErrors[] = 'ipb-confirmhideuser';
+ }
+
+ # Or if the user is trying to block themselves
+ if( (string)$this->target === $wgUser->getName() ){
+ $fields['Confirm']['type'] = 'check';
+ unset( $fields['Confirm']['default'] );
+ $this->preErrors[] = 'ipb-blockingself';
+ }
+ }
+
+ /**
+ * Add header elements like block log entries, etc.
+ * @param $form HTMLForm
+ * @return void
+ */
+ protected function doPreText( HTMLForm &$form ){
+ $form->addPreText( wfMsgExt( 'blockiptext', 'parse' ) );
+
+ $otherBlockMessages = array();
+ if( $this->target !== null ) {
+ # Get other blocks, i.e. from GlobalBlocking or TorBlock extension
+ wfRunHooks( 'OtherBlockLogLink', array( &$otherBlockMessages, $this->target ) );
+
+ if( count( $otherBlockMessages ) ) {
+ $s = Html::rawElement(
+ 'h2',
+ array(),
+ wfMsgExt( 'ipb-otherblocks-header', 'parseinline', count( $otherBlockMessages ) )
+ ) . "\n";
+ $list = '';
+ foreach( $otherBlockMessages as $link ) {
+ $list .= Html::rawElement( 'li', array(), $link ) . "\n";
+ }
+ $s .= Html::rawElement(
+ 'ul',
+ array( 'class' => 'mw-blockip-alreadyblocked' ),
+ $list
+ ) . "\n";
+ $form->addPreText( $s );
+ }
+ }
+ }
+
+ /**
+ * Add header text inside the form, just underneath where the errors would go
+ * @param $form HTMLForm
+ * @return void
+ */
+ protected function doHeaderText( HTMLForm &$form ){
+ global $wgRequest;
+ # Don't need to do anything if the form has been posted
+ if( !$wgRequest->wasPosted() && $this->preErrors ){
+ $s = HTMLForm::formatErrors( $this->preErrors );
+ if( $s ){
+ $form->addHeaderText( Html::rawElement(
+ 'div',
+ array( 'class' => 'error' ),
+ $s
+ ) );
+ }
+ }
+ }
+
+ /**
+ * Add footer elements to the form
+ * @param $form HTMLForm
+ * @return void
+ */
+ protected function doPostText( HTMLForm &$form ){
+ global $wgUser, $wgLang;
+
+ # Link to the user's contributions, if applicable
+ if( $this->target instanceof User ){
+ $contribsPage = SpecialPage::getTitleFor( 'Contributions', $this->target->getName() );
+ $links[] = Linker::link(
+ $contribsPage,
+ wfMsgExt( 'ipb-blocklist-contribs', 'escape', $this->target->getName() )
+ );
+ }
+
+ # Link to unblock the specified user, or to a blank unblock form
+ if( $this->target instanceof User ) {
+ $message = wfMsgExt( 'ipb-unblock-addr', array( 'parseinline' ), $this->target->getName() );
+ $list = SpecialPage::getTitleFor( 'Unblock', $this->target->getName() );
+ } else {
+ $message = wfMsgExt( 'ipb-unblock', array( 'parseinline' ) );
+ $list = SpecialPage::getTitleFor( 'Unblock' );
+ }
+ $links[] = Linker::linkKnown( $list, $message, array() );
+
+ # Link to the block list
+ $links[] = Linker::linkKnown(
+ SpecialPage::getTitleFor( 'BlockList' ),
+ wfMsg( 'ipb-blocklist' )
+ );
+
+ # Link to edit the block dropdown reasons, if applicable
+ if ( $wgUser->isAllowed( 'editinterface' ) ) {
+ $links[] = Linker::link(
+ Title::makeTitle( NS_MEDIAWIKI, 'Ipbreason-dropdown' ),
+ wfMsgHtml( 'ipb-edit-dropdown' ),
+ array(),
+ array( 'action' => 'edit' )
+ );
+ }
+
+ $form->addPostText( Html::rawElement(
+ 'p',
+ array( 'class' => 'mw-ipb-conveniencelinks' ),
+ $wgLang->pipeList( $links )
+ ) );
+
+ if( $this->target instanceof User ){
+ # Get relevant extracts from the block and suppression logs, if possible
+ $userpage = $this->target->getUserPage();
+ $out = '';
+
+ LogEventsList::showLogExtract(
+ $out,
+ 'block',
+ $userpage->getPrefixedText(),
+ '',
+ array(
+ 'lim' => 10,
+ 'msgKey' => array( 'blocklog-showlog', $userpage->getText() ),
+ 'showIfEmpty' => false
+ )
+ );
+ $form->addPostText( $out );
+
+ # Add suppression block entries if allowed
+ if( $wgUser->isAllowed( 'suppressionlog' ) ) {
+ LogEventsList::showLogExtract(
+ $out,
+ 'suppress',
+ $userpage->getPrefixedText(),
+ '',
+ array(
+ 'lim' => 10,
+ 'conds' => array( 'log_action' => array( 'block', 'reblock', 'unblock' ) ),
+ 'msgKey' => array( 'blocklog-showsuppresslog', $userpage->getText() ),
+ 'showIfEmpty' => false
+ )
+ );
+ $form->addPostText( $out );
+ }
+ }
+ }
+
+ /**
+ * Determine the target of the block, and the type of target
+ * TODO: should be in Block.php?
+ * @param $par String subpage parameter passed to setup, or data value from
+ * the HTMLForm
+ * @param $request WebRequest optionally try and get data from a request too
+ * @return void
+ */
+ public static function getTargetAndType( $par, WebRequest $request = null ){
+ $i = 0;
+ $target = null;
+ while( true ){
+ switch( $i++ ){
+ case 0:
+ # The HTMLForm will check wpTarget first and only if it doesn't get
+ # a value use the default, which will be generated from the options
+ # below; so this has to have a higher precedence here than $par, or
+ # we could end up with different values in $this->target and the HTMLForm!
+ if( $request instanceof WebRequest ){
+ $target = $request->getText( 'wpTarget', null );
+ }
+ break;
+ case 1:
+ $target = $par;
+ break;
+ case 2:
+ if( $request instanceof WebRequest ){
+ $target = $request->getText( 'ip', null );
+ }
+ break;
+ case 3:
+ # B/C @since 1.18
+ if( $request instanceof WebRequest ){
+ $target = $request->getText( 'wpBlockAddress', null );
+ }
+ break;
+ case 4:
+ break 2;
+ }
+ list( $target, $type ) = Block::parseTarget( $target );
+ if( $type !== null ){
+ return array( $target, $type );
+ }
+ }
+ return array( null, null );
+ }
+
+ /**
+ * HTMLForm field validation-callback for Target field.
+ * @since 1.18
+ * @param $value String
+ * @param $alldata Array
+ * @return Message
+ */
+ public static function validateTargetField( $value, $alldata = null ) {
+ global $wgBlockCIDRLimit;
+
+ list( $target, $type ) = self::getTargetAndType( $value );
+
+ if( $type == Block::TYPE_USER ){
+ # TODO: why do we not have a User->exists() method?
+ if( !$target->getId() ){
+ return wfMessage( 'nosuchusershort',
+ wfEscapeWikiText( $target->getName() ) );
+ }
+
+ $status = self::checkUnblockSelf( $target );
+ if ( $status !== true ) {
+ return wfMessage( 'badaccess', $status );
+ }
+
+ } elseif( $type == Block::TYPE_RANGE ){
+ list( $ip, $range ) = explode( '/', $target, 2 );
+
+ if( ( IP::isIPv4( $ip ) && $wgBlockCIDRLimit['IPv4'] == 32 )
+ || ( IP::isIPv6( $ip ) && $wgBlockCIDRLimit['IPv6'] == 128 ) )
+ {
+ # Range block effectively disabled
+ return wfMessage( 'range_block_disabled' );
+ }
+
+ if( ( IP::isIPv4( $ip ) && $range > 32 )
+ || ( IP::isIPv6( $ip ) && $range > 128 ) )
+ {
+ # Dodgy range
+ return wfMessage( 'ip_range_invalid' );
+ }
+
+ if( IP::isIPv4( $ip ) && $range < $wgBlockCIDRLimit['IPv4'] ) {
+ return wfMessage( 'ip_range_toolarge', $wgBlockCIDRLimit['IPv4'] );
+ }
+
+ if( IP::isIPv6( $ip ) && $range < $wgBlockCIDRLimit['IPv6'] ) {
+ return wfMessage( 'ip_range_toolarge', $wgBlockCIDRLimit['IPv6'] );
+ }
+
+ } elseif( $type == Block::TYPE_IP ){
+ # All is well
+
+ } else {
+ return wfMessage( 'badipaddress' );
+ }
+
+ return true;
+ }
+
+ /**
+ * Given the form data, actually implement a block
+ * @param $data Array
+ * @return Bool|String
+ */
+ public static function processForm( array $data ){
+ global $wgUser, $wgBlockAllowsUTEdit;
+
+ // Handled by field validator callback
+ // self::validateTargetField( $data['Target'] );
+
+ # This might have been a hidden field or a checkbox, so interesting data
+ # can come from it
+ $data['Confirm'] = !in_array( $data['Confirm'], array( '', '0', null, false ), true );
+
+ list( $target, $type ) = self::getTargetAndType( $data['Target'] );
+ if( $type == Block::TYPE_USER ){
+ $user = $target;
+ $target = $user->getName();
+ $userId = $user->getId();
+
+ # Give admins a heads-up before they go and block themselves. Much messier
+ # to do this for IPs, but it's pretty unlikely they'd ever get the 'block'
+ # permission anyway, although the code does allow for it
+ if( $target === $wgUser->getName() &&
+ ( $data['PreviousTarget'] !== $data['Target'] || !$data['Confirm'] ) )
+ {
+ return array( 'ipb-blockingself' );
+ }
+
+ } elseif( $type == Block::TYPE_RANGE ){
+ $userId = 0;
+
+ } elseif( $type == Block::TYPE_IP ){
+ $target = $target->getName();
+ $userId = 0;
+
+ } else {
+ # This should have been caught in the form field validation
+ return array( 'badipaddress' );
+ }
+
+ if( ( strlen( $data['Expiry'] ) == 0) || ( strlen( $data['Expiry'] ) > 50 )
+ || !self::parseExpiryInput( $data['Expiry'] ) )
+ {
+ return array( 'ipb_expiry_invalid' );
+ }
+
+ if( !isset( $data['DisableEmail'] ) ){
+ $data['DisableEmail'] = false;
+ }
+
+ # If the user has done the form 'properly', they won't even have been given the
+ # option to suppress-block unless they have the 'hideuser' permission
+ if( !isset( $data['HideUser'] ) ){
+ $data['HideUser'] = false;
+ }
+ if( $data['HideUser'] ) {
+ if( !$wgUser->isAllowed('hideuser') ){
+ # this codepath is unreachable except by a malicious user spoofing forms,
+ # or by race conditions (user has oversight and sysop, loads block form,
+ # and is de-oversighted before submission); so need to fail completely
+ # rather than just silently disable hiding
+ return array( 'badaccess-group0' );
+ }
+
+ # Recheck params here...
+ if( $type != Block::TYPE_USER ) {
+ $data['HideUser'] = false; # IP users should not be hidden
+
+ } elseif( !in_array( $data['Expiry'], array( 'infinite', 'infinity', 'indefinite' ) ) ) {
+ # Bad expiry.
+ return array( 'ipb_expiry_temp' );
+
+ } elseif( $user->getEditCount() > self::HIDEUSER_CONTRIBLIMIT ) {
+ # Typically, the user should have a handful of edits.
+ # Disallow hiding users with many edits for performance.
+ return array( 'ipb_hide_invalid' );
+
+ } elseif( !$data['Confirm'] ){
+ return array( 'ipb-confirmhideuser' );
+ }
+ }
+
+ # Create block object.
+ $block = new Block();
+ $block->setTarget( $target );
+ $block->setBlocker( $wgUser );
+ $block->mReason = $data['Reason'][0];
+ $block->mExpiry = self::parseExpiryInput( $data['Expiry'] );
+ $block->prevents( 'createaccount', $data['CreateAccount'] );
+ $block->prevents( 'editownusertalk', ( !$wgBlockAllowsUTEdit || $data['DisableUTEdit'] ) );
+ $block->prevents( 'sendemail', $data['DisableEmail'] );
+ $block->isHardblock( $data['HardBlock'] );
+ $block->isAutoblocking( $data['AutoBlock'] );
+ $block->mHideName = $data['HideUser'];
+
+ if( !wfRunHooks( 'BlockIp', array( &$block, &$wgUser ) ) ) {
+ return array( 'hookaborted' );
+ }
+
+ # Try to insert block. Is there a conflicting block?
+ $status = $block->insert();
+ if( !$status ) {
+ # Show form unless the user is already aware of this...
+ if( !$data['Confirm'] || ( array_key_exists( 'PreviousTarget', $data )
+ && $data['PreviousTarget'] !== $target ) )
+ {
+ return array( array( 'ipb_already_blocked', $block->getTarget() ) );
+ # Otherwise, try to update the block...
+ } else {
+ # This returns direct blocks before autoblocks/rangeblocks, since we should
+ # be sure the user is blocked by now it should work for our purposes
+ $currentBlock = Block::newFromTarget( $target );
+
+ if( $block->equals( $currentBlock ) ) {
+ return array( array( 'ipb_already_blocked', $block->getTarget() ) );
+ }
+
+ # If the name was hidden and the blocking user cannot hide
+ # names, then don't allow any block changes...
+ if( $currentBlock->mHideName && !$wgUser->isAllowed( 'hideuser' ) ) {
+ return array( 'cant-see-hidden-user' );
+ }
+
+ $currentBlock->delete();
+ $status = $block->insert();
+ $logaction = 'reblock';
+
+ # Unset _deleted fields if requested
+ if( $currentBlock->mHideName && !$data['HideUser'] ) {
+ RevisionDeleteUser::unsuppressUserName( $target, $userId );
+ }
+
+ # If hiding/unhiding a name, this should go in the private logs
+ if( (bool)$currentBlock->mHideName ){
+ $data['HideUser'] = true;
+ }
+ }
+ } else {
+ $logaction = 'block';
+ }
+
+ wfRunHooks( 'BlockIpComplete', array( $block, $wgUser ) );
+
+ # Set *_deleted fields if requested
+ if( $data['HideUser'] ) {
+ RevisionDeleteUser::suppressUserName( $target, $userId );
+ }
+
+ # Can't watch a rangeblock
+ if( $type != Block::TYPE_RANGE && $data['Watch'] ) {
+ $wgUser->addWatch( Title::makeTitle( NS_USER, $target ) );
+ }
+
+ # Block constructor sanitizes certain block options on insert
+ $data['BlockEmail'] = $block->prevents( 'sendemail' );
+ $data['AutoBlock'] = $block->isAutoblocking();
+
+ # Prepare log parameters
+ $logParams = array();
+ $logParams[] = $data['Expiry'];
+ $logParams[] = self::blockLogFlags( $data, $type );
+
+ # Make log entry, if the name is hidden, put it in the oversight log
+ $log_type = $data['HideUser'] ? 'suppress' : 'block';
+ $log = new LogPage( $log_type );
+ $log_id = $log->addEntry(
+ $logaction,
+ Title::makeTitle( NS_USER, $target ),
+ $data['Reason'][0],
+ $logParams
+ );
+ # Relate log ID to block IDs (bug 25763)
+ $blockIds = array_merge( array( $status['id'] ), $status['autoIds'] );
+ $log->addRelations( 'ipb_id', $blockIds, $log_id );
+
+ # Report to the user
+ return true;
+ }
+
+ /**
+ * Get an array of suggested block durations from MediaWiki:Ipboptions
+ * @todo FIXME: This uses a rather odd syntax for the options, should it be converted
+ * to the standard "**<duration>|<displayname>" format?
+ * @param $lang Language|null the language to get the durations in, or null to use
+ * the wiki's content language
+ * @return Array
+ */
+ public static function getSuggestedDurations( $lang = null ){
+ $a = array();
+ $msg = $lang === null
+ ? wfMessage( 'ipboptions' )->inContentLanguage()->text()
+ : wfMessage( 'ipboptions' )->inLanguage( $lang )->text();
+
+ if( $msg == '-' ){
+ return array();
+ }
+
+ foreach( explode( ',', $msg ) as $option ) {
+ if( strpos( $option, ':' ) === false ){
+ $option = "$option:$option";
+ }
+ list( $show, $value ) = explode( ':', $option );
+ $a[htmlspecialchars( $show )] = htmlspecialchars( $value );
+ }
+ return $a;
+ }
+
+ /**
+ * Convert a submitted expiry time, which may be relative ("2 weeks", etc) or absolute
+ * ("24 May 2034", etc), into an absolute timestamp we can put into the database.
+ * @param $expiry String: whatever was typed into the form
+ * @return String: timestamp or "infinity" string for the DB implementation
+ */
+ public static function parseExpiryInput( $expiry ) {
+ static $infinity;
+ if( $infinity == null ){
+ $infinity = wfGetDB( DB_SLAVE )->getInfinity();
+ }
+ if ( $expiry == 'infinite' || $expiry == 'indefinite' ) {
+ $expiry = $infinity;
+ } else {
+ $expiry = strtotime( $expiry );
+ if ( $expiry < 0 || $expiry === false ) {
+ return false;
+ }
+ $expiry = wfTimestamp( TS_MW, $expiry );
+ }
+ return $expiry;
+ }
+
+ /**
+ * Can we do an email block?
+ * @param $user User: the sysop wanting to make a block
+ * @return Boolean
+ */
+ public static function canBlockEmail( $user ) {
+ global $wgEnableUserEmail, $wgSysopEmailBans;
+ return ( $wgEnableUserEmail && $wgSysopEmailBans && $user->isAllowed( 'blockemail' ) );
+ }
+
+ /**
+ * bug 15810: blocked admins should not be able to block/unblock
+ * others, and probably shouldn't be able to unblock themselves
+ * either.
+ * @param $user User|Int|String
+ * @return Bool|String true or error message key
+ */
+ public static function checkUnblockSelf( $user ) {
+ global $wgUser;
+ if ( is_int( $user ) ) {
+ $user = User::newFromId( $user );
+ } elseif ( is_string( $user ) ) {
+ $user = User::newFromName( $user );
+ }
+ if( $wgUser->isBlocked() ){
+ if( $user instanceof User && $user->getId() == $wgUser->getId() ) {
+ # User is trying to unblock themselves
+ if ( $wgUser->isAllowed( 'unblockself' ) ) {
+ return true;
+ # User blocked themselves and is now trying to reverse it
+ } elseif ( $wgUser->blockedBy() === $wgUser->getName() ) {
+ return true;
+ } else {
+ return 'ipbnounblockself';
+ }
+ } else {
+ # User is trying to block/unblock someone else
+ return 'ipbblocked';
+ }
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ * Return a comma-delimited list of "flags" to be passed to the log
+ * reader for this block, to provide more information in the logs
+ * @param $data Array from HTMLForm data
+ * @param $type Block::TYPE_ constant
+ * @return array
+ */
+ protected static function blockLogFlags( array $data, $type ) {
+ global $wgBlockAllowsUTEdit;
+ $flags = array();
+
+ # when blocking a user the option 'anononly' is not available/has no effect -> do not write this into log
+ if( !$data['HardBlock'] && $type != Block::TYPE_USER ){
+ $flags[] = 'anononly';
+ }
+
+ if( $data['CreateAccount'] ){
+ $flags[] = 'nocreate';
+ }
+
+ # Same as anononly, this is not displayed when blocking an IP address
+ if( !$data['AutoBlock'] && $type != Block::TYPE_IP ){
+ $flags[] = 'noautoblock';
+ }
+
+ if( $data['DisableEmail'] ){
+ $flags[] = 'noemail';
+ }
+
+ if( $wgBlockAllowsUTEdit && $data['DisableUTEdit'] ){
+ $flags[] = 'nousertalk';
+ }
+
+ if( $data['HideUser'] ){
+ $flags[] = 'hiddenname';
+ }
+
+ return implode( ',', $flags );
+ }
+}
+
+# BC @since 1.18
+class IPBlockForm extends SpecialBlock {}
diff --git a/includes/specials/SpecialBlockList.php b/includes/specials/SpecialBlockList.php
new file mode 100644
index 00000000..ebeb5874
--- /dev/null
+++ b/includes/specials/SpecialBlockList.php
@@ -0,0 +1,437 @@
+<?php
+/**
+ * Implements Special:BlockList
+ *
+ * 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.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup SpecialPage
+ */
+
+/**
+ * A special page that lists existing blocks
+ *
+ * @ingroup SpecialPage
+ */
+class SpecialBlockList extends SpecialPage {
+
+ protected $target, $options;
+
+ function __construct() {
+ parent::__construct( 'BlockList' );
+ }
+
+ /**
+ * Main execution point
+ *
+ * @param $par String title fragment
+ */
+ public function execute( $par ) {
+ global $wgOut, $wgRequest, $wgLang;
+
+ $this->setHeaders();
+ $this->outputHeader();
+ $wgOut->setPageTitle( wfMsg( 'ipblocklist' ) );
+ $wgOut->addModuleStyles( 'mediawiki.special' );
+
+ $par = $wgRequest->getVal( 'ip', $par );
+ $this->target = trim( $wgRequest->getVal( 'wpTarget', $par ) );
+
+ $this->options = $wgRequest->getArray( 'wpOptions', array() );
+
+ $action = $wgRequest->getText( 'action' );
+
+ if( $action == 'unblock' || $action == 'submit' && $wgRequest->wasPosted() ) {
+ # B/C @since 1.18: Unblock interface is now at Special:Unblock
+ $title = SpecialPage::getTitleFor( 'Unblock', $this->target );
+ $wgOut->redirect( $title->getFullUrl() );
+ return;
+ }
+
+ # Just show the block list
+ $fields = array(
+ 'Target' => array(
+ 'type' => 'text',
+ 'label-message' => 'ipadressorusername',
+ 'tabindex' => '1',
+ 'size' => '45',
+ ),
+ 'Options' => array(
+ 'type' => 'multiselect',
+ 'options' => array(
+ wfMsg( 'blocklist-userblocks' ) => 'userblocks',
+ wfMsg( 'blocklist-tempblocks' ) => 'tempblocks',
+ wfMsg( 'blocklist-addressblocks' ) => 'addressblocks',
+ ),
+ 'flatlist' => true,
+ ),
+ 'Limit' => array(
+ 'class' => 'HTMLBlockedUsersItemSelect',
+ 'label-message' => 'table_pager_limit_label',
+ 'options' => array(
+ $wgLang->formatNum( 20 ) => 20,
+ $wgLang->formatNum( 50 ) => 50,
+ $wgLang->formatNum( 100 ) => 100,
+ $wgLang->formatNum( 250 ) => 250,
+ $wgLang->formatNum( 500 ) => 500,
+ ),
+ 'name' => 'limit',
+ 'default' => 50,
+ ),
+ );
+ $form = new HTMLForm( $fields, $this->getContext() );
+ $form->setMethod( 'get' );
+ $form->setWrapperLegend( wfMsg( 'ipblocklist-legend' ) );
+ $form->setSubmitText( wfMsg( 'ipblocklist-submit' ) );
+ $form->prepareForm();
+
+ $form->displayForm( '' );
+ $this->showList();
+ }
+
+ function showList() {
+ global $wgOut, $wgUser;
+
+ # Purge expired entries on one in every 10 queries
+ if ( !mt_rand( 0, 10 ) ) {
+ Block::purgeExpired();
+ }
+
+ $conds = array();
+ # Is the user allowed to see hidden blocks?
+ if ( !$wgUser->isAllowed( 'hideuser' ) ){
+ $conds['ipb_deleted'] = 0;
+ }
+
+ if ( $this->target !== '' ){
+ list( $target, $type ) = Block::parseTarget( $this->target );
+
+ switch( $type ){
+ case Block::TYPE_ID:
+ $conds['ipb_id'] = $target;
+ break;
+
+ case Block::TYPE_IP:
+ case Block::TYPE_RANGE:
+ list( $start, $end ) = IP::parseRange( $target );
+ $dbr = wfGetDB( DB_SLAVE );
+ $conds[] = $dbr->makeList(
+ array(
+ 'ipb_address' => $target,
+ Block::getRangeCond( $start, $end )
+ ),
+ LIST_OR
+ );
+ $conds['ipb_auto'] = 0;
+ break;
+
+ case Block::TYPE_USER:
+ $conds['ipb_address'] = (string)$this->target;
+ $conds['ipb_auto'] = 0;
+ break;
+ }
+ }
+
+ # Apply filters
+ if( in_array( 'userblocks', $this->options ) ) {
+ $conds['ipb_user'] = 0;
+ }
+ if( in_array( 'tempblocks', $this->options ) ) {
+ $conds['ipb_expiry'] = 'infinity';
+ }
+ if( in_array( 'addressblocks', $this->options ) ) {
+ $conds[] = "ipb_user != 0 OR ipb_range_end > ipb_range_start";
+ }
+
+ # Check for other blocks, i.e. global/tor blocks
+ $otherBlockLink = array();
+ wfRunHooks( 'OtherBlockLogLink', array( &$otherBlockLink, $this->target ) );
+
+ # Show additional header for the local block only when other blocks exists.
+ # Not necessary in a standard installation without such extensions enabled
+ if( count( $otherBlockLink ) ) {
+ $wgOut->addHTML(
+ Html::rawElement( 'h2', array(), wfMsg( 'ipblocklist-localblock' ) ) . "\n"
+ );
+ }
+
+ $pager = new BlockListPager( $this, $conds );
+ if ( $pager->getNumRows() ) {
+ $wgOut->addHTML(
+ $pager->getNavigationBar() .
+ $pager->getBody().
+ $pager->getNavigationBar()
+ );
+
+ } elseif ( $this->target ) {
+ $wgOut->addWikiMsg( 'ipblocklist-no-results' );
+
+ } else {
+ $wgOut->addWikiMsg( 'ipblocklist-empty' );
+ }
+
+ if( count( $otherBlockLink ) ) {
+ $wgOut->addHTML(
+ Html::rawElement(
+ 'h2',
+ array(),
+ wfMsgExt(
+ 'ipblocklist-otherblocks',
+ 'parseinline',
+ count( $otherBlockLink )
+ )
+ ) . "\n"
+ );
+ $list = '';
+ foreach( $otherBlockLink as $link ) {
+ $list .= Html::rawElement( 'li', array(), $link ) . "\n";
+ }
+ $wgOut->addHTML( Html::rawElement( 'ul', array( 'class' => 'mw-ipblocklist-otherblocks' ), $list ) . "\n" );
+ }
+ }
+}
+
+class BlockListPager extends TablePager {
+ protected $conds;
+ protected $page;
+
+ function __construct( $page, $conds ) {
+ $this->page = $page;
+ $this->conds = $conds;
+ $this->mDefaultDirection = true;
+ parent::__construct();
+ }
+
+ function getFieldNames() {
+ static $headers = null;
+
+ if ( $headers == array() ) {
+ $headers = array(
+ 'ipb_timestamp' => 'blocklist-timestamp',
+ 'ipb_target' => 'blocklist-target',
+ 'ipb_expiry' => 'blocklist-expiry',
+ 'ipb_by' => 'blocklist-by',
+ 'ipb_params' => 'blocklist-params',
+ 'ipb_reason' => 'blocklist-reason',
+ );
+ $headers = array_map( 'wfMsg', $headers );
+ }
+
+ return $headers;
+ }
+
+ function formatValue( $name, $value ) {
+ global $wgLang, $wgUser;
+
+ static $sk, $msg;
+ if ( empty( $sk ) ) {
+ $sk = $this->getSkin();
+ $msg = array(
+ 'anononlyblock',
+ 'createaccountblock',
+ 'noautoblockblock',
+ 'emailblock',
+ 'blocklist-nousertalk',
+ 'unblocklink',
+ 'change-blocklink',
+ 'infiniteblock',
+ );
+ $msg = array_combine( $msg, array_map( 'wfMessage', $msg ) );
+ }
+
+ $row = $this->mCurrentRow;
+ $formatted = '';
+
+ switch( $name ) {
+ case 'ipb_timestamp':
+ $formatted = $wgLang->timeanddate( $value, /* User preference timezone */ true );
+ break;
+
+ case 'ipb_target':
+ if( $row->ipb_auto ){
+ $formatted = wfMessage( 'autoblockid', $row->ipb_id )->parse();
+ } else {
+ list( $target, $type ) = Block::parseTarget( $row->ipb_address );
+ switch( $type ){
+ case Block::TYPE_USER:
+ case Block::TYPE_IP:
+ $formatted = $sk->userLink( $target->getId(), $target );
+ $formatted .= $sk->userToolLinks(
+ $target->getId(),
+ $target,
+ false,
+ Linker::TOOL_LINKS_NOBLOCK
+ );
+ break;
+ case Block::TYPE_RANGE:
+ $formatted = htmlspecialchars( $target );
+ }
+ }
+ break;
+
+ case 'ipb_expiry':
+ $formatted = $wgLang->formatExpiry( $value, /* User preference timezone */ true );
+ if( $wgUser->isAllowed( 'block' ) ){
+ if( $row->ipb_auto ){
+ $links[] = $sk->linkKnown(
+ SpecialPage::getTitleFor( 'Unblock' ),
+ $msg['unblocklink'],
+ array(),
+ array( 'wpTarget' => "#{$row->ipb_id}" )
+ );
+ } else {
+ $links[] = $sk->linkKnown(
+ SpecialPage::getTitleFor( 'Unblock', $row->ipb_address ),
+ $msg['unblocklink']
+ );
+ $links[] = $sk->linkKnown(
+ SpecialPage::getTitleFor( 'Block', $row->ipb_address ),
+ $msg['change-blocklink']
+ );
+ }
+ $formatted .= ' ' . Html::rawElement(
+ 'span',
+ array( 'class' => 'mw-blocklist-actions' ),
+ wfMsg( 'parentheses', $wgLang->pipeList( $links ) )
+ );
+ }
+ break;
+
+ case 'ipb_by':
+ $user = User::newFromId( $value );
+ if( $user instanceof User ){
+ $formatted = $sk->userLink( $user->getId(), $user->getName() );
+ $formatted .= $sk->userToolLinks( $user->getId(), $user->getName() );
+ }
+ break;
+
+ case 'ipb_reason':
+ $formatted = $sk->commentBlock( $value );
+ break;
+
+ case 'ipb_params':
+ $properties = array();
+ if ( $row->ipb_anon_only ) {
+ $properties[] = $msg['anononlyblock'];
+ }
+ if ( $row->ipb_create_account ) {
+ $properties[] = $msg['createaccountblock'];
+ }
+ if ( $row->ipb_user && !$row->ipb_enable_autoblock ) {
+ $properties[] = $msg['noautoblockblock'];
+ }
+
+ if ( $row->ipb_block_email ) {
+ $properties[] = $msg['emailblock'];
+ }
+
+ if ( !$row->ipb_allow_usertalk ) {
+ $properties[] = $msg['blocklist-nousertalk'];
+ }
+
+ $formatted = $wgLang->commaList( $properties );
+ break;
+
+ default:
+ $formatted = "Unable to format $name";
+ break;
+ }
+
+ return $formatted;
+ }
+
+ function getQueryInfo() {
+ $info = array(
+ 'tables' => array( 'ipblocks' ),
+ 'fields' => array(
+ 'ipb_id',
+ 'ipb_address',
+ 'ipb_user',
+ 'ipb_by',
+ 'ipb_reason',
+ 'ipb_timestamp',
+ 'ipb_auto',
+ 'ipb_anon_only',
+ 'ipb_create_account',
+ 'ipb_enable_autoblock',
+ 'ipb_expiry',
+ 'ipb_range_start',
+ 'ipb_range_end',
+ 'ipb_deleted',
+ 'ipb_block_email',
+ 'ipb_allow_usertalk',
+ ),
+ 'conds' => $this->conds,
+ );
+
+ global $wgUser;
+ # Is the user allowed to see hidden blocks?
+ if ( !$wgUser->isAllowed( 'hideuser' ) ){
+ $conds['ipb_deleted'] = 0;
+ }
+
+ return $info;
+ }
+
+ public function getTableClass(){
+ return 'TablePager mw-blocklist';
+ }
+
+ function getIndexField() {
+ return 'ipb_timestamp';
+ }
+
+ function getDefaultSort() {
+ return 'ipb_timestamp';
+ }
+
+ function isFieldSortable( $name ) {
+ return false;
+ }
+
+ function getTitle() {
+ return $this->page->getTitle();
+ }
+}
+
+/**
+ * Items per page dropdown. Essentially a crap workaround for bug 32603.
+ *
+ * @todo Do not release 1.19 with this.
+ */
+class HTMLBlockedUsersItemSelect extends HTMLSelectField {
+ /**
+ * Basically don't do any validation. If it's a number that's fine. Also,
+ * add it to the list if it's not there already
+ *
+ * @param $value
+ * @param $alldata
+ * @return bool
+ */
+ function validate( $value, $alldata ) {
+ if ( $value == '' ) {
+ return true;
+ }
+
+ if ( !in_array( $value, $this->mParams['options'] ) ) {
+ $this->mParams['options'][ $this->mParent->getLanguage()->formatNum( $value ) ] = intval($value);
+ asort( $this->mParams['options'] );
+ }
+
+ return true;
+ }
+
+}
diff --git a/includes/specials/SpecialBlockip.php b/includes/specials/SpecialBlockip.php
deleted file mode 100644
index 28a0f3f1..00000000
--- a/includes/specials/SpecialBlockip.php
+++ /dev/null
@@ -1,892 +0,0 @@
-<?php
-/**
- * Implements Special:Blockip
- *
- * 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.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup SpecialPage
- */
-
-/**
- * A special page that allows users with 'block' right to block users from
- * editing pages and other actions
- *
- * @ingroup SpecialPage
- */
-class IPBlockForm extends SpecialPage {
- var $BlockAddress, $BlockExpiry, $BlockReason, $BlockReasonList, $BlockOther, $BlockAnonOnly, $BlockCreateAccount,
- $BlockEnableAutoblock, $BlockEmail, $BlockHideName, $BlockAllowUsertalk, $BlockReblock;
- // The maximum number of edits a user can have and still be hidden
- const HIDEUSER_CONTRIBLIMIT = 1000;
-
- public function __construct() {
- parent::__construct( 'Blockip', 'block' );
- }
-
- public function execute( $par ) {
- global $wgUser, $wgOut, $wgRequest;
-
- # Can't block when the database is locked
- if( wfReadOnly() ) {
- $wgOut->readOnlyPage();
- return;
- }
- # Permission check
- if( !$this->userCanExecute( $wgUser ) ) {
- $wgOut->permissionRequired( 'block' );
- return;
- }
-
- $this->setup( $par );
-
- # bug 15810: blocked admins should have limited access here
- if ( $wgUser->isBlocked() ) {
- $status = IPBlockForm::checkUnblockSelf( $this->BlockAddress );
- if ( $status !== true ) {
- throw new ErrorPageError( 'badaccess', $status );
- }
- }
-
- $action = $wgRequest->getVal( 'action' );
- if( 'success' == $action ) {
- $this->showSuccess();
- } elseif( $wgRequest->wasPosted() && 'submit' == $action &&
- $wgUser->matchEditToken( $wgRequest->getVal( 'wpEditToken' ) ) ) {
- $this->doSubmit();
- } else {
- $this->showForm( '' );
- }
- }
-
- private function setup( $par ) {
- global $wgRequest, $wgUser, $wgBlockAllowsUTEdit;
-
- $this->BlockAddress = $wgRequest->getVal( 'wpBlockAddress', $wgRequest->getVal( 'ip', $par ) );
- $this->BlockAddress = strtr( $this->BlockAddress, '_', ' ' );
- $this->BlockReason = $wgRequest->getText( 'wpBlockReason' );
- $this->BlockReasonList = $wgRequest->getText( 'wpBlockReasonList' );
- $this->BlockExpiry = $wgRequest->getVal( 'wpBlockExpiry', wfMsg( 'ipbotheroption' ) );
- $this->BlockOther = $wgRequest->getVal( 'wpBlockOther', '' );
-
- # Unchecked checkboxes are not included in the form data at all, so having one
- # that is true by default is a bit tricky
- $byDefault = !$wgRequest->wasPosted();
- $this->BlockAnonOnly = $wgRequest->getBool( 'wpAnonOnly', $byDefault );
- $this->BlockCreateAccount = $wgRequest->getBool( 'wpCreateAccount', $byDefault );
- $this->BlockEnableAutoblock = $wgRequest->getBool( 'wpEnableAutoblock', $byDefault );
- $this->BlockEmail = false;
- if( self::canBlockEmail( $wgUser ) ) {
- $this->BlockEmail = $wgRequest->getBool( 'wpEmailBan', false );
- }
- $this->BlockWatchUser = $wgRequest->getBool( 'wpWatchUser', false ) && $wgUser->isLoggedIn();
- # Re-check user's rights to hide names, very serious, defaults to null
- if( $wgUser->isAllowed( 'hideuser' ) ) {
- $this->BlockHideName = $wgRequest->getBool( 'wpHideName', null );
- } else {
- $this->BlockHideName = false;
- }
- $this->BlockAllowUsertalk = ( $wgRequest->getBool( 'wpAllowUsertalk', $byDefault ) && $wgBlockAllowsUTEdit );
- $this->BlockReblock = $wgRequest->getBool( 'wpChangeBlock', false );
-
- $this->wasPosted = $wgRequest->wasPosted();
- }
-
- public function showForm( $err ) {
- global $wgOut, $wgUser, $wgSysopUserBans;
-
- $wgOut->setPageTitle( wfMsg( 'blockip-title' ) );
- $wgOut->addWikiMsg( 'blockiptext' );
-
- if( $wgSysopUserBans ) {
- $mIpaddress = Xml::label( wfMsg( 'ipadressorusername' ), 'mw-bi-target' );
- } else {
- $mIpaddress = Xml::label( wfMsg( 'ipaddress' ), 'mw-bi-target' );
- }
- $mIpbexpiry = Xml::label( wfMsg( 'ipbexpiry' ), 'wpBlockExpiry' );
- $mIpbother = Xml::label( wfMsg( 'ipbother' ), 'mw-bi-other' );
- $mIpbreasonother = Xml::label( wfMsg( 'ipbreason' ), 'wpBlockReasonList' );
- $mIpbreason = Xml::label( wfMsg( 'ipbotherreason' ), 'mw-bi-reason' );
-
- $titleObj = SpecialPage::getTitleFor( 'Blockip' );
- $user = User::newFromName( $this->BlockAddress );
-
- $alreadyBlocked = false;
- $otherBlockedMsgs = array();
- if( $err && $err[0] != 'ipb_already_blocked' ) {
- $key = array_shift( $err );
- $msg = wfMsgReal( $key, $err );
- $wgOut->setSubtitle( wfMsgHtml( 'formerror' ) );
- $wgOut->addHTML( Xml::tags( 'p', array( 'class' => 'error' ), $msg ) );
- } elseif( $this->BlockAddress !== null ) {
- # Get other blocks, i.e. from GlobalBlocking or TorBlock extension
- wfRunHooks( 'OtherBlockLogLink', array( &$otherBlockedMsgs, $this->BlockAddress ) );
-
- $userId = is_object( $user ) ? $user->getId() : 0;
- $currentBlock = Block::newFromDB( $this->BlockAddress, $userId );
- if( !is_null( $currentBlock ) && !$currentBlock->mAuto && # The block exists and isn't an autoblock
- ( $currentBlock->mRangeStart == $currentBlock->mRangeEnd || # The block isn't a rangeblock
- # or if it is, the range is what we're about to block
- ( $currentBlock->mAddress == $this->BlockAddress ) )
- ) {
- $alreadyBlocked = true;
- # Set the block form settings to the existing block
- if( !$this->wasPosted ) {
- $this->BlockAnonOnly = $currentBlock->mAnonOnly;
- $this->BlockCreateAccount = $currentBlock->mCreateAccount;
- $this->BlockEnableAutoblock = $currentBlock->mEnableAutoblock;
- $this->BlockEmail = $currentBlock->mBlockEmail;
- $this->BlockHideName = $currentBlock->mHideName;
- $this->BlockAllowUsertalk = $currentBlock->mAllowUsertalk;
- if( $currentBlock->mExpiry == 'infinity' ) {
- $this->BlockOther = 'indefinite';
- } else {
- $this->BlockOther = wfTimestamp( TS_ISO_8601, $currentBlock->mExpiry );
- }
- $this->BlockReason = $currentBlock->mReason;
- }
- }
- }
-
- # Show other blocks from extensions, i.e. GlockBlocking and TorBlock
- if( count( $otherBlockedMsgs ) ) {
- $wgOut->addHTML(
- Html::rawElement( 'h2', array(), wfMsgExt( 'ipb-otherblocks-header', 'parseinline', count( $otherBlockedMsgs ) ) ) . "\n"
- );
- $list = '';
- foreach( $otherBlockedMsgs as $link ) {
- $list .= Html::rawElement( 'li', array(), $link ) . "\n";
- }
- $wgOut->addHTML( Html::rawElement( 'ul', array( 'class' => 'mw-blockip-alreadyblocked' ), $list ) . "\n" );
- }
-
- # Username/IP is blocked already locally
- if( $alreadyBlocked ) {
- $wgOut->wrapWikiMsg( "<div class='mw-ipb-needreblock'>\n$1\n</div>", array( 'ipb-needreblock', $this->BlockAddress ) );
- }
-
- $scBlockExpiryOptions = wfMsgForContent( 'ipboptions' );
-
- $showblockoptions = $scBlockExpiryOptions != '-';
- if( !$showblockoptions ) $mIpbother = $mIpbexpiry;
-
- $blockExpiryFormOptions = Xml::option( wfMsg( 'ipbotheroption' ), 'other' );
- foreach( explode( ',', $scBlockExpiryOptions ) as $option ) {
- if( strpos( $option, ':' ) === false ) $option = "$option:$option";
- list( $show, $value ) = explode( ':', $option );
- $show = htmlspecialchars( $show );
- $value = htmlspecialchars( $value );
- $blockExpiryFormOptions .= Xml::option( $show, $value, $this->BlockExpiry === $value ) . "\n";
- }
-
- $reasonDropDown = Xml::listDropDown( 'wpBlockReasonList',
- wfMsgForContent( 'ipbreason-dropdown' ),
- wfMsgForContent( 'ipbreasonotherlist' ), $this->BlockReasonList, 'wpBlockDropDown', 4 );
-
- $wgOut->addModules( 'mediawiki.legacy.block' );
- $wgOut->addHTML(
- Xml::openElement( 'form', array( 'method' => 'post', 'action' => $titleObj->getLocalURL( 'action=submit' ), 'id' => 'blockip' ) ) .
- Xml::openElement( 'fieldset' ) .
- Xml::element( 'legend', null, wfMsg( 'blockip-legend' ) ) .
- Xml::openElement( 'table', array( 'border' => '0', 'id' => 'mw-blockip-table' ) ) .
- "<tr>
- <td class='mw-label'>
- {$mIpaddress}
- </td>
- <td class='mw-input'>" .
- Html::input( 'wpBlockAddress', $this->BlockAddress, 'text', array(
- 'tabindex' => '1',
- 'id' => 'mw-bi-target',
- 'onchange' => 'updateBlockOptions()',
- 'size' => '45',
- 'required' => ''
- ) + ( $this->BlockAddress ? array() : array( 'autofocus' ) ) ). "
- </td>
- </tr>
- <tr>"
- );
- if( $showblockoptions ) {
- $wgOut->addHTML("
- <td class='mw-label'>
- {$mIpbexpiry}
- </td>
- <td class='mw-input'>" .
- Xml::tags( 'select',
- array(
- 'id' => 'wpBlockExpiry',
- 'name' => 'wpBlockExpiry',
- 'onchange' => 'considerChangingExpiryFocus()',
- 'tabindex' => '2' ),
- $blockExpiryFormOptions ) .
- "</td>"
- );
- }
- $wgOut->addHTML("
- </tr>
- <tr id='wpBlockOther'>
- <td class='mw-label'>
- {$mIpbother}
- </td>
- <td class='mw-input'>" .
- Xml::input( 'wpBlockOther', 45, $this->BlockOther,
- array( 'tabindex' => '3', 'id' => 'mw-bi-other' ) ) . "
- </td>
- </tr>
- <tr>
- <td class='mw-label'>
- {$mIpbreasonother}
- </td>
- <td class='mw-input'>
- {$reasonDropDown}
- </td>
- </tr>
- <tr id=\"wpBlockReason\">
- <td class='mw-label'>
- {$mIpbreason}
- </td>
- <td class='mw-input'>" .
- Html::input( 'wpBlockReason', $this->BlockReason, 'text', array(
- 'tabindex' => '5',
- 'id' => 'mw-bi-reason',
- 'maxlength' => '200',
- 'size' => '45'
- ) + ( $this->BlockAddress ? array( 'autofocus' ) : array() ) ) . "
- </td>
- </tr>
- <tr id='wpAnonOnlyRow'>
- <td>&#160;</td>
- <td class='mw-input'>" .
- Xml::checkLabel( wfMsg( 'ipbanononly' ),
- 'wpAnonOnly', 'wpAnonOnly', $this->BlockAnonOnly,
- array( 'tabindex' => '6' ) ) . "
- </td>
- </tr>
- <tr id='wpCreateAccountRow'>
- <td>&#160;</td>
- <td class='mw-input'>" .
- Xml::checkLabel( wfMsg( 'ipbcreateaccount' ),
- 'wpCreateAccount', 'wpCreateAccount', $this->BlockCreateAccount,
- array( 'tabindex' => '7' ) ) . "
- </td>
- </tr>
- <tr id='wpEnableAutoblockRow'>
- <td>&#160;</td>
- <td class='mw-input'>" .
- Xml::checkLabel( wfMsg( 'ipbenableautoblock' ),
- 'wpEnableAutoblock', 'wpEnableAutoblock', $this->BlockEnableAutoblock,
- array( 'tabindex' => '8' ) ) . "
- </td>
- </tr>"
- );
-
- if( self::canBlockEmail( $wgUser ) ) {
- $wgOut->addHTML("
- <tr id='wpEnableEmailBan'>
- <td>&#160;</td>
- <td class='mw-input'>" .
- Xml::checkLabel( wfMsg( 'ipbemailban' ),
- 'wpEmailBan', 'wpEmailBan', $this->BlockEmail,
- array( 'tabindex' => '9' ) ) . "
- </td>
- </tr>"
- );
- }
-
- // Allow some users to hide name from block log, blocklist and listusers
- if( $wgUser->isAllowed( 'hideuser' ) ) {
- $wgOut->addHTML("
- <tr id='wpEnableHideUser'>
- <td>&#160;</td>
- <td class='mw-input'><strong>" .
- Xml::checkLabel( wfMsg( 'ipbhidename' ),
- 'wpHideName', 'wpHideName', $this->BlockHideName,
- array( 'tabindex' => '10' )
- ) . "
- </strong></td>
- </tr>"
- );
- }
-
- # Watchlist their user page? (Only if user is logged in)
- if( $wgUser->isLoggedIn() ) {
- $wgOut->addHTML("
- <tr id='wpEnableWatchUser'>
- <td>&#160;</td>
- <td class='mw-input'>" .
- Xml::checkLabel( wfMsg( 'ipbwatchuser' ),
- 'wpWatchUser', 'wpWatchUser', $this->BlockWatchUser,
- array( 'tabindex' => '11' ) ) . "
- </td>
- </tr>"
- );
- }
-
- # Can we explicitly disallow the use of user_talk?
- global $wgBlockAllowsUTEdit;
- if( $wgBlockAllowsUTEdit ){
- $wgOut->addHTML("
- <tr id='wpAllowUsertalkRow'>
- <td>&#160;</td>
- <td class='mw-input'>" .
- Xml::checkLabel( wfMsg( 'ipballowusertalk' ),
- 'wpAllowUsertalk', 'wpAllowUsertalk', $this->BlockAllowUsertalk,
- array( 'tabindex' => '12' ) ) . "
- </td>
- </tr>"
- );
- }
-
- $wgOut->addHTML("
- <tr>
- <td style='padding-top: 1em'>&#160;</td>
- <td class='mw-submit' style='padding-top: 1em'>" .
- Xml::submitButton( wfMsg( $alreadyBlocked ? 'ipb-change-block' : 'ipbsubmit' ),
- array( 'name' => 'wpBlock', 'tabindex' => '13' )
- + $wgUser->getSkin()->tooltipAndAccessKeyAttribs( 'blockip-block' ) ). "
- </td>
- </tr>" .
- Xml::closeElement( 'table' ) .
- Html::hidden( 'wpEditToken', $wgUser->editToken() ) .
- ( $alreadyBlocked ? Html::hidden( 'wpChangeBlock', 1 ) : "" ) .
- Xml::closeElement( 'fieldset' ) .
- Xml::closeElement( 'form' )
- );
-
- $wgOut->addHTML( $this->getConvenienceLinks() );
-
- if( is_object( $user ) ) {
- $this->showLogFragment( $wgOut, $user->getUserPage() );
- } elseif( preg_match( '/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/', $this->BlockAddress ) ) {
- $this->showLogFragment( $wgOut, Title::makeTitle( NS_USER, $this->BlockAddress ) );
- } elseif( preg_match( '/^\w{1,4}:\w{1,4}:\w{1,4}:\w{1,4}:\w{1,4}:\w{1,4}:\w{1,4}:\w{1,4}/', $this->BlockAddress ) ) {
- $this->showLogFragment( $wgOut, Title::makeTitle( NS_USER, $this->BlockAddress ) );
- }
- }
-
- /**
- * Can we do an email block?
- * @param $user User: the sysop wanting to make a block
- * @return Boolean
- */
- public static function canBlockEmail( $user ) {
- global $wgEnableUserEmail, $wgSysopEmailBans;
- return ( $wgEnableUserEmail && $wgSysopEmailBans && $user->isAllowed( 'blockemail' ) );
- }
-
- /**
- * bug 15810: blocked admins should not be able to block/unblock
- * others, and probably shouldn't be able to unblock themselves
- * either.
- * @param $user User, Int or String
- */
- public static function checkUnblockSelf( $user ) {
- global $wgUser;
- if ( is_int( $user ) ) {
- $user = User::newFromId( $user );
- } elseif ( is_string( $user ) ) {
- $user = User::newFromName( $user );
- }
- if( $user instanceof User && $user->getId() == $wgUser->getId() ) {
- # User is trying to unblock themselves
- if ( $wgUser->isAllowed( 'unblockself' ) ) {
- return true;
- } else {
- return 'ipbnounblockself';
- }
- } else {
- # User is trying to block/unblock someone else
- return 'ipbblocked';
- }
- }
-
- /**
- * Backend block code.
- * $userID and $expiry will be filled accordingly
- * @return array(message key, arguments) on failure, empty array on success
- */
- function doBlock( &$userId = null, &$expiry = null ) {
- global $wgUser, $wgSysopUserBans, $wgSysopRangeBans, $wgBlockAllowsUTEdit, $wgBlockCIDRLimit;
-
- $userId = 0;
- # Expand valid IPv6 addresses, usernames are left as is
- $this->BlockAddress = IP::sanitizeIP( $this->BlockAddress );
- # isIPv4() and IPv6() are used for final validation
- $rxIP4 = '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}';
- $rxIP6 = '\w{1,4}:\w{1,4}:\w{1,4}:\w{1,4}:\w{1,4}:\w{1,4}:\w{1,4}:\w{1,4}';
- $rxIP = "($rxIP4|$rxIP6)";
-
- # Check for invalid specifications
- if( !preg_match( "/^$rxIP$/", $this->BlockAddress ) ) {
- $matches = array();
- if( preg_match( "/^($rxIP4)\\/(\\d{1,2})$/", $this->BlockAddress, $matches ) ) {
- # IPv4
- if( $wgSysopRangeBans && $wgBlockCIDRLimit['IPv4'] != 32 ) {
- if( !IP::isIPv4( $this->BlockAddress ) || $matches[2] > 32 ) {
- return array( 'ip_range_invalid' );
- } elseif ( $matches[2] < $wgBlockCIDRLimit['IPv4'] ) {
- return array( 'ip_range_toolarge', $wgBlockCIDRLimit['IPv4'] );
- }
- $this->BlockAddress = Block::normaliseRange( $this->BlockAddress );
- } else {
- # Range block illegal
- return array( 'range_block_disabled' );
- }
- } elseif( preg_match( "/^($rxIP6)\\/(\\d{1,3})$/", $this->BlockAddress, $matches ) ) {
- # IPv6
- if( $wgSysopRangeBans && $wgBlockCIDRLimit['IPv6'] != 128 ) {
- if( !IP::isIPv6( $this->BlockAddress ) || $matches[2] > 128 ) {
- return array( 'ip_range_invalid' );
- } elseif( $matches[2] < $wgBlockCIDRLimit['IPv6'] ) {
- return array( 'ip_range_toolarge', $wgBlockCIDRLimit['IPv6'] );
- }
- $this->BlockAddress = Block::normaliseRange( $this->BlockAddress );
- } else {
- # Range block illegal
- return array('range_block_disabled');
- }
- } else {
- # Username block
- if( $wgSysopUserBans ) {
- $user = User::newFromName( $this->BlockAddress );
- if( $user instanceof User && $user->getId() ) {
- # Use canonical name
- $userId = $user->getId();
- $this->BlockAddress = $user->getName();
- } else {
- return array( 'nosuchusershort', htmlspecialchars( $user ? $user->getName() : $this->BlockAddress ) );
- }
- } else {
- return array( 'badipaddress' );
- }
- }
- }
-
- if( $wgUser->isBlocked() && ( $wgUser->getId() !== $userId ) ) {
- return array( 'cant-block-while-blocked' );
- }
-
- $reasonstr = $this->BlockReasonList;
- if( $reasonstr != 'other' && $this->BlockReason != '' ) {
- // Entry from drop down menu + additional comment
- $reasonstr .= wfMsgForContent( 'colon-separator' ) . $this->BlockReason;
- } elseif( $reasonstr == 'other' ) {
- $reasonstr = $this->BlockReason;
- }
-
- $expirestr = $this->BlockExpiry;
- if( $expirestr == 'other' )
- $expirestr = $this->BlockOther;
-
- if( ( strlen( $expirestr ) == 0) || ( strlen( $expirestr ) > 50 ) ) {
- return array( 'ipb_expiry_invalid' );
- }
-
- if( false === ( $expiry = Block::parseExpiryInput( $expirestr ) ) ) {
- // Bad expiry.
- return array( 'ipb_expiry_invalid' );
- }
-
- if( $this->BlockHideName ) {
- // Recheck params here...
- if( !$userId || !$wgUser->isAllowed('hideuser') ) {
- $this->BlockHideName = false; // IP users should not be hidden
- } elseif( $expiry !== 'infinity' ) {
- // Bad expiry.
- return array( 'ipb_expiry_temp' );
- } elseif( User::edits( $userId ) > self::HIDEUSER_CONTRIBLIMIT ) {
- // Typically, the user should have a handful of edits.
- // Disallow hiding users with many edits for performance.
- return array( 'ipb_hide_invalid' );
- }
- }
-
- # Create block object
- # Note: for a user block, ipb_address is only for display purposes
- $block = new Block( $this->BlockAddress, $userId, $wgUser->getId(),
- $reasonstr, wfTimestampNow(), 0, $expiry, $this->BlockAnonOnly,
- $this->BlockCreateAccount, $this->BlockEnableAutoblock, $this->BlockHideName,
- $this->BlockEmail,
- isset( $this->BlockAllowUsertalk ) ? $this->BlockAllowUsertalk : $wgBlockAllowsUTEdit
- );
-
- # Should this be privately logged?
- $suppressLog = (bool)$this->BlockHideName;
- if( wfRunHooks( 'BlockIp', array( &$block, &$wgUser ) ) ) {
- # Try to insert block. Is there a conflicting block?
- if( !$block->insert() ) {
- # Show form unless the user is already aware of this...
- if( !$this->BlockReblock ) {
- return array( 'ipb_already_blocked' );
- # Otherwise, try to update the block...
- } else {
- # This returns direct blocks before autoblocks/rangeblocks, since we should
- # be sure the user is blocked by now it should work for our purposes
- $currentBlock = Block::newFromDB( $this->BlockAddress, $userId );
- if( $block->equals( $currentBlock ) ) {
- return array( 'ipb_already_blocked' );
- }
- # If the name was hidden and the blocking user cannot hide
- # names, then don't allow any block changes...
- if( $currentBlock->mHideName && !$wgUser->isAllowed( 'hideuser' ) ) {
- return array( 'cant-see-hidden-user' );
- }
- $currentBlock->delete();
- $block->insert();
- # If hiding/unhiding a name, this should go in the private logs
- $suppressLog = $suppressLog || (bool)$currentBlock->mHideName;
- $log_action = 'reblock';
- # Unset _deleted fields if requested
- if( $currentBlock->mHideName && !$this->BlockHideName ) {
- self::unsuppressUserName( $this->BlockAddress, $userId );
- }
- }
- } else {
- $log_action = 'block';
- }
- wfRunHooks( 'BlockIpComplete', array( $block, $wgUser ) );
-
- # Set *_deleted fields if requested
- if( $this->BlockHideName ) {
- self::suppressUserName( $this->BlockAddress, $userId );
- }
-
- # Only show watch link when this is no range block
- if( $this->BlockWatchUser && $block->mRangeStart == $block->mRangeEnd ) {
- $wgUser->addWatch( Title::makeTitle( NS_USER, $this->BlockAddress ) );
- }
-
- # Block constructor sanitizes certain block options on insert
- $this->BlockEmail = $block->mBlockEmail;
- $this->BlockEnableAutoblock = $block->mEnableAutoblock;
-
- # Prepare log parameters
- $logParams = array();
- $logParams[] = $expirestr;
- $logParams[] = $this->blockLogFlags();
-
- # Make log entry, if the name is hidden, put it in the oversight log
- $log_type = $suppressLog ? 'suppress' : 'block';
- $log = new LogPage( $log_type );
- $log->addEntry( $log_action, Title::makeTitle( NS_USER, $this->BlockAddress ),
- $reasonstr, $logParams );
-
- # Report to the user
- return array();
- } else {
- return array( 'hookaborted' );
- }
- }
-
- public static function suppressUserName( $name, $userId, $dbw = null ) {
- $op = '|'; // bitwise OR
- return self::setUsernameBitfields( $name, $userId, $op, $dbw );
- }
-
- public static function unsuppressUserName( $name, $userId, $dbw = null ) {
- $op = '&'; // bitwise AND
- return self::setUsernameBitfields( $name, $userId, $op, $dbw );
- }
-
- private static function setUsernameBitfields( $name, $userId, $op, $dbw ) {
- if( $op !== '|' && $op !== '&' ) return false; // sanity check
- if( !$dbw )
- $dbw = wfGetDB( DB_MASTER );
- $delUser = Revision::DELETED_USER | Revision::DELETED_RESTRICTED;
- $delAction = LogPage::DELETED_ACTION | Revision::DELETED_RESTRICTED;
- # Normalize user name
- $userTitle = Title::makeTitleSafe( NS_USER, $name );
- $userDbKey = $userTitle->getDBkey();
- # To suppress, we OR the current bitfields with Revision::DELETED_USER
- # to put a 1 in the username *_deleted bit. To unsuppress we AND the
- # current bitfields with the inverse of Revision::DELETED_USER. The
- # username bit is made to 0 (x & 0 = 0), while others are unchanged (x & 1 = x).
- # The same goes for the sysop-restricted *_deleted bit.
- if( $op == '&' ) {
- $delUser = "~{$delUser}";
- $delAction = "~{$delAction}";
- }
- # Hide name from live edits
- $dbw->update( 'revision', array( "rev_deleted = rev_deleted $op $delUser" ),
- array( 'rev_user' => $userId ), __METHOD__ );
- # Hide name from deleted edits
- $dbw->update( 'archive', array( "ar_deleted = ar_deleted $op $delUser" ),
- array( 'ar_user_text' => $name ), __METHOD__ );
- # Hide name from logs
- $dbw->update( 'logging', array( "log_deleted = log_deleted $op $delUser" ),
- array( 'log_user' => $userId, "log_type != 'suppress'" ), __METHOD__ );
- $dbw->update( 'logging', array( "log_deleted = log_deleted $op $delAction" ),
- array( 'log_namespace' => NS_USER, 'log_title' => $userDbKey,
- "log_type != 'suppress'" ), __METHOD__ );
- # Hide name from RC
- $dbw->update( 'recentchanges', array( "rc_deleted = rc_deleted $op $delUser" ),
- array( 'rc_user_text' => $name ), __METHOD__ );
- $dbw->update( 'recentchanges', array( "rc_deleted = rc_deleted $op $delAction" ),
- array( 'rc_namespace' => NS_USER, 'rc_title' => $userDbKey, 'rc_logid > 0' ), __METHOD__ );
- # Hide name from live images
- $dbw->update( 'oldimage', array( "oi_deleted = oi_deleted $op $delUser" ),
- array( 'oi_user_text' => $name ), __METHOD__ );
- # Hide name from deleted images
- # WMF - schema change pending
- # $dbw->update( 'filearchive', array( "fa_deleted = fa_deleted $op $delUser" ),
- # array( 'fa_user_text' => $name ), __METHOD__ );
- # Done!
- return true;
- }
-
- /**
- * UI entry point for blocking
- * Wraps around doBlock()
- */
- public function doSubmit() {
- global $wgOut;
- $retval = $this->doBlock();
- if( empty( $retval ) ) {
- $titleObj = SpecialPage::getTitleFor( 'Blockip' );
- $wgOut->redirect( $titleObj->getFullURL( 'action=success&ip=' .
- urlencode( $this->BlockAddress ) ) );
- return;
- }
- $this->showForm( $retval );
- }
-
- public function showSuccess() {
- global $wgOut;
-
- $wgOut->setPageTitle( wfMsg( 'blockip-title' ) );
- $wgOut->setSubtitle( wfMsg( 'blockipsuccesssub' ) );
- $text = wfMsgExt( 'blockipsuccesstext', array( 'parse' ), $this->BlockAddress );
- $wgOut->addHTML( $text );
- }
-
- private function showLogFragment( $out, $title ) {
- global $wgUser;
-
- // Used to support GENDER in 'blocklog-showlog' and 'blocklog-showsuppresslog'
- $userBlocked = $title->getText();
-
- LogEventsList::showLogExtract(
- $out,
- 'block',
- $title->getPrefixedText(),
- '',
- array(
- 'lim' => 10,
- 'msgKey' => array(
- 'blocklog-showlog',
- $userBlocked
- ),
- 'showIfEmpty' => false
- )
- );
-
- // Add suppression block entries if allowed
- if( $wgUser->isAllowed( 'suppressionlog' ) ) {
- LogEventsList::showLogExtract( $out, 'suppress', $title->getPrefixedText(), '',
- array(
- 'lim' => 10,
- 'conds' => array(
- 'log_action' => array(
- 'block',
- 'reblock',
- 'unblock'
- )
- ),
- 'msgKey' => array(
- 'blocklog-showsuppresslog',
- $userBlocked
- ),
- 'showIfEmpty' => false
- )
- );
- }
- }
-
- /**
- * Return a comma-delimited list of "flags" to be passed to the log
- * reader for this block, to provide more information in the logs
- *
- * @return array
- */
- private function blockLogFlags() {
- global $wgBlockAllowsUTEdit;
- $flags = array();
- if( $this->BlockAnonOnly && IP::isIPAddress( $this->BlockAddress ) )
- // when blocking a user the option 'anononly' is not available/has no effect -> do not write this into log
- $flags[] = 'anononly';
- if( $this->BlockCreateAccount )
- $flags[] = 'nocreate';
- if( !$this->BlockEnableAutoblock && !IP::isIPAddress( $this->BlockAddress ) )
- // Same as anononly, this is not displayed when blocking an IP address
- $flags[] = 'noautoblock';
- if( $this->BlockEmail )
- $flags[] = 'noemail';
- if( !$this->BlockAllowUsertalk && $wgBlockAllowsUTEdit )
- $flags[] = 'nousertalk';
- if( $this->BlockHideName )
- $flags[] = 'hiddenname';
- return implode( ',', $flags );
- }
-
- /**
- * Builds unblock and block list links
- *
- * @return string
- */
- private function getConvenienceLinks() {
- global $wgUser, $wgLang;
- $skin = $wgUser->getSkin();
- if( $this->BlockAddress )
- $links[] = $this->getContribsLink( $skin );
- $links[] = $this->getUnblockLink( $skin );
- $links[] = $this->getBlockListLink( $skin );
- if ( $wgUser->isAllowed( 'editinterface' ) ) {
- $title = Title::makeTitle( NS_MEDIAWIKI, 'Ipbreason-dropdown' );
- $links[] = $skin->link(
- $title,
- wfMsgHtml( 'ipb-edit-dropdown' ),
- array(),
- array( 'action' => 'edit' )
- );
- }
- return '<p class="mw-ipb-conveniencelinks">' . $wgLang->pipeList( $links ) . '</p>';
- }
-
- /**
- * Build a convenient link to a user or IP's contribs
- * form
- *
- * @param $skin Skin to use
- * @return string
- */
- private function getContribsLink( $skin ) {
- $contribsPage = SpecialPage::getTitleFor( 'Contributions', $this->BlockAddress );
- return $skin->link( $contribsPage, wfMsgExt( 'ipb-blocklist-contribs', 'escape', $this->BlockAddress ) );
- }
-
- /**
- * Build a convenient link to unblock the given username or IP
- * address, if available; otherwise link to a blank unblock
- * form
- *
- * @param $skin Skin to use
- * @return string
- */
- private function getUnblockLink( $skin ) {
- $list = SpecialPage::getTitleFor( 'Ipblocklist' );
- $query = array( 'action' => 'unblock' );
-
- if( $this->BlockAddress ) {
- $addr = strtr( $this->BlockAddress, '_', ' ' );
- $message = wfMsg( 'ipb-unblock-addr', $addr );
- $query['ip'] = $this->BlockAddress;
- } else {
- $message = wfMsg( 'ipb-unblock' );
- }
- return $skin->linkKnown(
- $list,
- htmlspecialchars( $message ),
- array(),
- $query
- );
- }
-
- /**
- * Build a convenience link to the block list
- *
- * @param $skin Skin to use
- * @return string
- */
- private function getBlockListLink( $skin ) {
- return $skin->linkKnown(
- SpecialPage::getTitleFor( 'Ipblocklist' ),
- wfMsg( 'ipb-blocklist' )
- );
- }
-
- /**
- * Block a list of selected users
- *
- * @param $users Array
- * @param $reason String
- * @param $tag String: replaces user pages
- * @param $talkTag String: replaces user talk pages
- * @return Array: list of html-safe usernames
- */
- public static function doMassUserBlock( $users, $reason = '', $tag = '', $talkTag = '' ) {
- global $wgUser;
- $counter = $blockSize = 0;
- $safeUsers = array();
- $log = new LogPage( 'block' );
- foreach( $users as $name ) {
- # Enforce limits
- $counter++;
- $blockSize++;
- # Lets not go *too* fast
- if( $blockSize >= 20 ) {
- $blockSize = 0;
- wfWaitForSlaves( 5 );
- }
- $u = User::newFromName( $name, false );
- // If user doesn't exist, it ought to be an IP then
- if( is_null( $u ) || ( !$u->getId() && !IP::isIPAddress( $u->getName() ) ) ) {
- continue;
- }
- $userTitle = $u->getUserPage();
- $userTalkTitle = $u->getTalkPage();
- $userpage = new Article( $userTitle );
- $usertalk = new Article( $userTalkTitle );
- $safeUsers[] = '[[' . $userTitle->getPrefixedText() . '|' . $userTitle->getText() . ']]';
- $expirestr = $u->getId() ? 'indefinite' : '1 week';
- $expiry = Block::parseExpiryInput( $expirestr );
- $anonOnly = IP::isIPAddress( $u->getName() ) ? 1 : 0;
- // Create the block
- $block = new Block( $u->getName(), // victim
- $u->getId(), // uid
- $wgUser->getId(), // blocker
- $reason, // comment
- wfTimestampNow(), // block time
- 0, // auto ?
- $expiry, // duration
- $anonOnly, // anononly?
- 1, // block account creation?
- 1, // autoblocking?
- 0, // suppress name?
- 0 // block from sending email?
- );
- $oldblock = Block::newFromDB( $u->getName(), $u->getId() );
- if( !$oldblock ) {
- $block->insert();
- # Prepare log parameters
- $logParams = array();
- $logParams[] = $expirestr;
- if( $anonOnly ) {
- $logParams[] = 'anononly';
- }
- $logParams[] = 'nocreate';
- # Add log entry
- $log->addEntry( 'block', $userTitle, $reason, $logParams );
- }
- # Tag userpage! (check length to avoid mistakes)
- if( strlen( $tag ) > 2 ) {
- $userpage->doEdit( $tag, $reason, EDIT_MINOR );
- }
- if( strlen( $talkTag ) > 2 ) {
- $usertalk->doEdit( $talkTag, $reason, EDIT_MINOR );
- }
- }
- return $safeUsers;
- }
-}
diff --git a/includes/specials/SpecialBlockme.php b/includes/specials/SpecialBlockme.php
index f5131f5f..40747667 100644
--- a/includes/specials/SpecialBlockme.php
+++ b/includes/specials/SpecialBlockme.php
@@ -48,10 +48,12 @@ class SpecialBlockme extends UnlistedSpecialPage {
if ( !$user->isLoggedIn() ) {
$user->addToDatabase();
}
- $id = $user->getId();
- $reason = wfMsg( 'proxyblockreason' );
- $block = new Block( $ip, 0, $id, $reason, wfTimestampNow() );
+ $block = new Block();
+ $block->setTarget( $ip );
+ $block->setBlocker( $user );
+ $block->mReason = wfMsg( 'proxyblockreason' );
+
$block->insert();
$wgOut->addWikiMsg( 'proxyblocksuccess' );
diff --git a/includes/specials/SpecialBooksources.php b/includes/specials/SpecialBooksources.php
index 67fb5404..20819329 100644
--- a/includes/specials/SpecialBooksources.php
+++ b/includes/specials/SpecialBooksources.php
@@ -49,14 +49,13 @@ class SpecialBookSources extends SpecialPage {
* @param $isbn ISBN passed as a subpage parameter
*/
public function execute( $isbn ) {
- global $wgOut, $wgRequest;
$this->setHeaders();
- $this->isbn = self::cleanIsbn( $isbn ? $isbn : $wgRequest->getText( 'isbn' ) );
- $wgOut->addWikiMsg( 'booksources-summary' );
- $wgOut->addHTML( $this->makeForm() );
+ $this->outputHeader();
+ $this->isbn = self::cleanIsbn( $isbn ? $isbn : $this->getRequest()->getText( 'isbn' ) );
+ $this->getOutput()->addHTML( $this->makeForm() );
if( strlen( $this->isbn ) > 0 ) {
if( !self::isValidISBN( $this->isbn ) ) {
- $wgOut->wrapWikiMsg( "<div class=\"error\">\n$1\n</div>", 'booksources-invalid-isbn' );
+ $this->getOutput()->wrapWikiMsg( "<div class=\"error\">\n$1\n</div>", 'booksources-invalid-isbn' );
}
$this->showList();
}
@@ -72,26 +71,26 @@ class SpecialBookSources extends SpecialPage {
if( strlen( $isbn ) == 13 ) {
for( $i = 0; $i < 12; $i++ ) {
if($i % 2 == 0) {
- $sum += $isbn{$i};
+ $sum += $isbn[$i];
} else {
- $sum += 3 * $isbn{$i};
+ $sum += 3 * $isbn[$i];
}
}
-
+
$check = (10 - ($sum % 10)) % 10;
- if ($check == $isbn{12}) {
+ if ($check == $isbn[12]) {
return true;
}
} elseif( strlen( $isbn ) == 10 ) {
for($i = 0; $i < 9; $i++) {
- $sum += $isbn{$i} * ($i + 1);
+ $sum += $isbn[$i] * ($i + 1);
}
-
+
$check = $sum % 11;
if($check == 10) {
$check = "X";
}
- if($check == $isbn{9}) {
+ if($check == $isbn[9]) {
return true;
}
}
@@ -115,10 +114,10 @@ class SpecialBookSources extends SpecialPage {
*/
private function makeForm() {
global $wgScript;
- $title = self::getTitleFor( 'Booksources' );
+
$form = '<fieldset><legend>' . wfMsgHtml( 'booksources-search-legend' ) . '</legend>';
$form .= Xml::openElement( 'form', array( 'method' => 'get', 'action' => $wgScript ) );
- $form .= Html::hidden( 'title', $title->getPrefixedText() );
+ $form .= Html::hidden( 'title', $this->getTitle()->getPrefixedText() );
$form .= '<p>' . Xml::inputLabel( wfMsg( 'booksources-isbn' ), 'isbn', 'isbn', 20, $this->isbn );
$form .= '&#160;' . Xml::submitButton( wfMsg( 'booksources-go' ) ) . '</p>';
$form .= Xml::closeElement( 'form' );
@@ -133,27 +132,27 @@ class SpecialBookSources extends SpecialPage {
* @return string
*/
private function showList() {
- global $wgOut, $wgContLang;
+ global $wgContLang;
# Hook to allow extensions to insert additional HTML,
# e.g. for API-interacting plugins and so on
- wfRunHooks( 'BookInformation', array( $this->isbn, &$wgOut ) );
+ wfRunHooks( 'BookInformation', array( $this->isbn, $this->getOutput() ) );
# Check for a local page such as Project:Book_sources and use that if available
$title = Title::makeTitleSafe( NS_PROJECT, wfMsgForContent( 'booksources' ) ); # Show list in content language
if( is_object( $title ) && $title->exists() ) {
$rev = Revision::newFromTitle( $title );
- $wgOut->addWikiText( str_replace( 'MAGICNUMBER', $this->isbn, $rev->getText() ) );
+ $this->getOutput()->addWikiText( str_replace( 'MAGICNUMBER', $this->isbn, $rev->getText() ) );
return true;
}
# Fall back to the defaults given in the language file
- $wgOut->addWikiMsg( 'booksources-text' );
- $wgOut->addHTML( '<ul>' );
+ $this->getOutput()->addWikiMsg( 'booksources-text' );
+ $this->getOutput()->addHTML( '<ul>' );
$items = $wgContLang->getBookstoreList();
foreach( $items as $label => $url )
- $wgOut->addHTML( $this->makeListItem( $label, $url ) );
- $wgOut->addHTML( '</ul>' );
+ $this->getOutput()->addHTML( $this->makeListItem( $label, $url ) );
+ $this->getOutput()->addHTML( '</ul>' );
return true;
}
diff --git a/includes/specials/SpecialBrokenRedirects.php b/includes/specials/SpecialBrokenRedirects.php
index 98b02126..2330c896 100644
--- a/includes/specials/SpecialBrokenRedirects.php
+++ b/includes/specials/SpecialBrokenRedirects.php
@@ -28,42 +28,56 @@
* @ingroup SpecialPage
*/
class BrokenRedirectsPage extends PageQueryPage {
- var $targets = array();
- function getName() {
- return 'BrokenRedirects';
+ function __construct( $name = 'BrokenRedirects' ) {
+ parent::__construct( $name );
}
- function isExpensive( ) { return true; }
+ function isExpensive() { return true; }
function isSyndicated() { return false; }
+ function sortDescending() { return false; }
- function getPageHeader( ) {
+ function getPageHeader() {
return wfMsgExt( 'brokenredirectstext', array( 'parse' ) );
}
- function getSQL() {
- $dbr = wfGetDB( DB_SLAVE );
- list( $page, $redirect ) = $dbr->tableNamesN( 'page', 'redirect' );
-
- $sql = "SELECT 'BrokenRedirects' AS type,
- p1.page_namespace AS namespace,
- p1.page_title AS title,
- rd_namespace,
- rd_title
- FROM $redirect AS rd
- JOIN $page p1 ON (rd.rd_from=p1.page_id)
- LEFT JOIN $page AS p2 ON (rd_namespace=p2.page_namespace AND rd_title=p2.page_title )
- WHERE rd_namespace >= 0
- AND p2.page_namespace IS NULL";
- return $sql;
+ function getQueryInfo() {
+ return array(
+ 'tables' => array( 'redirect', 'p1' => 'page',
+ 'p2' => 'page' ),
+ 'fields' => array( 'p1.page_namespace AS namespace',
+ 'p1.page_title AS title',
+ 'rd_namespace',
+ 'rd_title'
+ ),
+ 'conds' => array( 'rd_namespace >= 0',
+ 'p2.page_namespace IS NULL'
+ ),
+ 'join_conds' => array( 'p1' => array( 'JOIN', array(
+ 'rd_from=p1.page_id',
+ ) ),
+ 'p2' => array( 'LEFT JOIN', array(
+ 'rd_namespace=p2.page_namespace',
+ 'rd_title=p2.page_title'
+ ) )
+ )
+ );
}
- function getOrder() {
- return '';
+ /**
+ * @return array
+ */
+ function getOrderFields() {
+ return array ( 'rd_namespace', 'rd_title', 'rd_from' );
}
+ /**
+ * @param $skin Skin
+ * @param $result
+ * @return String
+ */
function formatResult( $skin, $result ) {
- global $wgUser, $wgContLang, $wgLang;
+ global $wgUser, $wgLang;
$fromObj = Title::makeTitle( $result->namespace, $result->title );
if ( isset( $result->rd_title ) ) {
@@ -95,14 +109,14 @@ class BrokenRedirectsPage extends PageQueryPage {
array(),
array( 'action' => 'edit' )
);
- $to = $skin->link(
+ $to = $skin->link(
$toObj,
null,
array(),
array(),
array( 'broken' )
);
- $arr = $wgContLang->getArrow();
+ $arr = $wgLang->getArrow();
$out = $from . wfMsg( 'word-separator' );
@@ -120,14 +134,3 @@ class BrokenRedirectsPage extends PageQueryPage {
return $out;
}
}
-
-/**
- * constructor
- */
-function wfSpecialBrokenRedirects() {
- list( $limit, $offset ) = wfCheckLimits();
-
- $sbr = new BrokenRedirectsPage();
-
- return $sbr->doQuery( $offset, $limit );
-}
diff --git a/includes/specials/SpecialCategories.php b/includes/specials/SpecialCategories.php
index c2dd40cd..91d98b86 100644
--- a/includes/specials/SpecialCategories.php
+++ b/includes/specials/SpecialCategories.php
@@ -69,16 +69,20 @@ class CategoryPager extends AlphabeticPager {
$this->mOffset = $from;
}
}
-
+
function getQueryInfo() {
return array(
'tables' => array( 'category' ),
'fields' => array( 'cat_title','cat_pages' ),
- 'conds' => array( 'cat_pages > 0' ),
+ 'conds' => array( 'cat_pages > 0' ),
'options' => array( 'USE INDEX' => 'cat_title' ),
);
}
+ function getTitle() {
+ return SpecialPage::getTitleFor( 'Categories' );
+ }
+
function getIndexField() {
# return array( 'abc' => 'cat_title', 'count' => 'cat_pages' );
return 'cat_title';
@@ -116,19 +120,18 @@ class CategoryPager extends AlphabeticPager {
function formatRow($result) {
global $wgLang;
$title = Title::makeTitle( NS_CATEGORY, $result->cat_title );
- $titleText = $this->getSkin()->link( $title, htmlspecialchars( $title->getText() ) );
+ $titleText = Linker::link( $title, htmlspecialchars( $title->getText() ) );
$count = wfMsgExt( 'nmembers', array( 'parsemag', 'escape' ),
$wgLang->formatNum( $result->cat_pages ) );
- return Xml::tags('li', null, "$titleText ($count)" ) . "\n";
+ return Xml::tags('li', null, wfSpecialList( $titleText, $count ) ) . "\n";
}
-
+
public function getStartForm( $from ) {
global $wgScript;
- $t = SpecialPage::getTitleFor( 'Categories' );
-
+
return
Xml::tags( 'form', array( 'method' => 'get', 'action' => $wgScript ),
- Html::hidden( 'title', $t->getPrefixedText() ) .
+ Html::hidden( 'title', $this->getTitle()->getPrefixedText() ) .
Xml::fieldset( wfMsg( 'categories' ),
Xml::inputLabel( wfMsg( 'categoriesfrom' ),
'from', 'from', 20, $from ) .
diff --git a/includes/specials/SpecialResetpass.php b/includes/specials/SpecialChangePassword.php
index 0af6fbf0..46562b36 100644
--- a/includes/specials/SpecialResetpass.php
+++ b/includes/specials/SpecialChangePassword.php
@@ -1,6 +1,6 @@
<?php
/**
- * Implements Special:Resetpass
+ * Implements Special:ChangePassword
*
* 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
@@ -26,9 +26,9 @@
*
* @ingroup SpecialPage
*/
-class SpecialResetpass extends SpecialPage {
+class SpecialChangePassword extends SpecialPage {
public function __construct() {
- parent::__construct( 'Resetpass' );
+ parent::__construct( 'ChangePassword' );
}
/**
@@ -46,16 +46,12 @@ class SpecialResetpass extends SpecialPage {
$this->mOldpass = $wgRequest->getVal( 'wpPassword' );
$this->mNewpass = $wgRequest->getVal( 'wpNewPassword' );
$this->mRetype = $wgRequest->getVal( 'wpRetype' );
-
+ $this->mDomain = $wgRequest->getVal( 'wpDomain' );
+
$this->setHeaders();
$this->outputHeader();
$wgOut->disallowUserJs();
- if( !$wgAuth->allowPasswordChange() ) {
- $this->error( wfMsg( 'resetpass_forbidden' ) );
- return;
- }
-
if( !$wgRequest->wasPosted() && !$wgUser->isLoggedIn() ) {
$this->error( wfMsg( 'resetpass-no-info' ) );
return;
@@ -66,22 +62,35 @@ class SpecialResetpass extends SpecialPage {
return;
}
- if( $wgRequest->wasPosted() && $wgUser->matchEditToken( $wgRequest->getVal('token') ) ) {
+ if( $wgRequest->wasPosted() && $wgUser->matchEditToken( $wgRequest->getVal( 'token' ) ) ) {
try {
+ if ( isset( $_SESSION['wsDomain'] ) ) {
+ $this->mDomain = $_SESSION['wsDomain'];
+ }
+ $wgAuth->setDomain( $this->mDomain );
+ if( !$wgAuth->allowPasswordChange() ) {
+ $this->error( wfMsg( 'resetpass_forbidden' ) );
+ return;
+ }
+
$this->attemptReset( $this->mNewpass, $this->mRetype );
$wgOut->addWikiMsg( 'resetpass_success' );
if( !$wgUser->isLoggedIn() ) {
+ LoginForm::setLoginToken();
+ $token = LoginForm::getLoginToken();
$data = array(
- 'action' => 'submitlogin',
- 'wpName' => $this->mUserName,
- 'wpPassword' => $this->mNewpass,
- 'returnto' => $wgRequest->getVal( 'returnto' ),
+ 'action' => 'submitlogin',
+ 'wpName' => $this->mUserName,
+ 'wpDomain' => $this->mDomain,
+ 'wpLoginToken' => $token,
+ 'wpPassword' => $this->mNewpass,
+ 'returnto' => $wgRequest->getVal( 'returnto' ),
);
if( $wgRequest->getCheck( 'wpRemember' ) ) {
$data['wpRemember'] = 1;
}
$login = new LoginForm( new FauxRequest( $data, true ) );
- $login->execute();
+ $login->execute( null );
}
$this->doReturnTo();
} catch( PasswordError $e ) {
@@ -90,7 +99,7 @@ class SpecialResetpass extends SpecialPage {
}
$this->showForm();
}
-
+
function doReturnTo() {
global $wgRequest, $wgOut;
$titleObj = Title::newFromText( $wgRequest->getVal( 'returnto' ) );
@@ -118,7 +127,7 @@ class SpecialResetpass extends SpecialPage {
$rememberMe = '<tr>' .
'<td></td>' .
'<td class="mw-input">' .
- Xml::checkLabel(
+ Xml::checkLabel(
wfMsgExt( 'remembermypassword', 'parsemag', $wgLang->formatNum( ceil( $wgCookieExpiration / ( 3600 * 24 ) ) ) ),
'wpRemember', 'wpRemember',
$wgRequest->getCheck( 'wpRemember' ) ) .
@@ -139,6 +148,7 @@ class SpecialResetpass extends SpecialPage {
'id' => 'mw-resetpass-form' ) ) . "\n" .
Html::hidden( 'token', $wgUser->editToken() ) . "\n" .
Html::hidden( 'wpName', $this->mUserName ) . "\n" .
+ Html::hidden( 'wpDomain', $this->mDomain ) . "\n" .
Html::hidden( 'returnto', $wgRequest->getVal( 'returnto' ) ) . "\n" .
wfMsgExt( 'resetpass_text', array( 'parse' ) ) . "\n" .
Xml::openElement( 'table', array( 'id' => 'mw-resetpass-table' ) ) . "\n" .
@@ -183,7 +193,7 @@ class SpecialResetpass extends SpecialPage {
$out .= "\t<td class='mw-label'>";
if ( $type != 'text' )
$out .= Xml::label( wfMsg( $label ), $name );
- else
+ else
$out .= wfMsgHtml( $label );
$out .= "</td>\n";
$out .= "\t<td class='mw-input'>";
@@ -200,19 +210,29 @@ class SpecialResetpass extends SpecialPage {
protected function attemptReset( $newpass, $retype ) {
$user = User::newFromName( $this->mUserName );
if( !$user || $user->isAnon() ) {
- throw new PasswordError( 'no such user' );
+ throw new PasswordError( wfMsg( 'nosuchusershort', $this->mUserName ) );
}
-
+
if( $newpass !== $retype ) {
wfRunHooks( 'PrefsPasswordAudit', array( $user, $newpass, 'badretype' ) );
throw new PasswordError( wfMsg( 'badretype' ) );
}
+ $throttleCount = LoginForm::incLoginThrottle( $this->mUserName );
+ if ( $throttleCount === true ) {
+ throw new PasswordError( wfMsg( 'login-throttled' ) );
+ }
+
if( !$user->checkTemporaryPassword($this->mOldpass) && !$user->checkPassword($this->mOldpass) ) {
wfRunHooks( 'PrefsPasswordAudit', array( $user, $newpass, 'wrongpassword' ) );
throw new PasswordError( wfMsg( 'resetpass-wrong-oldpass' ) );
}
-
+
+ // Please reset throttle for successful logins, thanks!
+ if ( $throttleCount ) {
+ LoginForm::clearLoginThrottle( $this->mUserName );
+ }
+
try {
$user->setPassword( $this->mNewpass );
wfRunHooks( 'PrefsPasswordAudit', array( $user, $newpass, 'success' ) );
@@ -221,7 +241,7 @@ class SpecialResetpass extends SpecialPage {
wfRunHooks( 'PrefsPasswordAudit', array( $user, $newpass, 'error' ) );
throw new PasswordError( $e->getMessage() );
}
-
+
$user->setCookies();
$user->saveSettings();
}
diff --git a/includes/specials/SpecialComparePages.php b/includes/specials/SpecialComparePages.php
index 4650fc94..6b9ef0a9 100644
--- a/includes/specials/SpecialComparePages.php
+++ b/includes/specials/SpecialComparePages.php
@@ -40,47 +40,6 @@ class SpecialComparePages extends SpecialPage {
parent::__construct( 'ComparePages' );
}
- protected function setup( $par ) {
- global $wgRequest, $wgUser;
-
- // Options
- $opts = new FormOptions();
- $this->opts = $opts; // bind
- $opts->add( 'page1', '' );
- $opts->add( 'page2', '' );
- $opts->add( 'rev1', '' );
- $opts->add( 'rev2', '' );
- $opts->add( 'action', '' );
-
- // Set values
- $opts->fetchValuesFromRequest( $wgRequest );
-
- $title1 = Title::newFromText( $opts->getValue( 'page1' ) );
- $title2 = Title::newFromText( $opts->getValue( 'page2' ) );
-
- if( $title1 && $title1->exists() && $opts->getValue( 'rev1' ) == '' ) {
- $pda = new Article( $title1 );
- $pdi = $pda->getID();
- $pdLastRevision = Revision::loadFromPageId( wfGetDB( DB_SLAVE ), $pdi );
- $opts->setValue( 'rev1', $pdLastRevision->getId() );
- } elseif ( $opts->getValue( 'rev1' ) != '' ) {
- $pdrev = Revision::newFromId( $opts->getValue( 'rev1' ) );
- if( $pdrev ) $opts->setValue( 'page1', $pdrev->getTitle()->getPrefixedText() );
- }
- if( $title2 && $title2->exists() && $opts->getValue( 'rev2' ) == '' ) {
- $pda = new Article( $title2 );
- $pdi = $pda->getID();
- $pdLastRevision = Revision::loadFromPageId( wfGetDB( DB_SLAVE ), $pdi );
- $opts->setValue('rev2', $pdLastRevision->getId() );
- } elseif ( $opts->getValue( 'rev2' ) != '' ) {
- $pdrev = Revision::newFromId( $opts->getValue( 'rev2' ) );
- if( $pdrev ) $opts->setValue( 'page2', $pdrev->getTitle()->getPrefixedText() );
- }
-
- // Store some objects
- $this->skin = $wgUser->getSkin();
- }
-
/**
* Show a form for filtering namespace and username
*
@@ -91,80 +50,79 @@ class SpecialComparePages extends SpecialPage {
$this->setHeaders();
$this->outputHeader();
- $this->setup( $par );
+ $form = new HTMLForm( array(
+ 'Page1' => array(
+ 'type' => 'text',
+ 'name' => 'page1',
+ 'label-message' => 'compare-page1',
+ 'size' => '40',
+ 'section' => 'page1',
+ ),
+ 'Revision1' => array(
+ 'type' => 'int',
+ 'name' => 'rev1',
+ 'label-message' => 'compare-rev1',
+ 'size' => '8',
+ 'section' => 'page1',
+ ),
+ 'Page2' => array(
+ 'type' => 'text',
+ 'name' => 'page2',
+ 'label-message' => 'compare-page2',
+ 'size' => '40',
+ 'section' => 'page2',
+ ),
+ 'Revision2' => array(
+ 'type' => 'int',
+ 'name' => 'rev2',
+ 'label-message' => 'compare-rev2',
+ 'size' => '8',
+ 'section' => 'page2',
+ ),
+ 'Action' => array(
+ 'type' => 'hidden',
+ 'name' => 'action',
+ ),
+ 'Diffonly' => array(
+ 'type' => 'hidden',
+ 'name' => 'diffonly',
+ ),
+ ), 'compare' );
+ $form->setSubmitText( wfMsg( 'compare-submit' ) );
+ $form->suppressReset();
+ $form->setMethod( 'get' );
+ $form->setTitle( $this->getTitle() );
+
+ $form->loadData();
+ $form->displayForm( '' );
+
+ self::showDiff( $form->mFieldData );
+ }
- // Settings
- $this->form();
+ public static function showDiff( $data ){
+ $rev1 = self::revOrTitle( $data['Revision1'], $data['Page1'] );
+ $rev2 = self::revOrTitle( $data['Revision2'], $data['Page2'] );
- if( $this->opts->getValue( 'rev1' ) && $this->opts->getValue( 'rev2' ) ) {
+ if( $rev1 && $rev2 ) {
$de = new DifferenceEngine( null,
- $this->opts->getValue( 'rev1' ),
- $this->opts->getValue( 'rev2' ),
+ $rev1,
+ $rev2,
null, // rcid
- ( $this->opts->getValue( 'action' ) == 'purge' ),
+ ( $data["Action"] == 'purge' ),
false );
$de->showDiffPage( true );
}
}
- protected function form() {
- global $wgOut, $wgScript;
-
- // Consume values
- $page1 = $this->opts->consumeValue( 'page1' );
- $page2 = $this->opts->consumeValue( 'page2' );
- $rev1 = $this->opts->consumeValue( 'rev1' );
- $rev2 = $this->opts->consumeValue( 'rev2' );
-
- // Store query values in hidden fields so that form submission doesn't lose them
- $hidden = array();
- foreach ( $this->opts->getUnconsumedValues() as $key => $value ) {
- $hidden[] = Html::hidden( $key, $value );
+ public static function revOrTitle( $revision, $title ) {
+ if( $revision ){
+ return $revision;
+ } elseif( $title ) {
+ $title = Title::newFromText( $title );
+ if( $title instanceof Title ){
+ return $title->getLatestRevID();
+ }
}
- $hidden = implode( "\n", $hidden );
-
- $form = Html::openElement( 'form', array( 'action' => $wgScript ) ) .
- Html::hidden( 'title', $this->getTitle()->getPrefixedDBkey() ) .
- Xml::fieldset( wfMsg( 'compare-selector' ) ) .
- Html::openElement( 'table', array( 'id' => 'mw-diff-table', 'style' => 'width:100%' ) ) .
- "<tr>
- <td class='mw-label' style='width:10%'>" .
- Html::element( 'label', array( 'for' => 'page1' ), wfMsg( 'compare-page1' ) ) .
- "</td>
- <td class='mw-input' style='width:40%'>" .
- Html::input( 'page1', $page1, 'text', array( 'size' => 40, 'id' => 'page1' ) ) .
- "</td>
- <td class='mw-label' style='width:10%'>" .
- Html::element( 'label', array( 'for' => 'page2' ), wfMsg( 'compare-page2' ) ) .
- "</td>
- <td class='mw-input' style='width:40%'>" .
- Html::input( 'page2', $page2, 'text', array( 'size' => 40, 'id' => 'page2' ) ) .
- "</td>
- </tr>" .
- "<tr>
- <td class='mw-label'>" .
- Html::element( 'label', array( 'for' => 'rev1' ), wfMsg( 'compare-rev1' ) ) .
- "</td>
- <td class='mw-input'>" .
- Html::input( 'rev1', $rev1, 'text', array( 'size' => 8, 'id' => 'rev1' ) ) .
- "</td>
- <td class='mw-label'>" .
- Html::element( 'label', array( 'for' => 'rev2' ), wfMsg( 'compare-rev2' ) ) .
- "</td>
- <td class='mw-input'>" .
- Html::input( 'rev2', $rev2, 'text', array( 'size' => 8, 'id' => 'rev2' ) ) .
- "</td>
- </tr>" .
- "<tr> <td></td>
- <td class='mw-submit' colspan='3'>" .
- Xml::submitButton( wfMsg( 'compare-submit' ) ) .
- "</td>
- </tr>" .
- Html::closeElement( 'table' ) .
- Html::closeElement( 'fieldset' ) .
- $hidden .
- Html::closeElement( 'form' );
-
- $wgOut->addHTML( $form );
+ return null;
}
}
diff --git a/includes/specials/SpecialConfirmemail.php b/includes/specials/SpecialConfirmemail.php
index e556a60b..70bbfe39 100644
--- a/includes/specials/SpecialConfirmemail.php
+++ b/includes/specials/SpecialConfirmemail.php
@@ -44,31 +44,27 @@ class EmailConfirmation extends UnlistedSpecialPage {
* @param $code Confirmation code passed to the page
*/
function execute( $code ) {
- global $wgUser, $wgOut;
$this->setHeaders();
-
+
if ( wfReadOnly() ) {
- $wgOut->readOnlyPage();
- return;
+ throw new ReadOnlyError;
}
-
+
if( empty( $code ) ) {
- if( $wgUser->isLoggedIn() ) {
- if( User::isValidEmailAddr( $wgUser->getEmail() ) ) {
+ if( $this->getUser()->isLoggedIn() ) {
+ if( Sanitizer::validateEmail( $this->getUser()->getEmail() ) ) {
$this->showRequestForm();
} else {
- $wgOut->addWikiMsg( 'confirmemail_noemail' );
+ $this->getOutput()->addWikiMsg( 'confirmemail_noemail' );
}
} else {
- $title = SpecialPage::getTitleFor( 'Userlogin' );
- $skin = $wgUser->getSkin();
- $llink = $skin->linkKnown(
- $title,
+ $llink = Linker::linkKnown(
+ SpecialPage::getTitleFor( 'Userlogin' ),
wfMsgHtml( 'loginreqlink' ),
array(),
array( 'returnto' => $this->getTitle()->getPrefixedText() )
);
- $wgOut->addHTML( wfMsgWikiHtml( 'confirmemail_needlogin', $llink ) );
+ $this->getOutput()->addHTML( wfMessage( 'confirmemail_needlogin' )->rawParams( $llink )->parse() );
}
} else {
$this->attemptConfirm( $code );
@@ -79,33 +75,34 @@ class EmailConfirmation extends UnlistedSpecialPage {
* Show a nice form for the user to request a confirmation mail
*/
function showRequestForm() {
- global $wgOut, $wgUser, $wgLang, $wgRequest;
- if( $wgRequest->wasPosted() && $wgUser->matchEditToken( $wgRequest->getText( 'token' ) ) ) {
- $status = $wgUser->sendConfirmationMail();
+ $user = $this->getUser();
+ $out = $this->getOutput();
+ if( $this->getRequest()->wasPosted() && $user->matchEditToken( $this->getRequest()->getText( 'token' ) ) ) {
+ $status = $user->sendConfirmationMail();
if ( $status->isGood() ) {
- $wgOut->addWikiMsg( 'confirmemail_sent' );
+ $out->addWikiMsg( 'confirmemail_sent' );
} else {
- $wgOut->addWikiText( $status->getWikiText( 'confirmemail_sendfailed' ) );
+ $out->addWikiText( $status->getWikiText( 'confirmemail_sendfailed' ) );
}
} else {
- if( $wgUser->isEmailConfirmed() ) {
+ if( $user->isEmailConfirmed() ) {
// date and time are separate parameters to facilitate localisation.
// $time is kept for backward compat reasons.
// 'emailauthenticated' is also used in SpecialPreferences.php
- $time = $wgLang->timeAndDate( $wgUser->mEmailAuthenticated, true );
- $d = $wgLang->date( $wgUser->mEmailAuthenticated, true );
- $t = $wgLang->time( $wgUser->mEmailAuthenticated, true );
- $wgOut->addWikiMsg( 'emailauthenticated', $time, $d, $t );
+ $time = $this->getLang()->timeAndDate( $user->mEmailAuthenticated, true );
+ $d = $this->getLang()->date( $user->mEmailAuthenticated, true );
+ $t = $this->getLang()->time( $user->mEmailAuthenticated, true );
+ $out->addWikiMsg( 'emailauthenticated', $time, $d, $t );
}
- if( $wgUser->isEmailConfirmationPending() ) {
- $wgOut->wrapWikiMsg( "<div class=\"error mw-confirmemail-pending\">\n$1\n</div>", 'confirmemail_pending' );
+ if( $user->isEmailConfirmationPending() ) {
+ $out->wrapWikiMsg( "<div class=\"error mw-confirmemail-pending\">\n$1\n</div>", 'confirmemail_pending' );
}
- $wgOut->addWikiMsg( 'confirmemail_text' );
+ $out->addWikiMsg( 'confirmemail_text' );
$form = Xml::openElement( 'form', array( 'method' => 'post', 'action' => $this->getTitle()->getLocalUrl() ) );
- $form .= Html::hidden( 'token', $wgUser->editToken() );
+ $form .= Html::hidden( 'token', $user->editToken() );
$form .= Xml::submitButton( wfMsg( 'confirmemail_send' ) );
$form .= Xml::closeElement( 'form' );
- $wgOut->addHTML( $form );
+ $out->addHTML( $form );
}
}
@@ -116,19 +113,18 @@ class EmailConfirmation extends UnlistedSpecialPage {
* @param $code Confirmation code
*/
function attemptConfirm( $code ) {
- global $wgUser, $wgOut;
$user = User::newFromConfirmationCode( $code );
if( is_object( $user ) ) {
$user->confirmEmail();
$user->saveSettings();
- $message = $wgUser->isLoggedIn() ? 'confirmemail_loggedin' : 'confirmemail_success';
- $wgOut->addWikiMsg( $message );
- if( !$wgUser->isLoggedIn() ) {
+ $message = $this->getUser()->isLoggedIn() ? 'confirmemail_loggedin' : 'confirmemail_success';
+ $this->getOutput()->addWikiMsg( $message );
+ if( !$this->getUser()->isLoggedIn() ) {
$title = SpecialPage::getTitleFor( 'Userlogin' );
- $wgOut->returnToMain( true, $title );
+ $this->getOutput()->returnToMain( true, $title );
}
} else {
- $wgOut->addWikiMsg( 'confirmemail_invalid' );
+ $this->getOutput()->addWikiMsg( 'confirmemail_invalid' );
}
}
@@ -150,11 +146,9 @@ class EmailInvalidation extends UnlistedSpecialPage {
$this->setHeaders();
if ( wfReadOnly() ) {
- global $wgOut;
- $wgOut->readOnlyPage();
- return;
+ throw new ReadOnlyError;
}
-
+
$this->attemptInvalidate( $code );
}
@@ -165,17 +159,16 @@ class EmailInvalidation extends UnlistedSpecialPage {
* @param $code Confirmation code
*/
function attemptInvalidate( $code ) {
- global $wgUser, $wgOut;
$user = User::newFromConfirmationCode( $code );
if( is_object( $user ) ) {
$user->invalidateEmail();
$user->saveSettings();
- $wgOut->addWikiMsg( 'confirmemail_invalidated' );
- if( !$wgUser->isLoggedIn() ) {
- $wgOut->returnToMain();
+ $this->getOutput()->addWikiMsg( 'confirmemail_invalidated' );
+ if( !$this->getUser()->isLoggedIn() ) {
+ $this->getOutput()->returnToMain();
}
} else {
- $wgOut->addWikiMsg( 'confirmemail_invalid' );
+ $this->getOutput()->addWikiMsg( 'confirmemail_invalid' );
}
}
}
diff --git a/includes/specials/SpecialContributions.php b/includes/specials/SpecialContributions.php
index cee01a7f..fea27bfd 100644
--- a/includes/specials/SpecialContributions.php
+++ b/includes/specials/SpecialContributions.php
@@ -29,6 +29,8 @@
class SpecialContributions extends SpecialPage {
+ protected $opts;
+
public function __construct() {
parent::__construct( 'Contributions' );
}
@@ -38,6 +40,7 @@ class SpecialContributions extends SpecialPage {
$this->setHeaders();
$this->outputHeader();
+ $wgOut->addModuleStyles( 'mediawiki.special' );
$this->opts = array();
@@ -78,6 +81,10 @@ class SpecialContributions extends SpecialPage {
$target = $nt->getText();
$wgOut->setSubtitle( $this->contributionsSub( $nt, $id ) );
$wgOut->setHTMLTitle( wfMsg( 'pagetitle', wfMsgExt( 'contributions-title', array( 'parsemag' ),$target ) ) );
+ $user = User::newFromName( $target, false );
+ if ( is_object( $user ) ) {
+ $this->getSkin()->setRelevantUser( $user );
+ }
} else {
$wgOut->setSubtitle( wfMsgHtml( 'sp-contributions-newbies-sub') );
$wgOut->setHTMLTitle( wfMsg( 'pagetitle', wfMsg( 'sp-contributions-newbies-title' ) ) );
@@ -107,13 +114,43 @@ class SpecialContributions extends SpecialPage {
$this->opts['month'] = $wgRequest->getIntOrNull( 'month' );
}
- // Add RSS/atom links
- $this->setSyndicated();
$feedType = $wgRequest->getVal( 'feed' );
if( $feedType ) {
- return $this->feed( $feedType );
+ // Maintain some level of backwards compatability
+ // If people request feeds using the old parameters, redirect to API
+ $apiParams = array(
+ 'action' => 'feedcontributions',
+ 'feedformat' => $feedType,
+ 'user' => $target,
+ );
+ if ( $this->opts['topOnly'] ) {
+ $apiParams['toponly'] = true;
+ }
+ if ( $this->opts['deletedOnly'] ) {
+ $apiParams['deletedonly'] = true;
+ }
+ if ( $this->opts['tagFilter'] !== '' ) {
+ $apiParams['tagfilter'] = $this->opts['tagFilter'];
+ }
+ if ( $this->opts['namespace'] !== '' ) {
+ $apiParams['namespace'] = $this->opts['namespace'];
+ }
+ if ( $this->opts['year'] !== null ) {
+ $apiParams['year'] = $this->opts['year'];
+ }
+ if ( $this->opts['month'] !== null ) {
+ $apiParams['month'] = $this->opts['month'];
+ }
+
+ $url = wfScript( 'api' ) . '?' . wfArrayToCGI( $apiParams );
+
+ $wgOut->redirect( $url, '301' );
+ return;
}
+ // Add RSS/atom links
+ $this->addFeedLinks( array( 'action' => 'feedcontributions', 'user' => $target ) );
+
if ( wfRunHooks( 'SpecialContributionsBeforeMainOutput', array( $id ) ) ) {
$wgOut->addHTML( $this->getForm() );
@@ -130,7 +167,8 @@ class SpecialContributions extends SpecialPage {
$wgOut->addWikiMsg( 'nocontribs', $target );
} else {
# Show a message about slave lag, if applicable
- if( ( $lag = $pager->getDatabase()->getLag() ) > 0 )
+ $lag = wfGetLB()->safeGetLag( $pager->getDatabase() );
+ if( $lag > 0 )
$wgOut->showLagWarning( $lag );
$wgOut->addHTML(
@@ -141,7 +179,6 @@ class SpecialContributions extends SpecialPage {
}
$wgOut->preventClickjacking( $pager->getPreventClickjacking() );
-
# Show the appropriate "footer" message - WHOIS tools, etc.
if( $target != 'newbies' ) {
$message = 'sp-contributions-footer';
@@ -155,8 +192,7 @@ class SpecialContributions extends SpecialPage {
}
}
- $text = wfMsgNoTrans( $message, $target );
- if( !wfEmptyMsg( $message, $text ) && $text != '-' ) {
+ if( !wfMessage( $message, $target )->isDisabled() ) {
$wgOut->wrapWikiMsg(
"<div class='mw-contributions-footer'>\n$1\n</div>",
array( $message, $target ) );
@@ -165,23 +201,17 @@ class SpecialContributions extends SpecialPage {
}
}
- protected function setSyndicated() {
- global $wgOut;
- $wgOut->setSyndicated( true );
- $wgOut->setFeedAppendQuery( wfArrayToCGI( $this->opts ) );
- }
-
/**
* Generates the subheading with links
* @param $nt Title object for the target
* @param $id Integer: User ID for the target
* @return String: appropriately-escaped HTML to be output literally
- * @todo Fixme: almost the same as getSubTitle in SpecialDeletedContributions.php. Could be combined.
+ * @todo FIXME: Almost the same as getSubTitle in SpecialDeletedContributions.php. Could be combined.
*/
protected function contributionsSub( $nt, $id ) {
- global $wgSysopUserBans, $wgLang, $wgUser, $wgOut;
+ global $wgLang, $wgUser, $wgOut;
- $sk = $wgUser->getSkin();
+ $sk = $this->getSkin();
if ( $id === null ) {
$user = htmlspecialchars( $nt->getText() );
@@ -191,78 +221,7 @@ class SpecialContributions extends SpecialPage {
$userObj = User::newFromName( $nt->getText(), /* check for username validity not needed */ false );
$talk = $nt->getTalkPage();
if( $talk ) {
- # Talk page link
- $tools[] = $sk->link( $talk, wfMsgHtml( 'sp-contributions-talk' ) );
- if( ( $id !== null && $wgSysopUserBans ) || ( $id === null && IP::isIPAddress( $nt->getText() ) ) ) {
- if( $wgUser->isAllowed( 'block' ) ) { # Block / Change block / Unblock links
- if ( $userObj->isBlocked() ) {
- $tools[] = $sk->linkKnown( # Change block link
- SpecialPage::getTitleFor( 'Blockip', $nt->getDBkey() ),
- wfMsgHtml( 'change-blocklink' )
- );
- $tools[] = $sk->linkKnown( # Unblock link
- SpecialPage::getTitleFor( 'Ipblocklist' ),
- wfMsgHtml( 'unblocklink' ),
- array(),
- array(
- 'action' => 'unblock',
- 'ip' => $nt->getDBkey()
- )
- );
- }
- else { # User is not blocked
- $tools[] = $sk->linkKnown( # Block link
- SpecialPage::getTitleFor( 'Blockip', $nt->getDBkey() ),
- wfMsgHtml( 'blocklink' )
- );
- }
- }
- # Block log link
- $tools[] = $sk->linkKnown(
- SpecialPage::getTitleFor( 'Log' ),
- wfMsgHtml( 'sp-contributions-blocklog' ),
- array(),
- array(
- 'type' => 'block',
- 'page' => $nt->getPrefixedText()
- )
- );
- }
- # Uploads
- $tools[] = $sk->linkKnown(
- SpecialPage::getTitleFor( 'Listfiles' ),
- wfMsgHtml( 'sp-contributions-uploads' ),
- array(),
- array( 'user' => $nt->getText() )
- );
-
- # Other logs link
- $tools[] = $sk->linkKnown(
- SpecialPage::getTitleFor( 'Log' ),
- wfMsgHtml( 'sp-contributions-logs' ),
- array(),
- array( 'user' => $nt->getText() )
- );
-
- # Add link to deleted user contributions for priviledged users
- if( $wgUser->isAllowed( 'deletedhistory' ) ) {
- $tools[] = $sk->linkKnown(
- SpecialPage::getTitleFor( 'DeletedContributions', $nt->getDBkey() ),
- wfMsgHtml( 'sp-contributions-deleted' )
- );
- }
-
- # Add a link to change user rights for privileged users
- $userrightsPage = new UserrightsPage();
- if( $id !== null && $userrightsPage->userCanChangeRights( User::newFromId( $id ) ) ) {
- $tools[] = $sk->linkKnown(
- SpecialPage::getTitleFor( 'Userrights', $nt->getDBkey() ),
- wfMsgHtml( 'sp-contributions-userrights' )
- );
- }
-
- wfRunHooks( 'ContributionsToolLinks', array( $id, $nt, &$tools ) );
-
+ $tools = self::getUserLinks( $nt, $talk, $userObj, $wgUser );
$links = $wgLang->pipeList( $tools );
// Show a note if the user is blocked and display the last block log entry.
@@ -291,7 +250,7 @@ class SpecialContributions extends SpecialPage {
// languages that want to put the "for" bit right after $user but before
// $links. If 'contribsub' is around, use it for reverse compatibility,
// otherwise use 'contribsub2'.
- if( wfEmptyMsg( 'contribsub', wfMsg( 'contribsub' ) ) ) {
+ if( wfEmptyMsg( 'contribsub' ) ) {
return wfMsgHtml( 'contribsub2', $user, $links );
} else {
return wfMsgHtml( 'contribsub', "$user ($links)" );
@@ -299,6 +258,82 @@ class SpecialContributions extends SpecialPage {
}
/**
+ * Links to different places.
+ * @param $userpage Title: Target user page
+ * @param $talkpage Title: Talk page
+ * @param $target User: Target user object
+ * @param $subject User: The viewing user ($wgUser is still checked in some cases, like userrights page!!)
+ */
+ public static function getUserLinks( Title $userpage, Title $talkpage, User $target, User $subject ) {
+
+ $sk = $subject->getSkin();
+ $id = $target->getId();
+ $username = $target->getName();
+
+ $tools[] = $sk->link( $talkpage, wfMsgHtml( 'sp-contributions-talk' ) );
+
+ if( ( $id !== null ) || ( $id === null && IP::isIPAddress( $username ) ) ) {
+ if( $subject->isAllowed( 'block' ) ) { # Block / Change block / Unblock links
+ if ( $target->isBlocked() ) {
+ $tools[] = $sk->linkKnown( # Change block link
+ SpecialPage::getTitleFor( 'Block', $username ),
+ wfMsgHtml( 'change-blocklink' )
+ );
+ $tools[] = $sk->linkKnown( # Unblock link
+ SpecialPage::getTitleFor( 'Unblock', $username ),
+ wfMsgHtml( 'unblocklink' )
+ );
+ } else { # User is not blocked
+ $tools[] = $sk->linkKnown( # Block link
+ SpecialPage::getTitleFor( 'Block', $username ),
+ wfMsgHtml( 'blocklink' )
+ );
+ }
+ }
+ # Block log link
+ $tools[] = $sk->linkKnown(
+ SpecialPage::getTitleFor( 'Log', 'block' ),
+ wfMsgHtml( 'sp-contributions-blocklog' ),
+ array(),
+ array(
+ 'page' => $userpage->getPrefixedText()
+ )
+ );
+ }
+ # Uploads
+ $tools[] = $sk->linkKnown(
+ SpecialPage::getTitleFor( 'Listfiles', $username ),
+ wfMsgHtml( 'sp-contributions-uploads' )
+ );
+
+ # Other logs link
+ $tools[] = $sk->linkKnown(
+ SpecialPage::getTitleFor( 'Log', $username ),
+ wfMsgHtml( 'sp-contributions-logs' )
+ );
+
+ # Add link to deleted user contributions for priviledged users
+ if( $subject->isAllowed( 'deletedhistory' ) ) {
+ $tools[] = $sk->linkKnown(
+ SpecialPage::getTitleFor( 'DeletedContributions', $username ),
+ wfMsgHtml( 'sp-contributions-deleted' )
+ );
+ }
+
+ # Add a link to change user rights for privileged users
+ $userrightsPage = new UserrightsPage();
+ if( $id !== null && $userrightsPage->userCanChangeRights( $target ) ) {
+ $tools[] = $sk->linkKnown(
+ SpecialPage::getTitleFor( 'Userrights', $username ),
+ wfMsgHtml( 'sp-contributions-userrights' )
+ );
+ }
+
+ wfRunHooks( 'ContributionsToolLinks', array( $id, $userpage, &$tools ) );
+ return $tools;
+ }
+
+ /**
* Generates the namespace selector form with hidden attributes.
* @return String: HTML fragment
*/
@@ -374,104 +409,15 @@ class SpecialContributions extends SpecialPage {
Html::rawElement( 'p', array( 'style' => 'white-space: nowrap' ),
Xml::dateMenu( $this->opts['year'], $this->opts['month'] ) . ' ' .
Xml::submitButton( wfMsg( 'sp-contributions-submit' ) )
- ) . ' ';
- $explain = wfMsgExt( 'sp-contributions-explain', 'parseinline' );
- if( !wfEmptyMsg( 'sp-contributions-explain', $explain ) ) {
+ ) . ' ';
+ $explain = wfMessage( 'sp-contributions-explain' );
+ if ( $explain->exists() ) {
$f .= "<p id='mw-sp-contributions-explain'>{$explain}</p>";
}
$f .= Xml::closeElement('fieldset' ) .
Xml::closeElement( 'form' );
return $f;
}
-
- /**
- * Output a subscription feed listing recent edits to this page.
- * @param $type String
- */
- protected function feed( $type ) {
- global $wgFeed, $wgFeedClasses, $wgFeedLimit, $wgOut;
-
- if( !$wgFeed ) {
- $wgOut->addWikiMsg( 'feed-unavailable' );
- return;
- }
-
- if( !isset( $wgFeedClasses[$type] ) ) {
- $wgOut->addWikiMsg( 'feed-invalid' );
- return;
- }
-
- $feed = new $wgFeedClasses[$type](
- $this->feedTitle(),
- wfMsgExt( 'tagline', 'parsemag' ),
- $this->getTitle()->getFullUrl() . "/" . urlencode($this->opts['target'])
- );
-
- // Already valid title
- $nt = Title::makeTitleSafe( NS_USER, $this->opts['target'] );
- $target = $this->opts['target'] == 'newbies' ? 'newbies' : $nt->getText();
-
- $pager = new ContribsPager( array(
- 'target' => $target,
- 'namespace' => $this->opts['namespace'],
- 'year' => $this->opts['year'],
- 'month' => $this->opts['month'],
- 'tagFilter' => $this->opts['tagFilter'],
- 'deletedOnly' => $this->opts['deletedOnly'],
- 'topOnly' => $this->opts['topOnly'],
- ) );
-
- $pager->mLimit = min( $this->opts['limit'], $wgFeedLimit );
-
- $feed->outHeader();
- if( $pager->getNumRows() > 0 ) {
- foreach ( $pager->mResult as $row ) {
- $feed->outItem( $this->feedItem( $row ) );
- }
- }
- $feed->outFooter();
- }
-
- protected function feedTitle() {
- global $wgLanguageCode, $wgSitename;
- $page = SpecialPage::getPage( 'Contributions' );
- $desc = $page->getDescription();
- return "$wgSitename - $desc [$wgLanguageCode]";
- }
-
- protected function feedItem( $row ) {
- $title = Title::MakeTitle( intval( $row->page_namespace ), $row->page_title );
- if( $title ) {
- $date = $row->rev_timestamp;
- $comments = $title->getTalkPage()->getFullURL();
- $revision = Revision::newFromTitle( $title, $row->rev_id );
-
- return new FeedItem(
- $title->getPrefixedText(),
- $this->feedItemDesc( $revision ),
- $title->getFullURL(),
- $date,
- $this->feedItemAuthor( $revision ),
- $comments
- );
- } else {
- return null;
- }
- }
-
- protected function feedItemAuthor( $revision ) {
- return $revision->getUserText();
- }
-
- protected function feedItemDesc( $revision ) {
- if( $revision ) {
- return '<p>' . htmlspecialchars( $revision->getUserText() ) . wfMsgForContent( 'colon-separator' ) .
- htmlspecialchars( FeedItem::stripComment( $revision->getComment() ) ) .
- "</p>\n<hr />\n<div>" .
- nl2br( htmlspecialchars( $revision->getText() ) ) . "</div>";
- }
- return '';
- }
}
/**
@@ -513,6 +459,10 @@ class ContribsPager extends ReverseChronologicalPager {
return $query;
}
+ function getTitle() {
+ return SpecialPage::getTitleFor( 'Contributions' );
+ }
+
function getQueryInfo() {
global $wgUser;
list( $tables, $index, $userCond, $join_cond ) = $this->getUserCond();
@@ -521,7 +471,7 @@ class ContribsPager extends ReverseChronologicalPager {
// Paranoia: avoid brute force searches (bug 17342)
if( !$wgUser->isAllowed( 'deletedhistory' ) ) {
$conds[] = $this->mDb->bitAnd('rev_deleted',Revision::DELETED_USER) . ' = 0';
- } else if( !$wgUser->isAllowed( 'suppressrevision' ) ) {
+ } elseif( !$wgUser->isAllowed( 'suppressrevision' ) ) {
$conds[] = $this->mDb->bitAnd('rev_deleted',Revision::SUPPRESSED_USER) .
' != ' . Revision::SUPPRESSED_USER;
}
@@ -561,7 +511,7 @@ class ContribsPager extends ReverseChronologicalPager {
$condition[] = 'rev_user >' . (int)($max - $max / 100);
$condition[] = 'ug_group IS NULL';
$index = 'user_timestamp';
- # FIXME: other groups may have 'bot' rights
+ # @todo FIXME: Other groups may have 'bot' rights
$join_conds['user_groups'] = array( 'LEFT JOIN', "ug_user = rev_user AND ug_group = 'bot'" );
} else {
$tables = array( 'page', 'revision' );
@@ -608,7 +558,7 @@ class ContribsPager extends ReverseChronologicalPager {
* @todo This would probably look a lot nicer in a table.
*/
function formatRow( $row ) {
- global $wgUser, $wgLang, $wgContLang;
+ global $wgUser, $wgLang;
wfProfileIn( __METHOD__ );
$sk = $this->getSkin();
@@ -655,7 +605,7 @@ class ContribsPager extends ReverseChronologicalPager {
array( 'action' => 'history' )
);
- $comment = $wgContLang->getDirMark() . $sk->revComment( $rev, false, true );
+ $comment = $wgLang->getDirMark() . $sk->revComment( $rev, false, true );
$date = $wgLang->timeanddate( wfTimestamp( TS_MW, $row->rev_timestamp ), true );
if( $rev->userCan( Revision::DELETED_TEXT ) ) {
$d = $sk->linkKnown(
@@ -734,7 +684,7 @@ class ContribsPager extends ReverseChronologicalPager {
/**
* Get the Database object in use
*
- * @return Database
+ * @return DatabaseBase
*/
public function getDatabase() {
return $this->mDb;
diff --git a/includes/specials/SpecialDeadendpages.php b/includes/specials/SpecialDeadendpages.php
index dfa053aa..f8ef4d44 100644
--- a/includes/specials/SpecialDeadendpages.php
+++ b/includes/specials/SpecialDeadendpages.php
@@ -28,8 +28,8 @@
*/
class DeadendPagesPage extends PageQueryPage {
- function getName( ) {
- return "Deadendpages";
+ function __construct( $name = 'Deadendpages' ) {
+ parent::__construct( $name );
}
function getPageHeader() {
@@ -41,11 +41,13 @@ class DeadendPagesPage extends PageQueryPage {
*
* @return true
*/
- function isExpensive( ) {
- return 1;
+ function isExpensive() {
+ return true;
}
- function isSyndicated() { return false; }
+ function isSyndicated() {
+ return false;
+ }
/**
* @return false
@@ -54,28 +56,30 @@ class DeadendPagesPage extends PageQueryPage {
return false;
}
- /**
- * @return string an sqlquery
- */
- function getSQL() {
- $dbr = wfGetDB( DB_SLAVE );
- list( $page, $pagelinks ) = $dbr->tableNamesN( 'page', 'pagelinks' );
- return "SELECT 'Deadendpages' as type, page_namespace AS namespace, page_title as title, page_title AS value " .
- "FROM $page LEFT JOIN $pagelinks ON page_id = pl_from " .
- "WHERE pl_from IS NULL " .
- "AND page_namespace = 0 " .
- "AND page_is_redirect = 0";
+ function getQueryInfo() {
+ return array(
+ 'tables' => array( 'page', 'pagelinks' ),
+ 'fields' => array( 'page_namespace AS namespace',
+ 'page_title AS title',
+ 'page_title AS value'
+ ),
+ 'conds' => array( 'pl_from IS NULL',
+ 'page_namespace' => MWNamespace::getContentNamespaces(),
+ 'page_is_redirect' => 0
+ ),
+ 'join_conds' => array( 'pagelinks' => array( 'LEFT JOIN', array(
+ 'page_id=pl_from'
+ ) ) )
+ );
}
-}
-/**
- * Constructor
- */
-function wfSpecialDeadendpages() {
-
- list( $limit, $offset ) = wfCheckLimits();
-
- $depp = new DeadendPagesPage();
-
- return $depp->doQuery( $offset, $limit );
+ function getOrderFields() {
+ // For some crazy reason ordering by a constant
+ // causes a filesort
+ if( count( MWNamespace::getContentNamespaces() ) > 1 ) {
+ return array( 'page_namespace', 'page_title' );
+ } else {
+ return array( 'page_title' );
+ }
+ }
}
diff --git a/includes/specials/SpecialDeletedContributions.php b/includes/specials/SpecialDeletedContributions.php
index 92e22586..65858482 100644
--- a/includes/specials/SpecialDeletedContributions.php
+++ b/includes/specials/SpecialDeletedContributions.php
@@ -55,7 +55,7 @@ class DeletedContribsPager extends IndexPager {
// Paranoia: avoid brute force searches (bug 17792)
if( !$wgUser->isAllowed( 'deletedhistory' ) ) {
$conds[] = $this->mDb->bitAnd('ar_deleted',Revision::DELETED_USER) . ' = 0';
- } else if( !$wgUser->isAllowed( 'suppressrevision' ) ) {
+ } elseif( !$wgUser->isAllowed( 'suppressrevision' ) ) {
$conds[] = $this->mDb->bitAnd('ar_deleted',Revision::SUPPRESSED_USER) .
' != ' . Revision::SUPPRESSED_USER;
}
@@ -211,7 +211,7 @@ class DeletedContribsPager extends IndexPager {
} else {
$mflag = '';
}
-
+
// Revision delete link
$canHide = $wgUser->isAllowed( 'deleterevision' );
if( $canHide || ($rev->getVisibility() && $wgUser->isAllowed('deletedhistory')) ) {
@@ -234,9 +234,9 @@ class DeletedContribsPager extends IndexPager {
array( 'class' => 'mw-deletedcontribs-tools' ),
wfMsg( 'parentheses', $wgLang->pipeList( array( $last, $dellog, $reviewlink ) ) )
);
-
+
$ret = "{$del}{$link} {$tools} . . {$mflag} {$pagelink} {$comment}";
-
+
# Denote if username is redacted for this edit
if( $rev->isDeleted( Revision::DELETED_USER ) ) {
$ret .= " <strong>" . wfMsgHtml('rev-deleted-user-contribs') . "</strong>";
@@ -325,7 +325,8 @@ class DeletedContributionsPage extends SpecialPage {
}
# Show a message about slave lag, if applicable
- if( ( $lag = $pager->getDatabase()->getLag() ) > 0 )
+ $lag = wfGetLB()->safeGetLag( $pager->getDatabase() );
+ if( $lag > 0 )
$wgOut->showLagWarning( $lag );
$wgOut->addHTML(
@@ -340,9 +341,7 @@ class DeletedContributionsPage extends SpecialPage {
? 'sp-contributions-footer-anon'
: 'sp-contributions-footer';
-
- $text = wfMsgNoTrans( $message, $target );
- if( !wfEmptyMsg( $message, $text ) && $text != '-' ) {
+ if( !wfMessage( $message )->isDisabled() ) {
$wgOut->wrapWikiMsg( "<div class='mw-contributions-footer'>\n$1\n</div>", array( $message, $target ) );
}
}
@@ -353,12 +352,12 @@ class DeletedContributionsPage extends SpecialPage {
* @param $nt Title object for the target
* @param $id Integer: User ID for the target
* @return String: appropriately-escaped HTML to be output literally
- * @todo Fixme: almost the same as contributionsSub in SpecialContributions.php. Could be combined.
+ * @todo FIXME: Almost the same as contributionsSub in SpecialContributions.php. Could be combined.
*/
function getSubTitle( $nt, $id ) {
- global $wgSysopUserBans, $wgLang, $wgUser, $wgOut;
+ global $wgLang, $wgUser, $wgOut;
- $sk = $wgUser->getSkin();
+ $sk = $this->getSkin();
if ( $id === null ) {
$user = htmlspecialchars( $nt->getText() );
@@ -370,11 +369,11 @@ class DeletedContributionsPage extends SpecialPage {
if( $talk ) {
# Talk page link
$tools[] = $sk->link( $talk, wfMsgHtml( 'sp-contributions-talk' ) );
- if( ( $id !== null && $wgSysopUserBans ) || ( $id === null && IP::isIPAddress( $nt->getText() ) ) ) {
+ if( ( $id !== null ) || ( $id === null && IP::isIPAddress( $nt->getText() ) ) ) {
if( $wgUser->isAllowed( 'block' ) ) { # Block / Change block / Unblock links
if ( $userObj->isBlocked() ) {
$tools[] = $sk->linkKnown( # Change block link
- SpecialPage::getTitleFor( 'Blockip', $nt->getDBkey() ),
+ SpecialPage::getTitleFor( 'Block', $nt->getDBkey() ),
wfMsgHtml( 'change-blocklink' )
);
$tools[] = $sk->linkKnown( # Unblock link
@@ -383,13 +382,13 @@ class DeletedContributionsPage extends SpecialPage {
array(),
array(
'action' => 'unblock',
- 'ip' => $nt->getDBkey()
+ 'ip' => $nt->getDBkey()
)
);
}
else { # User is not blocked
$tools[] = $sk->linkKnown( # Block link
- SpecialPage::getTitleFor( 'Blockip', $nt->getDBkey() ),
+ SpecialPage::getTitleFor( 'Block', $nt->getDBkey() ),
wfMsgHtml( 'blocklink' )
);
}
@@ -455,7 +454,7 @@ class DeletedContributionsPage extends SpecialPage {
// languages that want to put the "for" bit right after $user but before
// $links. If 'contribsub' is around, use it for reverse compatibility,
// otherwise use 'contribsub2'.
- if( wfEmptyMsg( 'contribsub', wfMsg( 'contribsub' ) ) ) {
+ if( wfEmptyMsg( 'contribsub' ) ) {
return wfMsgHtml( 'contribsub2', $user, $links );
} else {
return wfMsgHtml( 'contribsub', "$user ($links)" );
diff --git a/includes/specials/SpecialDisambiguations.php b/includes/specials/SpecialDisambiguations.php
index 3e706189..431dfe76 100644
--- a/includes/specials/SpecialDisambiguations.php
+++ b/includes/specials/SpecialDisambiguations.php
@@ -28,33 +28,28 @@
*/
class DisambiguationsPage extends PageQueryPage {
- function getName() {
- return 'Disambiguations';
+ function __construct( $name = 'Disambiguations' ) {
+ parent::__construct( $name );
}
- function isExpensive( ) { return true; }
+ function isExpensive() { return true; }
function isSyndicated() { return false; }
-
- function getPageHeader( ) {
+ function getPageHeader() {
return wfMsgExt( 'disambiguations-text', array( 'parse' ) );
}
- function getSQL() {
- global $wgContentNamespaces;
-
+ function getQueryInfo() {
$dbr = wfGetDB( DB_SLAVE );
-
- $dMsgText = wfMsgForContent('disambiguationspage');
-
+ $dMsgText = wfMsgForContent( 'disambiguationspage' );
$linkBatch = new LinkBatch;
# If the text can be treated as a title, use it verbatim.
# Otherwise, pull the titles from the links table
$dp = Title::newFromText($dMsgText);
if( $dp ) {
- if($dp->getNamespace() != NS_TEMPLATE) {
- # FIXME we assume the disambiguation message is a template but
+ if( $dp->getNamespace() != NS_TEMPLATE ) {
+ # @todo FIXME: We assume the disambiguation message is a template but
# the page can potentially be from another namespace :/
wfDebug("Mediawiki:disambiguationspage message does not refer to a template!\n");
}
@@ -65,69 +60,79 @@ class DisambiguationsPage extends PageQueryPage {
$res = $dbr->select(
array('pagelinks', 'page'),
'pl_title',
- array('page_id = pl_from', 'pl_namespace' => NS_TEMPLATE,
- 'page_namespace' => $disPageObj->getNamespace(), 'page_title' => $disPageObj->getDBkey()),
+ array('page_id = pl_from',
+ 'pl_namespace' => NS_TEMPLATE,
+ 'page_namespace' => $disPageObj->getNamespace(),
+ 'page_title' => $disPageObj->getDBkey()),
__METHOD__ );
foreach ( $res as $row ) {
$linkBatch->addObj( Title::makeTitle( NS_TEMPLATE, $row->pl_title ));
}
}
-
- $set = $linkBatch->constructSet( 'lb.tl', $dbr );
+ $set = $linkBatch->constructSet( 'tl', $dbr );
if( $set === false ) {
- # We must always return a valid sql query, but this way DB will always quicly return an empty result
+ # We must always return a valid SQL query, but this way
+ # the DB will always quickly return an empty result
$set = 'FALSE';
wfDebug("Mediawiki:disambiguationspage message does not link to any templates!\n");
}
- list( $page, $pagelinks, $templatelinks) = $dbr->tableNamesN( 'page', 'pagelinks', 'templatelinks' );
+ // @todo FIXME: What are pagelinks and p2 doing here?
+ return array (
+ 'tables' => array( 'templatelinks', 'p1' => 'page', 'pagelinks', 'p2' => 'page' ),
+ 'fields' => array( 'p1.page_namespace AS namespace',
+ 'p1.page_title AS title',
+ 'pl_from AS value' ),
+ 'conds' => array( $set,
+ 'p1.page_id = tl_from',
+ 'pl_namespace = p1.page_namespace',
+ 'pl_title = p1.page_title',
+ 'p2.page_id = pl_from',
+ 'p2.page_namespace' => MWNamespace::getContentNamespaces() )
+ );
+ }
- if ( $wgContentNamespaces ) {
- $nsclause = 'IN (' . $dbr->makeList( $wgContentNamespaces ) . ')';
- } else {
- $nsclause = '= ' . NS_MAIN;
- }
+ function getOrderFields() {
+ return array( 'tl_namespace', 'tl_title', 'value' );
+ }
- $sql = "SELECT 'Disambiguations' AS \"type\", pb.page_namespace AS namespace,"
- ." pb.page_title AS title, la.pl_from AS value"
- ." FROM {$templatelinks} AS lb, {$page} AS pb, {$pagelinks} AS la, {$page} AS pa"
- ." WHERE $set" # disambiguation template(s)
- .' AND pa.page_id = la.pl_from'
- .' AND pa.page_namespace ' . $nsclause
- .' AND pb.page_id = lb.tl_from'
- .' AND pb.page_namespace = la.pl_namespace'
- .' AND pb.page_title = la.pl_title'
- .' ORDER BY lb.tl_namespace, lb.tl_title';
-
- return $sql;
+ function sortDescending() {
+ return false;
}
- function getOrder() {
- return '';
+ /**
+ * Fetch links and cache their existence
+ *
+ * @param $db DatabaseBase
+ * @param $res
+ */
+ function preprocessResults( $db, $res ) {
+ $batch = new LinkBatch;
+ foreach ( $res as $row ) {
+ $batch->add( $row->namespace, $row->title );
+ }
+ $batch->execute();
+
+ // Back to start for display
+ if ( $db->numRows( $res ) > 0 ) {
+ // If there are no rows we get an error seeking.
+ $db->dataSeek( $res, 0 );
+ }
}
function formatResult( $skin, $result ) {
- global $wgContLang;
+ global $wgLang;
+
$title = Title::newFromID( $result->value );
$dp = Title::makeTitle( $result->namespace, $result->title );
$from = $skin->link( $title );
- $edit = $skin->link( $title, wfMsgExt( 'parentheses', array( 'escape' ), wfMsg( 'editlink' ) ) , array(), array( 'redirect' => 'no', 'action' => 'edit' ) );
- $arr = $wgContLang->getArrow();
+ $edit = $skin->link( $title, wfMsgExt( 'parentheses', array( 'escape' ), wfMsg( 'editlink' ) ) ,
+ array(), array( 'redirect' => 'no', 'action' => 'edit' ) );
+ $arr = $wgLang->getArrow();
$to = $skin->link( $dp );
return "$from $edit $arr $to";
}
}
-
-/**
- * Constructor
- */
-function wfSpecialDisambiguations() {
- list( $limit, $offset ) = wfCheckLimits();
-
- $sd = new DisambiguationsPage();
-
- return $sd->doQuery( $offset, $limit );
-}
diff --git a/includes/specials/SpecialDoubleRedirects.php b/includes/specials/SpecialDoubleRedirects.php
index c7f63210..ec899d8a 100644
--- a/includes/specials/SpecialDoubleRedirects.php
+++ b/includes/specials/SpecialDoubleRedirects.php
@@ -29,63 +29,63 @@
*/
class DoubleRedirectsPage extends PageQueryPage {
- function getName() {
- return 'DoubleRedirects';
+ function __construct( $name = 'DoubleRedirects' ) {
+ parent::__construct( $name );
}
- function isExpensive( ) { return true; }
+ function isExpensive() { return true; }
function isSyndicated() { return false; }
+ function sortDescending() { return false; }
- function getPageHeader( ) {
+ function getPageHeader() {
return wfMsgExt( 'doubleredirectstext', array( 'parse' ) );
}
- function getSQLText( &$dbr, $namespace = null, $title = null ) {
-
- list( $page, $redirect ) = $dbr->tableNamesN( 'page', 'redirect' );
-
+ function reallyGetQueryInfo( $namespace = null, $title = null ) {
$limitToTitle = !( $namespace === null && $title === null );
- $sql = $limitToTitle ? "SELECT" : "SELECT 'DoubleRedirects' as type," ;
- $sql .=
- " pa.page_namespace as namespace, pa.page_title as title," .
- " pb.page_namespace as nsb, pb.page_title as tb," .
- " pc.page_namespace as nsc, pc.page_title as tc" .
- " FROM $redirect AS ra, $redirect AS rb, $page AS pa, $page AS pb, $page AS pc" .
- " WHERE ra.rd_from=pa.page_id" .
- " AND ra.rd_namespace=pb.page_namespace" .
- " AND ra.rd_title=pb.page_title" .
- " AND rb.rd_from=pb.page_id" .
- " AND rb.rd_namespace=pc.page_namespace" .
- " AND rb.rd_title=pc.page_title";
-
- if( $limitToTitle ) {
- $encTitle = $dbr->addQuotes( $title );
- $sql .= " AND pa.page_namespace=$namespace" .
- " AND pa.page_title=$encTitle";
+ $retval = array (
+ 'tables' => array ( 'ra' => 'redirect',
+ 'rb' => 'redirect', 'pa' => 'page',
+ 'pb' => 'page', 'pc' => 'page' ),
+ 'fields' => array ( 'pa.page_namespace AS namespace',
+ 'pa.page_title AS title',
+ 'pb.page_namespace AS nsb',
+ 'pb.page_title AS tb',
+ 'pc.page_namespace AS nsc',
+ 'pc.page_title AS tc' ),
+ 'conds' => array ( 'ra.rd_from = pa.page_id',
+ 'pb.page_namespace = ra.rd_namespace',
+ 'pb.page_title = ra.rd_title',
+ 'rb.rd_from = pb.page_id',
+ 'pc.page_namespace = rb.rd_namespace',
+ 'pc.page_title = rb.rd_title' )
+ );
+ if ( $limitToTitle ) {
+ $retval['conds']['pa.page_namespace'] = $namespace;
+ $retval['conds']['pa.page_title'] = $title;
}
-
- return $sql;
+ return $retval;
}
- function getSQL() {
- $dbr = wfGetDB( DB_SLAVE );
- return $this->getSQLText( $dbr );
+ function getQueryInfo() {
+ return $this->reallyGetQueryInfo();
}
- function getOrder() {
- return '';
+ function getOrderFields() {
+ return array ( 'ra.rd_namespace', 'ra.rd_title' );
}
function formatResult( $skin, $result ) {
- global $wgContLang;
+ global $wgLang;
- $fname = 'DoubleRedirectsPage::formatResult';
$titleA = Title::makeTitle( $result->namespace, $result->title );
if ( $result && !isset( $result->nsb ) ) {
$dbr = wfGetDB( DB_SLAVE );
- $sql = $this->getSQLText( $dbr, $result->namespace, $result->title );
- $res = $dbr->query( $sql, $fname );
+ $qi = $this->reallyGetQueryInfo( $result->namespace,
+ $result->title );
+ $res = $dbr->select($qi['tables'], $qi['fields'],
+ $qi['conds'], __METHOD__ );
if ( $res ) {
$result = $dbr->fetchObject( $res );
}
@@ -119,20 +119,8 @@ class DoubleRedirectsPage extends PageQueryPage {
array( 'redirect' => 'no' )
);
$linkC = $skin->linkKnown( $titleC );
- $arr = $wgContLang->getArrow() . $wgContLang->getDirMark();
+ $arr = $wgLang->getArrow() . $wgLang->getDirMark();
return( "{$linkA} {$edit} {$arr} {$linkB} {$arr} {$linkC}" );
}
}
-
-/**
- * constructor
- */
-function wfSpecialDoubleRedirects() {
- list( $limit, $offset ) = wfCheckLimits();
-
- $sdr = new DoubleRedirectsPage();
-
- return $sdr->doQuery( $offset, $limit );
-
-}
diff --git a/includes/specials/SpecialEditWatchlist.php b/includes/specials/SpecialEditWatchlist.php
new file mode 100644
index 00000000..bb2ecd80
--- /dev/null
+++ b/includes/specials/SpecialEditWatchlist.php
@@ -0,0 +1,596 @@
+<?php
+
+/**
+ * Provides the UI through which users can perform editing
+ * operations on their watchlist
+ *
+ * @ingroup Watchlist
+ * @author Rob Church <robchur@gmail.com>
+ */
+class SpecialEditWatchlist extends UnlistedSpecialPage {
+
+ /**
+ * Editing modes
+ */
+ const EDIT_CLEAR = 1;
+ const EDIT_RAW = 2;
+ const EDIT_NORMAL = 3;
+
+ protected $successMessage;
+
+ protected $toc;
+
+ public function __construct(){
+ parent::__construct( 'EditWatchlist' );
+ }
+
+ /**
+ * Main execution point
+ *
+ * @param $mode int
+ */
+ public function execute( $mode ) {
+ if( wfReadOnly() ) {
+ throw new ReadOnlyError;
+ }
+
+ $out = $this->getOutput();
+
+ # Anons don't get a watchlist
+ if( $this->getUser()->isAnon() ) {
+ $out->setPageTitle( wfMsg( 'watchnologin' ) );
+ $llink = Linker::linkKnown(
+ SpecialPage::getTitleFor( 'Userlogin' ),
+ wfMsgHtml( 'loginreqlink' ),
+ array(),
+ array( 'returnto' => $this->getTitle()->getPrefixedText() )
+ );
+ $out->addHTML( wfMessage( 'watchlistanontext' )->rawParams( $llink )->parse() );
+ return;
+ }
+
+ $sub = wfMsgExt(
+ 'watchlistfor2',
+ array( 'parseinline', 'replaceafter' ),
+ $this->getUser()->getName(),
+ SpecialEditWatchlist::buildTools( null )
+ );
+ $out->setSubtitle( $sub );
+
+ # B/C: $mode used to be waaay down the parameter list, and the first parameter
+ # was $wgUser
+ if( $mode instanceof User ){
+ $args = func_get_args();
+ if( count( $args >= 4 ) ){
+ $mode = $args[3];
+ }
+ }
+ $mode = self::getMode( $this->getRequest(), $mode );
+
+ switch( $mode ) {
+ case self::EDIT_CLEAR:
+ // The "Clear" link scared people too much.
+ // Pass on to the raw editor, from which it's very easy to clear.
+
+ case self::EDIT_RAW:
+ $out->setPageTitle( wfMsg( 'watchlistedit-raw-title' ) );
+ $form = $this->getRawForm();
+ if( $form->show() ){
+ $out->addHTML( $this->successMessage );
+ $out->returnToMain();
+ }
+ break;
+
+ case self::EDIT_NORMAL:
+ default:
+ $out->setPageTitle( wfMsg( 'watchlistedit-normal-title' ) );
+ $form = $this->getNormalForm();
+ if( $form->show() ){
+ $out->addHTML( $this->successMessage );
+ $out->returnToMain();
+ } elseif ( $this->toc !== false ) {
+ $out->prependHTML( $this->toc );
+ }
+ break;
+ }
+ }
+
+ /**
+ * Extract a list of titles from a blob of text, returning
+ * (prefixed) strings; unwatchable titles are ignored
+ *
+ * @param $list String
+ * @return array
+ */
+ private function extractTitles( $list ) {
+ $titles = array();
+ $list = explode( "\n", trim( $list ) );
+ if( !is_array( $list ) ) {
+ return array();
+ }
+ foreach( $list as $text ) {
+ $text = trim( $text );
+ if( strlen( $text ) > 0 ) {
+ $title = Title::newFromText( $text );
+ if( $title instanceof Title && $title->isWatchable() ) {
+ $titles[] = $title->getPrefixedText();
+ }
+ }
+ }
+ return array_unique( $titles );
+ }
+
+ public function submitRaw( $data ){
+ $wanted = $this->extractTitles( $data['Titles'] );
+ $current = $this->getWatchlist();
+
+ if( count( $wanted ) > 0 ) {
+ $toWatch = array_diff( $wanted, $current );
+ $toUnwatch = array_diff( $current, $wanted );
+ $this->watchTitles( $toWatch );
+ $this->unwatchTitles( $toUnwatch );
+ $this->getUser()->invalidateCache();
+
+ if( count( $toWatch ) > 0 || count( $toUnwatch ) > 0 ){
+ $this->successMessage = wfMessage( 'watchlistedit-raw-done' )->parse();
+ } else {
+ return false;
+ }
+
+ if( count( $toWatch ) > 0 ) {
+ $this->successMessage .= wfMessage(
+ 'watchlistedit-raw-added',
+ $this->getLang()->formatNum( count( $toWatch ) )
+ );
+ $this->showTitles( $toWatch, $this->successMessage );
+ }
+
+ if( count( $toUnwatch ) > 0 ) {
+ $this->successMessage .= wfMessage(
+ 'watchlistedit-raw-removed',
+ $this->getLang()->formatNum( count( $toUnwatch ) )
+ );
+ $this->showTitles( $toUnwatch, $this->successMessage );
+ }
+ } else {
+ $this->clearWatchlist();
+ $this->getUser()->invalidateCache();
+ $this->successMessage .= wfMessage(
+ 'watchlistedit-raw-removed',
+ $this->getLang()->formatNum( count( $current ) )
+ );
+ $this->showTitles( $current, $this->successMessage );
+ }
+ return true;
+ }
+
+ /**
+ * Print out a list of linked titles
+ *
+ * $titles can be an array of strings or Title objects; the former
+ * is preferred, since Titles are very memory-heavy
+ *
+ * @param $titles array of strings, or Title objects
+ * @param $output String
+ */
+ private function showTitles( $titles, &$output ) {
+ $talk = wfMsgHtml( 'talkpagelinktext' );
+ // Do a batch existence check
+ $batch = new LinkBatch();
+ foreach( $titles as $title ) {
+ if( !$title instanceof Title ) {
+ $title = Title::newFromText( $title );
+ }
+ if( $title instanceof Title ) {
+ $batch->addObj( $title );
+ $batch->addObj( $title->getTalkPage() );
+ }
+ }
+ $batch->execute();
+ // Print out the list
+ $output .= "<ul>\n";
+ foreach( $titles as $title ) {
+ if( !$title instanceof Title ) {
+ $title = Title::newFromText( $title );
+ }
+ if( $title instanceof Title ) {
+ $output .= "<li>"
+ . Linker::link( $title )
+ . ' (' . Linker::link( $title->getTalkPage(), $talk )
+ . ")</li>\n";
+ }
+ }
+ $output .= "</ul>\n";
+ }
+
+ /**
+ * Prepare a list of titles on a user's watchlist (excluding talk pages)
+ * and return an array of (prefixed) strings
+ *
+ * @return array
+ */
+ private function getWatchlist() {
+ $list = array();
+ $dbr = wfGetDB( DB_MASTER );
+ $res = $dbr->select(
+ 'watchlist',
+ '*',
+ array(
+ 'wl_user' => $this->getUser()->getId(),
+ ),
+ __METHOD__
+ );
+ if( $res->numRows() > 0 ) {
+ foreach ( $res as $row ) {
+ $title = Title::makeTitleSafe( $row->wl_namespace, $row->wl_title );
+ if( $title instanceof Title && !$title->isTalkPage() )
+ $list[] = $title->getPrefixedText();
+ }
+ $res->free();
+ }
+ return $list;
+ }
+
+ /**
+ * Get a list of titles on a user's watchlist, excluding talk pages,
+ * and return as a two-dimensional array with namespace, title and
+ * redirect status
+ *
+ * @return array
+ */
+ private function getWatchlistInfo() {
+ $titles = array();
+ $dbr = wfGetDB( DB_MASTER );
+
+ $res = $dbr->select(
+ array( 'watchlist', 'page' ),
+ array(
+ 'wl_namespace',
+ 'wl_title',
+ 'page_id',
+ 'page_len',
+ 'page_is_redirect',
+ 'page_latest'
+ ),
+ array( 'wl_user' => $this->getUser()->getId() ),
+ __METHOD__,
+ array( 'ORDER BY' => 'wl_namespace, wl_title' ),
+ array( 'page' => array(
+ 'LEFT JOIN',
+ 'wl_namespace = page_namespace AND wl_title = page_title'
+ ) )
+ );
+
+ if( $res && $dbr->numRows( $res ) > 0 ) {
+ $cache = LinkCache::singleton();
+ foreach ( $res as $row ) {
+ $title = Title::makeTitleSafe( $row->wl_namespace, $row->wl_title );
+ if( $title instanceof Title ) {
+ // Update the link cache while we're at it
+ if( $row->page_id ) {
+ $cache->addGoodLinkObj( $row->page_id, $title, $row->page_len, $row->page_is_redirect, $row->page_latest );
+ } else {
+ $cache->addBadLinkObj( $title );
+ }
+ // Ignore non-talk
+ if( !$title->isTalkPage() ) {
+ $titles[$row->wl_namespace][$row->wl_title] = $row->page_is_redirect;
+ }
+ }
+ }
+ }
+ return $titles;
+ }
+
+ /**
+ * Remove all titles from a user's watchlist
+ */
+ private function clearWatchlist() {
+ $dbw = wfGetDB( DB_MASTER );
+ $dbw->delete(
+ 'watchlist',
+ array( 'wl_user' => $this->getUser()->getId() ),
+ __METHOD__
+ );
+ }
+
+ /**
+ * Add a list of titles to a user's watchlist
+ *
+ * $titles can be an array of strings or Title objects; the former
+ * is preferred, since Titles are very memory-heavy
+ *
+ * @param $titles Array of strings, or Title objects
+ */
+ private function watchTitles( $titles ) {
+ $dbw = wfGetDB( DB_MASTER );
+ $rows = array();
+ foreach( $titles as $title ) {
+ if( !$title instanceof Title ) {
+ $title = Title::newFromText( $title );
+ }
+ if( $title instanceof Title ) {
+ $rows[] = array(
+ 'wl_user' => $this->getUser()->getId(),
+ 'wl_namespace' => ( $title->getNamespace() & ~1 ),
+ 'wl_title' => $title->getDBkey(),
+ 'wl_notificationtimestamp' => null,
+ );
+ $rows[] = array(
+ 'wl_user' => $this->getUser()->getId(),
+ 'wl_namespace' => ( $title->getNamespace() | 1 ),
+ 'wl_title' => $title->getDBkey(),
+ 'wl_notificationtimestamp' => null,
+ );
+ }
+ }
+ $dbw->insert( 'watchlist', $rows, __METHOD__, 'IGNORE' );
+ }
+
+ /**
+ * Remove a list of titles from a user's watchlist
+ *
+ * $titles can be an array of strings or Title objects; the former
+ * is preferred, since Titles are very memory-heavy
+ *
+ * @param $titles Array of strings, or Title objects
+ */
+ private function unwatchTitles( $titles ) {
+ $dbw = wfGetDB( DB_MASTER );
+ foreach( $titles as $title ) {
+ if( !$title instanceof Title ) {
+ $title = Title::newFromText( $title );
+ }
+ if( $title instanceof Title ) {
+ $dbw->delete(
+ 'watchlist',
+ array(
+ 'wl_user' => $this->getUser()->getId(),
+ 'wl_namespace' => ( $title->getNamespace() & ~1 ),
+ 'wl_title' => $title->getDBkey(),
+ ),
+ __METHOD__
+ );
+ $dbw->delete(
+ 'watchlist',
+ array(
+ 'wl_user' => $this->getUser()->getId(),
+ 'wl_namespace' => ( $title->getNamespace() | 1 ),
+ 'wl_title' => $title->getDBkey(),
+ ),
+ __METHOD__
+ );
+ $article = new Article( $title, 0 );
+ wfRunHooks( 'UnwatchArticleComplete', array( $this->getUser(), &$article ) );
+ }
+ }
+ }
+
+ public function submitNormal( $data ) {
+ $removed = array();
+
+ foreach( $data as $titles ) {
+ $this->unwatchTitles( $titles );
+ $removed += $titles;
+ }
+
+ if( count( $removed ) > 0 ) {
+ $this->successMessage = wfMessage(
+ 'watchlistedit-normal-done',
+ $this->getLang()->formatNum( count( $removed ) )
+ );
+ $this->showTitles( $removed, $this->successMessage );
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Get the standard watchlist editing form
+ *
+ * @return HTMLForm
+ */
+ protected function getNormalForm(){
+ global $wgContLang;
+
+ $fields = array();
+ $count = 0;
+
+ $haveInvalidNamespaces = false;
+ foreach( $this->getWatchlistInfo() as $namespace => $pages ){
+ if ( $namespace < 0 ) {
+ $haveInvalidNamespaces = true;
+ continue;
+ }
+
+ $fields['TitlesNs'.$namespace] = array(
+ 'class' => 'EditWatchlistCheckboxSeriesField',
+ 'options' => array(),
+ 'section' => "ns$namespace",
+ );
+
+ foreach( $pages as $dbkey => $redirect ){
+ $title = Title::makeTitleSafe( $namespace, $dbkey );
+ $text = $this->buildRemoveLine( $title, $redirect );
+ $fields['TitlesNs'.$namespace]['options'][$text] = $title->getEscapedText();
+ $count++;
+ }
+ }
+ if ( $haveInvalidNamespaces ) {
+ wfDebug( "User {$this->getContext()->getUser()->getId()} has invalid watchlist entries, clening up...\n" );
+ $this->getContext()->getUser()->cleanupWatchlist();
+ }
+
+ if ( count( $fields ) > 1 && $count > 30 ) {
+ $this->toc = Linker::tocIndent();
+ $tocLength = 0;
+ foreach( $fields as $key => $data ) {
+ $ns = substr( $data['section'], 2 );
+ $nsText = $ns == NS_MAIN
+ ? wfMsgHtml( 'blanknamespace' )
+ : htmlspecialchars( $wgContLang->getFormattedNsText( $ns ) );
+ $this->toc .= Linker::tocLine( "editwatchlist-{$data['section']}", $nsText, ++$tocLength, 1 ) . Linker::tocLineEnd();
+ }
+ $this->toc = Linker::tocList( $this->toc );
+ } else {
+ $this->toc = false;
+ }
+
+ $form = new EditWatchlistNormalHTMLForm( $fields, $this->getContext() );
+ $form->setTitle( $this->getTitle() );
+ $form->setSubmitText( wfMessage( 'watchlistedit-normal-submit' )->text() );
+ $form->setWrapperLegend( wfMessage( 'watchlistedit-normal-legend' )->text() );
+ $form->addHeaderText( wfMessage( 'watchlistedit-normal-explain' )->parse() );
+ $form->setSubmitCallback( array( $this, 'submitNormal' ) );
+ return $form;
+ }
+
+ /**
+ * Build the label for a checkbox, with a link to the title, and various additional bits
+ *
+ * @param $title Title
+ * @param $redirect bool
+ * @return string
+ */
+ private function buildRemoveLine( $title, $redirect ) {
+ $link = Linker::link( $title );
+ if( $redirect ) {
+ $link = '<span class="watchlistredir">' . $link . '</span>';
+ }
+ $tools[] = Linker::link( $title->getTalkPage(), wfMsgHtml( 'talkpagelinktext' ) );
+ if( $title->exists() ) {
+ $tools[] = Linker::linkKnown(
+ $title,
+ wfMsgHtml( 'history_short' ),
+ array(),
+ array( 'action' => 'history' )
+ );
+ }
+ if( $title->getNamespace() == NS_USER && !$title->isSubpage() ) {
+ $tools[] = Linker::linkKnown(
+ SpecialPage::getTitleFor( 'Contributions', $title->getText() ),
+ wfMsgHtml( 'contributions' )
+ );
+ }
+
+ wfRunHooks( 'WatchlistEditorBuildRemoveLine', array( &$tools, $title, $redirect, $this->getSkin() ) );
+
+ return $link . " (" . $this->getLang()->pipeList( $tools ) . ")";
+ }
+
+ /**
+ * Get a form for editing the watchlist in "raw" mode
+ *
+ * @return HTMLForm
+ */
+ protected function getRawForm(){
+ $titles = implode( $this->getWatchlist(), "\n" );
+ $fields = array(
+ 'Titles' => array(
+ 'type' => 'textarea',
+ 'label-message' => 'watchlistedit-raw-titles',
+ 'default' => $titles,
+ ),
+ );
+ $form = new HTMLForm( $fields );
+ $form->setTitle( $this->getTitle( 'raw' ) );
+ $form->setSubmitText( wfMessage( 'watchlistedit-raw-submit' )->text() );
+ $form->setWrapperLegend( wfMessage( 'watchlistedit-raw-legend' )->text() );
+ $form->addHeaderText( wfMessage( 'watchlistedit-raw-explain' )->parse() );
+ $form->setSubmitCallback( array( $this, 'submitRaw' ) );
+ return $form;
+ }
+
+ /**
+ * Determine whether we are editing the watchlist, and if so, what
+ * kind of editing operation
+ *
+ * @param $request WebRequest
+ * @param $par mixed
+ * @return int
+ */
+ public static function getMode( $request, $par ) {
+ $mode = strtolower( $request->getVal( 'action', $par ) );
+ switch( $mode ) {
+ case 'clear':
+ case self::EDIT_CLEAR:
+ return self::EDIT_CLEAR;
+
+ case 'raw':
+ case self::EDIT_RAW:
+ return self::EDIT_RAW;
+
+ case 'edit':
+ case self::EDIT_NORMAL:
+ return self::EDIT_NORMAL;
+
+ default:
+ return false;
+ }
+ }
+
+ /**
+ * Build a set of links for convenient navigation
+ * between watchlist viewing and editing modes
+ *
+ * @param $unused Unused
+ * @return string
+ */
+ public static function buildTools( $unused ) {
+ global $wgLang;
+
+ $tools = array();
+ $modes = array(
+ 'view' => array( 'Watchlist', false ),
+ 'edit' => array( 'EditWatchlist', false ),
+ 'raw' => array( 'EditWatchlist', 'raw' ),
+ );
+ foreach( $modes as $mode => $arr ) {
+ // can use messages 'watchlisttools-view', 'watchlisttools-edit', 'watchlisttools-raw'
+ $tools[] = Linker::linkKnown(
+ SpecialPage::getTitleFor( $arr[0], $arr[1] ),
+ wfMsgHtml( "watchlisttools-{$mode}" )
+ );
+ }
+ return Html::rawElement( 'span',
+ array( 'class' => 'mw-watchlist-toollinks' ),
+ wfMsg( 'parentheses', $wgLang->pipeList( $tools ) ) );
+ }
+}
+
+# B/C since 1.18
+class WatchlistEditor extends SpecialEditWatchlist {}
+
+/**
+ * Extend HTMLForm purely so we can have a more sane way of getting the section headers
+ */
+class EditWatchlistNormalHTMLForm extends HTMLForm {
+ public function getLegend( $namespace ){
+ $namespace = substr( $namespace, 2 );
+ return $namespace == NS_MAIN
+ ? wfMsgHtml( 'blanknamespace' )
+ : htmlspecialchars( $this->getContext()->getLang()->getFormattedNsText( $namespace ) );
+ }
+ public function getBody() {
+ return $this->displaySection( $this->mFieldTree, '', 'editwatchlist-' );
+ }
+}
+
+class EditWatchlistCheckboxSeriesField extends HTMLMultiSelectField {
+ /**
+ * HTMLMultiSelectField throws validation errors if we get input data
+ * that doesn't match the data set in the form setup. This causes
+ * problems if something gets removed from the watchlist while the
+ * form is open (bug 32126), but we know that invalid items will
+ * be harmless so we can override it here.
+ *
+ * @param $value String the value the field was submitted with
+ * @param $alldata Array the data collected from the form
+ * @return Mixed Bool true on success, or String error to display.
+ */
+ function validate( $value, $alldata ) {
+ // Need to call into grandparent to be a good citizen. :)
+ return HTMLFormField::validate( $value, $alldata );
+ }
+}
diff --git a/includes/specials/SpecialEmailuser.php b/includes/specials/SpecialEmailuser.php
index 61271227..7c2ba570 100644
--- a/includes/specials/SpecialEmailuser.php
+++ b/includes/specials/SpecialEmailuser.php
@@ -28,20 +28,20 @@
*/
class SpecialEmailUser extends UnlistedSpecialPage {
protected $mTarget;
-
- public function __construct(){
+
+ public function __construct() {
parent::__construct( 'Emailuser' );
}
-
- protected function getFormFields(){
+
+ protected function getFormFields() {
global $wgUser;
return array(
'From' => array(
'type' => 'info',
'raw' => 1,
- 'default' => $wgUser->getSkin()->link(
- $wgUser->getUserPage(),
- htmlspecialchars( $wgUser->getName() )
+ 'default' => $this->getSkin()->link(
+ $wgUser->getUserPage(),
+ htmlspecialchars( $wgUser->getName() )
),
'label-message' => 'emailfrom',
'id' => 'mw-emailuser-sender',
@@ -49,8 +49,8 @@ class SpecialEmailUser extends UnlistedSpecialPage {
'To' => array(
'type' => 'info',
'raw' => 1,
- 'default' => $wgUser->getSkin()->link(
- $this->mTargetObj->getUserPage(),
+ 'default' => $this->getSkin()->link(
+ $this->mTargetObj->getUserPage(),
htmlspecialchars( $this->mTargetObj->getName() )
),
'label-message' => 'emailto',
@@ -82,25 +82,17 @@ class SpecialEmailUser extends UnlistedSpecialPage {
),
);
}
-
+
public function execute( $par ) {
global $wgRequest, $wgOut, $wgUser;
$this->setHeaders();
$this->outputHeader();
-
+ $wgOut->addModuleStyles( 'mediawiki.special' );
$this->mTarget = is_null( $par )
? $wgRequest->getVal( 'wpTarget', $wgRequest->getVal( 'target', '' ) )
: $par;
-
- $ret = self::getTarget( $this->mTarget );
- if( $ret instanceof User ){
- $this->mTargetObj = $ret;
- } else {
- $wgOut->showErrorPage( "{$ret}title", "{$ret}text" );
- return false;
- }
-
+ // error out if sending user cannot do this
$error = self::getPermissionsError( $wgUser, $wgRequest->getVal( 'wpEditToken' ) );
switch ( $error ) {
case null:
@@ -125,7 +117,19 @@ class SpecialEmailUser extends UnlistedSpecialPage {
$wgOut->showErrorPage( $title, $msg, $params );
return;
}
-
+ // Got a valid target user name? Else ask for one.
+ $ret = self::getTarget( $this->mTarget );
+ if( !$ret instanceof User ) {
+ if( $this->mTarget != '' ) {
+ $ret = ( $ret == 'notarget' ) ? 'emailnotarget' : ( $ret . 'text' );
+ $wgOut->wrapWikiMsg( "<p class='error'>$1</p>", $ret );
+ }
+ $wgOut->addHTML( self::userForm( $this->mTarget ) );
+ return false;
+ }
+
+ $this->mTargetObj = $ret;
+
$form = new HTMLForm( $this->getFormFields() );
$form->addPreText( wfMsgExt( 'emailpagetext', 'parseinline' ) );
$form->setSubmitText( wfMsg( 'emailsend' ) );
@@ -133,16 +137,16 @@ class SpecialEmailUser extends UnlistedSpecialPage {
$form->setSubmitCallback( array( __CLASS__, 'submit' ) );
$form->setWrapperLegend( wfMsgExt( 'email-legend', 'parsemag' ) );
$form->loadData();
-
- if( !wfRunHooks( 'EmailUserForm', array( &$form ) ) ){
+
+ if( !wfRunHooks( 'EmailUserForm', array( &$form ) ) ) {
return false;
}
-
- $wgOut->setPagetitle( wfMsg( 'emailpage' ) );
+
+ $wgOut->setPageTitle( wfMsg( 'emailpage' ) );
$result = $form->show();
-
- if( $result === true || ( $result instanceof Status && $result->isGood() ) ){
- $wgOut->setPagetitle( wfMsg( 'emailsent' ) );
+
+ if( $result === true || ( $result instanceof Status && $result->isGood() ) ) {
+ $wgOut->setPageTitle( wfMsg( 'emailsent' ) );
$wgOut->addWikiMsg( 'emailsenttext' );
$wgOut->returnToMain( false, $this->mTargetObj->getUserPage() );
}
@@ -159,15 +163,15 @@ class SpecialEmailUser extends UnlistedSpecialPage {
wfDebug( "Target is empty.\n" );
return 'notarget';
}
-
+
$nu = User::newFromName( $target );
if( !$nu instanceof User || !$nu->getId() ) {
wfDebug( "Target is invalid user.\n" );
return 'notarget';
- } else if ( !$nu->isEmailConfirmed() ) {
+ } elseif ( !$nu->isEmailConfirmed() ) {
wfDebug( "User has no valid email.\n" );
return 'noemail';
- } else if ( !$nu->canReceiveEmail() ) {
+ } elseif ( !$nu->canReceiveEmail() ) {
wfDebug( "User does not allow user emails.\n" );
return 'nowikiemail';
}
@@ -184,15 +188,15 @@ class SpecialEmailUser extends UnlistedSpecialPage {
*/
public static function getPermissionsError( $user, $editToken ) {
global $wgEnableEmail, $wgEnableUserEmail;
- if( !$wgEnableEmail || !$wgEnableUserEmail ){
+ if( !$wgEnableEmail || !$wgEnableUserEmail ) {
return 'usermaildisabled';
}
-
+
if( !$user->isAllowed( 'sendemail' ) ) {
return 'badaccess';
}
-
- if( !$user->isEmailConfirmed() ){
+
+ if( !$user->isEmailConfirmed() ) {
return 'mailnologin';
}
@@ -217,8 +221,28 @@ class SpecialEmailUser extends UnlistedSpecialPage {
}
/**
+ * Form to ask for target user name.
+ *
+ * @param $name String: user name submitted.
+ * @return String: form asking for user name.
+ */
+
+ function userForm( $name ) {
+ global $wgScript ;
+ $string = Xml::openElement( 'form', array( 'method' => 'get', 'action' => $wgScript, 'id' => 'askusername' ) ) .
+ Html::hidden( 'title', $this->getTitle()->getPrefixedText() ) .
+ Xml::openElement( 'fieldset' ) .
+ Html::rawElement( 'legend', null, wfMessage( 'emailtarget' )->parse() ) .
+ Xml::inputLabel( wfMessage( 'emailusername' )->text(), 'target', 'emailusertarget', 30, $name ) . ' ' .
+ Xml::submitButton( wfMessage( 'emailusernamesubmit' )->text() ) .
+ Xml::closeElement( 'fieldset' ) .
+ Xml::closeElement( 'form' ) . "\n";
+ return $string;
+ }
+
+ /**
* Really send a mail. Permissions should have been checked using
- * getPermissionsError(). It is probably also a good
+ * getPermissionsError(). It is probably also a good
* idea to check the edit token and ping limiter in advance.
*
* @return Mixed: Status object, or potentially a String on error
@@ -228,7 +252,7 @@ class SpecialEmailUser extends UnlistedSpecialPage {
global $wgUser, $wgUserEmailUseReplyTo;
$target = self::getTarget( $data['Target'] );
- if( !$target instanceof User ){
+ if( !$target instanceof User ) {
return wfMsgExt( $target . 'text', 'parse' );
}
$to = new MailAddress( $target );
@@ -238,17 +262,17 @@ class SpecialEmailUser extends UnlistedSpecialPage {
// Add a standard footer and trim up trailing newlines
$text = rtrim( $text ) . "\n\n-- \n";
- $text .= wfMsgExt(
+ $text .= wfMsgExt(
'emailuserfooter',
- array( 'content', 'parsemag' ),
- array( $from->name, $to->name )
+ array( 'content', 'parsemag' ),
+ array( $from->name, $to->name )
);
$error = '';
if( !wfRunHooks( 'EmailUser', array( &$to, &$from, &$subject, &$text, &$error ) ) ) {
return $error;
}
-
+
if( $wgUserEmailUseReplyTo ) {
// Put the generic wiki autogenerated address in the From:
// header and reserve the user for Reply-To.
@@ -283,12 +307,12 @@ class SpecialEmailUser extends UnlistedSpecialPage {
return $status;
} else {
// if the user requested a copy of this mail, do this now,
- // unless they are emailing themselves, in which case one
+ // unless they are emailing themselves, in which case one
// copy of the message is sufficient.
if ( $data['CCMe'] && $to != $from ) {
$cc_subject = wfMsg(
- 'emailccsubject',
- $target->getName(),
+ 'emailccsubject',
+ $target->getName(),
$subject
);
wfRunHooks( 'EmailUserCC', array( &$from, &$from, &$cc_subject, &$text ) );
diff --git a/includes/specials/SpecialExport.php b/includes/specials/SpecialExport.php
index eaed2393..50754b6a 100644
--- a/includes/specials/SpecialExport.php
+++ b/includes/specials/SpecialExport.php
@@ -40,7 +40,7 @@ class SpecialExport extends SpecialPage {
public function execute( $par ) {
global $wgOut, $wgRequest, $wgSitename, $wgExportAllowListContributors;
global $wgExportAllowHistory, $wgExportMaxHistory, $wgExportMaxLinkDepth;
- global $wgExportFromNamespaces, $wgUser;
+ global $wgExportFromNamespaces;
$this->setHeaders();
$this->outputHeader();
@@ -63,16 +63,18 @@ class SpecialExport extends SpecialPage {
$t = Title::makeTitleSafe( NS_MAIN, $catname );
if ( $t ) {
/**
- * @todo Fixme: this can lead to hitting memory limit for very large
+ * @todo FIXME: This can lead to hitting memory limit for very large
* categories. Ideally we would do the lookup synchronously
* during the export in a single query.
*/
$catpages = $this->getPagesFromCategory( $t );
- if ( $catpages ) $page .= "\n" . implode( "\n", $catpages );
+ if ( $catpages ) {
+ $page .= "\n" . implode( "\n", $catpages );
+ }
}
}
}
- else if( $wgRequest->getCheck( 'addns' ) && $wgExportFromNamespaces ) {
+ elseif( $wgRequest->getCheck( 'addns' ) && $wgExportFromNamespaces ) {
$page = $wgRequest->getText( 'pages' );
$nsindex = $wgRequest->getText( 'nsindex', '' );
@@ -81,20 +83,22 @@ class SpecialExport extends SpecialPage {
* Same implementation as above, so same @todo
*/
$nspages = $this->getPagesFromNamespace( $nsindex );
- if ( $nspages ) $page .= "\n" . implode( "\n", $nspages );
+ if ( $nspages ) {
+ $page .= "\n" . implode( "\n", $nspages );
+ }
}
}
- else if( $wgRequest->wasPosted() && $par == '' ) {
+ elseif( $wgRequest->wasPosted() && $par == '' ) {
$page = $wgRequest->getText( 'pages' );
$this->curonly = $wgRequest->getCheck( 'curonly' );
$rawOffset = $wgRequest->getVal( 'offset' );
-
+
if( $rawOffset ) {
$offset = wfTimestamp( TS_MW, $rawOffset );
} else {
$offset = null;
}
-
+
$limit = $wgRequest->getInt( 'limit' );
$dir = $wgRequest->getVal( 'dir' );
$history = array(
@@ -103,7 +107,7 @@ class SpecialExport extends SpecialPage {
'limit' => $wgExportMaxHistory,
);
$historyCheck = $wgRequest->getCheck( 'history' );
-
+
if ( $this->curonly ) {
$history = WikiExporter::CURRENT;
} elseif ( !$historyCheck ) {
@@ -118,19 +122,23 @@ class SpecialExport extends SpecialPage {
}
}
- if( $page != '' ) $this->doExport = true;
+ if( $page != '' ) {
+ $this->doExport = true;
+ }
} else {
// Default to current-only for GET requests.
$page = $wgRequest->getText( 'pages', $par );
$historyCheck = $wgRequest->getCheck( 'history' );
-
+
if( $historyCheck ) {
$history = WikiExporter::FULL;
} else {
$history = WikiExporter::CURRENT;
}
- if( $page != '' ) $this->doExport = true;
+ if( $page != '' ) {
+ $this->doExport = true;
+ }
}
if( !$wgExportAllowHistory ) {
@@ -139,24 +147,26 @@ class SpecialExport extends SpecialPage {
}
$list_authors = $wgRequest->getCheck( 'listauthors' );
- if ( !$this->curonly || !$wgExportAllowListContributors ) $list_authors = false ;
+ if ( !$this->curonly || !$wgExportAllowListContributors ) {
+ $list_authors = false ;
+ }
if ( $this->doExport ) {
$wgOut->disable();
-
+
// Cancel output buffering and gzipping if set
// This should provide safer streaming for pages with history
wfResetOutputBuffers();
$wgRequest->response()->header( "Content-type: application/xml; charset=utf-8" );
-
+
if( $wgRequest->getCheck( 'wpDownload' ) ) {
// Provide a sane filename suggestion
$filename = urlencode( $wgSitename . '-' . wfTimestampNow() . '.xml' );
$wgRequest->response()->header( "Content-disposition: attachment;filename={$filename}" );
}
-
+
$this->doExport( $page, $history, $list_authors );
-
+
return;
}
@@ -176,23 +186,38 @@ class SpecialExport extends SpecialPage {
$form .= '<br />';
if( $wgExportAllowHistory ) {
- $form .= Xml::checkLabel( wfMsg( 'exportcuronly' ), 'curonly', 'curonly', true ) . '<br />';
+ $form .= Xml::checkLabel(
+ wfMsg( 'exportcuronly' ),
+ 'curonly',
+ 'curonly',
+ $wgRequest->wasPosted() ? $wgRequest->getCheck( 'curonly' ) : true
+ ) . '<br />';
} else {
$wgOut->addHTML( wfMsgExt( 'exportnohistory', 'parse' ) );
}
-
- $form .= Xml::checkLabel( wfMsg( 'export-templates' ), 'templates', 'wpExportTemplates', false ) . '<br />';
-
+
+ $form .= Xml::checkLabel(
+ wfMsg( 'export-templates' ),
+ 'templates',
+ 'wpExportTemplates',
+ $wgRequest->wasPosted() ? $wgRequest->getCheck( 'templates' ) : false
+ ) . '<br />';
+
if( $wgExportMaxLinkDepth || $this->userCanOverrideExportDepth() ) {
$form .= Xml::inputLabel( wfMsg( 'export-pagelinks' ), 'pagelink-depth', 'pagelink-depth', 20, 0 ) . '<br />';
}
// Enable this when we can do something useful exporting/importing image information. :)
//$form .= Xml::checkLabel( wfMsg( 'export-images' ), 'images', 'wpExportImages', false ) . '<br />';
- $form .= Xml::checkLabel( wfMsg( 'export-download' ), 'wpDownload', 'wpDownload', true ) . '<br />';
-
- $form .= Xml::submitButton( wfMsg( 'export-submit' ), $wgUser->getSkin()->tooltipAndAccessKeyAttribs( 'export' ) );
+ $form .= Xml::checkLabel(
+ wfMsg( 'export-download' ),
+ 'wpDownload',
+ 'wpDownload',
+ $wgRequest->wasPosted() ? $wgRequest->getCheck( 'wpDownload' ) : true
+ ) . '<br />';
+
+ $form .= Xml::submitButton( wfMsg( 'export-submit' ), Linker::tooltipAndAccesskeyAttribs( 'export' ) );
$form .= Xml::closeElement( 'form' );
-
+
$wgOut->addHTML( $form );
}
@@ -247,7 +272,7 @@ class SpecialExport extends SpecialPage {
foreach( $pages as $k => $v ) {
$pages[$k] = str_replace( " ", "_", $v );
}
-
+
$pages = array_unique( $pages );
/* Ok, let's get to it... */
@@ -266,11 +291,11 @@ class SpecialExport extends SpecialPage {
set_time_limit(0);
wfRestoreWarnings();
}
-
+
$exporter = new WikiExporter( $db, $history, $buffer );
$exporter->list_authors = $list_authors;
$exporter->openStream();
-
+
foreach( $pages as $page ) {
/*
if( $wgExportMaxHistory && !$this->curonly ) {
@@ -286,14 +311,18 @@ class SpecialExport extends SpecialPage {
}*/
#Bug 8824: Only export pages the user can read
$title = Title::newFromText( $page );
- if( is_null( $title ) ) continue; #TODO: perhaps output an <error> tag or something.
- if( !$title->userCanRead() ) continue; #TODO: perhaps output an <error> tag or something.
+ if( is_null( $title ) ) {
+ continue; #TODO: perhaps output an <error> tag or something.
+ }
+ if( !$title->userCanRead() ) {
+ continue; #TODO: perhaps output an <error> tag or something.
+ }
$exporter->pageByTitle( $title );
}
$exporter->closeStream();
-
+
if( $lb ) {
$lb->closeAll();
}
@@ -314,7 +343,7 @@ class SpecialExport extends SpecialPage {
);
$pages = array();
-
+
foreach ( $res as $row ) {
$n = $row->page_title;
if ($row->page_namespace) {
@@ -340,10 +369,10 @@ class SpecialExport extends SpecialPage {
);
$pages = array();
-
+
foreach ( $res as $row ) {
$n = $row->page_title;
-
+
if ( $row->page_namespace ) {
$ns = $wgContLang->getNsText( $row->page_namespace );
$n = $ns . ':' . $n;
@@ -373,17 +402,17 @@ class SpecialExport extends SpecialPage {
*/
private function validateLinkDepth( $depth ) {
global $wgExportMaxLinkDepth;
-
+
if( $depth < 0 ) {
return 0;
}
-
+
if ( !$this->userCanOverrideExportDepth() ) {
if( $depth > $wgExportMaxLinkDepth ) {
return $wgExportMaxLinkDepth;
}
}
-
+
/*
* There's a HARD CODED limit of 5 levels of recursion here to prevent a
* crazy-big export from being done by someone setting the depth
@@ -394,24 +423,24 @@ class SpecialExport extends SpecialPage {
/** Expand a list of pages to include pages linked to from that page. */
private function getPageLinks( $inputPages, $pageSet, $depth ) {
- for(; $depth > 0; --$depth ) {
+ for( ; $depth > 0; --$depth ) {
$pageSet = $this->getLinks(
$inputPages, $pageSet, 'pagelinks',
- array( 'pl_namespace AS namespace', 'pl_title AS title' ),
+ array( 'pl_namespace AS namespace', 'pl_title AS title' ),
array( 'page_id=pl_from' )
);
$inputPages = array_keys( $pageSet );
}
-
+
return $pageSet;
}
/**
* Expand a list of pages to include images used in those pages.
- *
+ *
* @param $inputPages array, list of titles to look up
* @param $pageSet array, associative array indexed by titles for output
- *
+ *
* @return array associative array index by titles
*/
private function getImages( $inputPages, $pageSet ) {
@@ -429,13 +458,13 @@ class SpecialExport extends SpecialPage {
*/
private function getLinks( $inputPages, $pageSet, $table, $fields, $join ) {
$dbr = wfGetDB( DB_SLAVE );
-
+
foreach( $inputPages as $page ) {
$title = Title::newFromText( $page );
-
+
if( $title ) {
$pageSet[$title->getPrefixedText()] = true;
- /// @todo Fixme: May or may not be more efficient to batch these
+ /// @todo FIXME: May or may not be more efficient to batch these
/// by namespace when given multiple input pages.
$result = $dbr->select(
array( 'page', $table ),
@@ -449,15 +478,15 @@ class SpecialExport extends SpecialPage {
),
__METHOD__
);
-
+
foreach( $result as $row ) {
$template = Title::makeTitle( $row->namespace, $row->title );
$pageSet[$template->getPrefixedText()] = true;
}
}
}
-
+
return $pageSet;
}
-
-} \ No newline at end of file
+
+}
diff --git a/includes/specials/SpecialFewestrevisions.php b/includes/specials/SpecialFewestrevisions.php
index c265ed38..6d621a2e 100644
--- a/includes/specials/SpecialFewestrevisions.php
+++ b/includes/specials/SpecialFewestrevisions.php
@@ -29,8 +29,8 @@
*/
class FewestrevisionsPage extends QueryPage {
- function getName() {
- return 'Fewestrevisions';
+ function __construct( $name = 'Fewestrevisions' ) {
+ parent::__construct( $name );
}
function isExpensive() {
@@ -41,31 +41,34 @@ class FewestrevisionsPage extends QueryPage {
return false;
}
- function getSql() {
- $dbr = wfGetDB( DB_SLAVE );
- list( $revision, $page ) = $dbr->tableNamesN( 'revision', 'page' );
-
- return "SELECT 'Fewestrevisions' as type,
- page_namespace as namespace,
- page_title as title,
- page_is_redirect as redirect,
- COUNT(*) as value
- FROM $revision
- JOIN $page ON page_id = rev_page
- WHERE page_namespace = " . NS_MAIN . "
- GROUP BY page_namespace, page_title, page_is_redirect
- HAVING COUNT(*) > 1";
+ function getQueryInfo() {
+ return array (
+ 'tables' => array ( 'revision', 'page' ),
+ 'fields' => array ( 'page_namespace AS namespace',
+ 'page_title AS title',
+ 'COUNT(*) AS value',
+ 'page_is_redirect AS redirect' ),
+ 'conds' => array ( 'page_namespace' => MWNamespace::getContentNamespaces(),
+ 'page_id = rev_page' ),
+ 'options' => array ( 'HAVING' => 'COUNT(*) > 1',
// ^^^ This was probably here to weed out redirects.
// Since we mark them as such now, it might be
// useful to remove this. People _do_ create pages
// and never revise them, they aren't necessarily
// redirects.
+ 'GROUP BY' => 'page_namespace, page_title, page_is_redirect' )
+ );
}
+
function sortDescending() {
return false;
}
+ /**
+ * @param $skin Skin object
+ * @param $result Object: database row
+ */
function formatResult( $skin, $result ) {
global $wgLang, $wgContLang;
@@ -94,9 +97,3 @@ class FewestrevisionsPage extends QueryPage {
return wfSpecialList( $plink, $nlink );
}
}
-
-function wfSpecialFewestrevisions() {
- list( $limit, $offset ) = wfCheckLimits();
- $frp = new FewestrevisionsPage();
- $frp->doQuery( $offset, $limit );
-}
diff --git a/includes/specials/SpecialFileDuplicateSearch.php b/includes/specials/SpecialFileDuplicateSearch.php
index 172e92ad..a296fd95 100644
--- a/includes/specials/SpecialFileDuplicateSearch.php
+++ b/includes/specials/SpecialFileDuplicateSearch.php
@@ -29,123 +29,161 @@
* @ingroup SpecialPage
*/
class FileDuplicateSearchPage extends QueryPage {
- var $hash, $filename;
+ protected $hash = '', $filename = '';
- function __construct( $hash, $filename ) {
- $this->hash = $hash;
- $this->filename = $filename;
+ /**
+ * @var File $file selected reference file, if present
+ */
+ protected $file = null;
+
+ function __construct( $name = 'FileDuplicateSearch' ) {
+ parent::__construct( $name );
}
- function getName() { return 'FileDuplicateSearch'; }
- function isExpensive() { return false; }
function isSyndicated() { return false; }
+ function isCacheable() { return false; }
+ function isCached() { return false; }
function linkParameters() {
return array( 'filename' => $this->filename );
}
- function getSQL() {
- $dbr = wfGetDB( DB_SLAVE );
- $image = $dbr->tableName( 'image' );
- $hash = $dbr->addQuotes( $this->hash );
-
- return "SELECT 'FileDuplicateSearch' AS type,
- img_name AS title,
- img_sha1 AS value,
- img_user_text,
- img_timestamp
- FROM $image
- WHERE img_sha1 = $hash
- ";
+ /**
+ * Fetch dupes from all connected file repositories.
+ *
+ * @return Array of File objects
+ */
+ function getDupes() {
+ return RepoGroup::singleton()->findBySha1( $this->hash );
}
- function formatResult( $skin, $result ) {
- global $wgContLang, $wgLang;
+ /**
+ *
+ * @param $dupes Array of File objects
+ */
+ function showList( $dupes ) {
+ global $wgOut;
+ $skin = $this->getSkin();
- $nt = Title::makeTitle( NS_FILE, $result->title );
- $text = $wgContLang->convert( $nt->getText() );
- $plink = $skin->link(
- Title::newFromText( $nt->getPrefixedText() ),
- $text
- );
+ $html = array();
+ $html[] = $this->openList( 0 );
- $user = $skin->link( Title::makeTitle( NS_USER, $result->img_user_text ), $result->img_user_text );
- $time = $wgLang->timeanddate( $result->img_timestamp );
+ foreach ( $dupes as $dupe ) {
+ $line = $this->formatResult( $skin, $dupe );
+ $html[] = "<li>" . $line . "</li>";
+ }
+ $html[] = $this->closeList();
- return "$plink . . $user . . $time";
+ $wgOut->addHtml( implode( "\n", $html ) );
}
-}
-/**
- * Output the HTML search form, and constructs the FileDuplicateSearch object.
- */
-function wfSpecialFileDuplicateSearch( $par = null ) {
- global $wgRequest, $wgOut, $wgLang, $wgContLang, $wgScript;
-
- $hash = '';
- $filename = isset( $par ) ? $par : $wgRequest->getText( 'filename' );
-
- $title = Title::makeTitleSafe( NS_FILE, $filename );
- if( $title && $title->getText() != '' ) {
- $dbr = wfGetDB( DB_SLAVE );
- $image = $dbr->tableName( 'image' );
- $encFilename = $dbr->addQuotes( htmlspecialchars( $title->getDBkey() ) );
- $sql = "SELECT img_sha1 from $image where img_name = $encFilename";
- $res = $dbr->query( $sql );
- $row = $dbr->fetchRow( $res );
- if( $row !== false ) {
- $hash = $row[0];
- }
+ function getQueryInfo() {
+ return array(
+ 'tables' => array( 'image' ),
+ 'fields' => array(
+ 'img_name AS title',
+ 'img_sha1 AS value',
+ 'img_user_text',
+ 'img_timestamp'
+ ),
+ 'conds' => array( 'img_sha1' => $this->hash )
+ );
}
- # Create the input form
- $wgOut->addHTML(
- Xml::openElement( 'form', array( 'id' => 'fileduplicatesearch', 'method' => 'get', 'action' => $wgScript ) ) .
- Html::hidden( 'title', SpecialPage::getTitleFor( 'FileDuplicateSearch' )->getPrefixedDbKey() ) .
- Xml::openElement( 'fieldset' ) .
- Xml::element( 'legend', null, wfMsg( 'fileduplicatesearch-legend' ) ) .
- Xml::inputLabel( wfMsg( 'fileduplicatesearch-filename' ), 'filename', 'filename', 50, $filename ) . ' ' .
- Xml::submitButton( wfMsg( 'fileduplicatesearch-submit' ) ) .
- Xml::closeElement( 'fieldset' ) .
- Xml::closeElement( 'form' )
- );
-
- if( $hash != '' ) {
- $align = $wgContLang->alignEnd();
-
- # Show a thumbnail of the file
- $img = wfFindFile( $title );
- if ( $img ) {
- $thumb = $img->transform( array( 'width' => 120, 'height' => 120 ) );
- if( $thumb ) {
- $wgOut->addHTML( '<div style="float:' . $align . '" id="mw-fileduplicatesearch-icon">' .
- $thumb->toHtml( array( 'desc-link' => false ) ) . '<br />' .
- wfMsgExt( 'fileduplicatesearch-info', array( 'parse' ),
- $wgLang->formatNum( $img->getWidth() ),
- $wgLang->formatNum( $img->getHeight() ),
- $wgLang->formatSize( $img->getSize() ),
- $img->getMimeType()
- ) .
- '</div>' );
- }
+ function execute( $par ) {
+ global $wgRequest, $wgOut, $wgLang, $wgScript;
+
+ $this->setHeaders();
+ $this->outputHeader();
+
+ $this->filename = isset( $par ) ? $par : $wgRequest->getText( 'filename' );
+ $this->file = null;
+ $this->hash = '';
+ $title = Title::newFromText( $this->filename, NS_FILE );
+ if( $title && $title->getText() != '' ) {
+ $this->file = wfFindFile( $title );
}
- # Do the query
- $wpp = new FileDuplicateSearchPage( $hash, $filename );
- list( $limit, $offset ) = wfCheckLimits();
- $count = $wpp->doQuery( $offset, $limit );
+ # Create the input form
+ $wgOut->addHTML(
+ Xml::openElement( 'form', array( 'id' => 'fileduplicatesearch', 'method' => 'get', 'action' => $wgScript ) ) .
+ Html::hidden( 'title', $this->getTitle()->getPrefixedDbKey() ) .
+ Xml::openElement( 'fieldset' ) .
+ Xml::element( 'legend', null, wfMsg( 'fileduplicatesearch-legend' ) ) .
+ Xml::inputLabel( wfMsg( 'fileduplicatesearch-filename' ), 'filename', 'filename', 50, $this->filename ) . ' ' .
+ Xml::submitButton( wfMsg( 'fileduplicatesearch-submit' ) ) .
+ Xml::closeElement( 'fieldset' ) .
+ Xml::closeElement( 'form' )
+ );
- # Show a short summary
- if( $count == 1 ) {
- $wgOut->wrapWikiMsg(
- "<p class='mw-fileduplicatesearch-result-1'>\n$1\n</p>",
- array( 'fileduplicatesearch-result-1', $filename )
- );
- } elseif ( $count > 1 ) {
+ if( $this->file ) {
+ $this->hash = $this->file->getSha1();
+ } elseif( $this->filename !== '' ) {
$wgOut->wrapWikiMsg(
- "<p class='mw-fileduplicatesearch-result-n'>\n$1\n</p>",
- array( 'fileduplicatesearch-result-n', $filename, $wgLang->formatNum( $count - 1 ) )
+ "<p class='mw-fileduplicatesearch-noresults'>\n$1\n</p>",
+ array( 'fileduplicatesearch-noresults', wfEscapeWikiText( $this->filename ) )
);
}
+
+ if( $this->hash != '' ) {
+ # Show a thumbnail of the file
+ $img = $this->file;
+ if ( $img ) {
+ $thumb = $img->transform( array( 'width' => 120, 'height' => 120 ) );
+ if( $thumb ) {
+ $wgOut->addHTML( '<div id="mw-fileduplicatesearch-icon">' .
+ $thumb->toHtml( array( 'desc-link' => false ) ) . '<br />' .
+ wfMsgExt( 'fileduplicatesearch-info', array( 'parse' ),
+ $wgLang->formatNum( $img->getWidth() ),
+ $wgLang->formatNum( $img->getHeight() ),
+ $wgLang->formatSize( $img->getSize() ),
+ $img->getMimeType()
+ ) .
+ '</div>' );
+ }
+ }
+
+ $dupes = $this->getDupes();
+ $numRows = count( $dupes );
+
+ # Show a short summary
+ if( $numRows == 1 ) {
+ $wgOut->wrapWikiMsg(
+ "<p class='mw-fileduplicatesearch-result-1'>\n$1\n</p>",
+ array( 'fileduplicatesearch-result-1', wfEscapeWikiText( $this->filename ) )
+ );
+ } elseif ( $numRows ) {
+ $wgOut->wrapWikiMsg(
+ "<p class='mw-fileduplicatesearch-result-n'>\n$1\n</p>",
+ array( 'fileduplicatesearch-result-n', wfEscapeWikiText( $this->filename ),
+ $wgLang->formatNum( $numRows - 1 ) )
+ );
+ }
+
+ $this->showList( $dupes );
+ }
+ }
+
+ /**
+ *
+ * @param Skin $skin
+ * @param File $result
+ * @return string
+ */
+ function formatResult( $skin, $result ) {
+ global $wgContLang, $wgLang;
+
+ $nt = $result->getTitle();
+ $text = $wgContLang->convert( $nt->getText() );
+ $plink = $skin->link(
+ Title::newFromText( $nt->getPrefixedText() ),
+ $text
+ );
+
+ $userText = $result->getUser( 'text' );
+ $user = $skin->link( Title::makeTitle( NS_USER, $userText ), $userText );
+ $time = $wgLang->timeanddate( $result->getTimestamp() );
+
+ return "$plink . . $user . . $time";
}
}
diff --git a/includes/specials/SpecialFilepath.php b/includes/specials/SpecialFilepath.php
index 8bb0890c..08f90fd2 100644
--- a/includes/specials/SpecialFilepath.php
+++ b/includes/specials/SpecialFilepath.php
@@ -40,19 +40,25 @@ class SpecialFilepath extends SpecialPage {
$file = !is_null( $par ) ? $par : $wgRequest->getText( 'file' );
- $title = Title::makeTitleSafe( NS_FILE, $file );
+ $title = Title::newFromText( $file, NS_FILE );
if ( ! $title instanceof Title || $title->getNamespace() != NS_FILE ) {
$this->showForm( $title );
} else {
$file = wfFindFile( $title );
+
if ( $file && $file->exists() ) {
+ // Default behaviour: Use the direct link to the file.
$url = $file->getURL();
$width = $wgRequest->getInt( 'width', -1 );
$height = $wgRequest->getInt( 'height', -1 );
+
+ // If a width is requested...
if ( $width != -1 ) {
$mto = $file->transform( array( 'width' => $width, 'height' => $height ) );
+ // ... and we can
if ( $mto && !$mto->isError() ) {
+ // ... change the URL to point to a thumbnail.
$url = $mto->getURL();
}
}
@@ -64,6 +70,9 @@ class SpecialFilepath extends SpecialPage {
}
}
+ /**
+ * @param $title Title
+ */
function showForm( $title ) {
global $wgOut, $wgScript;
diff --git a/includes/specials/SpecialImport.php b/includes/specials/SpecialImport.php
index 7d1cf0dd..fc904a23 100644
--- a/includes/specials/SpecialImport.php
+++ b/includes/specials/SpecialImport.php
@@ -30,14 +30,15 @@
* @ingroup SpecialPage
*/
class SpecialImport extends SpecialPage {
-
+
private $interwiki = false;
private $namespace;
private $frompage = '';
private $logcomment= false;
private $history = true;
private $includeTemplates = false;
-
+ private $pageLinkDepth;
+
/**
* Constructor
*/
@@ -46,26 +47,27 @@ class SpecialImport extends SpecialPage {
global $wgImportTargetNamespace;
$this->namespace = $wgImportTargetNamespace;
}
-
+
/**
* Execute
*/
function execute( $par ) {
global $wgRequest, $wgUser, $wgOut;
-
+
$this->setHeaders();
$this->outputHeader();
-
+
if ( wfReadOnly() ) {
$wgOut->readOnlyPage();
return;
}
-
- if( !$wgUser->isAllowed( 'import' ) && !$wgUser->isAllowed( 'importupload' ) )
+
+ if( !$wgUser->isAllowedAny( 'import', 'importupload' ) ) {
return $wgOut->permissionRequired( 'import' );
+ }
- # TODO: allow Title::getUserPermissionsErrors() to take an array
- # FIXME: Title::checkSpecialsAndNSPermissions() has a very wierd expectation of what
+ # @todo Allow Title::getUserPermissionsErrors() to take an array
+ # @todo FIXME: Title::checkSpecialsAndNSPermissions() has a very wierd expectation of what
# getUserPermissionsErrors() might actually be used for, hence the 'ns-specialprotected'
$errors = wfMergeErrorArrays(
$this->getTitle()->getUserPermissionsErrors(
@@ -88,7 +90,7 @@ class SpecialImport extends SpecialPage {
}
$this->showForm();
}
-
+
/**
* Do the actual import
*/
@@ -162,7 +164,7 @@ class SpecialImport extends SpecialPage {
# Success!
$wgOut->addWikiMsg( 'importsuccess' );
}
- $wgOut->addWikiText( '<hr />' );
+ $wgOut->addHTML( '<hr />' );
}
}
@@ -290,7 +292,7 @@ class SpecialImport extends SpecialPage {
<td>
</td>
<td class='mw-submit'>" .
- Xml::submitButton( wfMsg( 'import-interwiki-submit' ), $wgUser->getSkin()->tooltipAndAccessKeyAttribs( 'import' ) ) .
+ Xml::submitButton( wfMsg( 'import-interwiki-submit' ), Linker::tooltipAndAccesskeyAttribs( 'import' ) ) .
"</td>
</tr>" .
Xml::closeElement( 'table' ).
@@ -312,8 +314,8 @@ class ImportReporter {
private $mLogItemCount = 0;
function __construct( $importer, $upload, $interwiki , $reason=false ) {
- $this->mOriginalPageOutCallback =
- $importer->setPageOutCallback( array( $this, 'reportPage' ) );
+ $this->mOriginalPageOutCallback =
+ $importer->setPageOutCallback( array( $this, 'reportPage' ) );
$this->mOriginalLogCallback =
$importer->setLogItemCallback( array( $this, 'reportLogItem' ) );
$this->mPageCount = 0;
@@ -326,7 +328,7 @@ class ImportReporter {
global $wgOut;
$wgOut->addHTML( "<ul>\n" );
}
-
+
function reportLogItem( /* ... */ ) {
$this->mLogItemCount++;
if ( is_callable( $this->mOriginalLogCallback ) ) {
@@ -334,21 +336,27 @@ class ImportReporter {
}
}
+ /**
+ * @param Title $title
+ * @param Title $origTitle
+ * @param int $revisionCount
+ * @param $successCount
+ * @param $pageInfo
+ * @return void
+ */
function reportPage( $title, $origTitle, $revisionCount, $successCount, $pageInfo ) {
global $wgOut, $wgUser, $wgLang, $wgContLang;
-
+
$args = func_get_args();
call_user_func_array( $this->mOriginalPageOutCallback, $args );
- $skin = $wgUser->getSkin();
-
$this->mPageCount++;
$localCount = $wgLang->formatNum( $successCount );
$contentCount = $wgContLang->formatNum( $successCount );
if( $successCount > 0 ) {
- $wgOut->addHTML( "<li>" . $skin->linkKnown( $title ) . " " .
+ $wgOut->addHTML( "<li>" . Linker::linkKnown( $title ) . " " .
wfMsgExt( 'import-revision-count', array( 'parsemag', 'escape' ), $localCount ) .
"</li>\n"
);
@@ -382,14 +390,14 @@ class ImportReporter {
$article->updateRevisionOn( $dbw, $nullRevision );
wfRunHooks( 'NewRevisionFromEditComplete', array($article, $nullRevision, $latest, $wgUser) );
} else {
- $wgOut->addHTML( "<li>" . $skin->linkKnown( $title ) . " " .
+ $wgOut->addHTML( "<li>" . Linker::linkKnown( $title ) . " " .
wfMsgHtml( 'import-nonewrevisions' ) . "</li>\n" );
}
}
function close() {
global $wgOut, $wgLang;
-
+
if ( $this->mLogItemCount > 0 ) {
$msg = wfMsgExt( 'imported-log-entries', 'parseinline',
$wgLang->formatNum( $this->mLogItemCount ) );
diff --git a/includes/specials/SpecialIpblocklist.php b/includes/specials/SpecialIpblocklist.php
deleted file mode 100644
index 24d7f008..00000000
--- a/includes/specials/SpecialIpblocklist.php
+++ /dev/null
@@ -1,581 +0,0 @@
-<?php
-/**
- * Implements Special:ipblocklist
- *
- * 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.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup SpecialPage
- */
-
-/**
- * A special page that lists existing blocks and allows users with the 'block'
- * permission to remove blocks
- *
- * @ingroup SpecialPage
- */
-class IPUnblockForm extends SpecialPage {
- var $ip, $reason, $id;
- var $hideuserblocks, $hidetempblocks, $hideaddressblocks;
-
- function __construct() {
- parent::__construct( 'Ipblocklist' );
- }
-
- /**
- * Main execution point
- *
- * @param $ip part of title: Special:Ipblocklist/<ip>.
- */
- function execute( $ip ) {
- global $wgUser, $wgOut, $wgRequest;
-
- $this->setHeaders();
- $this->outputHeader();
-
- $ip = $wgRequest->getVal( 'ip', $ip );
- $this->ip = trim( $wgRequest->getVal( 'wpUnblockAddress', $ip ) );
- $this->id = $wgRequest->getVal( 'id' );
- $this->reason = $wgRequest->getText( 'wpUnblockReason' );
- $this->hideuserblocks = $wgRequest->getBool( 'hideuserblocks' );
- $this->hidetempblocks = $wgRequest->getBool( 'hidetempblocks' );
- $this->hideaddressblocks = $wgRequest->getBool( 'hideaddressblocks' );
-
- $action = $wgRequest->getText( 'action' );
- $successip = $wgRequest->getVal( 'successip' );
-
- if( $action == 'unblock' || $action == 'submit' && $wgRequest->wasPosted() ) {
- # Check permissions
- if( !$wgUser->isAllowed( 'block' ) ) {
- $wgOut->permissionRequired( 'block' );
- return;
- }
- # Check for database lock
- if( wfReadOnly() ) {
- $wgOut->readOnlyPage();
- return;
- }
-
- # bug 15810: blocked admins should have limited access here
- if ( $wgUser->isBlocked() ) {
- if ( $this->id ) {
- # This doesn't pick up on autoblocks, but admins
- # should have the ipblock-exempt permission anyway
- $block = Block::newFromID( $this->id );
- $user = User::newFromName( $block->mAddress );
- } else {
- $user = User::newFromName( $this->ip );
- }
- $status = IPBlockForm::checkUnblockSelf( $user );
- if ( $status !== true ) {
- throw new ErrorPageError( 'badaccess', $status );
- }
- }
-
- if( $action == 'unblock' ){
- # Show unblock form
- $this->showForm( '' );
- } elseif( $action == 'submit'
- && $wgRequest->wasPosted()
- && $wgUser->matchEditToken( $wgRequest->getVal( 'wpEditToken' ) ) )
- {
- # Remove blocks and redirect user to success page
- $this->doSubmit();
- }
-
- } elseif( $action == 'success' ) {
- # Inform the user of a successful unblock
- # (No need to check permissions or locks here,
- # if something was done, then it's too late!)
- if ( substr( $successip, 0, 1) == '#' ) {
- // A block ID was unblocked
- $this->showList( $wgOut->parse( wfMsg( 'unblocked-id', $successip ) ) );
- } else {
- // A username/IP was unblocked
- $this->showList( $wgOut->parse( wfMsg( 'unblocked', $successip ) ) );
- }
- } else {
- # Just show the block list
- $this->showList( '' );
- }
- }
-
- /**
- * Generates the unblock form
- *
- * @param $err string: error message
- * @return $out string: HTML form
- */
- function showForm( $err ) {
- global $wgOut, $wgUser, $wgSysopUserBans;
-
- $wgOut->addWikiMsg( 'unblockiptext' );
-
- $action = $this->getTitle()->getLocalURL( 'action=submit' );
-
- if ( $err != '' ) {
- $wgOut->setSubtitle( wfMsg( 'formerror' ) );
- $wgOut->addWikiText( Html::rawElement( 'span', array( 'class' => 'error' ), $err ) . "\n" );
- }
-
- $addressPart = false;
- if ( $this->id ) {
- $block = Block::newFromID( $this->id );
- if ( $block ) {
- $encName = htmlspecialchars( $block->getRedactedName() );
- $encId = $this->id;
- $addressPart = $encName . Html::hidden( 'id', $encId );
- $ipa = wfMsgHtml( $wgSysopUserBans ? 'ipadressorusername' : 'ipaddress' );
- }
- }
- if ( !$addressPart ) {
- $addressPart = Xml::input( 'wpUnblockAddress', 40, $this->ip, array( 'type' => 'text', 'tabindex' => '1' ) );
- $ipa = Xml::label( wfMsg( $wgSysopUserBans ? 'ipadressorusername' : 'ipaddress' ), 'wpUnblockAddress' );
- }
-
- $wgOut->addHTML(
- Html::openElement( 'form', array( 'method' => 'post', 'action' => $action, 'id' => 'unblockip' ) ) .
- Html::openElement( 'fieldset' ) .
- Html::element( 'legend', null, wfMsg( 'ipb-unblock' ) ) .
- Html::openElement( 'table', array( 'id' => 'mw-unblock-table' ) ).
- "<tr>
- <td class='mw-label'>
- {$ipa}
- </td>
- <td class='mw-input'>
- {$addressPart}
- </td>
- </tr>
- <tr>
- <td class='mw-label'>" .
- Xml::label( wfMsg( 'ipbreason' ), 'wpUnblockReason' ) .
- "</td>
- <td class='mw-input'>" .
- Xml::input( 'wpUnblockReason', 40, $this->reason, array( 'type' => 'text', 'tabindex' => '2' ) ) .
- "</td>
- </tr>
- <tr>
- <td>&#160;</td>
- <td class='mw-submit'>" .
- Xml::submitButton( wfMsg( 'ipusubmit' ), array( 'name' => 'wpBlock', 'tabindex' => '3' ) ) .
- "</td>
- </tr>" .
- Html::closeElement( 'table' ) .
- Html::closeElement( 'fieldset' ) .
- Html::hidden( 'wpEditToken', $wgUser->editToken() ) .
- Html::closeElement( 'form' ) . "\n"
- );
-
- }
-
- const UNBLOCK_SUCCESS = 0; // Success
- const UNBLOCK_NO_SUCH_ID = 1; // No such block ID
- const UNBLOCK_USER_NOT_BLOCKED = 2; // IP wasn't blocked
- const UNBLOCK_BLOCKED_AS_RANGE = 3; // IP is part of a range block
- const UNBLOCK_UNKNOWNERR = 4; // Unknown error
-
- /**
- * Backend code for unblocking. doSubmit() wraps around this.
- * $range is only used when UNBLOCK_BLOCKED_AS_RANGE is returned, in which
- * case it contains the range $ip is part of.
- * @return array array(message key, parameters) on failure, empty array on success
- */
- public static function doUnblock( &$id, &$ip, &$reason, &$range = null, $blocker = null ) {
- if ( $id ) {
- $block = Block::newFromID( $id );
- if ( !$block ) {
- return array( 'ipb_cant_unblock', htmlspecialchars( $id ) );
- }
- $ip = $block->getRedactedName();
- } else {
- $ip = trim( $ip );
- if ( substr( $ip, 0, 1 ) == "#" ) {
- $id = substr( $ip, 1 );
- $block = Block::newFromID( $id );
- if( !$block ) {
- return array( 'ipb_cant_unblock', htmlspecialchars( $id ) );
- }
- $ip = $block->getRedactedName();
- } else {
- # FIXME: do proper sanitisation/cleanup here
- $ip = str_replace( '_', ' ', $ip );
-
- $block = Block::newFromDB( $ip );
- if ( !$block ) {
- return array( 'ipb_cant_unblock', htmlspecialchars( $id ) );
- }
- if( $block->mRangeStart != $block->mRangeEnd && !strstr( $ip, "/" ) ) {
- /* If the specified IP is a single address, and the block is
- * a range block, don't unblock the range. */
- $range = $block->mAddress;
- return array( 'ipb_blocked_as_range', $ip, $range );
- }
- }
- }
- // Yes, this is really necessary
- $id = $block->mId;
-
- # If the name was hidden and the blocking user cannot hide
- # names, then don't allow any block removals...
- if( $blocker && $block->mHideName && !$blocker->isAllowed( 'hideuser' ) ) {
- return array( 'ipb_cant_unblock', htmlspecialchars( $id ) );
- }
-
- # Delete block
- if ( !$block->delete() ) {
- return array( 'ipb_cant_unblock', htmlspecialchars( $id ) );
- }
-
- # Unset _deleted fields as needed
- if( $block->mHideName ) {
- IPBlockForm::unsuppressUserName( $block->mAddress, $block->mUser );
- }
-
- # Make log entry
- $log = new LogPage( 'block' );
- $log->addEntry( 'unblock', Title::makeTitle( NS_USER, $ip ), $reason );
- return array();
- }
-
- function doSubmit() {
- global $wgOut, $wgUser;
-
- $retval = self::doUnblock( $this->id, $this->ip, $this->reason, $range, $wgUser );
- if( !empty( $retval ) ) {
- $key = array_shift( $retval );
- $this->showForm( wfMsgReal( $key, $retval ) );
- return;
- }
-
- # Report to the user
- $success = $this->getTitle()->getFullURL( 'action=success&successip=' . urlencode( $this->ip ) );
- $wgOut->redirect( $success );
- }
-
- function showList( $msg ) {
- global $wgOut, $wgUser;
-
- if ( $msg != '' ) {
- $wgOut->setSubtitle( $msg );
- }
-
- // Purge expired entries on one in every 10 queries
- if ( !mt_rand( 0, 10 ) ) {
- Block::purgeExpired();
- }
-
- $conds = array();
- // Is user allowed to see all the blocks?
- if ( !$wgUser->isAllowed( 'hideuser' ) )
- $conds['ipb_deleted'] = 0;
- if ( $this->ip == '' ) {
- // No extra conditions
- } elseif ( substr( $this->ip, 0, 1 ) == '#' ) {
- $conds['ipb_id'] = substr( $this->ip, 1 );
- // Single IPs
- } elseif ( IP::isIPAddress( $this->ip ) && strpos( $this->ip, '/' ) === false ) {
- $iaddr = IP::toHex( $this->ip );
- if( $iaddr ) {
- # Only scan ranges which start in this /16, this improves search speed
- # Blocks should not cross a /16 boundary.
- $range = substr( $iaddr, 0, 4 );
- // Fixme -- encapsulate this sort of query-building.
- $dbr = wfGetDB( DB_SLAVE );
- $encIp = $dbr->addQuotes( IP::sanitizeIP( $this->ip ) );
- $encAddr = $dbr->addQuotes( $iaddr );
- $conds[] = "(ipb_address = $encIp) OR
- (ipb_range_start" . $dbr->buildLike( $range, $dbr->anyString() ) . " AND
- ipb_range_start <= $encAddr
- AND ipb_range_end >= $encAddr)";
- } else {
- $conds['ipb_address'] = IP::sanitizeIP( $this->ip );
- }
- $conds['ipb_auto'] = 0;
- // IP range
- } elseif ( IP::isIPAddress( $this->ip ) ) {
- $conds['ipb_address'] = Block::normaliseRange( $this->ip );
- $conds['ipb_auto'] = 0;
- } else {
- $user = User::newFromName( $this->ip );
- if ( $user && ( $id = $user->getId() ) != 0 ) {
- $conds['ipb_user'] = $id;
- } else {
- // Uh...?
- $conds['ipb_address'] = $this->ip;
- $conds['ipb_auto'] = 0;
- }
- }
- // Apply filters
- if( $this->hideuserblocks ) {
- $conds['ipb_user'] = 0;
- }
- if( $this->hidetempblocks ) {
- $conds['ipb_expiry'] = 'infinity';
- }
- if( $this->hideaddressblocks ) {
- $conds[] = "ipb_user != 0 OR ipb_range_end > ipb_range_start";
- }
-
- // Search form
- $wgOut->addHTML( $this->searchForm() );
-
- // Check for other blocks, i.e. global/tor blocks
- $otherBlockLink = array();
- wfRunHooks( 'OtherBlockLogLink', array( &$otherBlockLink, $this->ip ) );
-
- // Show additional header for the local block only when other blocks exists.
- // Not necessary in a standard installation without such extensions enabled
- if( count( $otherBlockLink ) ) {
- $wgOut->addHTML(
- Html::rawElement( 'h2', array(), wfMsg( 'ipblocklist-localblock' ) ) . "\n"
- );
- }
- $pager = new IPBlocklistPager( $this, $conds );
- if ( $pager->getNumRows() ) {
- $wgOut->addHTML(
- $pager->getNavigationBar() .
- Html::rawElement( 'ul', null, $pager->getBody() ) .
- $pager->getNavigationBar()
- );
- } elseif ( $this->ip != '') {
- $wgOut->addWikiMsg( 'ipblocklist-no-results' );
- } else {
- $wgOut->addWikiMsg( 'ipblocklist-empty' );
- }
-
- if( count( $otherBlockLink ) ) {
- $wgOut->addHTML(
- Html::rawElement( 'h2', array(), wfMsgExt( 'ipblocklist-otherblocks', 'parseinline', count( $otherBlockLink ) ) ) . "\n"
- );
- $list = '';
- foreach( $otherBlockLink as $link ) {
- $list .= Html::rawElement( 'li', array(), $link ) . "\n";
- }
- $wgOut->addHTML( Html::rawElement( 'ul', array( 'class' => 'mw-ipblocklist-otherblocks' ), $list ) . "\n" );
- }
-
- }
-
- function searchForm() {
- global $wgScript, $wgLang;
-
- $showhide = array( wfMsg( 'show' ), wfMsg( 'hide' ) );
- $nondefaults = array();
- if( $this->hideuserblocks ) {
- $nondefaults['hideuserblocks'] = $this->hideuserblocks;
- }
- if( $this->hidetempblocks ) {
- $nondefaults['hidetempblocks'] = $this->hidetempblocks;
- }
- if( $this->hideaddressblocks ) {
- $nondefaults['hideaddressblocks'] = $this->hideaddressblocks;
- }
- $ubLink = $this->makeOptionsLink( $showhide[1-$this->hideuserblocks],
- array( 'hideuserblocks' => 1-$this->hideuserblocks ), $nondefaults);
- $tbLink = $this->makeOptionsLink( $showhide[1-$this->hidetempblocks],
- array( 'hidetempblocks' => 1-$this->hidetempblocks ), $nondefaults);
- $sipbLink = $this->makeOptionsLink( $showhide[1-$this->hideaddressblocks],
- array( 'hideaddressblocks' => 1-$this->hideaddressblocks ), $nondefaults);
-
- $links = array();
- $links[] = wfMsgHtml( 'ipblocklist-sh-userblocks', $ubLink );
- $links[] = wfMsgHtml( 'ipblocklist-sh-tempblocks', $tbLink );
- $links[] = wfMsgHtml( 'ipblocklist-sh-addressblocks', $sipbLink );
- $hl = $wgLang->pipeList( $links );
-
- return
- Html::rawElement( 'form', array( 'action' => $wgScript ),
- Html::hidden( 'title', $this->getTitle()->getPrefixedDbKey() ) .
- Html::openElement( 'fieldset' ) .
- Html::element( 'legend', null, wfMsg( 'ipblocklist-legend' ) ) .
- Xml::inputLabel( wfMsg( 'ipblocklist-username' ), 'ip', 'ip', /* size */ false, $this->ip ) .
- '&#160;' .
- Xml::submitButton( wfMsg( 'ipblocklist-submit' ) ) . '<br />' .
- $hl .
- Html::closeElement( 'fieldset' )
- );
- }
-
- /**
- * Makes change an option link which carries all the other options
- *
- * @param $title see Title
- * @param $override Array: special query string options, will override the
- * ones in $options
- * @param $options Array: query string options
- * @param $active Boolean: whether to display the link in bold
- */
- function makeOptionsLink( $title, $override, $options, $active = false ) {
- global $wgUser;
- $sk = $wgUser->getSkin();
- $params = $override + $options;
- return $sk->link( $this->getTitle(), htmlspecialchars( $title ),
- ( $active ? array( 'style'=>'font-weight: bold;' ) : array() ), $params, array( 'known' ) );
- }
-
- /**
- * Callback function to output a block
- */
- function formatRow( $block ) {
- global $wgUser, $wgLang, $wgBlockAllowsUTEdit;
-
- wfProfileIn( __METHOD__ );
-
- static $sk=null, $msg=null;
-
- if( is_null( $sk ) )
- $sk = $wgUser->getSkin();
- if( is_null( $msg ) ) {
- $msg = array();
- $keys = array( 'infiniteblock', 'expiringblock', 'unblocklink', 'change-blocklink',
- 'anononlyblock', 'createaccountblock', 'noautoblockblock', 'emailblock', 'blocklist-nousertalk', 'blocklistline' );
- foreach( $keys as $key ) {
- $msg[$key] = wfMsgHtml( $key );
- }
- }
-
- # Prepare links to the blocker's user and talk pages
- $blocker_id = $block->getBy();
- $blocker_name = $block->getByName();
- $blocker = $sk->userLink( $blocker_id, $blocker_name );
- $blocker .= $sk->userToolLinks( $blocker_id, $blocker_name );
-
- # Prepare links to the block target's user and contribs. pages (as applicable, don't do it for autoblocks)
- if( $block->mAuto ) {
- $target = $block->getRedactedName(); # Hide the IP addresses of auto-blocks; privacy
- } else {
- $target = $sk->userLink( $block->mUser, $block->mAddress )
- . $sk->userToolLinks( $block->mUser, $block->mAddress, false, Linker::TOOL_LINKS_NOBLOCK );
- }
-
- $formattedTime = htmlspecialchars( $wgLang->timeanddate( $block->mTimestamp, true ) );
-
- $properties = array();
- $properties[] = Block::formatExpiry( $block->mExpiry );
- if ( $block->mAnonOnly ) {
- $properties[] = $msg['anononlyblock'];
- }
- if ( $block->mCreateAccount ) {
- $properties[] = $msg['createaccountblock'];
- }
- if (!$block->mEnableAutoblock && $block->mUser ) {
- $properties[] = $msg['noautoblockblock'];
- }
-
- if ( $block->mBlockEmail && $block->mUser ) {
- $properties[] = $msg['emailblock'];
- }
-
- if ( !$block->mAllowUsertalk && $wgBlockAllowsUTEdit ) {
- $properties[] = $msg['blocklist-nousertalk'];
- }
-
- $properties = $wgLang->commaList( $properties );
-
- $line = wfMsgReplaceArgs( $msg['blocklistline'], array( $formattedTime, $blocker, $target, $properties ) );
-
- $changeblocklink = '';
- $toolLinks = '';
- if ( $wgUser->isAllowed( 'block' ) ) {
- $unblocklink = $sk->link( $this->getTitle(),
- $msg['unblocklink'],
- array(),
- array( 'action' => 'unblock', 'id' => $block->mId ),
- 'known' );
-
- # Create changeblocklink for all blocks with exception of autoblocks
- if( !$block->mAuto ) {
- $changeblocklink = wfMsgExt( 'pipe-separator', 'escapenoentities' ) .
- $sk->link( SpecialPage::getTitleFor( 'Blockip', $block->mAddress ),
- $msg['change-blocklink'],
- array(), array(), 'known' );
- }
- $toolLinks = "($unblocklink$changeblocklink)";
- }
-
- $comment = $sk->commentBlock( htmlspecialchars($block->mReason) );
-
- $s = "{$line} $comment";
- if ( $block->mHideName )
- $s = '<span class="history-deleted">' . $s . '</span>';
-
- wfProfileOut( __METHOD__ );
- return "<li>$s $toolLinks</li>\n";
- }
-}
-
-/**
- * @todo document
- * @ingroup Pager
- */
-class IPBlocklistPager extends ReverseChronologicalPager {
- public $mForm, $mConds;
-
- function __construct( $form, $conds = array() ) {
- $this->mForm = $form;
- $this->mConds = $conds;
- parent::__construct();
- }
-
- function getStartBody() {
- wfProfileIn( __METHOD__ );
- # Do a link batch query
- $this->mResult->seek( 0 );
- $lb = new LinkBatch;
-
- /*
- while ( $row = $this->mResult->fetchObject() ) {
- $lb->addObj( Title::makeTitleSafe( NS_USER, $row->user_name ) );
- $lb->addObj( Title::makeTitleSafe( NS_USER_TALK, $row->user_name ) );
- $lb->addObj( Title::makeTitleSafe( NS_USER, $row->ipb_address ) );
- $lb->addObj( Title::makeTitleSafe( NS_USER_TALK, $row->ipb_address ) );
- }*/
- # Faster way
- # Usernames and titles are in fact related by a simple substitution of space -> underscore
- # The last few lines of Title::secureAndSplit() tell the story.
- foreach ( $this->mResult as $row ) {
- $name = str_replace( ' ', '_', $row->ipb_by_text );
- $lb->add( NS_USER, $name );
- $lb->add( NS_USER_TALK, $name );
- $name = str_replace( ' ', '_', $row->ipb_address );
- $lb->add( NS_USER, $name );
- $lb->add( NS_USER_TALK, $name );
- }
- $lb->execute();
- wfProfileOut( __METHOD__ );
- return '';
- }
-
- function formatRow( $row ) {
- $block = new Block;
- $block->initFromRow( $row );
- return $this->mForm->formatRow( $block );
- }
-
- function getQueryInfo() {
- $conds = $this->mConds;
- $conds[] = 'ipb_expiry>' . $this->mDb->addQuotes( $this->mDb->timestamp() );
- return array(
- 'tables' => 'ipblocks',
- 'fields' => '*',
- 'conds' => $conds,
- );
- }
-
- function getIndexField() {
- return 'ipb_timestamp';
- }
-}
diff --git a/includes/specials/SpecialLinkSearch.php b/includes/specials/SpecialLinkSearch.php
index 9dee9d5a..bef859a2 100644
--- a/includes/specials/SpecialLinkSearch.php
+++ b/includes/specials/SpecialLinkSearch.php
@@ -21,74 +21,10 @@
* @ingroup SpecialPage
* @author Brion Vibber
*/
-
-/**
- * Special:LinkSearch to search the external-links table.
- */
-function wfSpecialLinkSearch( $par ) {
-
- list( $limit, $offset ) = wfCheckLimits();
- global $wgOut, $wgUrlProtocols, $wgMiserMode, $wgLang;
- $target = $GLOBALS['wgRequest']->getVal( 'target', $par );
- $namespace = $GLOBALS['wgRequest']->getIntorNull( 'namespace', null );
-
- $protocols_list[] = '';
- foreach( $wgUrlProtocols as $prot ) {
- $protocols_list[] = $prot;
- }
-
- $target2 = $target;
- $protocol = '';
- $pr_sl = strpos($target2, '//' );
- $pr_cl = strpos($target2, ':' );
- if ( $pr_sl ) {
- // For protocols with '//'
- $protocol = substr( $target2, 0 , $pr_sl+2 );
- $target2 = substr( $target2, $pr_sl+2 );
- } elseif ( !$pr_sl && $pr_cl ) {
- // For protocols without '//' like 'mailto:'
- $protocol = substr( $target2, 0 , $pr_cl+1 );
- $target2 = substr( $target2, $pr_cl+1 );
- } elseif ( $protocol == '' && $target2 != '' ) {
- // default
- $protocol = 'http://';
- }
- if ( !in_array( $protocol, $protocols_list ) ) {
- // unsupported protocol, show original search request
- $target2 = $target;
- $protocol = '';
- }
-
- $self = Title::makeTitle( NS_SPECIAL, 'Linksearch' );
-
- $wgOut->allowClickjacking();
- $wgOut->addWikiMsg( 'linksearch-text', '<nowiki>' . $wgLang->commaList( $wgUrlProtocols ) . '</nowiki>' );
- $s = Xml::openElement( 'form', array( 'id' => 'mw-linksearch-form', 'method' => 'get', 'action' => $GLOBALS['wgScript'] ) ) .
- Html::hidden( 'title', $self->getPrefixedDbKey() ) .
- '<fieldset>' .
- Xml::element( 'legend', array(), wfMsg( 'linksearch' ) ) .
- Xml::inputLabel( wfMsg( 'linksearch-pat' ), 'target', 'target', 50, $target ) . ' ';
- if ( !$wgMiserMode ) {
- $s .= Xml::label( wfMsg( 'linksearch-ns' ), 'namespace' ) . ' ' .
- Xml::namespaceSelector( $namespace, '' );
- }
- $s .= Xml::submitButton( wfMsg( 'linksearch-ok' ) ) .
- '</fieldset>' .
- Xml::closeElement( 'form' );
- $wgOut->addHTML( $s );
-
- if( $target != '' ) {
- $searcher = new LinkSearchPage;
- $searcher->setParams( array(
- 'query' => $target2,
- 'namespace' => $namespace,
- 'protocol' => $protocol ) );
- $searcher->doQuery( $offset, $limit );
- }
-}
/**
+ * Special:LinkSearch to search the external-links table.
* @ingroup SpecialPage
*/
class LinkSearchPage extends QueryPage {
@@ -98,8 +34,75 @@ class LinkSearchPage extends QueryPage {
$this->mProt = $params['protocol'];
}
- function getName() {
- return 'LinkSearch';
+ function __construct( $name = 'LinkSearch' ) {
+ parent::__construct( $name );
+ }
+
+ function isCacheable() {
+ return false;
+ }
+
+ function execute( $par ) {
+ global $wgOut, $wgRequest, $wgUrlProtocols, $wgMiserMode, $wgLang;
+ $this->setHeaders();
+ $wgOut->allowClickjacking();
+
+ $target = $wgRequest->getVal( 'target', $par );
+ $namespace = $wgRequest->getIntorNull( 'namespace', null );
+
+ $protocols_list = array();
+ foreach( $wgUrlProtocols as $prot ) {
+ if ( $prot !== '//' ) {
+ $protocols_list[] = $prot;
+ }
+ }
+
+ $target2 = $target;
+ $protocol = '';
+ $pr_sl = strpos($target2, '//' );
+ $pr_cl = strpos($target2, ':' );
+ if ( $pr_sl ) {
+ // For protocols with '//'
+ $protocol = substr( $target2, 0 , $pr_sl+2 );
+ $target2 = substr( $target2, $pr_sl+2 );
+ } elseif ( !$pr_sl && $pr_cl ) {
+ // For protocols without '//' like 'mailto:'
+ $protocol = substr( $target2, 0 , $pr_cl+1 );
+ $target2 = substr( $target2, $pr_cl+1 );
+ } elseif ( $protocol == '' && $target2 != '' ) {
+ // default
+ $protocol = 'http://';
+ }
+ if ( $protocol != '' && !in_array( $protocol, $protocols_list ) ) {
+ // unsupported protocol, show original search request
+ $target2 = $target;
+ $protocol = '';
+ }
+
+ $out->addWikiMsg( 'linksearch-text', '<nowiki>' . $this->getLanguage()->commaList( $protocols_list ) . '</nowiki>' );
+ $s = Xml::openElement( 'form', array( 'id' => 'mw-linksearch-form', 'method' => 'get', 'action' => $GLOBALS['wgScript'] ) ) .
+ Html::hidden( 'title', $self->getPrefixedDbKey() ) .
+ '<fieldset>' .
+ Xml::element( 'legend', array(), wfMsg( 'linksearch' ) ) .
+ Xml::inputLabel( wfMsg( 'linksearch-pat' ), 'target', 'target', 50, $target ) . ' ';
+ if ( !$wgMiserMode ) {
+ $s .= Xml::label( wfMsg( 'linksearch-ns' ), 'namespace' ) . ' ' .
+ Xml::namespaceSelector( $namespace, '' );
+ }
+ $s .= Xml::submitButton( wfMsg( 'linksearch-ok' ) ) .
+ '</fieldset>' .
+ Xml::closeElement( 'form' );
+ $wgOut->addHTML( $s );
+
+ if( $target != '' ) {
+ $this->setParams( array(
+ 'query' => $target2,
+ 'namespace' => $namespace,
+ 'protocol' => $protocol ) );
+ parent::execute( $par );
+ if( $this->mMungedQuery === false )
+ $wgOut->addWikiMsg( 'linksearch-error' );
+ }
}
/**
@@ -111,15 +114,17 @@ class LinkSearchPage extends QueryPage {
/**
* Return an appropriately formatted LIKE query and the clause
+ *
+ * @return array
*/
- static function mungeQuery( $query , $prot ) {
+ static function mungeQuery( $query, $prot ) {
$field = 'el_index';
$rv = LinkFilter::makeLikeArray( $query , $prot );
- if ($rv === false) {
+ if ( $rv === false ) {
// LinkFilter doesn't handle wildcard in IP, so we'll have to munge here.
if (preg_match('/^(:?[0-9]{1,3}\.)+\*\s*$|^(:?[0-9]{1,3}\.){3}[0-9]{1,3}:[0-9]*\*\s*$/', $query)) {
$dbr = wfGetDB( DB_SLAVE );
- $rv = array( $prot . rtrim($query, " \t*"), $dbr->anyString() );
+ $rv = array( $prot . rtrim( $query, " \t*" ), $dbr->anyString() );
$field = 'el_to';
}
}
@@ -136,35 +141,32 @@ class LinkSearchPage extends QueryPage {
return $params;
}
- function getSQL() {
+ function getQueryInfo() {
global $wgMiserMode;
$dbr = wfGetDB( DB_SLAVE );
- $page = $dbr->tableName( 'page' );
- $externallinks = $dbr->tableName( 'externallinks' );
-
- /* strip everything past first wildcard, so that index-based-only lookup would be done */
- list( $munged, $clause ) = self::mungeQuery( $this->mQuery, $this->mProt );
- $stripped = LinkFilter::keepOneWildcard( $munged );
+ // strip everything past first wildcard, so that
+ // index-based-only lookup would be done
+ list( $this->mMungedQuery, $clause ) = self::mungeQuery(
+ $this->mQuery, $this->mProt );
+ if( $this->mMungedQuery === false )
+ // Invalid query; return no results
+ return array( 'tables' => 'page', 'fields' => 'page_id', 'conds' => '0=1' );
+
+ $stripped = LinkFilter::keepOneWildcard( $this->mMungedQuery );
$like = $dbr->buildLike( $stripped );
-
- $encSQL = '';
- if ( isset ($this->mNs) && !$wgMiserMode )
- $encSQL = 'AND page_namespace=' . $dbr->addQuotes( $this->mNs );
-
- $use_index = $dbr->useIndexClause( $clause );
- return
- "SELECT
- page_namespace AS namespace,
- page_title AS title,
- el_index AS value,
- el_to AS url
- FROM
- $page,
- $externallinks $use_index
- WHERE
- page_id=el_from
- AND $clause $like
- $encSQL";
+ $retval = array (
+ 'tables' => array ( 'page', 'externallinks' ),
+ 'fields' => array ( 'page_namespace AS namespace',
+ 'page_title AS title',
+ 'el_index AS value', 'el_to AS url' ),
+ 'conds' => array ( 'page_id = el_from',
+ "$clause $like" ),
+ 'options' => array( 'USE INDEX' => $clause )
+ );
+ if ( isset( $this->mNs ) && !$wgMiserMode ) {
+ $retval['conds']['page_namespace'] = $this->mNs;
+ }
+ return $retval;
}
function formatResult( $skin, $result ) {
@@ -179,7 +181,7 @@ class LinkSearchPage extends QueryPage {
/**
* Override to check query validity.
*/
- function doQuery( $offset, $limit, $shownavigation=true ) {
+ function doQuery( $offset = false, $limit = false ) {
global $wgOut;
list( $this->mMungedQuery, ) = LinkSearchPage::mungeQuery( $this->mQuery, $this->mProt );
if( $this->mMungedQuery === false ) {
@@ -188,7 +190,7 @@ class LinkSearchPage extends QueryPage {
// For debugging
// Generates invalid xhtml with patterns that contain --
//$wgOut->addHTML( "\n<!-- " . htmlspecialchars( $this->mMungedQuery ) . " -->\n" );
- parent::doQuery( $offset, $limit, $shownavigation );
+ parent::doQuery( $offset, $limit );
}
}
@@ -198,7 +200,7 @@ class LinkSearchPage extends QueryPage {
* it as good enough for optimizing sort. The implicit ordering
* from the scan will usually do well enough for our needs.
*/
- function getOrder() {
- return '';
+ function getOrderFields() {
+ return array();
}
}
diff --git a/includes/specials/SpecialListfiles.php b/includes/specials/SpecialListfiles.php
index 350e833b..427de167 100644
--- a/includes/specials/SpecialListfiles.php
+++ b/includes/specials/SpecialListfiles.php
@@ -20,16 +20,38 @@
* @file
* @ingroup SpecialPage
*/
-
-function wfSpecialListfiles( $par = null ) {
- global $wgOut;
- $pager = new ImageListPager( $par );
+class SpecialListFiles extends IncludableSpecialPage {
- $limit = $pager->getForm();
- $body = $pager->getBody();
- $nav = $pager->getNavigationBar();
- $wgOut->addHTML( "$limit<br />\n$body<br />\n$nav" );
+ public function __construct(){
+ parent::__construct( 'Listfiles' );
+ }
+
+ public function execute( $par ){
+ global $wgOut, $wgRequest;
+ $this->setHeaders();
+ $this->outputHeader();
+
+ if ( $this->including() ) {
+ $userName = $par;
+ $search = '';
+ } else {
+ $userName = $wgRequest->getText( 'user', $par );
+ $search = $wgRequest->getText( 'ilsearch', '' );
+ }
+
+ $pager = new ImageListPager( $userName, $search, $this->including() );
+
+ if ( $this->including() ) {
+ $html = $pager->getBody();
+ } else {
+ $form = $pager->getForm();
+ $body = $pager->getBody();
+ $nav = $pager->getNavigationBar();
+ $html = "$form<br />\n$body<br />\n$nav";
+ }
+ $wgOut->addHTML( $html );
+ }
}
/**
@@ -39,46 +61,62 @@ class ImageListPager extends TablePager {
var $mFieldNames = null;
var $mQueryConds = array();
var $mUserName = null;
-
- function __construct( $par = null ) {
+ var $mSearch = '';
+ var $mIncluding = false;
+
+ function __construct( $userName = null, $search = '', $including = false ) {
global $wgRequest, $wgMiserMode;
- if ( $wgRequest->getText( 'sort', 'img_date' ) == 'img_date' ) {
- $this->mDefaultDirection = true;
- } else {
- $this->mDefaultDirection = false;
- }
-
- $userName = $wgRequest->getText( 'user', $par );
+
+ $this->mIncluding = $including;
+
if ( $userName ) {
$nt = Title::newFromText( $userName, NS_USER );
if ( !is_null( $nt ) ) {
$this->mUserName = $nt->getText();
$this->mQueryConds['img_user_text'] = $this->mUserName;
}
- }
-
- $search = $wgRequest->getText( 'ilsearch' );
+ }
+
if ( $search != '' && !$wgMiserMode ) {
- $nt = Title::newFromURL( $search );
+ $this->mSearch = $search;
+ $nt = Title::newFromURL( $this->mSearch );
if ( $nt ) {
$dbr = wfGetDB( DB_SLAVE );
- $this->mQueryConds[] = 'LOWER(img_name)' . $dbr->buildLike( $dbr->anyString(),
- strtolower( $nt->getDBkey() ), $dbr->anyString() );
+ $this->mQueryConds[] = 'LOWER(img_name)' .
+ $dbr->buildLike( $dbr->anyString(),
+ strtolower( $nt->getDBkey() ), $dbr->anyString() );
}
}
+ if ( !$including ) {
+ if ( $wgRequest->getText( 'sort', 'img_date' ) == 'img_date' ) {
+ $this->mDefaultDirection = true;
+ } else {
+ $this->mDefaultDirection = false;
+ }
+ } else {
+ $this->mDefaultDirection = true;
+ }
+
parent::__construct();
}
+ function getTitle() {
+ return SpecialPage::getTitleFor( 'Listfiles' );
+ }
+
+ /**
+ * @return Array
+ */
function getFieldNames() {
if ( !$this->mFieldNames ) {
global $wgMiserMode;
$this->mFieldNames = array(
- 'thumb' => wfMsg( 'listfiles_thumb' ),
'img_timestamp' => wfMsg( 'listfiles_date' ),
'img_name' => wfMsg( 'listfiles_name' ),
- 'img_user_text' => wfMsg( 'listfiles_user' ),
+ 'thumb' => wfMsg( 'listfiles_thumb' ),
'img_size' => wfMsg( 'listfiles_size' ),
+ 'img_user_text' => wfMsg( 'listfiles_user' ),
'img_description' => wfMsg( 'listfiles_description' ),
);
if( !$wgMiserMode ) {
@@ -89,6 +127,9 @@ class ImageListPager extends TablePager {
}
function isFieldSortable( $field ) {
+ if ( $this->mIncluding ) {
+ return false;
+ }
static $sortable = array( 'img_timestamp', 'img_name' );
if ( $field == 'img_size' ) {
# No index for both img_size and img_user_text
@@ -101,7 +142,7 @@ class ImageListPager extends TablePager {
$tables = array( 'image' );
$fields = array_keys( $this->getFieldNames() );
$fields[] = 'img_user';
- $fields[array_search('thumb', $fields)] = 'img_name as thumb';
+ $fields[array_search('thumb', $fields)] = 'img_name AS thumb';
$options = $join_conds = array();
# Depends on $wgMiserMode
@@ -111,7 +152,7 @@ class ImageListPager extends TablePager {
# Need to rewrite this one
foreach ( $fields as &$field ) {
if ( $field == 'count' ) {
- $field = 'COUNT(oi_archive_name) as count';
+ $field = 'COUNT(oi_archive_name) AS count';
}
}
unset( $field );
@@ -120,7 +161,8 @@ class ImageListPager extends TablePager {
if( $dbr->implicitGroupby() ) {
$options = array( 'GROUP BY' => 'img_name' );
} else {
- $columnlist = implode( ',', preg_grep( '/^img/', array_keys( $this->getFieldNames() ) ) );
+ $columnlist = implode( ',',
+ preg_grep( '/^img/', array_keys( $this->getFieldNames() ) ) );
$options = array( 'GROUP BY' => "img_user, $columnlist" );
}
$join_conds = array( 'oldimage' => array( 'LEFT JOIN', 'oi_name = img_name' ) );
@@ -159,7 +201,7 @@ class ImageListPager extends TablePager {
switch ( $field ) {
case 'thumb':
$file = wfLocalFile( $value );
- $thumb = $file->transform( array( 'width' => 180 ) );
+ $thumb = $file->transform( array( 'width' => 180, 'height' => 360 ) );
return $thumb->toHtml( array( 'desc-link' => true ) );
case 'img_timestamp':
return htmlspecialchars( $wgLang->timeanddate( $value, true ) );
@@ -167,12 +209,18 @@ class ImageListPager extends TablePager {
static $imgfile = null;
if ( $imgfile === null ) $imgfile = wfMsg( 'imgfile' );
- $filePage = Title::makeTitle( NS_FILE, $value );
- $link = $this->getSkin()->linkKnown( $filePage, htmlspecialchars( $filePage->getText() ) );
- $image = wfLocalFile( $value );
- $url = $image->getURL();
- $download = Xml::element('a', array( 'href' => $url ), $imgfile );
- return "$link ($download)";
+ // Weird files can maybe exist? Bug 22227
+ $filePage = Title::makeTitleSafe( NS_FILE, $value );
+ if( $filePage ) {
+ $link = $this->getSkin()->linkKnown( $filePage, htmlspecialchars( $filePage->getText() ) );
+ $download = Xml::element( 'a',
+ array( 'href' => wfLocalFile( $filePage )->getURL() ),
+ $imgfile
+ );
+ return "$link ($download)";
+ } else {
+ return htmlspecialchars( $value );
+ }
case 'img_user_text':
if ( $this->mCurrentRow->img_user ) {
$link = $this->getSkin()->link(
@@ -188,34 +236,34 @@ class ImageListPager extends TablePager {
case 'img_description':
return $this->getSkin()->commentBlock( $value );
case 'count':
- return intval($value)+1;
+ return intval( $value ) + 1;
}
}
function getForm() {
- global $wgRequest, $wgScript, $wgMiserMode;
- $search = $wgRequest->getText( 'ilsearch' );
+ global $wgScript, $wgMiserMode;
$inputForm = array();
$inputForm['table_pager_limit_label'] = $this->getLimitSelect();
if ( !$wgMiserMode ) {
- $inputForm['listfiles_search_for'] = Html::input( 'ilsearch', $search, 'text', array(
- 'size' => '40',
- 'maxlength' => '255',
- 'id' => 'mw-ilsearch',
+ $inputForm['listfiles_search_for'] = Html::input( 'ilsearch', $this->mSearch, 'text',
+ array(
+ 'size' => '40',
+ 'maxlength' => '255',
+ 'id' => 'mw-ilsearch',
) );
}
$inputForm['username'] = Html::input( 'user', $this->mUserName, 'text', array(
- 'size' => '40',
- 'maxlength' => '255',
- 'id' => 'mw-listfiles-user',
+ 'size' => '40',
+ 'maxlength' => '255',
+ 'id' => 'mw-listfiles-user',
) );
- $s = Html::openElement( 'form', array( 'method' => 'get', 'action' => $wgScript, 'id' => 'mw-listfiles-form' ) ) .
+ return Html::openElement( 'form',
+ array( 'method' => 'get', 'action' => $wgScript, 'id' => 'mw-listfiles-form' ) ) .
Xml::fieldset( wfMsg( 'listfiles' ) ) .
Xml::buildForm( $inputForm, 'table_pager_limit_submit' ) .
$this->getHiddenFields( array( 'limit', 'ilsearch', 'user' ) ) .
Html::closeElement( 'fieldset' ) .
Html::closeElement( 'form' ) . "\n";
- return $s;
}
function getTableClass() {
@@ -229,7 +277,7 @@ class ImageListPager extends TablePager {
function getSortHeaderClass() {
return 'listfiles_sort ' . parent::getSortHeaderClass();
}
-
+
function getPagingQueries() {
$queries = parent::getPagingQueries();
if ( !is_null( $this->mUserName ) ) {
@@ -243,9 +291,7 @@ class ImageListPager extends TablePager {
function getDefaultQuery() {
$queries = parent::getDefaultQuery();
- if ( !isset( $queries['user'] )
- && !is_null( $this->mUserName ) )
- {
+ if ( !isset( $queries['user'] ) && !is_null( $this->mUserName ) ) {
$queries['user'] = $this->mUserName;
}
return $queries;
diff --git a/includes/specials/SpecialListgrouprights.php b/includes/specials/SpecialListgrouprights.php
index 910ffd08..07e08e77 100644
--- a/includes/specials/SpecialListgrouprights.php
+++ b/includes/specials/SpecialListgrouprights.php
@@ -30,29 +30,27 @@
*/
class SpecialListGroupRights extends SpecialPage {
- var $skin;
-
/**
* Constructor
*/
function __construct() {
- global $wgUser;
parent::__construct( 'Listgrouprights' );
- $this->skin = $wgUser->getSkin();
}
/**
* Show the special page
*/
public function execute( $par ) {
- global $wgOut, $wgImplicitGroups;
+ global $wgImplicitGroups;
global $wgGroupPermissions, $wgRevokePermissions, $wgAddGroups, $wgRemoveGroups;
global $wgGroupsAddToSelf, $wgGroupsRemoveFromSelf;
+ $out = $this->getOutput();
$this->setHeaders();
$this->outputHeader();
+ $out->addModuleStyles( 'mediawiki.special' );
- $wgOut->addHTML(
+ $out->addHTML(
Xml::openElement( 'table', array( 'class' => 'wikitable mw-listgrouprights-table' ) ) .
'<tr>' .
Xml::element( 'th', null, wfMsg( 'listgrouprights-group' ) ) .
@@ -60,7 +58,7 @@ class SpecialListGroupRights extends SpecialPage {
'</tr>'
);
- $allGroups = array_unique( array_merge(
+ $allGroups = array_unique( array_merge(
array_keys( $wgGroupPermissions ),
array_keys( $wgRevokePermissions ),
array_keys( $wgAddGroups ),
@@ -69,34 +67,28 @@ class SpecialListGroupRights extends SpecialPage {
array_keys( $wgGroupsRemoveFromSelf )
) );
asort( $allGroups );
-
+
foreach ( $allGroups as $group ) {
- $permissions = isset( $wgGroupPermissions[$group] )
- ? $wgGroupPermissions[$group]
+ $permissions = isset( $wgGroupPermissions[$group] )
+ ? $wgGroupPermissions[$group]
: array();
$groupname = ( $group == '*' ) // Replace * with a more descriptive groupname
- ? 'all'
- : $group;
+ ? 'all'
+ : $group;
- $msg = wfMsg( 'group-' . $groupname );
- if ( wfEmptyMsg( 'group-' . $groupname, $msg ) || $msg == '' ) {
- $groupnameLocalized = $groupname;
- } else {
- $groupnameLocalized = $msg;
- }
+ $msg = wfMessage( 'group-' . $groupname );
+ $groupnameLocalized = !$msg->isBlank() ? $msg->text() : $groupname;
- $msg = wfMsgForContent( 'grouppage-' . $groupname );
- if ( wfEmptyMsg( 'grouppage-' . $groupname, $msg ) || $msg == '' ) {
- $grouppageLocalized = MWNamespace::getCanonicalName( NS_PROJECT ) . ':' . $groupname;
- } else {
- $grouppageLocalized = $msg;
- }
+ $msg = wfMessage( 'grouppage-' . $groupname )->inContentLanguage();
+ $grouppageLocalized = !$msg->isBlank() ?
+ $msg->text() :
+ MWNamespace::getCanonicalName( NS_PROJECT ) . ':' . $groupname;
if( $group == '*' ) {
// Do not make a link for the generic * group
$grouppage = htmlspecialchars( $groupnameLocalized );
} else {
- $grouppage = $this->skin->link(
+ $grouppage = Linker::link(
Title::newFromText( $grouppageLocalized ),
htmlspecialchars( $groupnameLocalized )
);
@@ -104,7 +96,7 @@ class SpecialListGroupRights extends SpecialPage {
if ( $group === 'user' ) {
// Link to Special:listusers for implicit group 'user'
- $grouplink = '<br />' . $this->skin->link(
+ $grouplink = '<br />' . Linker::link(
SpecialPage::getTitleFor( 'Listusers' ),
wfMsgHtml( 'listgrouprights-members' ),
array(),
@@ -112,7 +104,7 @@ class SpecialListGroupRights extends SpecialPage {
array( 'known', 'noclasses' )
);
} elseif ( !in_array( $group, $wgImplicitGroups ) ) {
- $grouplink = '<br />' . $this->skin->link(
+ $grouplink = '<br />' . Linker::link(
SpecialPage::getTitleFor( 'Listusers' ),
wfMsgHtml( 'listgrouprights-members' ),
array(),
@@ -131,7 +123,7 @@ class SpecialListGroupRights extends SpecialPage {
$removegroupsSelf = isset( $wgGroupsRemoveFromSelf[$group] ) ? $wgGroupsRemoveFromSelf[$group] : array();
$id = $group == '*' ? false : Sanitizer::escapeId( $group );
- $wgOut->addHTML( Html::rawElement( 'tr', array( 'id' => $id ),
+ $out->addHTML( Html::rawElement( 'tr', array( 'id' => $id ),
"
<td>$grouppage$grouplink</td>
<td>" .
@@ -140,10 +132,10 @@ class SpecialListGroupRights extends SpecialPage {
'
) );
}
- $wgOut->addHTML(
+ $out->addHTML(
Xml::closeElement( 'table' ) . "\n<br /><hr />\n"
);
- $wgOut->wrapWikiMsg( "<div class=\"mw-listgrouprights-key\">\n$1\n</div>", 'listgrouprights-key' );
+ $out->wrapWikiMsg( "<div class=\"mw-listgrouprights-key\">\n$1\n</div>", 'listgrouprights-key' );
}
/**
@@ -158,7 +150,7 @@ class SpecialListGroupRights extends SpecialPage {
* @return string List of all granted permissions, separated by comma separator
*/
private static function formatPermissions( $permissions, $revoke, $add, $remove, $addSelf, $removeSelf ) {
- global $wgLang;
+ global $wgLang;
$r = array();
foreach( $permissions as $permission => $granted ) {
@@ -183,25 +175,25 @@ class SpecialListGroupRights extends SpecialPage {
sort( $r );
if( $add === true ){
$r[] = wfMsgExt( 'listgrouprights-addgroup-all', array( 'escape' ) );
- } else if( is_array( $add ) && count( $add ) ) {
+ } elseif( is_array( $add ) && count( $add ) ) {
$add = array_values( array_unique( $add ) );
$r[] = wfMsgExt( 'listgrouprights-addgroup', array( 'parseinline' ), $wgLang->listToText( array_map( array( 'User', 'makeGroupLinkWiki' ), $add ) ), count( $add ) );
}
if( $remove === true ){
$r[] = wfMsgExt( 'listgrouprights-removegroup-all', array( 'escape' ) );
- } else if( is_array( $remove ) && count( $remove ) ) {
+ } elseif( is_array( $remove ) && count( $remove ) ) {
$remove = array_values( array_unique( $remove ) );
$r[] = wfMsgExt( 'listgrouprights-removegroup', array( 'parseinline' ), $wgLang->listToText( array_map( array( 'User', 'makeGroupLinkWiki' ), $remove ) ), count( $remove ) );
}
if( $addSelf === true ){
$r[] = wfMsgExt( 'listgrouprights-addgroup-self-all', array( 'escape' ) );
- } else if( is_array( $addSelf ) && count( $addSelf ) ) {
+ } elseif( is_array( $addSelf ) && count( $addSelf ) ) {
$addSelf = array_values( array_unique( $addSelf ) );
$r[] = wfMsgExt( 'listgrouprights-addgroup-self', array( 'parseinline' ), $wgLang->listToText( array_map( array( 'User', 'makeGroupLinkWiki' ), $addSelf ) ), count( $addSelf ) );
}
if( $removeSelf === true ){
$r[] = wfMsgExt( 'listgrouprights-removegroup-self-all', array( 'escape' ) );
- } else if( is_array( $removeSelf ) && count( $removeSelf ) ) {
+ } elseif( is_array( $removeSelf ) && count( $removeSelf ) ) {
$removeSelf = array_values( array_unique( $removeSelf ) );
$r[] = wfMsgExt( 'listgrouprights-removegroup-self', array( 'parseinline' ), $wgLang->listToText( array_map( array( 'User', 'makeGroupLinkWiki' ), $removeSelf ) ), count( $removeSelf ) );
}
diff --git a/includes/specials/SpecialListredirects.php b/includes/specials/SpecialListredirects.php
index 315047da..acf5fbd9 100644
--- a/includes/specials/SpecialListredirects.php
+++ b/includes/specials/SpecialListredirects.php
@@ -30,22 +30,72 @@
*/
class ListredirectsPage extends QueryPage {
- function getName() { return( 'Listredirects' ); }
- function isExpensive() { return( true ); }
- function isSyndicated() { return( false ); }
- function sortDescending() { return( false ); }
+ function __construct( $name = 'Listredirects' ) {
+ parent::__construct( $name );
+ }
+
+ function isExpensive() { return true; }
+ function isSyndicated() { return false; }
+ function sortDescending() { return false; }
- function getSQL() {
- $dbr = wfGetDB( DB_SLAVE );
- $page = $dbr->tableName( 'page' );
- $sql = "SELECT 'Listredirects' AS type, page_title AS title, page_namespace AS namespace,
- 0 AS value FROM $page WHERE page_is_redirect = 1";
- return( $sql );
+ function getQueryInfo() {
+ return array(
+ 'tables' => array( 'p1' => 'page', 'redirect', 'p2' => 'page' ),
+ 'fields' => array( 'p1.page_namespace AS namespace',
+ 'p1.page_title AS title',
+ 'rd_namespace',
+ 'rd_title',
+ 'rd_fragment',
+ 'rd_interwiki',
+ 'p2.page_id AS redirid' ),
+ 'conds' => array( 'p1.page_is_redirect' => 1 ),
+ 'join_conds' => array( 'redirect' => array(
+ 'LEFT JOIN', 'rd_from=p1.page_id' ),
+ 'p2' => array( 'LEFT JOIN', array(
+ 'p2.page_namespace=rd_namespace',
+ 'p2.page_title=rd_title' ) ) )
+ );
}
- function formatResult( $skin, $result ) {
- global $wgContLang;
+ function getOrderFields() {
+ return array ( 'p1.page_namespace', 'p1.page_title' );
+ }
+ /**
+ * Cache page existence for performance
+ *
+ * @param $db DatabaseBase
+ * @param $res ResultWrapper
+ */
+ function preprocessResults( $db, $res ) {
+ $batch = new LinkBatch;
+ foreach ( $res as $row ) {
+ $batch->add( $row->namespace, $row->title );
+ $batch->addObj( $this->getRedirectTarget( $row ) );
+ }
+ $batch->execute();
+
+ // Back to start for display
+ if ( $db->numRows( $res ) > 0 ) {
+ // If there are no rows we get an error seeking.
+ $db->dataSeek( $res, 0 );
+ }
+ }
+
+ protected function getRedirectTarget( $row ) {
+ if ( isset( $row->rd_title ) ) {
+ return Title::makeTitle( $row->rd_namespace,
+ $row->rd_title, $row->rd_fragment,
+ $row->rd_interwiki
+ );
+ } else {
+ $title = Title::makeTitle( $row->namespace, $row->title );
+ $article = new Article( $title );
+ return $article->getRedirectTarget();
+ }
+ }
+
+ function formatResult( $skin, $result ) {
# Make a link to the redirect itself
$rd_title = Title::makeTitle( $result->namespace, $result->title );
$rd_link = $skin->link(
@@ -56,25 +106,15 @@ class ListredirectsPage extends QueryPage {
);
# Find out where the redirect leads
- $revision = Revision::newFromTitle( $rd_title );
- if( $revision ) {
+ $target = $this->getRedirectTarget( $result );
+ if( $target ) {
+ global $wgLang;
# Make a link to the destination page
- $target = Title::newFromRedirect( $revision->getText() );
- if( $target ) {
- $arr = $wgContLang->getArrow() . $wgContLang->getDirMark();
- $targetLink = $skin->link( $target );
- return "$rd_link $arr $targetLink";
- } else {
- return "<del>$rd_link</del>";
- }
+ $arr = $wgLang->getArrow() . $wgLang->getDirMark();
+ $targetLink = $skin->link( $target );
+ return "$rd_link $arr $targetLink";
} else {
return "<del>$rd_link</del>";
}
}
}
-
-function wfSpecialListredirects() {
- list( $limit, $offset ) = wfCheckLimits();
- $lrp = new ListredirectsPage();
- $lrp->doQuery( $offset, $limit );
-}
diff --git a/includes/specials/SpecialListusers.php b/includes/specials/SpecialListusers.php
index abc0363a..0531444a 100644
--- a/includes/specials/SpecialListusers.php
+++ b/includes/specials/SpecialListusers.php
@@ -41,7 +41,7 @@ class UsersPager extends AlphabeticPager {
if ( $parms[0] != '' && ( in_array( $par, User::getAllGroups() ) || in_array( $par, $symsForAll ) ) ) {
$this->requestedGroup = $par;
$un = $wgRequest->getText( 'username' );
- } else if ( count( $parms ) == 2 ) {
+ } elseif ( count( $parms ) == 2 ) {
$this->requestedGroup = $parms[0];
$un = $parms[1];
} else {
@@ -64,6 +64,9 @@ class UsersPager extends AlphabeticPager {
parent::__construct();
}
+ function getTitle() {
+ return SpecialPage::getTitleFor( 'Listusers' );
+ }
function getIndexField() {
return $this->creationSort ? 'user_id' : 'user_name';
@@ -74,13 +77,16 @@ class UsersPager extends AlphabeticPager {
$dbr = wfGetDB( DB_SLAVE );
$conds = array();
// Don't show hidden names
- if( !$wgUser->isAllowed('hideuser') )
+ if( !$wgUser->isAllowed('hideuser') ) {
$conds[] = 'ipb_deleted IS NULL';
+ }
+
+ $options = array();
+
if( $this->requestedGroup != '' ) {
$conds['ug_group'] = $this->requestedGroup;
- $useIndex = '';
} else {
- $useIndex = $dbr->useIndexClause( $this->creationSort ? 'PRIMARY' : 'user_name');
+ //$options['USE INDEX'] = $this->creationSort ? 'PRIMARY' : 'user_name';
}
if( $this->requestedUser != '' ) {
# Sorted either by account creation or name
@@ -94,11 +100,10 @@ class UsersPager extends AlphabeticPager {
$conds[] = 'user_editcount > 0';
}
- list ($user,$user_groups,$ipblocks) = $dbr->tableNamesN('user','user_groups','ipblocks');
+ $options['GROUP BY'] = $this->creationSort ? 'user_id' : 'user_name';
$query = array(
- 'tables' => " $user $useIndex LEFT JOIN $user_groups ON user_id=ug_user
- LEFT JOIN $ipblocks ON user_id=ipb_user AND ipb_deleted=1 AND ipb_auto=0 ",
+ 'tables' => array( 'user', 'user_groups', 'ipblocks'),
'fields' => array(
$this->creationSort ? 'MAX(user_name) AS user_name' : 'user_name',
$this->creationSort ? 'user_id' : 'MAX(user_id) AS user_id',
@@ -108,7 +113,11 @@ class UsersPager extends AlphabeticPager {
'MIN(user_registration) AS creation',
'MAX(ipb_deleted) AS ipb_deleted' // block/hide status
),
- 'options' => array('GROUP BY' => $this->creationSort ? 'user_id' : 'user_name'),
+ 'options' => $options,
+ 'join_conds' => array(
+ 'user_groups' => array( 'LEFT JOIN', 'user_id=ug_user' ),
+ 'ipblocks' => array( 'LEFT JOIN', 'user_id=ipb_user AND ipb_deleted=1 AND ipb_auto=0' ),
+ ),
'conds' => $conds
);
@@ -123,7 +132,7 @@ class UsersPager extends AlphabeticPager {
return '';
$userPage = Title::makeTitle( NS_USER, $row->user_name );
- $name = $this->getSkin()->link( $userPage, htmlspecialchars( $userPage->getText() ) );
+ $name = Linker::link( $userPage, htmlspecialchars( $userPage->getText() ) );
$groups_list = self::getGroups( $row->user_id );
if( count( $groups_list ) > 0 ) {
@@ -247,7 +256,7 @@ class UsersPager extends AlphabeticPager {
*/
protected static function getGroups( $uid ) {
$user = User::newFromId( $uid );
- $groups = array_diff( $user->getEffectiveGroups(), $user->getImplicitGroups() );
+ $groups = array_diff( $user->getEffectiveGroups(), User::getImplicitGroups() );
return $groups;
}
@@ -266,25 +275,42 @@ class UsersPager extends AlphabeticPager {
}
/**
- * constructor
- * $par string (optional) A group to list users from
+ * @ingroup SpecialPage
*/
-function wfSpecialListusers( $par = null ) {
- global $wgOut;
-
- $up = new UsersPager($par);
-
- # getBody() first to check, if empty
- $usersbody = $up->getBody();
- $s = Xml::openElement( 'div', array('class' => 'mw-spcontent') );
- $s .= $up->getPageHeader();
- if( $usersbody ) {
- $s .= $up->getNavigationBar();
- $s .= '<ul>' . $usersbody . '</ul>';
- $s .= $up->getNavigationBar() ;
- } else {
- $s .= '<p>' . wfMsgHTML('listusers-noresult') . '</p>';
- };
- $s .= Xml::closeElement( 'div' );
- $wgOut->addHTML( $s );
+class SpecialListUsers extends SpecialPage {
+
+ /**
+ * Constructor
+ */
+ public function __construct() {
+ parent::__construct( 'Listusers' );
+ }
+
+ /**
+ * Show the special page
+ *
+ * @param $par string (optional) A group to list users from
+ */
+ public function execute( $par ) {
+ global $wgOut;
+
+ $this->setHeaders();
+ $this->outputHeader();
+
+ $up = new UsersPager( $par );
+
+ # getBody() first to check, if empty
+ $usersbody = $up->getBody();
+
+ $s = $up->getPageHeader();
+ if( $usersbody ) {
+ $s .= $up->getNavigationBar();
+ $s .= Html::rawElement( 'ul', array(), $usersbody );
+ $s .= $up->getNavigationBar();
+ } else {
+ $s .= wfMessage( 'listusers-noresult' )->parseAsBlock();
+ }
+
+ $wgOut->addHTML( $s );
+ }
}
diff --git a/includes/specials/SpecialLockdb.php b/includes/specials/SpecialLockdb.php
index aad3cea4..5c861b31 100644
--- a/includes/specials/SpecialLockdb.php
+++ b/includes/specials/SpecialLockdb.php
@@ -34,12 +34,13 @@ class SpecialLockdb extends SpecialPage {
}
public function execute( $par ) {
- global $wgUser, $wgOut, $wgRequest;
+ global $wgUser, $wgRequest;
$this->setHeaders();
- if( !$wgUser->isAllowed( 'siteadmin' ) ) {
- $wgOut->permissionRequired( 'siteadmin' );
+ # Permission check
+ if( !$this->userCanExecute( $wgUser ) ) {
+ $this->displayRestrictionError();
return;
}
@@ -57,7 +58,7 @@ class SpecialLockdb extends SpecialPage {
if ( $action == 'success' ) {
$this->showSuccess();
- } else if ( $action == 'submit' && $wgRequest->wasPosted() &&
+ } elseif ( $action == 'submit' && $wgRequest->wasPosted() &&
$wgUser->matchEditToken( $wgRequest->getVal( 'wpEditToken' ) ) ) {
$this->doSubmit();
} else {
@@ -109,7 +110,10 @@ class SpecialLockdb extends SpecialPage {
$this->showForm( wfMsg( 'locknoconfirm' ) );
return;
}
- $fp = @fopen( $wgReadOnlyFile, 'w' );
+
+ wfSuppressWarnings();
+ $fp = fopen( $wgReadOnlyFile, 'w' );
+ wfRestoreWarnings();
if ( false === $fp ) {
# This used to show a file not found error, but the likeliest reason for fopen()
@@ -119,8 +123,14 @@ class SpecialLockdb extends SpecialPage {
return;
}
fwrite( $fp, $this->reason );
- fwrite( $fp, "\n<p>(by " . $wgUser->getName() . " at " .
- $wgContLang->timeanddate( wfTimestampNow() ) . ")</p>\n" );
+ $timestamp = wfTimestampNow();
+ fwrite( $fp, "\n<p>" . wfMsgExt(
+ 'lockedbyandtime',
+ array( 'content', 'parsemag' ),
+ $wgUser->getName(),
+ $wgContLang->date( $timestamp ),
+ $wgContLang->time( $timestamp )
+ ) . "</p>\n" );
fclose( $fp );
$wgOut->redirect( $this->getTitle()->getFullURL( 'action=success' ) );
diff --git a/includes/specials/SpecialLog.php b/includes/specials/SpecialLog.php
index a2af8de5..d8f6d8cf 100644
--- a/includes/specials/SpecialLog.php
+++ b/includes/specials/SpecialLog.php
@@ -95,10 +95,10 @@ class SpecialLog extends SpecialPage {
}
private function show( FormOptions $opts, array $extraConds ) {
- global $wgOut, $wgUser;
+ global $wgOut;
# Create a LogPager item to get the results and a LogEventsList item to format them...
- $loglist = new LogEventsList( $wgUser->getSkin(), $wgOut, 0 );
+ $loglist = new LogEventsList( $this->getSkin(), $wgOut, 0 );
$pager = new LogPager( $loglist, $opts->getValue( 'type' ), $opts->getValue( 'user' ),
$opts->getValue( 'page' ), $opts->getValue( 'pattern' ), $extraConds, $opts->getValue( 'year' ),
$opts->getValue( 'month' ), $opts->getValue( 'tagfilter' ) );
@@ -106,6 +106,11 @@ class SpecialLog extends SpecialPage {
# Set title and add header
$loglist->showHeader( $pager->getType() );
+ # Set relevant user
+ if ( $pager->getUser() ) {
+ $this->getSkin()->setRelevantUser( User::newFromName( $pager->getUser() ) );
+ }
+
# Show form options
$loglist->showOptions( $pager->getType(), $pager->getUser(), $pager->getPage(), $pager->getPattern(),
$pager->getYear(), $pager->getMonth(), $pager->getFilterParams(), $opts->getValue( 'tagfilter' ) );
diff --git a/includes/specials/SpecialLonelypages.php b/includes/specials/SpecialLonelypages.php
index 0788037f..0800e43c 100644
--- a/includes/specials/SpecialLonelypages.php
+++ b/includes/specials/SpecialLonelypages.php
@@ -29,9 +29,10 @@
*/
class LonelyPagesPage extends PageQueryPage {
- function getName() {
- return "Lonelypages";
+ function __construct( $name = 'Lonelypages' ) {
+ parent::__construct( $name );
}
+
function getPageHeader() {
return wfMsgExt( 'lonelypagestext', array( 'parse' ) );
}
@@ -45,35 +46,36 @@ class LonelyPagesPage extends PageQueryPage {
}
function isSyndicated() { return false; }
- function getSQL() {
- $dbr = wfGetDB( DB_SLAVE );
- list( $page, $pagelinks, $templatelinks ) = $dbr->tableNamesN( 'page', 'pagelinks', 'templatelinks' );
-
- return
- "SELECT 'Lonelypages' AS type,
- page_namespace AS namespace,
- page_title AS title,
- page_title AS value
- FROM $page
- LEFT JOIN $pagelinks
- ON page_namespace=pl_namespace AND page_title=pl_title
- LEFT JOIN $templatelinks
- ON page_namespace=tl_namespace AND page_title=tl_title
- WHERE pl_namespace IS NULL
- AND page_namespace=".NS_MAIN."
- AND page_is_redirect=0
- AND tl_namespace IS NULL";
-
+ function getQueryInfo() {
+ return array (
+ 'tables' => array ( 'page', 'pagelinks',
+ 'templatelinks' ),
+ 'fields' => array ( 'page_namespace AS namespace',
+ 'page_title AS title',
+ 'page_title AS value' ),
+ 'conds' => array ( 'pl_namespace IS NULL',
+ 'page_namespace' => MWNamespace::getContentNamespaces(),
+ 'page_is_redirect' => 0,
+ 'tl_namespace IS NULL' ),
+ 'join_conds' => array (
+ 'pagelinks' => array (
+ 'LEFT JOIN', array (
+ 'pl_namespace = page_namespace',
+ 'pl_title = page_title' ) ),
+ 'templatelinks' => array (
+ 'LEFT JOIN', array (
+ 'tl_namespace = page_namespace',
+ 'tl_title = page_title' ) ) )
+ );
}
-}
-/**
- * Constructor
- */
-function wfSpecialLonelypages() {
- list( $limit, $offset ) = wfCheckLimits();
-
- $lpp = new LonelyPagesPage();
-
- return $lpp->doQuery( $offset, $limit );
+ function getOrderFields() {
+ // For some crazy reason ordering by a constant
+ // causes a filesort in MySQL 5
+ if( count( MWNamespace::getContentNamespaces() ) > 1 ) {
+ return array( 'page_namespace', 'page_title' );
+ } else {
+ return array( 'page_title' );
+ }
+ }
}
diff --git a/includes/specials/SpecialLongpages.php b/includes/specials/SpecialLongpages.php
index cd0f3090..dd60e37d 100644
--- a/includes/specials/SpecialLongpages.php
+++ b/includes/specials/SpecialLongpages.php
@@ -27,22 +27,11 @@
*/
class LongPagesPage extends ShortPagesPage {
- function getName() {
- return "Longpages";
+ function __construct( $name = 'Longpages' ) {
+ parent::__construct( $name );
}
function sortDescending() {
return true;
}
}
-
-/**
- * constructor
- */
-function wfSpecialLongpages() {
- list( $limit, $offset ) = wfCheckLimits();
-
- $lpp = new LongPagesPage();
-
- $lpp->doQuery( $offset, $limit );
-}
diff --git a/includes/specials/SpecialMIMEsearch.php b/includes/specials/SpecialMIMEsearch.php
index 79683a35..aefe7bf5 100644
--- a/includes/specials/SpecialMIMEsearch.php
+++ b/includes/specials/SpecialMIMEsearch.php
@@ -28,50 +28,62 @@
* @ingroup SpecialPage
*/
class MIMEsearchPage extends QueryPage {
- var $major, $minor;
+ protected $major, $minor;
- function __construct( $major, $minor ) {
- $this->major = $major;
- $this->minor = $minor;
+ function __construct( $name = 'MIMEsearch' ) {
+ parent::__construct( $name );
}
- function getName() { return 'MIMEsearch'; }
-
- /**
- * Due to this page relying upon extra fields being passed in the SELECT it
- * will fail if it's set as expensive and misermode is on
- */
function isExpensive() { return true; }
function isSyndicated() { return false; }
+ function isCacheable() { return false; }
function linkParameters() {
- $arr = array( $this->major, $this->minor );
- $mime = implode( '/', $arr );
- return array( 'mime' => $mime );
+ return array( 'mime' => "{$this->major}/{$this->minor}" );
}
- function getSQL() {
- $dbr = wfGetDB( DB_SLAVE );
- $image = $dbr->tableName( 'image' );
- $major = $dbr->addQuotes( $this->major );
- $minor = $dbr->addQuotes( $this->minor );
+ public function getQueryInfo() {
+ return array(
+ 'tables' => array( 'image' ),
+ 'fields' => array( "'" . NS_FILE . "' AS namespace",
+ 'img_name AS title',
+ 'img_major_mime AS value',
+ 'img_size',
+ 'img_width',
+ 'img_height',
+ 'img_user_text',
+ 'img_timestamp' ),
+ 'conds' => array( 'img_major_mime' => $this->major,
+ 'img_minor_mime' => $this->minor )
+ );
+ }
- return
- "SELECT 'MIMEsearch' AS type,
- " . NS_FILE . " AS namespace,
- img_name AS title,
- img_major_mime AS value,
+ function execute( $par ) {
+ global $wgRequest, $wgOut;
+ $mime = $par ? $par : $wgRequest->getText( 'mime' );
+
+ $this->setHeaders();
+ $this->outputHeader();
+ $wgOut->addHTML(
+ Xml::openElement( 'form', array( 'id' => 'specialmimesearch', 'method' => 'get', 'action' => SpecialPage::getTitleFor( 'MIMEsearch' )->getLocalUrl() ) ) .
+ Xml::openElement( 'fieldset' ) .
+ Html::hidden( 'title', SpecialPage::getTitleFor( 'MIMEsearch' )->getPrefixedText() ) .
+ Xml::element( 'legend', null, wfMsg( 'mimesearch' ) ) .
+ Xml::inputLabel( wfMsg( 'mimetype' ), 'mime', 'mime', 20, $mime ) . ' ' .
+ Xml::submitButton( wfMsg( 'ilsubmit' ) ) .
+ Xml::closeElement( 'fieldset' ) .
+ Xml::closeElement( 'form' )
+ );
- img_size,
- img_width,
- img_height,
- img_user_text,
- img_timestamp
- FROM $image
- WHERE img_major_mime = $major AND img_minor_mime = $minor
- ";
+ list( $this->major, $this->minor ) = File::splitMime( $mime );
+ if ( $this->major == '' || $this->minor == '' || $this->minor == 'unknown' ||
+ !self::isValidType( $this->major ) ) {
+ return;
+ }
+ parent::execute( $par );
}
+
function formatResult( $skin, $result ) {
global $wgContLang, $wgLang;
@@ -83,7 +95,7 @@ class MIMEsearchPage extends QueryPage {
);
$download = $skin->makeMediaLinkObj( $nt, wfMsgHtml( 'download' ) );
- $bytes = wfMsgExt( 'nbytes', array( 'parsemag', 'escape'),
+ $bytes = wfMsgExt( 'nbytes', array( 'parsemag', 'escape' ),
$wgLang->formatNum( $result->img_size ) );
$dimensions = htmlspecialchars( wfMsg( 'widthheight',
$wgLang->formatNum( $result->img_width ),
@@ -94,63 +106,24 @@ class MIMEsearchPage extends QueryPage {
return "($download) $plink . . $dimensions . . $bytes . . $user . . $time";
}
-}
-
-/**
- * Output the HTML search form, and constructs the MIMEsearchPage object.
- */
-function wfSpecialMIMEsearch( $par = null ) {
- global $wgRequest, $wgOut;
-
- $mime = isset( $par ) ? $par : $wgRequest->getText( 'mime' );
- $wgOut->addHTML(
- Xml::openElement( 'form', array( 'id' => 'specialmimesearch', 'method' => 'get', 'action' => SpecialPage::getTitleFor( 'MIMEsearch' )->getLocalUrl() ) ) .
- Xml::openElement( 'fieldset' ) .
- Html::hidden( 'title', SpecialPage::getTitleFor( 'MIMEsearch' )->getPrefixedText() ) .
- Xml::element( 'legend', null, wfMsg( 'mimesearch' ) ) .
- Xml::inputLabel( wfMsg( 'mimetype' ), 'mime', 'mime', 20, $mime ) . ' ' .
- Xml::submitButton( wfMsg( 'ilsubmit' ) ) .
- Xml::closeElement( 'fieldset' ) .
- Xml::closeElement( 'form' )
- );
-
- list( $major, $minor ) = wfSpecialMIMEsearchParse( $mime );
- if ( $major == '' or $minor == '' or !wfSpecialMIMEsearchValidType( $major ) )
- return;
- $wpp = new MIMEsearchPage( $major, $minor );
-
- list( $limit, $offset ) = wfCheckLimits();
- $wpp->doQuery( $offset, $limit );
-}
-
-function wfSpecialMIMEsearchParse( $str ) {
- // searched for an invalid MIME type.
- if( strpos( $str, '/' ) === false) {
- return array ('', '');
+ /**
+ * @param $type string
+ * @return bool
+ */
+ protected static function isValidType( $type ) {
+ // From maintenance/tables.sql => img_major_mime
+ $types = array(
+ 'unknown',
+ 'application',
+ 'audio',
+ 'image',
+ 'text',
+ 'video',
+ 'message',
+ 'model',
+ 'multipart'
+ );
+ return in_array( $type, $types );
}
-
- list( $major, $minor ) = explode( '/', $str, 2 );
-
- return array(
- ltrim( $major, ' ' ),
- rtrim( $minor, ' ' )
- );
-}
-
-function wfSpecialMIMEsearchValidType( $type ) {
- // From maintenance/tables.sql => img_major_mime
- $types = array(
- 'unknown',
- 'application',
- 'audio',
- 'image',
- 'text',
- 'video',
- 'message',
- 'model',
- 'multipart'
- );
-
- return in_array( $type, $types );
}
diff --git a/includes/specials/SpecialMergeHistory.php b/includes/specials/SpecialMergeHistory.php
index 43b4ef6a..88e90ee5 100644
--- a/includes/specials/SpecialMergeHistory.php
+++ b/includes/specials/SpecialMergeHistory.php
@@ -29,14 +29,23 @@
*/
class SpecialMergeHistory extends SpecialPage {
var $mAction, $mTarget, $mDest, $mTimestamp, $mTargetID, $mDestID, $mComment;
+
+ /**
+ * @var Title
+ */
var $mTargetObj, $mDestObj;
public function __construct() {
parent::__construct( 'MergeHistory', 'mergehistory' );
}
+ /**
+ * @param $request WebRequest
+ * @return void
+ */
private function loadRequestParams( $request ) {
global $wgUser;
+
$this->mAction = $request->getVal( 'action' );
$this->mTarget = $request->getVal( 'target' );
$this->mDest = $request->getVal( 'dest' );
@@ -45,7 +54,7 @@ class SpecialMergeHistory extends SpecialPage {
$this->mTargetID = intval( $request->getVal( 'targetID' ) );
$this->mDestID = intval( $request->getVal( 'destID' ) );
$this->mTimestamp = $request->getVal( 'mergepoint' );
- if( !preg_match("/[0-9]{14}/",$this->mTimestamp) ) {
+ if( !preg_match( '/[0-9]{14}/', $this->mTimestamp ) ) {
$this->mTimestamp = '';
}
$this->mComment = $request->getText( 'wpComment' );
@@ -73,7 +82,7 @@ class SpecialMergeHistory extends SpecialPage {
}
}
- function execute( $par ) {
+ public function execute( $par ) {
global $wgOut, $wgRequest, $wgUser;
if ( wfReadOnly() ) {
@@ -91,7 +100,7 @@ class SpecialMergeHistory extends SpecialPage {
$this->setHeaders();
$this->outputHeader();
- if( $this->mTargetID && $this->mDestID && $this->mAction=="submit" && $this->mMerge ) {
+ if( $this->mTargetID && $this->mDestID && $this->mAction == 'submit' && $this->mMerge ) {
return $this->merge();
}
@@ -109,14 +118,14 @@ class SpecialMergeHistory extends SpecialPage {
);
}
- if ( !$this->mDestObj instanceof Title) {
+ if ( !$this->mDestObj instanceof Title ) {
$errors[] = wfMsgExt( 'mergehistory-invalid-destination', array( 'parse' ) );
} elseif( !$this->mDestObj->exists() ) {
$errors[] = wfMsgExt( 'mergehistory-no-destination', array( 'parse' ),
wfEscapeWikiText( $this->mDestObj->getPrefixedText() )
);
}
-
+
if ( $this->mTargetObj && $this->mDestObj && $this->mTargetObj->equals( $this->mDestObj ) ) {
$errors[] = wfMsgExt( 'mergehistory-same-destination', array( 'parse' ) );
}
@@ -146,37 +155,47 @@ class SpecialMergeHistory extends SpecialPage {
Html::hidden( 'submitted', '1' ) .
Html::hidden( 'mergepoint', $this->mTimestamp ) .
Xml::openElement( 'table' ) .
- "<tr>
- <td>".Xml::label( wfMsg( 'mergehistory-from' ), 'target' )."</td>
- <td>".Xml::input( 'target', 30, $this->mTarget, array('id'=>'target') )."</td>
+ '<tr>
+ <td>' . Xml::label( wfMsg( 'mergehistory-from' ), 'target' ) . '</td>
+ <td>' . Xml::input( 'target', 30, $this->mTarget, array( 'id' => 'target' ) ) . '</td>
</tr><tr>
- <td>".Xml::label( wfMsg( 'mergehistory-into' ), 'dest' )."</td>
- <td>".Xml::input( 'dest', 30, $this->mDest, array('id'=>'dest') )."</td>
- </tr><tr><td>" .
+ <td>' . Xml::label( wfMsg( 'mergehistory-into' ), 'dest' ) . '</td>
+ <td>' . Xml::input( 'dest', 30, $this->mDest, array( 'id' => 'dest' ) ) . '</td>
+ </tr><tr><td>' .
Xml::submitButton( wfMsg( 'mergehistory-go' ) ) .
- "</td></tr>" .
+ '</td></tr>' .
Xml::closeElement( 'table' ) .
'</fieldset>' .
- '</form>' );
+ '</form>'
+ );
}
private function showHistory() {
global $wgUser, $wgOut;
- $this->sk = $wgUser->getSkin();
+ $this->sk = $this->getSkin();
- $wgOut->setPagetitle( wfMsg( "mergehistory" ) );
+ $wgOut->setPageTitle( wfMsg( 'mergehistory' ) );
$this->showMergeForm();
# List all stored revisions
- $revisions = new MergeHistoryPager( $this, array(), $this->mTargetObj, $this->mDestObj );
+ $revisions = new MergeHistoryPager(
+ $this, array(), $this->mTargetObj, $this->mDestObj
+ );
$haveRevisions = $revisions && $revisions->getNumRows() > 0;
$titleObj = $this->getTitle();
$action = $titleObj->getLocalURL( array( 'action' => 'submit' ) );
# Start the form here
- $top = Xml::openElement( 'form', array( 'method' => 'post', 'action' => $action, 'id' => 'merge' ) );
+ $top = Xml::openElement(
+ 'form',
+ array(
+ 'method' => 'post',
+ 'action' => $action,
+ 'id' => 'merge'
+ )
+ );
$wgOut->addHTML( $top );
if( $haveRevisions ) {
@@ -184,43 +203,46 @@ class SpecialMergeHistory extends SpecialPage {
# in a nice little table
$table =
Xml::openElement( 'fieldset' ) .
- wfMsgExt( 'mergehistory-merge', array('parseinline'),
+ wfMsgExt( 'mergehistory-merge', array( 'parseinline' ),
$this->mTargetObj->getPrefixedText(), $this->mDestObj->getPrefixedText() ) .
Xml::openElement( 'table', array( 'id' => 'mw-mergehistory-table' ) ) .
- "<tr>
- <td class='mw-label'>" .
+ '<tr>
+ <td class="mw-label">' .
Xml::label( wfMsg( 'mergehistory-reason' ), 'wpComment' ) .
- "</td>
- <td class='mw-input'>" .
- Xml::input( 'wpComment', 50, $this->mComment, array('id' => 'wpComment') ) .
- "</td>
+ '</td>
+ <td class="mw-input">' .
+ Xml::input( 'wpComment', 50, $this->mComment, array( 'id' => 'wpComment' ) ) .
+ '</td>
</tr>
<tr>
<td>&#160;</td>
- <td class='mw-submit'>" .
+ <td class="mw-submit">' .
Xml::submitButton( wfMsg( 'mergehistory-submit' ), array( 'name' => 'merge', 'id' => 'mw-merge-submit' ) ) .
- "</td>
- </tr>" .
+ '</td>
+ </tr>' .
Xml::closeElement( 'table' ) .
Xml::closeElement( 'fieldset' );
$wgOut->addHTML( $table );
}
- $wgOut->addHTML( "<h2 id=\"mw-mergehistory\">" . wfMsgHtml( "mergehistory-list" ) . "</h2>\n" );
+ $wgOut->addHTML(
+ '<h2 id="mw-mergehistory">' .
+ wfMsgHtml( 'mergehistory-list' ) . "</h2>\n"
+ );
if( $haveRevisions ) {
$wgOut->addHTML( $revisions->getNavigationBar() );
- $wgOut->addHTML( "<ul>" );
+ $wgOut->addHTML( '<ul>' );
$wgOut->addHTML( $revisions->getBody() );
- $wgOut->addHTML( "</ul>" );
+ $wgOut->addHTML( '</ul>' );
$wgOut->addHTML( $revisions->getNavigationBar() );
} else {
- $wgOut->addWikiMsg( "mergehistory-empty" );
+ $wgOut->addWikiMsg( 'mergehistory-empty' );
}
# Show relevant lines from the deletion log:
- $wgOut->addHTML( "<h2>" . htmlspecialchars( LogPage::logName( 'merge' ) ) . "</h2>\n" );
+ $wgOut->addHTML( '<h2>' . htmlspecialchars( LogPage::logName( 'merge' ) ) . "</h2>\n" );
LogEventsList::showLogExtract( $wgOut, 'merge', $this->mTargetObj->getPrefixedText() );
# When we submit, go by page ID to avoid some nasty but unlikely collisions.
@@ -245,7 +267,7 @@ class SpecialMergeHistory extends SpecialPage {
$last = $this->message['last'];
$ts = wfTimestamp( TS_MW, $row->rev_timestamp );
- $checkBox = Xml::radio( "mergepoint", $ts, false );
+ $checkBox = Xml::radio( 'mergepoint', $ts, false );
$pageLink = $this->sk->linkKnown(
$rev->getTitle(),
@@ -258,9 +280,9 @@ class SpecialMergeHistory extends SpecialPage {
}
# Last link
- if( !$rev->userCan( Revision::DELETED_TEXT ) )
+ if( !$rev->userCan( Revision::DELETED_TEXT ) ) {
$last = $this->message['last'];
- else if( isset($this->prevId[$row->rev_id]) )
+ } elseif( isset( $this->prevId[$row->rev_id] ) ) {
$last = $this->sk->linkKnown(
$rev->getTitle(),
$this->message['last'],
@@ -270,10 +292,12 @@ class SpecialMergeHistory extends SpecialPage {
'oldid' => $this->prevId[$row->rev_id]
)
);
+ }
$userLink = $this->sk->revUserTools( $rev );
- if(!is_null($size = $row->rev_len)) {
+ $size = $row->rev_len;
+ if( !is_null( $size ) ) {
$stxt = $this->sk->formatRevisionSize( $size );
}
$comment = $this->sk->revComment( $rev );
@@ -288,8 +312,9 @@ class SpecialMergeHistory extends SpecialPage {
function getPageLink( $row, $titleObj, $ts, $target ) {
global $wgLang;
- if( !$this->userCan($row, Revision::DELETED_TEXT) ) {
- return '<span class="history-deleted">' . $wgLang->timeanddate( $ts, true ) . '</span>';
+ if( !$this->userCan( $row, Revision::DELETED_TEXT ) ) {
+ return '<span class="history-deleted">' .
+ $wgLang->timeanddate( $ts, true ) . '</span>';
} else {
$link = $this->sk->linkKnown(
$titleObj,
@@ -300,8 +325,9 @@ class SpecialMergeHistory extends SpecialPage {
'timestamp' => $ts
)
);
- if( $this->isDeleted($row, Revision::DELETED_TEXT) )
+ if( $this->isDeleted( $row, Revision::DELETED_TEXT ) ) {
$link = '<span class="history-deleted">' . $link . '</span>';
+ }
return $link;
}
}
@@ -313,63 +339,80 @@ class SpecialMergeHistory extends SpecialPage {
# keep it consistent...
$targetTitle = Title::newFromID( $this->mTargetID );
$destTitle = Title::newFromID( $this->mDestID );
- if( is_null($targetTitle) || is_null($destTitle) )
+ if( is_null( $targetTitle ) || is_null( $destTitle ) ) {
return false; // validate these
- if( $targetTitle->getArticleId() == $destTitle->getArticleId() )
+ }
+ if( $targetTitle->getArticleId() == $destTitle->getArticleId() ) {
return false;
+ }
# Verify that this timestamp is valid
# Must be older than the destination page
$dbw = wfGetDB( DB_MASTER );
# Get timestamp into DB format
- $this->mTimestamp = $this->mTimestamp ? $dbw->timestamp($this->mTimestamp) : '';
+ $this->mTimestamp = $this->mTimestamp ? $dbw->timestamp( $this->mTimestamp ) : '';
# Max timestamp should be min of destination page
- $maxtimestamp = $dbw->selectField( 'revision', 'MIN(rev_timestamp)',
- array('rev_page' => $this->mDestID ),
- __METHOD__ );
+ $maxtimestamp = $dbw->selectField(
+ 'revision',
+ 'MIN(rev_timestamp)',
+ array( 'rev_page' => $this->mDestID ),
+ __METHOD__
+ );
# Destination page must exist with revisions
if( !$maxtimestamp ) {
- $wgOut->addWikiMsg('mergehistory-fail');
+ $wgOut->addWikiMsg( 'mergehistory-fail' );
return false;
}
# Get the latest timestamp of the source
- $lasttimestamp = $dbw->selectField( array('page','revision'),
+ $lasttimestamp = $dbw->selectField(
+ array( 'page', 'revision' ),
'rev_timestamp',
- array('page_id' => $this->mTargetID, 'page_latest = rev_id' ),
- __METHOD__ );
+ array( 'page_id' => $this->mTargetID, 'page_latest = rev_id' ),
+ __METHOD__
+ );
# $this->mTimestamp must be older than $maxtimestamp
if( $this->mTimestamp >= $maxtimestamp ) {
- $wgOut->addWikiMsg('mergehistory-fail');
+ $wgOut->addWikiMsg( 'mergehistory-fail' );
return false;
}
# Update the revisions
if( $this->mTimestamp ) {
$timewhere = "rev_timestamp <= {$this->mTimestamp}";
- $TimestampLimit = wfTimestamp(TS_MW,$this->mTimestamp);
+ $timestampLimit = wfTimestamp( TS_MW, $this->mTimestamp );
} else {
$timewhere = "rev_timestamp <= {$maxtimestamp}";
- $TimestampLimit = wfTimestamp(TS_MW,$lasttimestamp);
+ $timestampLimit = wfTimestamp( TS_MW, $lasttimestamp );
}
# Do the moving...
- $dbw->update( 'revision',
+ $dbw->update(
+ 'revision',
array( 'rev_page' => $this->mDestID ),
- array( 'rev_page' => $this->mTargetID,
- $timewhere ),
- __METHOD__ );
+ array( 'rev_page' => $this->mTargetID, $timewhere ),
+ __METHOD__
+ );
$count = $dbw->affectedRows();
# Make the source page a redirect if no revisions are left
- $haveRevisions = $dbw->selectField( 'revision',
+ $haveRevisions = $dbw->selectField(
+ 'revision',
'rev_timestamp',
array( 'rev_page' => $this->mTargetID ),
__METHOD__,
- array( 'FOR UPDATE' ) );
+ array( 'FOR UPDATE' )
+ );
if( !$haveRevisions ) {
if( $this->mComment ) {
- $comment = wfMsgForContent( 'mergehistory-comment', $targetTitle->getPrefixedText(),
- $destTitle->getPrefixedText(), $this->mComment );
+ $comment = wfMsgForContent(
+ 'mergehistory-comment',
+ $targetTitle->getPrefixedText(),
+ $destTitle->getPrefixedText(),
+ $this->mComment
+ );
} else {
- $comment = wfMsgForContent( 'mergehistory-autocomment', $targetTitle->getPrefixedText(),
- $destTitle->getPrefixedText() );
+ $comment = wfMsgForContent(
+ 'mergehistory-autocomment',
+ $targetTitle->getPrefixedText(),
+ $destTitle->getPrefixedText()
+ );
}
$mwRedir = MagicWord::get( 'redirect' );
$redirectText = $mwRedir->getSynonym( 0 ) . ' [[' . $destTitle->getPrefixedText() . "]]\n";
@@ -389,22 +432,26 @@ class SpecialMergeHistory extends SpecialPage {
'pl_from' => $this->mDestID,
'pl_namespace' => $destTitle->getNamespace(),
'pl_title' => $destTitle->getDBkey() ),
- __METHOD__ );
+ __METHOD__
+ );
} else {
$targetTitle->invalidateCache(); // update histories
}
$destTitle->invalidateCache(); // update histories
# Check if this did anything
if( !$count ) {
- $wgOut->addWikiMsg('mergehistory-fail');
+ $wgOut->addWikiMsg( 'mergehistory-fail' );
return false;
}
# Update our logs
$log = new LogPage( 'merge' );
- $log->addEntry( 'merge', $targetTitle, $this->mComment,
- array($destTitle->getPrefixedText(),$TimestampLimit) );
+ $log->addEntry(
+ 'merge', $targetTitle, $this->mComment,
+ array( $destTitle->getPrefixedText(), $timestampLimit )
+ );
- $wgOut->addHTML( wfMsgExt( 'mergehistory-success', array('parseinline'),
+ $wgOut->addHTML(
+ wfMsgExt( 'mergehistory-success', array('parseinline'),
$targetTitle->getPrefixedText(), $destTitle->getPrefixedText(), $count ) );
wfRunHooks( 'ArticleMergeComplete', array( $targetTitle, $destTitle ) );
@@ -423,14 +470,21 @@ class MergeHistoryPager extends ReverseChronologicalPager {
$this->articleID = $source->getArticleID();
$dbr = wfGetDB( DB_SLAVE );
- $maxtimestamp = $dbr->selectField( 'revision', 'MIN(rev_timestamp)',
- array('rev_page' => $dest->getArticleID() ),
- __METHOD__ );
+ $maxtimestamp = $dbr->selectField(
+ 'revision',
+ 'MIN(rev_timestamp)',
+ array( 'rev_page' => $dest->getArticleID() ),
+ __METHOD__
+ );
$this->maxTimestamp = $maxtimestamp;
parent::__construct();
}
+ function getTitle() {
+ return SpecialPage::getTitleFor( 'Contributions' );
+ }
+
function getStartBody() {
wfProfileIn( __METHOD__ );
# Do a link batch query
@@ -442,11 +496,12 @@ class MergeHistoryPager extends ReverseChronologicalPager {
$batch->addObj( Title::makeTitleSafe( NS_USER, $row->rev_user_text ) );
$batch->addObj( Title::makeTitleSafe( NS_USER_TALK, $row->rev_user_text ) );
- $rev_id = isset($rev_id) ? $rev_id : $row->rev_id;
- if( $rev_id > $row->rev_id )
+ $rev_id = isset( $rev_id ) ? $rev_id : $row->rev_id;
+ if( $rev_id > $row->rev_id ) {
$this->mForm->prevId[$rev_id] = $row->rev_id;
- else if( $rev_id < $row->rev_id )
+ } elseif( $rev_id < $row->rev_id ) {
$this->mForm->prevId[$row->rev_id] = $rev_id;
+ }
$rev_id = $row->rev_id;
}
@@ -468,9 +523,12 @@ class MergeHistoryPager extends ReverseChronologicalPager {
$conds[] = 'page_id = rev_page';
$conds[] = "rev_timestamp < {$this->maxTimestamp}";
return array(
- 'tables' => array('revision','page'),
- 'fields' => array( 'rev_minor_edit', 'rev_timestamp', 'rev_user', 'rev_user_text', 'rev_comment',
- 'rev_id', 'rev_page', 'rev_parent_id', 'rev_text_id', 'rev_len', 'rev_deleted' ),
+ 'tables' => array( 'revision', 'page' ),
+ 'fields' => array(
+ 'rev_minor_edit', 'rev_timestamp', 'rev_user', 'rev_user_text',
+ 'rev_comment', 'rev_id', 'rev_page', 'rev_parent_id',
+ 'rev_text_id', 'rev_len', 'rev_deleted'
+ ),
'conds' => $conds
);
}
diff --git a/includes/specials/SpecialMostcategories.php b/includes/specials/SpecialMostcategories.php
index 124f0bd5..2e437196 100644
--- a/includes/specials/SpecialMostcategories.php
+++ b/includes/specials/SpecialMostcategories.php
@@ -31,28 +31,32 @@
*/
class MostcategoriesPage extends QueryPage {
- function getName() { return 'Mostcategories'; }
+ function __construct( $name = 'Mostcategories' ) {
+ parent::__construct( $name );
+ }
+
function isExpensive() { return true; }
function isSyndicated() { return false; }
- function getSQL() {
- $dbr = wfGetDB( DB_SLAVE );
- list( $categorylinks, $page) = $dbr->tableNamesN( 'categorylinks', 'page' );
- return
- "
- SELECT
- 'Mostcategories' as type,
- page_namespace as namespace,
- page_title as title,
- COUNT(*) as value
- FROM $categorylinks
- LEFT JOIN $page ON cl_from = page_id
- WHERE page_namespace = " . NS_MAIN . "
- GROUP BY page_namespace, page_title
- HAVING COUNT(*) > 1
- ";
+ function getQueryInfo() {
+ return array (
+ 'tables' => array ( 'categorylinks', 'page' ),
+ 'fields' => array ( 'page_namespace AS namespace',
+ 'page_title AS title',
+ 'COUNT(*) AS value' ),
+ 'conds' => array ( 'page_namespace' => MWNamespace::getContentNamespaces() ),
+ 'options' => array ( 'HAVING' => 'COUNT(*) > 1',
+ 'GROUP BY' => 'page_namespace, page_title' ),
+ 'join_conds' => array ( 'page' => array ( 'LEFT JOIN',
+ 'page_id = cl_from' ) )
+ );
}
+ /**
+ * @param $skin Skin
+ * @param $result
+ * @return string
+ */
function formatResult( $skin, $result ) {
global $wgLang;
$title = Title::makeTitleSafe( $result->namespace, $result->title );
@@ -62,14 +66,3 @@ class MostcategoriesPage extends QueryPage {
return wfSpecialList( $link, $count );
}
}
-
-/**
- * constructor
- */
-function wfSpecialMostcategories() {
- list( $limit, $offset ) = wfCheckLimits();
-
- $wpp = new MostcategoriesPage();
-
- $wpp->doQuery( $offset, $limit );
-}
diff --git a/includes/specials/SpecialMostimages.php b/includes/specials/SpecialMostimages.php
index 411a281b..ac2b5206 100644
--- a/includes/specials/SpecialMostimages.php
+++ b/includes/specials/SpecialMostimages.php
@@ -31,24 +31,22 @@
*/
class MostimagesPage extends ImageQueryPage {
- function getName() { return 'Mostimages'; }
+ function __construct( $name = 'Mostimages' ) {
+ parent::__construct( $name );
+ }
+
function isExpensive() { return true; }
function isSyndicated() { return false; }
- function getSQL() {
- $dbr = wfGetDB( DB_SLAVE );
- $imagelinks = $dbr->tableName( 'imagelinks' );
- return
- "
- SELECT
- 'Mostimages' as type,
- " . NS_FILE . " as namespace,
- il_to as title,
- COUNT(*) as value
- FROM $imagelinks
- GROUP BY il_to
- HAVING COUNT(*) > 1
- ";
+ function getQueryInfo() {
+ return array (
+ 'tables' => array ( 'imagelinks' ),
+ 'fields' => array ( "'" . NS_FILE . "' AS namespace",
+ 'il_to AS title',
+ 'COUNT(*) AS value' ),
+ 'options' => array ( 'GROUP BY' => 'il_to',
+ 'HAVING' => 'COUNT(*) > 1' )
+ );
}
function getCellHtml( $row ) {
@@ -58,14 +56,3 @@ class MostimagesPage extends ImageQueryPage {
}
}
-
-/**
- * Constructor
- */
-function wfSpecialMostimages() {
- list( $limit, $offset ) = wfCheckLimits();
-
- $wpp = new MostimagesPage();
-
- $wpp->doQuery( $offset, $limit );
-}
diff --git a/includes/specials/SpecialMostlinked.php b/includes/specials/SpecialMostlinked.php
index c731588a..58f686e8 100644
--- a/includes/specials/SpecialMostlinked.php
+++ b/includes/specials/SpecialMostlinked.php
@@ -32,43 +32,34 @@
*/
class MostlinkedPage extends QueryPage {
- function getName() { return 'Mostlinked'; }
+ function __construct( $name = 'Mostlinked' ) {
+ parent::__construct( $name );
+ }
+
function isExpensive() { return true; }
function isSyndicated() { return false; }
- function getSQL() {
- global $wgMiserMode;
-
- $dbr = wfGetDB( DB_SLAVE );
-
- # In miser mode, reduce the query cost by adding a threshold for large wikis
- if ( $wgMiserMode ) {
- $numPages = SiteStats::pages();
- if ( $numPages > 10000 ) {
- $cutoff = 100;
- } elseif ( $numPages > 100 ) {
- $cutoff = intval( sqrt( $numPages ) );
- } else {
- $cutoff = 1;
- }
- } else {
- $cutoff = 1;
- }
-
- list( $pagelinks, $page ) = $dbr->tableNamesN( 'pagelinks', 'page' );
- return
- "SELECT 'Mostlinked' AS type,
- pl_namespace AS namespace,
- pl_title AS title,
- COUNT(*) AS value
- FROM $pagelinks
- LEFT JOIN $page ON pl_namespace=page_namespace AND pl_title=page_title
- GROUP BY pl_namespace, pl_title
- HAVING COUNT(*) > $cutoff";
+ function getQueryInfo() {
+ return array (
+ 'tables' => array ( 'pagelinks', 'page' ),
+ 'fields' => array ( 'pl_namespace AS namespace',
+ 'pl_title AS title',
+ 'COUNT(*) AS value',
+ 'page_namespace' ),
+ 'options' => array ( 'HAVING' => 'COUNT(*) > 1',
+ 'GROUP BY' => 'pl_namespace, pl_title, '.
+ 'page_namespace' ),
+ 'join_conds' => array ( 'page' => array ( 'LEFT JOIN',
+ array ( 'page_namespace = pl_namespace',
+ 'page_title = pl_title' ) ) )
+ );
}
/**
* Pre-fill the link cache
+ *
+ * @param $db DatabaseBase
+ * @param $res
*/
function preprocessResults( $db, $res ) {
if( $db->numRows( $res ) > 0 ) {
@@ -114,14 +105,3 @@ class MostlinkedPage extends QueryPage {
return wfSpecialList( $link, $wlh );
}
}
-
-/**
- * constructor
- */
-function wfSpecialMostlinked() {
- list( $limit, $offset ) = wfCheckLimits();
-
- $wpp = new MostlinkedPage();
-
- $wpp->doQuery( $offset, $limit );
-}
diff --git a/includes/specials/SpecialMostlinkedcategories.php b/includes/specials/SpecialMostlinkedcategories.php
index e1fc1d95..195282f7 100644
--- a/includes/specials/SpecialMostlinkedcategories.php
+++ b/includes/specials/SpecialMostlinkedcategories.php
@@ -31,65 +31,60 @@
*/
class MostlinkedCategoriesPage extends QueryPage {
- function getName() { return 'Mostlinkedcategories'; }
+ function __construct( $name = 'Mostlinkedcategories' ) {
+ parent::__construct( $name );
+ }
+
function isExpensive() { return true; }
function isSyndicated() { return false; }
- function getSQL() {
- $dbr = wfGetDB( DB_SLAVE );
- $categorylinks = $dbr->tableName( 'categorylinks' );
- $name = $dbr->addQuotes( $this->getName() );
- return
- "
- SELECT
- $name as type,
- " . NS_CATEGORY . " as namespace,
- cl_to as title,
- COUNT(*) as value
- FROM $categorylinks
- GROUP BY cl_to
- ";
+ function getQueryInfo() {
+ return array (
+ 'tables' => array ( 'categorylinks' ),
+ 'fields' => array ( 'cl_to AS title',
+ NS_CATEGORY . ' AS namespace',
+ 'COUNT(*) AS value' ),
+ 'options' => array ( 'GROUP BY' => 'cl_to' )
+ );
}
function sortDescending() { return true; }
/**
* Fetch user page links and cache their existence
+ *
+ * @param $db DatabaseBase
+ * @param $res DatabaseResult
*/
function preprocessResults( $db, $res ) {
$batch = new LinkBatch;
foreach ( $res as $row ) {
- $batch->add( $row->namespace, $row->title );
+ $batch->add( NS_CATEGORY, $row->title );
}
$batch->execute();
// Back to start for display
- if ( $db->numRows( $res ) > 0 )
+ if ( $db->numRows( $res ) > 0 ) {
// If there are no rows we get an error seeking.
$db->dataSeek( $res, 0 );
+ }
}
+ /**
+ * @param $skin Skin
+ * @param $result
+ * @return string
+ */
function formatResult( $skin, $result ) {
global $wgLang, $wgContLang;
- $nt = Title::makeTitle( $result->namespace, $result->title );
+ $nt = Title::makeTitle( NS_CATEGORY, $result->title );
$text = $wgContLang->convert( $nt->getText() );
$plink = $skin->link( $nt, htmlspecialchars( $text ) );
- $nlinks = wfMsgExt( 'nmembers', array( 'parsemag', 'escape'),
+ $nlinks = wfMsgExt( 'nmembers', array( 'parsemag', 'escape' ),
$wgLang->formatNum( $result->value ) );
- return wfSpecialList($plink, $nlinks);
+ return wfSpecialList( $plink, $nlinks );
}
}
-
-/**
- * constructor
- */
-function wfSpecialMostlinkedCategories() {
- list( $limit, $offset ) = wfCheckLimits();
-
- $wpp = new MostlinkedCategoriesPage();
-
- $wpp->doQuery( $offset, $limit );
-}
diff --git a/includes/specials/SpecialMostlinkedtemplates.php b/includes/specials/SpecialMostlinkedtemplates.php
index 822d6bc9..69771925 100644
--- a/includes/specials/SpecialMostlinkedtemplates.php
+++ b/includes/specials/SpecialMostlinkedtemplates.php
@@ -21,22 +21,17 @@
* @ingroup SpecialPage
* @author Rob Church <robchur@gmail.com>
*/
-
+
/**
* Special page lists templates with a large number of
* transclusion links, i.e. "most used" templates
*
* @ingroup SpecialPage
*/
-class SpecialMostlinkedtemplates extends QueryPage {
+class MostlinkedTemplatesPage extends QueryPage {
- /**
- * Name of the report
- *
- * @return String
- */
- public function getName() {
- return 'Mostlinkedtemplates';
+ function __construct( $name = 'Mostlinkedtemplates' ) {
+ parent::__construct( $name );
}
/**
@@ -66,22 +61,15 @@ class SpecialMostlinkedtemplates extends QueryPage {
return true;
}
- /**
- * Generate SQL for the report
- *
- * @return String
- */
- public function getSql() {
- $dbr = wfGetDB( DB_SLAVE );
- $templatelinks = $dbr->tableName( 'templatelinks' );
- $name = $dbr->addQuotes( $this->getName() );
- return "SELECT {$name} AS type,
- " . NS_TEMPLATE . " AS namespace,
- tl_title AS title,
- COUNT(*) AS value
- FROM {$templatelinks}
- WHERE tl_namespace = " . NS_TEMPLATE . "
- GROUP BY tl_title";
+ public function getQueryInfo() {
+ return array (
+ 'tables' => array ( 'templatelinks' ),
+ 'fields' => array ( 'tl_namespace AS namespace',
+ 'tl_title AS title',
+ 'COUNT(*) AS value' ),
+ 'conds' => array ( 'tl_namespace' => NS_TEMPLATE ),
+ 'options' => array( 'GROUP BY' => 'tl_namespace, tl_title' )
+ );
}
/**
@@ -108,7 +96,7 @@ class SpecialMostlinkedtemplates extends QueryPage {
* @return String
*/
public function formatResult( $skin, $result ) {
- $title = Title::makeTitleSafe( $result->namespace, $result->title );
+ $title = Title::makeTitle( $result->namespace, $result->title );
return wfSpecialList(
$skin->link( $title ),
@@ -133,13 +121,3 @@ class SpecialMostlinkedtemplates extends QueryPage {
}
}
-/**
- * Execution function
- *
- * @param $par Mixed: parameters passed to the page
- */
-function wfSpecialMostlinkedtemplates( $par = false ) {
- list( $limit, $offset ) = wfCheckLimits();
- $mlt = new SpecialMostlinkedtemplates();
- $mlt->doQuery( $offset, $limit );
-}
diff --git a/includes/specials/SpecialMostrevisions.php b/includes/specials/SpecialMostrevisions.php
index f9bafabc..b0253316 100644
--- a/includes/specials/SpecialMostrevisions.php
+++ b/includes/specials/SpecialMostrevisions.php
@@ -23,64 +23,12 @@
* @ingroup SpecialPage
* @author Ævar Arnfjörð Bjarmason <avarab@gmail.com>
*/
-
-/**
- * A special page to show pages with highest revision count
- *
- * @ingroup SpecialPage
- */
-class MostrevisionsPage extends QueryPage {
-
- function getName() { return 'Mostrevisions'; }
- function isExpensive() { return true; }
- function isSyndicated() { return false; }
-
- function getSQL() {
- $dbr = wfGetDB( DB_SLAVE );
- list( $revision, $page ) = $dbr->tableNamesN( 'revision', 'page' );
- return
- "
- SELECT
- 'Mostrevisions' as type,
- page_namespace as namespace,
- page_title as title,
- COUNT(*) as value
- FROM $revision
- JOIN $page ON page_id = rev_page
- WHERE page_namespace = " . NS_MAIN . "
- GROUP BY page_namespace, page_title
- HAVING COUNT(*) > 1
- ";
+class MostrevisionsPage extends FewestrevisionsPage {
+ function __construct( $name = 'Mostrevisions' ) {
+ parent::__construct( $name );
}
- function formatResult( $skin, $result ) {
- global $wgLang, $wgContLang;
-
- $nt = Title::makeTitle( $result->namespace, $result->title );
- $text = $wgContLang->convert( $nt->getPrefixedText() );
-
- $plink = $skin->linkKnown( $nt, $text );
-
- $nl = wfMsgExt( 'nrevisions', array( 'parsemag', 'escape'),
- $wgLang->formatNum( $result->value ) );
- $nlink = $skin->linkKnown(
- $nt,
- $nl,
- array(),
- array( 'action' => 'history' )
- );
-
- return wfSpecialList($plink, $nlink);
+ function sortDescending() {
+ return true;
}
}
-
-/**
- * constructor
- */
-function wfSpecialMostrevisions() {
- list( $limit, $offset ) = wfCheckLimits();
-
- $wpp = new MostrevisionsPage();
-
- $wpp->doQuery( $offset, $limit );
-}
diff --git a/includes/specials/SpecialMovepage.php b/includes/specials/SpecialMovepage.php
index 2f156c65..7ac7eba4 100644
--- a/includes/specials/SpecialMovepage.php
+++ b/includes/specials/SpecialMovepage.php
@@ -27,6 +27,10 @@
* @ingroup SpecialPage
*/
class MovePageForm extends UnlistedSpecialPage {
+
+ /**
+ * @var Title
+ */
var $oldTitle, $newTitle; # Objects
var $reason; # Text input
var $moveTalk, $deleteAndMove, $moveSubpages, $fixRedirects, $leaveRedirect, $moveOverShared; # Checks
@@ -70,7 +74,9 @@ class MovePageForm extends UnlistedSpecialPage {
# Check rights
$permErrors = $this->oldTitle->getUserPermissionsErrors( 'move', $wgUser );
if( !empty( $permErrors ) ) {
- $wgOut->showPermissionsErrorPage( $permErrors );
+ // Auto-block user's IP if the account was "hard" blocked
+ $user->spreadAnyEditBlock();
+ $this->getOutput()->showPermissionsErrorPage( $permErrors );
return;
}
@@ -103,12 +109,14 @@ class MovePageForm extends UnlistedSpecialPage {
function showForm( $err ) {
global $wgOut, $wgUser, $wgContLang, $wgFixDoubleRedirects;
- $skin = $wgUser->getSkin();
+ $skin = $this->getSkin();
$oldTitleLink = $skin->link( $this->oldTitle );
$wgOut->setPagetitle( wfMsg( 'move-page', $this->oldTitle->getPrefixedText() ) );
- $wgOut->setSubtitle( wfMsg( 'move-page-backlink', $oldTitleLink ) );
+ $skin->setRelevantTitle( $this->oldTitle );
+
+ $wgOut->addModules( 'mediawiki.special.movePage' );
$newTitle = $this->newTitle;
@@ -211,7 +219,7 @@ class MovePageForm extends UnlistedSpecialPage {
Xml::element( 'legend', null, wfMsg( 'move-page-legend' ) ) .
Xml::openElement( 'table', array( 'border' => '0', 'id' => 'mw-movepage-table' ) ) .
"<tr>
- <td class='mw-label'>" .
+ <td class='mw-label'>" .
wfMsgHtml( 'movearticle' ) .
"</td>
<td class='mw-input'>
@@ -233,7 +241,7 @@ class MovePageForm extends UnlistedSpecialPage {
"</td>
<td class='mw-input'>" .
Html::element( 'textarea', array( 'name' => 'wpReason', 'id' => 'wpReason', 'cols' => 60, 'rows' => 2,
- 'maxlength' => 200 ), $this->reason ) .
+ 'maxlength' => 200 ), $this->reason ) . // maxlength byte limit is enforce in mediawiki.special.movePage.js
"</td>
</tr>"
);
@@ -398,7 +406,7 @@ class MovePageForm extends UnlistedSpecialPage {
# Do the actual move.
$error = $ot->moveTo( $nt, true, $this->reason, $createRedirect );
if ( $error !== true ) {
- # FIXME: show all the errors in a list, not just the first one
+ # @todo FIXME: Show all the errors in a list, not just the first one
$this->showForm( reset( $error ) );
return;
}
@@ -407,7 +415,7 @@ class MovePageForm extends UnlistedSpecialPage {
DoubleRedirectJob::fixRedirects( 'move', $ot, $nt );
}
- wfRunHooks( 'SpecialMovepageAfterMove', array( &$this , &$ot , &$nt ) ) ;
+ wfRunHooks( 'SpecialMovepageAfterMove', array( &$this, &$ot, &$nt ) );
$wgOut->setPagetitle( wfMsg( 'pagemovedsub' ) );
@@ -442,10 +450,10 @@ class MovePageForm extends UnlistedSpecialPage {
#
# If the target namespace doesn't allow subpages, moving with subpages
# would mean that you couldn't move them back in one operation, which
- # is bad. FIXME: A specific error message should be given in this
- # case.
+ # is bad.
+ # @todo FIXME: A specific error message should be given in this case.
- // FIXME: Use Title::moveSubpages() here
+ // @todo FIXME: Use Title::moveSubpages() here
$dbr = wfGetDB( DB_MASTER );
if( $this->moveSubpages && (
MWNamespace::hasSubpages( $nt->getNamespace() ) || (
@@ -486,7 +494,7 @@ class MovePageForm extends UnlistedSpecialPage {
}
$extraOutput = array();
- $skin = $wgUser->getSkin();
+ $skin = $this->getSkin();
$count = 1;
foreach( $extraPages as $oldSubpage ) {
if( $ot->equals( $oldSubpage ) ) {
@@ -561,7 +569,7 @@ class MovePageForm extends UnlistedSpecialPage {
# Re-clear the file redirect cache, which may have been polluted by
# parsing in messages above. See CR r56745.
- # FIXME: needs a more robust solution inside FileRepo.
+ # @todo FIXME: Needs a more robust solution inside FileRepo.
if( $ot->getNamespace() == NS_FILE ) {
RepoGroup::singleton()->getLocalRepo()->invalidateImageRedirect( $ot );
}
@@ -573,7 +581,7 @@ class MovePageForm extends UnlistedSpecialPage {
}
function showSubpages( $title, $out ) {
- global $wgUser, $wgLang;
+ global $wgLang;
if( !MWNamespace::hasSubpages( $title->getNamespace() ) )
return;
@@ -590,7 +598,7 @@ class MovePageForm extends UnlistedSpecialPage {
}
$out->addWikiMsg( 'movesubpagetext', $wgLang->formatNum( $count ) );
- $skin = $wgUser->getSkin();
+ $skin = $this->getSkin();
$out->addHTML( "<ul>\n" );
foreach( $subpages as $subpage ) {
diff --git a/includes/specials/SpecialNewimages.php b/includes/specials/SpecialNewimages.php
index cecd7dfd..ea20c2f7 100644
--- a/includes/specials/SpecialNewimages.php
+++ b/includes/specials/SpecialNewimages.php
@@ -20,244 +20,152 @@
* @file
* @ingroup SpecialPage
*/
+class SpecialNewFiles extends IncludableSpecialPage {
-/**
- * @todo FIXME: this code is crap, should use Pager and Database::select().
- */
-function wfSpecialNewimages( $par, $specialPage ) {
- global $wgUser, $wgOut, $wgLang, $wgRequest, $wgMiserMode;
-
- $wpIlMatch = $wgRequest->getText( 'wpIlMatch' );
- $dbr = wfGetDB( DB_SLAVE );
- $sk = $wgUser->getSkin();
- $shownav = !$specialPage->including();
- $hidebots = $wgRequest->getBool( 'hidebots' , 1 );
+ public function __construct(){
+ parent::__construct( 'Newimages' );
+ }
- $hidebotsql = '';
- if ( $hidebots ) {
- # Make a list of group names which have the 'bot' flag set.
- $botconds = array();
- foreach ( User::getGroupsWithPermission('bot') as $groupname ) {
- $botconds[] = 'ug_group = ' . $dbr->addQuotes( $groupname );
- }
+ public function execute( $par ){
+ $this->setHeaders();
+ $this->outputHeader();
- # If not bot groups, do not set $hidebotsql
- if ( $botconds ) {
- $isbotmember = $dbr->makeList( $botconds, LIST_OR );
+ $pager = new NewFilesPager( $par );
- # This join, in conjunction with WHERE ug_group IS NULL, returns
- # only those rows from IMAGE where the uploading user is not a mem-
- # ber of a group which has the 'bot' permission set.
- $ug = $dbr->tableName( 'user_groups' );
- $hidebotsql = " LEFT JOIN $ug ON img_user=ug_user AND ($isbotmember)";
+ if ( !$this->including() ) {
+ $form = $pager->getForm();
+ $form->prepareForm();
+ $form->displayForm( '' );
+ }
+ $this->getOutput()->addHTML( $pager->getBody() );
+ if ( !$this->including() ) {
+ $this->getOutput()->addHTML( $pager->getNavigationBar() );
}
}
+}
- $image = $dbr->tableName( 'image' );
- $sql = "SELECT img_timestamp from $image";
- if ($hidebotsql) {
- $sql .= "$hidebotsql WHERE ug_group IS NULL";
- }
- $sql .= ' ORDER BY img_timestamp DESC';
- $sql = $dbr->limitResult($sql, 1, false);
- $res = $dbr->query( $sql, __FUNCTION__ );
- $row = $dbr->fetchRow( $res );
- if( $row !== false ) {
- $ts = $row[0];
- } else {
- $ts = false;
- }
+/**
+ * @ingroup SpecialPage Pager
+ */
+class NewFilesPager extends ReverseChronologicalPager {
- # If we were clever, we'd use this to cache.
- $latestTimestamp = wfTimestamp( TS_MW, $ts );
+ function __construct( $par = null ) {
+ global $wgRequest;
- # Hardcode this for now.
- $limit = 48;
- $parval = intval( $par );
- if ( $parval ) {
- if ( $parval <= $limit && $parval > 0 ) {
- $limit = $parval;
- }
- }
+ $this->like = $wgRequest->getText( 'like' );
+ $this->showbots = $wgRequest->getBool( 'showbots' , 0 );
+ $this->skin = $this->getSkin();
- $where = array();
- $searchpar = array();
- if ( $wpIlMatch != '' && !$wgMiserMode) {
- $nt = Title::newFromURL( $wpIlMatch );
- if( $nt ) {
- $where[] = 'LOWER(img_name) ' . $dbr->buildLike( $dbr->anyString(), strtolower( $nt->getDBkey() ), $dbr->anyString() );
- $searchpar['wpIlMatch'] = $wpIlMatch;
- }
+ parent::__construct();
}
- $invertSort = false;
- $until = $wgRequest->getVal( 'until' );
- if( $until ) {
- $where[] = "img_timestamp < '" . $dbr->timestamp( $until ) . "'";
+ function getTitle() {
+ return SpecialPage::getTitleFor( 'Newimages' );
}
- $from = $wgRequest->getVal( 'from' );
- if( $from ) {
- $where[] = "img_timestamp >= '" . $dbr->timestamp( $from ) . "'";
- $invertSort = true;
- }
- $sql = 'SELECT img_size, img_name, img_user, img_user_text,'.
- "img_description,img_timestamp FROM $image";
- if( $hidebotsql ) {
- $sql .= $hidebotsql;
- $where[] = 'ug_group IS NULL';
- }
- if( count( $where ) ) {
- $sql .= ' WHERE ' . $dbr->makeList( $where, LIST_AND );
- }
- $sql.=' ORDER BY img_timestamp '. ( $invertSort ? '' : ' DESC' );
- $sql = $dbr->limitResult($sql, ( $limit + 1 ), false);
- $res = $dbr->query( $sql, __FUNCTION__ );
+ function getQueryInfo() {
+ global $wgMiserMode;
+ $conds = $jconds = array();
+ $tables = array( 'image' );
- /**
- * We have to flip things around to get the last N after a certain date
- */
- $images = array();
- foreach ( $res as $s ) {
- if( $invertSort ) {
- array_unshift( $images, $s );
- } else {
- array_push( $images, $s );
+ if( !$this->showbots ) {
+ $tables[] = 'user_groups';
+ $conds[] = 'ug_group IS NULL';
+ $jconds['user_groups'] = array(
+ 'LEFT JOIN',
+ array(
+ 'ug_group' => User::getGroupsWithPermission( 'bot' ),
+ 'ug_user = img_user'
+ )
+ );
}
- }
- $gallery = new ImageGallery();
- $firstTimestamp = null;
- $lastTimestamp = null;
- $shownImages = 0;
- foreach( $images as $s ) {
- $shownImages++;
- if( $shownImages > $limit ) {
- # One extra just to test for whether to show a page link;
- # don't actually show it.
- break;
+ if( !$wgMiserMode && $this->like !== null ){
+ $dbr = wfGetDB( DB_SLAVE );
+ $likeObj = Title::newFromURL( $this->like );
+ if( $likeObj instanceof Title ){
+ $like = $dbr->buildLike( $dbr->anyString(), strtolower( $likeObj->getDBkey() ), $dbr->anyString() );
+ $conds[] = "LOWER(img_name) $like";
+ }
}
- $name = $s->img_name;
- $ut = $s->img_user_text;
-
- $nt = Title::newFromText( $name, NS_FILE );
- $ul = $sk->link( Title::makeTitle( NS_USER, $ut ), $ut );
-
- $gallery->add( $nt, "$ul<br />\n<i>".htmlspecialchars($wgLang->timeanddate( $s->img_timestamp, true ))."</i><br />\n" );
+ $query = array(
+ 'tables' => $tables,
+ 'fields' => '*',
+ 'join_conds' => $jconds,
+ 'conds' => $conds
+ );
- $timestamp = wfTimestamp( TS_MW, $s->img_timestamp );
- if( empty( $firstTimestamp ) ) {
- $firstTimestamp = $timestamp;
- }
- $lastTimestamp = $timestamp;
+ return $query;
}
- $titleObj = SpecialPage::getTitleFor( 'Newimages' );
- $action = $titleObj->getLocalURL( $hidebots ? '' : 'hidebots=0' );
- if ( $shownav && !$wgMiserMode ) {
- $wgOut->addHTML(
- Xml::openElement( 'form', array( 'action' => $action, 'method' => 'post', 'id' => 'imagesearch' ) ) .
- Xml::fieldset( wfMsg( 'newimages-legend' ) ) .
- Xml::inputLabel( wfMsg( 'newimages-label' ), 'wpIlMatch', 'wpIlMatch', 20, $wpIlMatch ) . ' ' .
- Xml::submitButton( wfMsg( 'ilsubmit' ), array( 'name' => 'wpIlSubmit' ) ) .
- Xml::closeElement( 'fieldset' ) .
- Xml::closeElement( 'form' )
- );
+ function getIndexField(){
+ return 'img_timestamp';
}
- $bydate = wfMsg( 'bydate' );
- $lt = $wgLang->formatNum( min( $shownImages, $limit ) );
- if ( $shownav ) {
- $text = wfMsgExt( 'imagelisttext', array('parse'), $lt, $bydate );
- $wgOut->addHTML( $text . "\n" );
+ function getStartBody(){
+ $this->gallery = new ImageGallery();
}
- /**
- * Paging controls...
- */
-
- # If we change bot visibility, this needs to be carried along.
- if( !$hidebots ) {
- $botpar = array( 'hidebots' => 0 );
- } else {
- $botpar = array();
+ function getEndBody(){
+ return $this->gallery->toHTML();
}
- $now = wfTimestampNow();
- $d = $wgLang->date( $now, true );
- $t = $wgLang->time( $now, true );
- $query = array_merge(
- array( 'from' => $now ),
- $botpar,
- $searchpar
- );
-
- $dateLink = $sk->linkKnown(
- $titleObj,
- htmlspecialchars( wfMsg( 'sp-newimages-showfrom', $d, $t ) ),
- array(),
- $query
- );
- $query = array_merge(
- array( 'hidebots' => ( $hidebots ? 0 : 1 ) ),
- $searchpar
- );
+ function formatRow( $row ) {
+ global $wgLang;
- $showhide = $hidebots ? wfMsg( 'show' ) : wfMsg( 'hide' );
+ $name = $row->img_name;
+ $user = User::newFromId( $row->img_user );
- $botLink = $sk->linkKnown(
- $titleObj,
- htmlspecialchars( wfMsg( 'showhidebots', $showhide ) ),
- array(),
- $query
- );
+ $title = Title::makeTitle( NS_FILE, $name );
+ $ul = $this->skin->link( $user->getUserpage(), $user->getName() );
- $opts = array( 'parsemag', 'escapenoentities' );
- $prevLink = wfMsgExt( 'pager-newer-n', $opts, $wgLang->formatNum( $limit ) );
- if( $firstTimestamp && $firstTimestamp != $latestTimestamp ) {
- $query = array_merge(
- array( 'from' => $firstTimestamp ),
- $botpar,
- $searchpar
- );
-
- $prevLink = $sk->linkKnown(
- $titleObj,
- $prevLink,
- array(),
- $query
+ $this->gallery->add(
+ $title,
+ "$ul<br />\n<i>"
+ . htmlspecialchars( $wgLang->timeanddate( $row->img_timestamp, true ) )
+ . "</i><br />\n"
);
}
- $nextLink = wfMsgExt( 'pager-older-n', $opts, $wgLang->formatNum( $limit ) );
- if( $invertSort || ( $shownImages > $limit && $lastTimestamp ) ) {
- $query = array_merge(
- array( 'until' => ( $lastTimestamp ? $lastTimestamp : "" ) ),
- $botpar,
- $searchpar
- );
-
- $nextLink = $sk->linkKnown(
- $titleObj,
- $nextLink,
- array(),
- $query
+ function getForm() {
+ global $wgRequest, $wgMiserMode;
+
+ $fields = array(
+ 'like' => array(
+ 'type' => 'text',
+ 'label-message' => 'newimages-label',
+ 'name' => 'like',
+ ),
+ 'showbots' => array(
+ 'type' => 'check',
+ 'label' => wfMessage( 'showhidebots', wfMsg( 'show' ) ),
+ 'name' => 'showbots',
+ # 'default' => $wgRequest->getBool( 'showbots', 0 ),
+ ),
+ 'limit' => array(
+ 'type' => 'hidden',
+ 'default' => $wgRequest->getText( 'limit' ),
+ 'name' => 'limit',
+ ),
+ 'offset' => array(
+ 'type' => 'hidden',
+ 'default' => $wgRequest->getText( 'offset' ),
+ 'name' => 'offset',
+ ),
);
- }
-
- $prevnext = '<p>' . $botLink . ' '. wfMsgHtml( 'viewprevnext', $prevLink, $nextLink, $dateLink ) .'</p>';
+ if( $wgMiserMode ){
+ unset( $fields['like'] );
+ }
- if ($shownav)
- $wgOut->addHTML( $prevnext );
+ $form = new HTMLForm( $fields );
+ $form->setTitle( $this->getTitle() );
+ $form->setSubmitText( wfMsg( 'ilsubmit' ) );
+ $form->setMethod( 'get' );
+ $form->setWrapperLegend( wfMsg( 'newimages-legend' ) );
- if( count( $images ) ) {
- $wgOut->addHTML( $gallery->toHTML() );
- if ($shownav)
- $wgOut->addHTML( $prevnext );
- } else {
- $wgOut->addWikiMsg( 'noimages' );
+ return $form;
}
}
diff --git a/includes/specials/SpecialNewpages.php b/includes/specials/SpecialNewpages.php
index 3235436a..bf9fb9f7 100644
--- a/includes/specials/SpecialNewpages.php
+++ b/includes/specials/SpecialNewpages.php
@@ -29,7 +29,12 @@
class SpecialNewpages extends IncludableSpecialPage {
// Stored objects
- protected $opts, $skin;
+
+ /**
+ * @var FormOptions
+ */
+ protected $opts;
+ protected $customFilters;
// Some internal settings
protected $showNavigation = false;
@@ -39,24 +44,30 @@ class SpecialNewpages extends IncludableSpecialPage {
}
protected function setup( $par ) {
- global $wgRequest, $wgUser, $wgEnableNewpagesUserFilter;
+ global $wgEnableNewpagesUserFilter;
// Options
$opts = new FormOptions();
$this->opts = $opts; // bind
$opts->add( 'hideliu', false );
- $opts->add( 'hidepatrolled', $wgUser->getBoolOption( 'newpageshidepatrolled' ) );
+ $opts->add( 'hidepatrolled', $this->getUser()->getBoolOption( 'newpageshidepatrolled' ) );
$opts->add( 'hidebots', false );
$opts->add( 'hideredirs', true );
- $opts->add( 'limit', (int)$wgUser->getOption( 'rclimit' ) );
+ $opts->add( 'limit', (int)$this->getUser()->getOption( 'rclimit' ) );
$opts->add( 'offset', '' );
$opts->add( 'namespace', '0' );
$opts->add( 'username', '' );
$opts->add( 'feed', '' );
$opts->add( 'tagfilter', '' );
+ $this->customFilters = array();
+ wfRunHooks( 'SpecialNewPagesFilters', array( $this, &$this->customFilters ) );
+ foreach( $this->customFilters as $key => $params ) {
+ $opts->add( $key, $params['default'] );
+ }
+
// Set values
- $opts->fetchValuesFromRequest( $wgRequest );
+ $opts->fetchValuesFromRequest( $this->getRequest() );
if ( $par ) $this->parseParams( $par );
// Validate
@@ -64,36 +75,42 @@ class SpecialNewpages extends IncludableSpecialPage {
if( !$wgEnableNewpagesUserFilter ) {
$opts->setValue( 'username', '' );
}
-
- // Store some objects
- $this->skin = $wgUser->getSkin();
}
protected function parseParams( $par ) {
global $wgLang;
$bits = preg_split( '/\s*,\s*/', trim( $par ) );
foreach ( $bits as $bit ) {
- if ( 'shownav' == $bit )
+ if ( 'shownav' == $bit ) {
$this->showNavigation = true;
- if ( 'hideliu' === $bit )
+ }
+ if ( 'hideliu' === $bit ) {
$this->opts->setValue( 'hideliu', true );
- if ( 'hidepatrolled' == $bit )
+ }
+ if ( 'hidepatrolled' == $bit ) {
$this->opts->setValue( 'hidepatrolled', true );
- if ( 'hidebots' == $bit )
+ }
+ if ( 'hidebots' == $bit ) {
$this->opts->setValue( 'hidebots', true );
- if ( 'showredirs' == $bit )
+ }
+ if ( 'showredirs' == $bit ) {
$this->opts->setValue( 'hideredirs', false );
- if ( is_numeric( $bit ) )
+ }
+ if ( is_numeric( $bit ) ) {
$this->opts->setValue( 'limit', intval( $bit ) );
+ }
$m = array();
- if ( preg_match( '/^limit=(\d+)$/', $bit, $m ) )
- $this->opts->setValue( 'limit', intval($m[1]) );
+ if ( preg_match( '/^limit=(\d+)$/', $bit, $m ) ) {
+ $this->opts->setValue( 'limit', intval( $m[1] ) );
+ }
// PG offsets not just digits!
- if ( preg_match( '/^offset=([^=]+)$/', $bit, $m ) )
- $this->opts->setValue( 'offset', intval($m[1]) );
- if ( preg_match( '/^username=(.*)$/', $bit, $m ) )
+ if ( preg_match( '/^offset=([^=]+)$/', $bit, $m ) ) {
+ $this->opts->setValue( 'offset', intval( $m[1] ) );
+ }
+ if ( preg_match( '/^username=(.*)$/', $bit, $m ) ) {
$this->opts->setValue( 'username', $m[1] );
+ }
if ( preg_match( '/^namespace=(.*)$/', $bit, $m ) ) {
$ns = $wgLang->getNsIndex( $m[1] );
if( $ns !== false ) {
@@ -110,7 +127,7 @@ class SpecialNewpages extends IncludableSpecialPage {
* @return String
*/
public function execute( $par ) {
- global $wgOut;
+ $out = $this->getOutput();
$this->setHeaders();
$this->outputHeader();
@@ -135,15 +152,17 @@ class SpecialNewpages extends IncludableSpecialPage {
if( $pager->getNumRows() ) {
$navigation = '';
- if ( $this->showNavigation ) $navigation = $pager->getNavigationBar();
- $wgOut->addHTML( $navigation . $pager->getBody() . $navigation );
+ if ( $this->showNavigation ) {
+ $navigation = $pager->getNavigationBar();
+ }
+ $out->addHTML( $navigation . $pager->getBody() . $navigation );
} else {
- $wgOut->addWikiMsg( 'specialpage-empty' );
+ $out->addWikiMsg( 'specialpage-empty' );
}
}
protected function filterLinks() {
- global $wgGroupPermissions, $wgUser, $wgLang;
+ global $wgGroupPermissions, $wgLang;
// show/hide links
$showhide = array( wfMsgHtml( 'show' ), wfMsgHtml( 'hide' ) );
@@ -155,24 +174,28 @@ class SpecialNewpages extends IncludableSpecialPage {
'hidebots' => 'rcshowhidebots',
'hideredirs' => 'whatlinkshere-hideredirs'
);
+ foreach ( $this->customFilters as $key => $params ) {
+ $filters[$key] = $params['msg'];
+ }
// Disable some if needed
- # FIXME: throws E_NOTICEs if not set; and doesn't obey hooks etc
- if ( $wgGroupPermissions['*']['createpage'] !== true )
- unset($filters['hideliu']);
-
- if ( !$wgUser->useNPPatrol() )
- unset($filters['hidepatrolled']);
+ # @todo FIXME: Throws E_NOTICEs if not set; and doesn't obey hooks etc.
+ if ( $wgGroupPermissions['*']['createpage'] !== true ) {
+ unset( $filters['hideliu'] );
+ }
+ if ( !$this->getUser()->useNPPatrol() ) {
+ unset( $filters['hidepatrolled'] );
+ }
$links = array();
$changed = $this->opts->getChangedValues();
- unset($changed['offset']); // Reset offset if query type changes
+ unset( $changed['offset'] ); // Reset offset if query type changes
$self = $this->getTitle();
foreach ( $filters as $key => $msg ) {
- $onoff = 1 - $this->opts->getValue($key);
- $link = $this->skin->link( $self, $showhide[$onoff], array(),
- array( $key => $onoff ) + $changed
+ $onoff = 1 - $this->opts->getValue( $key );
+ $link = $this->getSkin()->link( $self, $showhide[$onoff], array(),
+ array( $key => $onoff ) + $changed
);
$links[$key] = wfMsgHtml( $msg, $link );
}
@@ -181,7 +204,7 @@ class SpecialNewpages extends IncludableSpecialPage {
}
protected function form() {
- global $wgOut, $wgEnableNewpagesUserFilter, $wgScript;
+ global $wgEnableNewpagesUserFilter, $wgScript;
// Consume values
$this->opts->consumeValue( 'offset' ); // don't carry offset, DWIW
@@ -201,61 +224,62 @@ class SpecialNewpages extends IncludableSpecialPage {
$hidden = implode( "\n", $hidden );
$tagFilter = ChangeTags::buildTagFilterSelector( $tagFilterVal );
- if ($tagFilter)
+ if ( $tagFilter ) {
list( $tagFilterLabel, $tagFilterSelector ) = $tagFilter;
+ }
$form = Xml::openElement( 'form', array( 'action' => $wgScript ) ) .
Html::hidden( 'title', $this->getTitle()->getPrefixedDBkey() ) .
Xml::fieldset( wfMsg( 'newpages' ) ) .
Xml::openElement( 'table', array( 'id' => 'mw-newpages-table' ) ) .
- "<tr>
- <td class='mw-label'>" .
+ '<tr>
+ <td class="mw-label">' .
Xml::label( wfMsg( 'namespace' ), 'namespace' ) .
- "</td>
- <td class='mw-input'>" .
+ '</td>
+ <td class="mw-input">' .
Xml::namespaceSelector( $namespace, 'all' ) .
- "</td>
- </tr>" . ( $tagFilter ? (
- "<tr>
- <td class='mw-label'>" .
+ '</td>
+ </tr>' . ( $tagFilter ? (
+ '<tr>
+ <td class="mw-label">' .
$tagFilterLabel .
- "</td>
- <td class='mw-input'>" .
+ '</td>
+ <td class="mw-input">' .
$tagFilterSelector .
- "</td>
- </tr>" ) : '' ) .
- ($wgEnableNewpagesUserFilter ?
- "<tr>
- <td class='mw-label'>" .
+ '</td>
+ </tr>' ) : '' ) .
+ ( $wgEnableNewpagesUserFilter ?
+ '<tr>
+ <td class="mw-label">' .
Xml::label( wfMsg( 'newpages-username' ), 'mw-np-username' ) .
- "</td>
- <td class='mw-input'>" .
+ '</td>
+ <td class="mw-input">' .
Xml::input( 'username', 30, $userText, array( 'id' => 'mw-np-username' ) ) .
- "</td>
- </tr>" : "" ) .
- "<tr> <td></td>
- <td class='mw-submit'>" .
+ '</td>
+ </tr>' : '' ) .
+ '<tr> <td></td>
+ <td class="mw-submit">' .
Xml::submitButton( wfMsg( 'allpagessubmit' ) ) .
- "</td>
- </tr>" .
- "<tr>
+ '</td>
+ </tr>' .
+ '<tr>
<td></td>
- <td class='mw-input'>" .
+ <td class="mw-input">' .
$this->filterLinks() .
- "</td>
- </tr>" .
+ '</td>
+ </tr>' .
Xml::closeElement( 'table' ) .
Xml::closeElement( 'fieldset' ) .
$hidden .
Xml::closeElement( 'form' );
- $wgOut->addHTML( $form );
+ $this->getOutput()->addHTML( $form );
}
protected function setSyndicated() {
- global $wgOut;
- $wgOut->setSyndicated( true );
- $wgOut->setFeedAppendQuery( wfArrayToCGI( $this->opts->getAllValues() ) );
+ $out = $this->getOutput();
+ $out->setSyndicated( true );
+ $out->setFeedAppendQuery( wfArrayToCGI( $this->opts->getAllValues() ) );
}
/**
@@ -265,11 +289,20 @@ class SpecialNewpages extends IncludableSpecialPage {
* @return String
*/
public function formatRow( $result ) {
- global $wgLang, $wgContLang;
+ global $wgLang;
+
+ # Revision deletion works on revisions, so we should cast one
+ $row = array(
+ 'comment' => $result->rc_comment,
+ 'deleted' => $result->rc_deleted,
+ 'user_text' => $result->rc_user_text,
+ 'user' => $result->rc_user,
+ );
+ $rev = new Revision( $row );
$classes = array();
-
- $dm = $wgContLang->getDirMark();
+
+ $dm = $wgLang->getDirMark();
$title = Title::makeTitleSafe( $result->rc_namespace, $result->rc_title );
$time = Html::element( 'span', array( 'class' => 'mw-newpages-time' ),
@@ -278,17 +311,18 @@ class SpecialNewpages extends IncludableSpecialPage {
$query = array( 'redirect' => 'no' );
- if( $this->patrollable( $result ) )
+ if( $this->patrollable( $result ) ) {
$query['rcid'] = $result->rc_id;
+ }
- $plink = $this->skin->linkKnown(
+ $plink = $this->getSkin()->linkKnown(
$title,
null,
array( 'class' => 'mw-newpages-pagename' ),
$query,
array( 'known' ) // Set explicitly to avoid the default of 'known','noclasses'. This breaks the colouration for stubs
);
- $histLink = $this->skin->linkKnown(
+ $histLink = $this->getSkin()->linkKnown(
$title,
wfMsgHtml( 'hist' ),
array(),
@@ -300,10 +334,10 @@ class SpecialNewpages extends IncludableSpecialPage {
'[' . wfMsgExt( 'nbytes', array( 'parsemag', 'escape' ), $wgLang->formatNum( $result->length ) ) .
']'
);
- $ulink = $this->skin->userLink( $result->rc_user, $result->rc_user_text ) . ' ' .
- $this->skin->userToolLinks( $result->rc_user, $result->rc_user_text );
- $comment = $this->skin->commentBlock( $result->rc_comment );
-
+
+ $ulink = $this->getSkin()->revUserTools( $rev );
+ $comment = $this->getSkin()->revComment( $rev );
+
if ( $this->patrollable( $result ) ) {
$classes[] = 'not-patrolled';
}
@@ -321,7 +355,7 @@ class SpecialNewpages extends IncludableSpecialPage {
$tagDisplay = '';
}
- $css = count($classes) ? ' class="'.implode( " ", $classes).'"' : '';
+ $css = count( $classes ) ? ' class="' . implode( ' ', $classes ) . '"' : '';
return "<li{$css}>{$time} {$dm}{$plink} {$hist} {$dm}{$length} {$dm}{$ulink} {$comment} {$tagDisplay}</li>\n";
}
@@ -333,8 +367,7 @@ class SpecialNewpages extends IncludableSpecialPage {
* @return Boolean
*/
protected function patrollable( $result ) {
- global $wgUser;
- return ( $wgUser->useNPPatrol() && !$result->rc_patrolled );
+ return ( $this->getUser()->useNPPatrol() && !$result->rc_patrolled );
}
/**
@@ -343,22 +376,23 @@ class SpecialNewpages extends IncludableSpecialPage {
* @param $type String
*/
protected function feed( $type ) {
- global $wgFeed, $wgFeedClasses, $wgFeedLimit, $wgOut;
+ global $wgFeed, $wgFeedClasses, $wgFeedLimit;
if ( !$wgFeed ) {
- $wgOut->addWikiMsg( 'feed-unavailable' );
+ $this->getOutput()->addWikiMsg( 'feed-unavailable' );
return;
}
if( !isset( $wgFeedClasses[$type] ) ) {
- $wgOut->addWikiMsg( 'feed-invalid' );
+ $this->getOutput()->addWikiMsg( 'feed-invalid' );
return;
}
$feed = new $wgFeedClasses[$type](
$this->feedTitle(),
wfMsgExt( 'tagline', 'parsemag' ),
- $this->getTitle()->getFullUrl() );
+ $this->getTitle()->getFullUrl()
+ );
$pager = new NewPagesPager( $this, $this->opts );
$limit = $this->opts->getValue( 'limit' );
@@ -375,8 +409,7 @@ class SpecialNewpages extends IncludableSpecialPage {
protected function feedTitle() {
global $wgLanguageCode, $wgSitename;
- $page = SpecialPage::getPage( 'Newpages' );
- $desc = $page->getDescription();
+ $desc = $this->getDescription();
return "$wgSitename - $desc [$wgLanguageCode]";
}
@@ -392,7 +425,8 @@ class SpecialNewpages extends IncludableSpecialPage {
$title->getFullURL(),
$date,
$this->feedItemAuthor( $row ),
- $comments);
+ $comments
+ );
} else {
return null;
}
@@ -406,7 +440,7 @@ class SpecialNewpages extends IncludableSpecialPage {
$revision = Revision::newFromId( $row->rev_id );
if( $revision ) {
return '<p>' . htmlspecialchars( $revision->getUserText() ) . wfMsgForContent( 'colon-separator' ) .
- htmlspecialchars( FeedItem::stripComment( $revision->getComment() ) ) .
+ htmlspecialchars( FeedItem::stripComment( $revision->getComment() ) ) .
"</p>\n<hr />\n<div>" .
nl2br( htmlspecialchars( $revision->getText() ) ) . "</div>";
}
@@ -419,7 +453,12 @@ class SpecialNewpages extends IncludableSpecialPage {
*/
class NewPagesPager extends ReverseChronologicalPager {
// Stored opts
- protected $opts, $mForm;
+ protected $opts;
+
+ /**
+ * @var HtmlForm
+ */
+ protected $mForm;
function __construct( $form, FormOptions $opts ) {
parent::__construct();
@@ -427,15 +466,30 @@ class NewPagesPager extends ReverseChronologicalPager {
$this->opts = $opts;
}
+ /**
+ * @return Title
+ */
function getTitle() {
static $title = null;
- if ( $title === null )
+ if ( $title === null ) {
$title = $this->mForm->getTitle();
+ }
return $title;
}
+ /**
+ * @return User
+ */
+ function getUser() {
+ static $user = null;
+ if ( $user === null ) {
+ $user = $this->mForm->getUser();
+ }
+ return $user;
+ }
+
function getQueryInfo() {
- global $wgEnableNewpagesUserFilter, $wgGroupPermissions, $wgUser;
+ global $wgEnableNewpagesUserFilter, $wgGroupPermissions;
$conds = array();
$conds['rc_new'] = 1;
@@ -461,7 +515,7 @@ class NewPagesPager extends ReverseChronologicalPager {
$conds['rc_user'] = 0;
}
# If this user cannot see patrolled edits or they are off, don't do dumb queries!
- if( $this->opts->getValue( 'hidepatrolled' ) && $wgUser->useNPPatrol() ) {
+ if( $this->opts->getValue( 'hidepatrolled' ) && $this->getUser()->useNPPatrol() ) {
$conds['rc_patrolled'] = 0;
}
if( $this->opts->getValue( 'hidebots' ) ) {
@@ -471,31 +525,39 @@ class NewPagesPager extends ReverseChronologicalPager {
if ( $this->opts->getValue( 'hideredirs' ) ) {
$conds['page_is_redirect'] = 0;
}
-
+
// Allow changes to the New Pages query
- wfRunHooks('SpecialNewpagesConditions', array(&$this, $this->opts, &$conds));
+ $tables = array( 'recentchanges', 'page' );
+ $fields = array(
+ 'rc_namespace', 'rc_title', 'rc_cur_id', 'rc_user', 'rc_user_text',
+ 'rc_comment', 'rc_timestamp', 'rc_patrolled','rc_id', 'rc_deleted',
+ 'page_len AS length', 'page_latest AS rev_id', 'ts_tags'
+ );
+ $join_conds = array( 'page' => array( 'INNER JOIN', 'page_id=rc_cur_id' ) );
+
+ wfRunHooks( 'SpecialNewpagesConditions',
+ array( &$this, $this->opts, &$conds, &$tables, &$fields, &$join_conds ) );
$info = array(
- 'tables' => array( 'recentchanges', 'page' ),
- 'fields' => 'rc_namespace,rc_title, rc_cur_id, rc_user,rc_user_text,rc_comment,
- rc_timestamp,rc_patrolled,rc_id,page_len as length, page_latest as rev_id, ts_tags',
- 'conds' => $conds,
- 'options' => array( 'USE INDEX' => array('recentchanges' => $rcIndexes) ),
- 'join_conds' => array(
- 'page' => array('INNER JOIN', 'page_id=rc_cur_id'),
- ),
+ 'tables' => $tables,
+ 'fields' => $fields,
+ 'conds' => $conds,
+ 'options' => array( 'USE INDEX' => array( 'recentchanges' => $rcIndexes ) ),
+ 'join_conds' => $join_conds
);
- ## Empty array for fields, it'll be set by us anyway.
+ // Empty array for fields, it'll be set by us anyway.
$fields = array();
- ## Modify query for tags
- ChangeTags::modifyDisplayQuery( $info['tables'],
- $fields,
- $info['conds'],
- $info['join_conds'],
- $info['options'],
- $this->opts['tagfilter'] );
+ // Modify query for tags
+ ChangeTags::modifyDisplayQuery(
+ $info['tables'],
+ $fields,
+ $info['conds'],
+ $info['join_conds'],
+ $info['options'],
+ $this->opts['tagfilter']
+ );
return $info;
}
@@ -517,10 +579,10 @@ class NewPagesPager extends ReverseChronologicalPager {
$linkBatch->add( $row->rc_namespace, $row->rc_title );
}
$linkBatch->execute();
- return "<ul>";
+ return '<ul>';
}
function getEndBody() {
- return "</ul>";
+ return '</ul>';
}
}
diff --git a/includes/specials/SpecialPasswordReset.php b/includes/specials/SpecialPasswordReset.php
new file mode 100644
index 00000000..1caa2c51
--- /dev/null
+++ b/includes/specials/SpecialPasswordReset.php
@@ -0,0 +1,273 @@
+<?php
+/**
+ * Implements Special:Blankpage
+ *
+ * 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.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup SpecialPage
+ */
+
+/**
+ * Special page for requesting a password reset email
+ *
+ * @ingroup SpecialPage
+ */
+class SpecialPasswordReset extends FormSpecialPage {
+
+ public function __construct() {
+ parent::__construct( 'PasswordReset' );
+ }
+
+ public function userCanExecute( User $user ) {
+ $error = $this->canChangePassword( $user );
+ if ( is_string( $error ) ) {
+ throw new ErrorPageError( 'internalerror', $error );
+ } else if ( !$error ) {
+ throw new ErrorPageError( 'internalerror', 'resetpass_forbidden' );
+ }
+
+ return parent::userCanExecute( $user );
+ }
+
+ protected function getFormFields() {
+ global $wgPasswordResetRoutes, $wgAuth;
+ $a = array();
+ if ( isset( $wgPasswordResetRoutes['username'] ) && $wgPasswordResetRoutes['username'] ) {
+ $a['Username'] = array(
+ 'type' => 'text',
+ 'label-message' => 'passwordreset-username',
+ );
+ }
+
+ if ( isset( $wgPasswordResetRoutes['email'] ) && $wgPasswordResetRoutes['email'] ) {
+ $a['Email'] = array(
+ 'type' => 'email',
+ 'label-message' => 'passwordreset-email',
+ );
+ }
+
+ if ( isset( $wgPasswordResetRoutes['domain'] ) && $wgPasswordResetRoutes['domain'] ) {
+ $domains = $wgAuth->domainList();
+ $a['Domain'] = array(
+ 'type' => 'select',
+ 'options' => $domains,
+ 'label-message' => 'passwordreset-domain',
+ );
+ }
+
+ return $a;
+ }
+
+ public function alterForm( HTMLForm $form ) {
+ $form->setSubmitText( wfMessage( "mailmypassword" ) );
+ }
+
+ protected function preText() {
+ global $wgPasswordResetRoutes;
+ $i = 0;
+ if ( isset( $wgPasswordResetRoutes['username'] ) && $wgPasswordResetRoutes['username'] ) {
+ $i++;
+ }
+ if ( isset( $wgPasswordResetRoutes['email'] ) && $wgPasswordResetRoutes['email'] ) {
+ $i++;
+ }
+ if ( isset( $wgPasswordResetRoutes['domain'] ) && $wgPasswordResetRoutes['domain'] ) {
+ $i++;
+ }
+ return wfMessage( 'passwordreset-pretext', $i )->parseAsBlock();
+ }
+
+ /**
+ * Process the form. At this point we know that the user passes all the criteria in
+ * userCanExecute(), and if the data array contains 'Username', etc, then Username
+ * resets are allowed.
+ * @param $data array
+ * @return Bool|Array
+ */
+ public function onSubmit( array $data ) {
+ global $wgAuth;
+
+ if ( isset( $data['Domain'] ) ) {
+ if ( $wgAuth->validDomain( $data['Domain'] ) ) {
+ $wgAuth->setDomain( $data['Domain'] );
+ } else {
+ $wgAuth->setDomain( 'invaliddomain' );
+ }
+ }
+
+ if ( isset( $data['Username'] ) && $data['Username'] !== '' ) {
+ $method = 'username';
+ $users = array( User::newFromName( $data['Username'] ) );
+ } elseif ( isset( $data['Email'] )
+ && $data['Email'] !== ''
+ && Sanitizer::validateEmail( $data['Email'] ) )
+ {
+ $method = 'email';
+ $res = wfGetDB( DB_SLAVE )->select(
+ 'user',
+ '*',
+ array( 'user_email' => $data['Email'] ),
+ __METHOD__
+ );
+ if ( $res ) {
+ $users = array();
+ foreach( $res as $row ){
+ $users[] = User::newFromRow( $row );
+ }
+ } else {
+ // Some sort of database error, probably unreachable
+ throw new MWException( 'Unknown database error in ' . __METHOD__ );
+ }
+ } else {
+ // The user didn't supply any data
+ return false;
+ }
+
+ // Check for hooks (captcha etc), and allow them to modify the users list
+ $error = array();
+ if ( !wfRunHooks( 'SpecialPasswordResetOnSubmit', array( &$users, $data, &$error ) ) ) {
+ return array( $error );
+ }
+
+ if( count( $users ) == 0 ){
+ if( $method == 'email' ){
+ // Don't reveal whether or not an email address is in use
+ return true;
+ } else {
+ return array( 'noname' );
+ }
+ }
+
+ $firstUser = $users[0];
+
+ if ( !$firstUser instanceof User || !$firstUser->getID() ) {
+ return array( array( 'nosuchuser', $data['Username'] ) );
+ }
+
+ // Check against the rate limiter
+ if ( $this->getUser()->pingLimiter( 'mailpassword' ) ) {
+ throw new ThrottledError;
+ }
+
+ // Check against password throttle
+ foreach ( $users as $user ) {
+ if ( $user->isPasswordReminderThrottled() ) {
+ global $wgPasswordReminderResendTime;
+ # Round the time in hours to 3 d.p., in case someone is specifying
+ # minutes or seconds.
+ return array( array( 'throttled-mailpassword', round( $wgPasswordReminderResendTime, 3 ) ) );
+ }
+ }
+
+ global $wgNewPasswordExpiry;
+
+ // All the users will have the same email address
+ if ( $firstUser->getEmail() == '' ) {
+ // This won't be reachable from the email route, so safe to expose the username
+ return array( array( 'noemail', $firstUser->getName() ) );
+ }
+
+ // We need to have a valid IP address for the hook, but per bug 18347, we should
+ // send the user's name if they're logged in.
+ $ip = wfGetIP();
+ if ( !$ip ) {
+ return array( 'badipaddress' );
+ }
+ $caller = $this->getUser();
+ wfRunHooks( 'User::mailPasswordInternal', array( &$caller, &$ip, &$firstUser ) );
+ $username = $caller->getName();
+ $msg = IP::isValid( $username )
+ ? 'passwordreset-emailtext-ip'
+ : 'passwordreset-emailtext-user';
+
+ $passwords = array();
+ foreach ( $users as $user ) {
+ $password = $user->randomPassword();
+ $user->setNewpassword( $password );
+ $user->saveSettings();
+ $passwords[] = wfMessage( 'passwordreset-emailelement', $user->getName(), $password );
+ }
+ $passwordBlock = implode( "\n\n", $passwords );
+
+ // Send in the user's language; which should hopefully be the same
+ $userLanguage = $firstUser->getOption( 'language' );
+
+ $body = wfMessage( $msg )->inLanguage( $userLanguage );
+ $body->params(
+ $username,
+ $passwordBlock,
+ count( $passwords ),
+ Title::newMainPage()->getCanonicalUrl(),
+ round( $wgNewPasswordExpiry / 86400 )
+ );
+
+ $title = wfMessage( 'passwordreset-emailtitle' );
+
+ $result = $firstUser->sendMail( $title->text(), $body->text() );
+
+ if ( $result->isGood() ) {
+ return true;
+ } else {
+ // @todo FIXME: The email didn't send, but we have already set the password throttle
+ // timestamp, so they won't be able to try again until it expires... :(
+ return array( array( 'mailerror', $result->getMessage() ) );
+ }
+ }
+
+ public function onSuccess() {
+ $this->getOutput()->addWikiMsg( 'passwordreset-emailsent' );
+ $this->getOutput()->returnToMain();
+ }
+
+ function canChangePassword(User $user) {
+ global $wgPasswordResetRoutes, $wgAuth;
+
+ // Maybe password resets are disabled, or there are no allowable routes
+ if ( !is_array( $wgPasswordResetRoutes ) ||
+ !in_array( true, array_values( $wgPasswordResetRoutes ) ) ) {
+ return 'passwordreset-disabled';
+ }
+
+ // Maybe the external auth plugin won't allow local password changes
+ if ( !$wgAuth->allowPasswordChange() ) {
+ return 'resetpass_forbidden';
+ }
+
+ // Maybe the user is blocked (check this here rather than relying on the parent
+ // method as we have a more specific error message to use here
+ if ( $user->isBlocked() ) {
+ return 'blocked-mailpassword';
+ }
+
+ return true;
+ }
+
+
+ /**
+ * Hide the password reset page if resets are disabled.
+ * @return Bool
+ */
+ function isListed() {
+ global $wgUser;
+
+ if ( $this->canChangePassword( $wgUser ) === true ) {
+ return parent::isListed();
+ }
+
+ return false;
+ }
+} \ No newline at end of file
diff --git a/includes/specials/SpecialPopularpages.php b/includes/specials/SpecialPopularpages.php
index 375cefdf..7c7190ad 100644
--- a/includes/specials/SpecialPopularpages.php
+++ b/includes/specials/SpecialPopularpages.php
@@ -28,8 +28,8 @@
*/
class PopularPagesPage extends QueryPage {
- function getName() {
- return "Popularpages";
+ function __construct( $name = 'Popularpages' ) {
+ parent::__construct( $name );
}
function isExpensive() {
@@ -38,31 +38,21 @@ class PopularPagesPage extends QueryPage {
}
function isSyndicated() { return false; }
- function getSQL() {
- $dbr = wfGetDB( DB_SLAVE );
- $page = $dbr->tableName( 'page' );
-
- $query =
- "SELECT 'Popularpages' as type,
- page_namespace as namespace,
- page_title as title,
- page_counter as value
- FROM $page ";
- $where =
- "WHERE page_is_redirect=0 AND page_namespace";
-
- global $wgContentNamespaces;
- if( empty( $wgContentNamespaces ) ) {
- $where .= '='.NS_MAIN;
- } else if( count( $wgContentNamespaces ) > 1 ) {
- $where .= ' in (' . implode( ', ', $wgContentNamespaces ) . ')';
- } else {
- $where .= '='.$wgContentNamespaces[0];
- }
-
- return $query . $where;
+ function getQueryInfo() {
+ return array (
+ 'tables' => array( 'page' ),
+ 'fields' => array( 'page_namespace AS namespace',
+ 'page_title AS title',
+ 'page_counter AS value'),
+ 'conds' => array( 'page_is_redirect' => 0,
+ 'page_namespace' => MWNamespace::getContentNamespaces() ) );
}
+ /**
+ * @param $skin Skin
+ * @param $result
+ * @return string
+ */
function formatResult( $skin, $result ) {
global $wgLang, $wgContLang;
$title = Title::makeTitle( $result->namespace, $result->title );
@@ -78,14 +68,3 @@ class PopularPagesPage extends QueryPage {
return wfSpecialList($link, $nv);
}
}
-
-/**
- * Constructor
- */
-function wfSpecialPopularpages() {
- list( $limit, $offset ) = wfCheckLimits();
-
- $ppp = new PopularPagesPage();
-
- return $ppp->doQuery( $offset, $limit );
-}
diff --git a/includes/specials/SpecialPreferences.php b/includes/specials/SpecialPreferences.php
index e63aeee6..edc26bc1 100644
--- a/includes/specials/SpecialPreferences.php
+++ b/includes/specials/SpecialPreferences.php
@@ -52,7 +52,6 @@ class SpecialPreferences extends SpecialPage {
return;
}
- $wgOut->addModules( 'mediawiki.legacy.prefs' );
$wgOut->addModules( 'mediawiki.special.preferences' );
if ( $wgRequest->getCheck( 'success' ) ) {
@@ -61,7 +60,7 @@ class SpecialPreferences extends SpecialPage {
'savedprefs'
);
}
-
+
if ( $wgRequest->getCheck( 'eauth' ) ) {
$wgOut->wrapWikiMsg( "<div class='error' style='clear: both;'>\n$1\n</div>",
'eauthentsent', $wgUser->getName() );
@@ -78,7 +77,7 @@ class SpecialPreferences extends SpecialPage {
$wgOut->addWikiMsg( 'prefs-reset-intro' );
- $htmlForm = new HTMLForm( array(), 'prefs-restore' );
+ $htmlForm = new HTMLForm( array(), $this->getContext(), 'prefs-restore' );
$htmlForm->setSubmitText( wfMsg( 'restoreprefs' ) );
$htmlForm->setTitle( $this->getTitle( 'reset' ) );
diff --git a/includes/specials/SpecialPrefixindex.php b/includes/specials/SpecialPrefixindex.php
index 09e7734c..28be4daf 100644
--- a/includes/specials/SpecialPrefixindex.php
+++ b/includes/specials/SpecialPrefixindex.php
@@ -28,11 +28,11 @@
*/
class SpecialPrefixindex extends SpecialAllpages {
// Inherit $maxPerPage
-
+
function __construct(){
parent::__construct( 'Prefixindex' );
}
-
+
/**
* Entry point : initialise variables and call subfunctions.
* @param $par String: becomes "FOO" when called like Special:Prefixindex/FOO (default null)
@@ -42,34 +42,39 @@ class SpecialPrefixindex extends SpecialAllpages {
$this->setHeaders();
$this->outputHeader();
+ $wgOut->addModuleStyles( 'mediawiki.special' );
# GET values
$from = $wgRequest->getVal( 'from', '' );
$prefix = $wgRequest->getVal( 'prefix', '' );
- $namespace = $wgRequest->getInt( 'namespace' );
- $namespaces = $wgContLang->getNamespaces();
+ $ns = $wgRequest->getIntOrNull( 'namespace' );
+ $namespace = (int)$ns; // if no namespace given, use 0 (NS_MAIN).
- $wgOut->setPagetitle( ( $namespace > 0 && in_array( $namespace, array_keys( $namespaces ) ) )
- ? wfMsg( 'allinnamespace', str_replace( '_', ' ', $namespaces[$namespace] ) )
- : wfMsg( 'prefixindex' )
+ $namespaces = $wgContLang->getNamespaces();
+ $wgOut->setPagetitle(
+ ( $namespace > 0 && in_array( $namespace, array_keys( $namespaces ) ) )
+ ? wfMsg( 'allinnamespace', str_replace( '_', ' ', $namespaces[$namespace] ) )
+ : wfMsg( 'prefixindex' )
);
$showme = '';
- if( isset( $par ) ){
+ if( isset( $par ) ) {
$showme = $par;
- } elseif( $prefix != '' ){
+ } elseif( $prefix != '' ) {
$showme = $prefix;
- } elseif( $from != '' ){
+ } elseif( $from != '' ) {
// For back-compat with Special:Allpages
$showme = $from;
}
- if ($showme != '' || $namespace) {
+
+ // Bug 27864: if transcluded, show all pages instead of the form.
+ if ( $this->including() || $showme != '' || $ns !== null ) {
$this->showPrefixChunk( $namespace, $showme, $from );
} else {
$wgOut->addHTML( $this->namespacePrefixForm( $namespace, null ) );
}
}
-
+
/**
* HTML for the top form
* @param $namespace Integer: a namespace constant (default NS_MAIN).
@@ -115,9 +120,9 @@ class SpecialPrefixindex extends SpecialAllpages {
* @param $from String: list all pages from this name (default FALSE)
*/
function showPrefixChunk( $namespace = NS_MAIN, $prefix, $from = null ) {
- global $wgOut, $wgUser, $wgContLang, $wgLang;
+ global $wgOut, $wgContLang, $wgLang;
- $sk = $wgUser->getSkin();
+ $sk = $this->getSkin();
if (!isset($from)) $from = $prefix;
@@ -126,7 +131,7 @@ class SpecialPrefixindex extends SpecialAllpages {
$namespaces = $wgContLang->getNamespaces();
if ( !$prefixList || !$fromList ) {
- $out = wfMsgWikiHtml( 'allpagesbadtitle' );
+ $out = wfMsgExt( 'allpagesbadtitle', 'parse' );
} elseif ( !in_array( $namespace, array_keys( $namespaces ) ) ) {
// Show errormessage and reset to NS_MAIN
$out = wfMsgExt( 'allpages-bad-ns', array( 'parseinline' ), $namespace );
@@ -135,7 +140,7 @@ class SpecialPrefixindex extends SpecialAllpages {
list( $namespace, $prefixKey, $prefix ) = $prefixList;
list( /* $fromNS */, $fromKey, ) = $fromList;
- ### FIXME: should complain if $fromNs != $namespace
+ ### @todo FIXME: Should complain if $fromNs != $namespace
$dbr = wfGetDB( DB_SLAVE );
@@ -154,12 +159,12 @@ class SpecialPrefixindex extends SpecialAllpages {
)
);
- ### FIXME: side link to previous
+ ### @todo FIXME: Side link to previous
$n = 0;
if( $res->numRows() > 0 ) {
$out = Xml::openElement( 'table', array( 'border' => '0', 'id' => 'mw-prefixindex-list-table' ) );
-
+
while( ( $n < $this->maxPerPage ) && ( $s = $res->fetchObject() ) ) {
$t = Title::makeTitle( $s->page_namespace, $s->page_title );
if( $t ) {
@@ -190,6 +195,7 @@ class SpecialPrefixindex extends SpecialAllpages {
}
}
+ $footer = '';
if ( $this->including() ) {
$out2 = '';
} else {
@@ -200,8 +206,7 @@ class SpecialPrefixindex extends SpecialAllpages {
<td>' .
$nsForm .
'</td>
- <td id="mw-prefixindex-nav-form">' .
- $sk->linkKnown( $self, wfMsgHtml( 'allpages' ) );
+ <td id="mw-prefixindex-nav-form" class="mw-prefixindex-nav">';
if( isset( $res ) && $res && ( $n == $this->maxPerPage ) && ( $s = $res->fetchObject() ) ) {
$query = array(
@@ -213,20 +218,21 @@ class SpecialPrefixindex extends SpecialAllpages {
$query['namespace'] = $namespace;
}
- $out2 = $wgLang->pipeList( array(
- $out2,
- $sk->linkKnown(
+ $nextLink = Linker::linkKnown(
$self,
wfMsgHtml( 'nextpage', str_replace( '_',' ', htmlspecialchars( $s->page_title ) ) ),
array(),
$query
- )
- ) );
+ );
+ $out2 .= $nextLink;
+
+ $footer = "\n" . Html::element( "hr" )
+ . Html::rawElement( "div", array( "class" => "mw-prefixindex-nav" ), $nextLink );
}
$out2 .= "</td></tr>" .
Xml::closeElement( 'table' );
}
- $wgOut->addHTML( $out2 . $out );
+ $this->getOutput()->addHTML( $out2 . $out . $footer );
}
}
diff --git a/includes/specials/SpecialProtectedpages.php b/includes/specials/SpecialProtectedpages.php
index c676aa00..b1f61f09 100644
--- a/includes/specials/SpecialProtectedpages.php
+++ b/includes/specials/SpecialProtectedpages.php
@@ -76,14 +76,16 @@ class SpecialProtectedpages extends SpecialPage {
* @return string Formatted <li> element
*/
public function formatRow( $row ) {
- global $wgUser, $wgLang, $wgContLang;
+ global $wgUser, $wgLang;
wfProfileIn( __METHOD__ );
- static $skin=null;
+ static $skin = null, $infinity = null;
- if( is_null( $skin ) )
+ if( is_null( $skin ) ){
$skin = $wgUser->getSkin();
+ $infinity = wfGetDB( DB_SLAVE )->getInfinity();
+ }
$title = Title::makeTitleSafe( $row->page_namespace, $row->page_title );
$link = $skin->link( $title );
@@ -100,17 +102,21 @@ class SpecialProtectedpages extends SpecialPage {
$stxt = '';
- if( $row->pr_expiry != 'infinity' && strlen($row->pr_expiry) ) {
- $expiry = Block::decodeExpiry( $row->pr_expiry );
+ $expiry = $wgLang->formatExpiry( $row->pr_expiry, TS_MW );
+ if( $expiry != $infinity ) {
- $expiry_description = wfMsg( 'protect-expiring' , $wgLang->timeanddate( $expiry ) ,
- $wgLang->date( $expiry ) , $wgLang->time( $expiry ) );
+ $expiry_description = wfMsg(
+ 'protect-expiring',
+ $wgLang->timeanddate( $expiry ),
+ $wgLang->date( $expiry ),
+ $wgLang->time( $expiry )
+ );
$description_items[] = htmlspecialchars($expiry_description);
}
if(!is_null($size = $row->page_len)) {
- $stxt = $wgContLang->getDirMark() . ' ' . $skin->formatRevisionSize( $size );
+ $stxt = $wgLang->getDirMark() . ' ' . $skin->formatRevisionSize( $size );
}
# Show a link to the change protection form for allowed users otherwise a link to the protection log
@@ -139,7 +145,7 @@ class SpecialProtectedpages extends SpecialPage {
return Html::rawElement(
'li',
array(),
- wfSpecialList( $link . $stxt, $wgLang->commaList( $description_items ) ) . $changeProtection ) . "\n";
+ wfSpecialList( $link . $stxt, $wgLang->commaList( $description_items ), false ) . $changeProtection ) . "\n";
}
/**
@@ -193,7 +199,7 @@ class SpecialProtectedpages extends SpecialPage {
return
Xml::checkLabel( wfMsg('protectedpages-indef'), 'indefonly', 'indefonly', $indefOnly ) . "\n";
}
-
+
/**
* @return string Formatted HTML
*/
@@ -288,7 +294,7 @@ class ProtectedPagesPager extends AlphabeticPager {
public $mForm, $mConds;
private $type, $level, $namespace, $sizetype, $size, $indefonly;
- function __construct( $form, $conds = array(), $type, $level, $namespace, $sizetype='', $size=0,
+ function __construct( $form, $conds = array(), $type, $level, $namespace, $sizetype='', $size=0,
$indefonly = false, $cascadeonly = false )
{
$this->mForm = $form;
@@ -313,6 +319,10 @@ class ProtectedPagesPager extends AlphabeticPager {
return '';
}
+ function getTitle() {
+ return SpecialPage::getTitleFor( 'Protectedpages' );
+ }
+
function formatRow( $row ) {
return $this->mForm->formatRow( $row );
}
@@ -323,15 +333,16 @@ class ProtectedPagesPager extends AlphabeticPager {
'OR pr_expiry IS NULL)';
$conds[] = 'page_id=pr_page';
$conds[] = 'pr_type=' . $this->mDb->addQuotes( $this->type );
-
+
if( $this->sizetype=='min' ) {
$conds[] = 'page_len>=' . $this->size;
- } else if( $this->sizetype=='max' ) {
+ } elseif( $this->sizetype=='max' ) {
$conds[] = 'page_len<=' . $this->size;
}
if( $this->indefonly ) {
- $conds[] = "pr_expiry = 'infinity' OR pr_expiry IS NULL";
+ $db = wfGetDB( DB_SLAVE );
+ $conds[] = "pr_expiry = {$db->addQuotes( $db->getInfinity() )} OR pr_expiry IS NULL";
}
if( $this->cascadeonly ) {
$conds[] = "pr_cascade = '1'";
diff --git a/includes/specials/SpecialProtectedtitles.php b/includes/specials/SpecialProtectedtitles.php
index 5b18d87f..5fb91af7 100644
--- a/includes/specials/SpecialProtectedtitles.php
+++ b/includes/specials/SpecialProtectedtitles.php
@@ -70,16 +70,20 @@ class SpecialProtectedtitles extends SpecialPage {
/**
* Callback function to output a restriction
+ *
+ * @return string
*/
function formatRow( $row ) {
- global $wgUser, $wgLang;
+ global $wgLang;
wfProfileIn( __METHOD__ );
- static $skin=null;
+ static $skin = null, $infinity = null;
- if( is_null( $skin ) )
- $skin = $wgUser->getSkin();
+ if( is_null( $skin ) ){
+ $skin = $this->getSkin();
+ $infinity = wfGetDB( DB_SLAVE )->getInfinity();
+ }
$title = Title::makeTitleSafe( $row->pt_namespace, $row->pt_title );
$link = $skin->link( $title );
@@ -90,19 +94,17 @@ class SpecialProtectedtitles extends SpecialPage {
$description_items[] = $protType;
- $stxt = '';
-
- if ( $row->pt_expiry != 'infinity' && strlen($row->pt_expiry) ) {
- $expiry = Block::decodeExpiry( $row->pt_expiry );
+ $expiry = strlen( $row->pt_expiry ) ? $wgLang->formatExpiry( $row->pt_expiry, TS_MW ) : $infinity;
+ if( $expiry != $infinity ) {
$expiry_description = wfMsg( 'protect-expiring', $wgLang->timeanddate( $expiry ) , $wgLang->date( $expiry ) , $wgLang->time( $expiry ) );
- $description_items[] = $expiry_description;
+ $description_items[] = htmlspecialchars($expiry_description);
}
wfProfileOut( __METHOD__ );
- return '<li>' . wfSpecialList( $link . $stxt, implode( $description_items, ', ' ) ) . "</li>\n";
+ return '<li>' . wfSpecialList( $link, implode( $description_items, ', ' ) ) . "</li>\n";
}
/**
@@ -205,6 +207,10 @@ class ProtectedTitlesPager extends AlphabeticPager {
return '';
}
+ function getTitle() {
+ return SpecialPage::getTitleFor( 'Protectedtitles' );
+ }
+
function formatRow( $row ) {
return $this->mForm->formatRow( $row );
}
diff --git a/includes/specials/SpecialRandompage.php b/includes/specials/SpecialRandompage.php
index 6299f384..e299dc77 100644
--- a/includes/specials/SpecialRandompage.php
+++ b/includes/specials/SpecialRandompage.php
@@ -43,7 +43,9 @@ class RandomPage extends SpecialPage {
}
public function setNamespace ( $ns ) {
- if( !$ns || $ns < NS_MAIN ) $ns = NS_MAIN;
+ if( !$ns || $ns < NS_MAIN ) {
+ $ns = NS_MAIN;
+ }
$this->namespaces = array( $ns );
}
@@ -63,7 +65,7 @@ class RandomPage extends SpecialPage {
if( is_null( $title ) ) {
$this->setHeaders();
- $wgOut->addWikiMsg( strtolower( $this->mName ) . '-nopages',
+ $wgOut->addWikiMsg( strtolower( $this->mName ) . '-nopages',
$this->getNsList(), count( $this->namespaces ) );
return;
}
@@ -83,15 +85,15 @@ class RandomPage extends SpecialPage {
global $wgContLang;
$nsNames = array();
foreach( $this->namespaces as $n ) {
- if( $n === NS_MAIN )
- $nsNames[] = wfMsgForContent( 'blanknamespace' );
- else
+ if( $n === NS_MAIN ) {
+ $nsNames[] = wfMsgNoTrans( 'blanknamespace' );
+ } else {
$nsNames[] = $wgContLang->getNsText( $n );
+ }
}
return $wgContLang->commaList( $nsNames );
}
-
/**
* Choose a random title.
* @return Title object (or null if nothing to choose from)
@@ -99,7 +101,8 @@ class RandomPage extends SpecialPage {
public function getRandomTitle() {
$randstr = wfRandom();
$title = null;
- if ( !wfRunHooks( 'SpecialRandomGetRandomTitle', array( &$randstr, &$this->isRedir, &$this->namespaces, &$this->extra, &$title ) ) ) {
+ if ( !wfRunHooks( 'SpecialRandomGetRandomTitle', array( &$randstr, &$this->isRedir, &$this->namespaces,
+ &$this->extra, &$title ) ) ) {
return $title;
}
$row = $this->selectRandomPageFromDB( $randstr );
@@ -111,53 +114,50 @@ class RandomPage extends SpecialPage {
* any more bias than what the page_random scheme
* causes anyway. Trust me, I'm a mathematician. :)
*/
- if( !$row )
+ if( !$row ) {
$row = $this->selectRandomPageFromDB( "0" );
+ }
- if( $row )
+ if( $row ) {
return Title::makeTitleSafe( $row->page_namespace, $row->page_title );
- else
+ } else {
return null;
+ }
+ }
+
+ protected function getQueryInfo( $randstr ) {
+ $redirect = $this->isRedirect() ? 1 : 0;
+
+ return array(
+ 'tables' => array( 'page' ),
+ 'fields' => array( 'page_title', 'page_namespace' ),
+ 'conds' => array_merge( array(
+ 'page_namespace' => $this->namespaces,
+ 'page_is_redirect' => $redirect,
+ 'page_random >= ' . $randstr
+ ), $this->extra ),
+ 'options' => array(
+ 'ORDER BY' => 'page_random',
+ 'USE INDEX' => 'page_random',
+ 'LIMIT' => 1,
+ ),
+ 'join_conds' => array()
+ );
}
- private function selectRandomPageFromDB( $randstr ) {
- global $wgExtraRandompageSQL;
+ private function selectRandomPageFromDB( $randstr, $fname = __METHOD__ ) {
$dbr = wfGetDB( DB_SLAVE );
- $use_index = $dbr->useIndexClause( 'page_random' );
- $page = $dbr->tableName( 'page' );
+ $query = $this->getQueryInfo( $randstr );
+ $res = $dbr->select(
+ $query['tables'],
+ $query['fields'],
+ $query['conds'],
+ $fname,
+ $query['options'],
+ $query['join_conds']
+ );
- $ns = implode( ",", $this->namespaces );
- $redirect = $this->isRedirect() ? 1 : 0;
-
- if ( $wgExtraRandompageSQL ) {
- $this->extra[] = $wgExtraRandompageSQL;
- }
- if ( $this->addExtraSQL() ) {
- $this->extra[] = $this->addExtraSQL();
- }
- $extra = '';
- if ( $this->extra ) {
- $extra = 'AND (' . implode( ') AND (', $this->extra ) . ')';
- }
- $sql = "SELECT page_title, page_namespace
- FROM $page $use_index
- WHERE page_namespace IN ( $ns )
- AND page_is_redirect = $redirect
- AND page_random >= $randstr
- $extra
- ORDER BY page_random";
-
- $sql = $dbr->limitResult( $sql, 1, 0 );
- $res = $dbr->query( $sql, __METHOD__ );
return $dbr->fetchObject( $res );
}
-
- /* an alternative to $wgExtraRandompageSQL so subclasses
- * can add their own SQL by overriding this function
- * @deprecated, append to $this->extra instead
- */
- public function addExtraSQL() {
- return '';
- }
}
diff --git a/includes/specials/SpecialRecentchanges.php b/includes/specials/SpecialRecentchanges.php
index c012beca..6c78ced0 100644
--- a/includes/specials/SpecialRecentchanges.php
+++ b/includes/specials/SpecialRecentchanges.php
@@ -28,6 +28,7 @@
*/
class SpecialRecentChanges extends IncludableSpecialPage {
var $rcOptions, $rcSubpage;
+ protected $customFilters;
public function __construct( $name = 'Recentchanges' ) {
parent::__construct( $name );
@@ -39,22 +40,22 @@ class SpecialRecentChanges extends IncludableSpecialPage {
* @return FormOptions
*/
public function getDefaultOptions() {
- global $wgUser;
$opts = new FormOptions();
- $opts->add( 'days', (int)$wgUser->getOption( 'rcdays' ) );
- $opts->add( 'limit', (int)$wgUser->getOption( 'rclimit' ) );
+ $opts->add( 'days', (int)$this->getUser()->getOption( 'rcdays' ) );
+ $opts->add( 'limit', (int)$this->getUser()->getOption( 'rclimit' ) );
$opts->add( 'from', '' );
- $opts->add( 'hideminor', $wgUser->getBoolOption( 'hideminor' ) );
+ $opts->add( 'hideminor', $this->getUser()->getBoolOption( 'hideminor' ) );
$opts->add( 'hidebots', true );
$opts->add( 'hideanons', false );
$opts->add( 'hideliu', false );
- $opts->add( 'hidepatrolled', $wgUser->getBoolOption( 'hidepatrolled' ) );
+ $opts->add( 'hidepatrolled', $this->getUser()->getBoolOption( 'hidepatrolled' ) );
$opts->add( 'hidemyself', false );
$opts->add( 'namespace', '', FormOptions::INTNULL );
$opts->add( 'invert', false );
+ $opts->add( 'associated', false );
$opts->add( 'categories', '' );
$opts->add( 'categories_any', false );
@@ -65,13 +66,20 @@ class SpecialRecentChanges extends IncludableSpecialPage {
/**
* Create a FormOptions object with options as specified by the user
*
+ * @param $parameters array
+ *
* @return FormOptions
*/
public function setup( $parameters ) {
- global $wgRequest;
-
$opts = $this->getDefaultOptions();
- $opts->fetchValuesFromRequest( $wgRequest );
+
+ $this->customFilters = array();
+ wfRunHooks( 'SpecialRecentChangesFilters', array( $this, &$this->customFilters ) );
+ foreach( $this->customFilters as $key => $params ) {
+ $opts->add( $key, $params['default'] );
+ }
+
+ $opts->fetchValuesFromRequest( $this->getRequest() );
// Give precedence to subpage syntax
if( $parameters !== null ) {
@@ -88,10 +96,10 @@ class SpecialRecentChanges extends IncludableSpecialPage {
* @return FormOptions
*/
public function feedSetup() {
- global $wgFeedLimit, $wgRequest;
+ global $wgFeedLimit;
$opts = $this->getDefaultOptions();
# Feed is cached on limit,hideminor,namespace; other params would randomly not work
- $opts->fetchValuesFromRequest( $wgRequest, array( 'limit', 'hideminor', 'namespace' ) );
+ $opts->fetchValuesFromRequest( $this->getRequest(), array( 'limit', 'hideminor', 'namespace' ) );
$opts->validateIntBounds( 'limit', 0, $wgFeedLimit );
return $opts;
}
@@ -101,9 +109,12 @@ class SpecialRecentChanges extends IncludableSpecialPage {
*/
public function getOptions() {
if ( $this->rcOptions === null ) {
- global $wgRequest;
- $feedFormat = $wgRequest->getVal( 'feed' );
- $this->rcOptions = $feedFormat ? $this->feedSetup() : $this->setup( $this->rcSubpage );
+ if ( $this->including() ) {
+ $isFeed = false;
+ } else {
+ $isFeed = (bool)$this->getRequest()->getVal( 'feed' );
+ }
+ $this->rcOptions = $isFeed ? $this->feedSetup() : $this->setup( $this->rcSubpage );
}
return $this->rcOptions;
}
@@ -115,12 +126,11 @@ class SpecialRecentChanges extends IncludableSpecialPage {
* @param $subpage String
*/
public function execute( $subpage ) {
- global $wgRequest, $wgOut;
$this->rcSubpage = $subpage;
- $feedFormat = $wgRequest->getVal( 'feed' );
+ $feedFormat = $this->including() ? null : $this->getRequest()->getVal( 'feed' );
# 10 seconds server-side caching max
- $wgOut->setSquidMaxage( 10 );
+ $this->getOutput()->setSquidMaxage( 10 );
# Check if the client has a cached version
$lastmod = $this->checkLastModified( $feedFormat );
if( $lastmod === false ) {
@@ -130,6 +140,7 @@ class SpecialRecentChanges extends IncludableSpecialPage {
$opts = $this->getOptions();
$this->setHeaders();
$this->outputHeader();
+ $this->addRecentChangesJS();
// Fetch results, prepare a batch link existence check query
$conds = $this->buildMainQueryConds( $opts );
@@ -144,8 +155,8 @@ class SpecialRecentChanges extends IncludableSpecialPage {
if( !$feedFormat ) {
$batch = new LinkBatch;
foreach( $rows as $row ) {
- $batch->add( NS_USER, $row->rc_user_text );
- $batch->add( NS_USER_TALK, $row->rc_user_text );
+ $batch->add( NS_USER, $row->rc_user_text );
+ $batch->add( NS_USER_TALK, $row->rc_user_text );
$batch->add( $row->rc_namespace, $row->rc_title );
}
$batch->execute();
@@ -169,7 +180,8 @@ class SpecialRecentChanges extends IncludableSpecialPage {
$changesFeed = new ChangesFeed( $feedFormat, 'rcfeed' );
$formatter = $changesFeed->getFeedObject(
wfMsgForContent( 'recentchanges' ),
- wfMsgForContent( 'recentchanges-feed-description' )
+ wfMsgForContent( 'recentchanges-feed-description' ),
+ $this->getTitle()->getFullURL()
);
return array( $changesFeed, $formatter );
}
@@ -184,20 +196,42 @@ class SpecialRecentChanges extends IncludableSpecialPage {
public function parseParameters( $par, FormOptions $opts ) {
$bits = preg_split( '/\s*,\s*/', trim( $par ) );
foreach( $bits as $bit ) {
- if( 'hidebots' === $bit ) $opts['hidebots'] = true;
- if( 'bots' === $bit ) $opts['hidebots'] = false;
- if( 'hideminor' === $bit ) $opts['hideminor'] = true;
- if( 'minor' === $bit ) $opts['hideminor'] = false;
- if( 'hideliu' === $bit ) $opts['hideliu'] = true;
- if( 'hidepatrolled' === $bit ) $opts['hidepatrolled'] = true;
- if( 'hideanons' === $bit ) $opts['hideanons'] = true;
- if( 'hidemyself' === $bit ) $opts['hidemyself'] = true;
+ if( 'hidebots' === $bit ) {
+ $opts['hidebots'] = true;
+ }
+ if( 'bots' === $bit ) {
+ $opts['hidebots'] = false;
+ }
+ if( 'hideminor' === $bit ) {
+ $opts['hideminor'] = true;
+ }
+ if( 'minor' === $bit ) {
+ $opts['hideminor'] = false;
+ }
+ if( 'hideliu' === $bit ) {
+ $opts['hideliu'] = true;
+ }
+ if( 'hidepatrolled' === $bit ) {
+ $opts['hidepatrolled'] = true;
+ }
+ if( 'hideanons' === $bit ) {
+ $opts['hideanons'] = true;
+ }
+ if( 'hidemyself' === $bit ) {
+ $opts['hidemyself'] = true;
+ }
- if( is_numeric( $bit ) ) $opts['limit'] = $bit;
+ if( is_numeric( $bit ) ) {
+ $opts['limit'] = $bit;
+ }
$m = array();
- if( preg_match( '/^limit=(\d+)$/', $bit, $m ) ) $opts['limit'] = $m[1];
- if( preg_match( '/^days=(\d+)$/', $bit, $m ) ) $opts['days'] = $m[1];
+ if( preg_match( '/^limit=(\d+)$/', $bit, $m ) ) {
+ $opts['limit'] = $m[1];
+ }
+ if( preg_match( '/^days=(\d+)$/', $bit, $m ) ) {
+ $opts['days'] = $m[1];
+ }
}
}
@@ -210,11 +244,10 @@ class SpecialRecentChanges extends IncludableSpecialPage {
* @return String or false
*/
public function checkLastModified( $feedFormat ) {
- global $wgUseRCPatrol, $wgOut;
$dbr = wfGetDB( DB_SLAVE );
$lastmod = $dbr->selectField( 'recentchanges', 'MAX(rc_timestamp)', false, __METHOD__ );
- if( $feedFormat || !$wgUseRCPatrol ) {
- if( $lastmod && $wgOut->checkLastModified( $lastmod ) ) {
+ if( $feedFormat || !$this->getUser()->useRCPatrol() ) {
+ if( $lastmod && $this->getOutput()->checkLastModified( $lastmod ) ) {
# Client cache fresh and headers sent, nothing more to do.
return false;
}
@@ -229,8 +262,6 @@ class SpecialRecentChanges extends IncludableSpecialPage {
* @return array
*/
public function buildMainQueryConds( FormOptions $opts ) {
- global $wgUser;
-
$dbr = wfGetDB( DB_SLAVE );
$conds = array();
@@ -261,35 +292,58 @@ class SpecialRecentChanges extends IncludableSpecialPage {
$conds[] = 'rc_timestamp >= ' . $dbr->addQuotes( $cutoff );
-
- $hidePatrol = $wgUser->useRCPatrol() && $opts['hidepatrolled'];
+ $hidePatrol = $this->getUser()->useRCPatrol() && $opts['hidepatrolled'];
$hideLoggedInUsers = $opts['hideliu'] && !$forcebot;
$hideAnonymousUsers = $opts['hideanons'] && !$forcebot;
- if( $opts['hideminor'] ) $conds['rc_minor'] = 0;
- if( $opts['hidebots'] ) $conds['rc_bot'] = 0;
- if( $hidePatrol ) $conds['rc_patrolled'] = 0;
- if( $forcebot ) $conds['rc_bot'] = 1;
- if( $hideLoggedInUsers ) $conds[] = 'rc_user = 0';
- if( $hideAnonymousUsers ) $conds[] = 'rc_user != 0';
+ if( $opts['hideminor'] ) {
+ $conds['rc_minor'] = 0;
+ }
+ if( $opts['hidebots'] ) {
+ $conds['rc_bot'] = 0;
+ }
+ if( $hidePatrol ) {
+ $conds['rc_patrolled'] = 0;
+ }
+ if( $forcebot ) {
+ $conds['rc_bot'] = 1;
+ }
+ if( $hideLoggedInUsers ) {
+ $conds[] = 'rc_user = 0';
+ }
+ if( $hideAnonymousUsers ) {
+ $conds[] = 'rc_user != 0';
+ }
if( $opts['hidemyself'] ) {
- if( $wgUser->getId() ) {
- $conds[] = 'rc_user != ' . $dbr->addQuotes( $wgUser->getId() );
+ if( $this->getUser()->getId() ) {
+ $conds[] = 'rc_user != ' . $dbr->addQuotes( $this->getUser()->getId() );
} else {
- $conds[] = 'rc_user_text != ' . $dbr->addQuotes( $wgUser->getName() );
+ $conds[] = 'rc_user_text != ' . $dbr->addQuotes( $this->getUser()->getName() );
}
}
# Namespace filtering
if( $opts['namespace'] !== '' ) {
- if( !$opts['invert'] ) {
- $conds[] = 'rc_namespace = ' . $dbr->addQuotes( $opts['namespace'] );
+ $selectedNS = $dbr->addQuotes( $opts['namespace'] );
+ $operator = $opts['invert'] ? '!=' : '=';
+ $boolean = $opts['invert'] ? 'AND' : 'OR';
+
+ # namespace association (bug 2429)
+ if( !$opts['associated'] ) {
+ $condition = "rc_namespace $operator $selectedNS";
} else {
- $conds[] = 'rc_namespace != ' . $dbr->addQuotes( $opts['namespace'] );
+ # Also add the associated namespace
+ $associatedNS = $dbr->addQuotes(
+ MWNamespace::getAssociated( $opts['namespace'] )
+ );
+ $condition = "(rc_namespace $operator $selectedNS "
+ . $boolean
+ . " rc_namespace $operator $associatedNS)";
}
- }
+ $conds[] = $condition;
+ }
return $conds;
}
@@ -301,75 +355,94 @@ class SpecialRecentChanges extends IncludableSpecialPage {
* @return database result or false (for Recentchangeslinked only)
*/
public function doMainQuery( $conds, $opts ) {
- global $wgUser;
-
$tables = array( 'recentchanges' );
$join_conds = array();
- $query_options = array( 'USE INDEX' => array('recentchanges' => 'rc_timestamp') );
+ $query_options = array(
+ 'USE INDEX' => array( 'recentchanges' => 'rc_timestamp' )
+ );
- $uid = $wgUser->getId();
+ $uid = $this->getUser()->getId();
$dbr = wfGetDB( DB_SLAVE );
$limit = $opts['limit'];
$namespace = $opts['namespace'];
- $select = '*';
$invert = $opts['invert'];
+ $associated = $opts['associated'];
+ $fields = array( $dbr->tableName( 'recentchanges' ) . '.*' ); // all rc columns
// JOIN on watchlist for users
- if( $uid ) {
+ if ( $uid ) {
$tables[] = 'watchlist';
+ $fields[] = 'wl_user';
+ $fields[] = 'wl_notificationtimestamp';
$join_conds['watchlist'] = array('LEFT JOIN',
"wl_user={$uid} AND wl_title=rc_title AND wl_namespace=rc_namespace");
}
- if ($wgUser->isAllowed("rollback")) {
+ if ( $this->getUser()->isAllowed( 'rollback' ) ) {
$tables[] = 'page';
+ $fields[] = 'page_latest';
$join_conds['page'] = array('LEFT JOIN', 'rc_cur_id=page_id');
}
if ( !$this->including() ) {
// Tag stuff.
// Doesn't work when transcluding. See bug 23293
- $fields = array();
- // Fields are * in this case, so let the function modify an empty array to keep it happy.
ChangeTags::modifyDisplayQuery(
- $tables, $fields, $conds, $join_conds, $query_options, $opts['tagfilter']
+ $tables, $fields, $conds, $join_conds, $query_options,
+ $opts['tagfilter']
);
}
- if ( !wfRunHooks( 'SpecialRecentChangesQuery', array( &$conds, &$tables, &$join_conds, $opts, &$query_options, &$select ) ) )
+ if ( !wfRunHooks( 'SpecialRecentChangesQuery',
+ array( &$conds, &$tables, &$join_conds, $opts, &$query_options, &$fields ) ) )
+ {
return false;
+ }
// Don't use the new_namespace_time timestamp index if:
// (a) "All namespaces" selected
- // (b) We want all pages NOT in a certain namespaces (inverted)
+ // (b) We want pages in more than one namespace (inverted/associated)
// (c) There is a tag to filter on (use tag index instead)
// (d) UNION + sort/limit is not an option for the DBMS
- if( is_null( $namespace )
- || ( $invert && !is_null( $namespace ) )
+ if( $namespace === ''
+ || ( $invert || $associated )
|| $opts['tagfilter'] != ''
|| !$dbr->unionSupportsOrderAndLimit() )
{
- $res = $dbr->select( $tables, '*', $conds, __METHOD__,
+ $res = $dbr->select( $tables, $fields, $conds, __METHOD__,
array( 'ORDER BY' => 'rc_timestamp DESC', 'LIMIT' => $limit ) +
$query_options,
$join_conds );
// We have a new_namespace_time index! UNION over new=(0,1) and sort result set!
} else {
// New pages
- $sqlNew = $dbr->selectSQLText( $tables, $select,
+ $sqlNew = $dbr->selectSQLText(
+ $tables,
+ $fields,
array( 'rc_new' => 1 ) + $conds,
__METHOD__,
- array( 'ORDER BY' => 'rc_timestamp DESC', 'LIMIT' => $limit,
- 'USE INDEX' => array('recentchanges' => 'rc_timestamp') ),
- $join_conds );
+ array(
+ 'ORDER BY' => 'rc_timestamp DESC',
+ 'LIMIT' => $limit,
+ 'USE INDEX' => array( 'recentchanges' => 'new_name_timestamp' )
+ ),
+ $join_conds
+ );
// Old pages
- $sqlOld = $dbr->selectSQLText( $tables, '*',
+ $sqlOld = $dbr->selectSQLText(
+ $tables,
+ $fields,
array( 'rc_new' => 0 ) + $conds,
__METHOD__,
- array( 'ORDER BY' => 'rc_timestamp DESC', 'LIMIT' => $limit,
- 'USE INDEX' => array('recentchanges' => 'rc_timestamp') ),
- $join_conds );
+ array(
+ 'ORDER BY' => 'rc_timestamp DESC',
+ 'LIMIT' => $limit,
+ 'USE INDEX' => array( 'recentchanges' => 'new_name_timestamp' )
+ ),
+ $join_conds
+ );
# Join the two fast queries, and sort the result set
- $sql = $dbr->unionQueries(array($sqlNew, $sqlOld), false).' ORDER BY rc_timestamp DESC';
- $sql = $dbr->limitResult($sql, $limit, false);
+ $sql = $dbr->unionQueries( array( $sqlNew, $sqlOld ), false ) .
+ ' ORDER BY rc_timestamp DESC';
+ $sql = $dbr->limitResult( $sql, $limit, false );
$res = $dbr->query( $sql, __METHOD__ );
}
@@ -377,14 +450,13 @@ class SpecialRecentChanges extends IncludableSpecialPage {
}
/**
- * Send output to $wgOut, only called if not used feeds
+ * Send output to the OutputPage object, only called if not used feeds
*
* @param $rows Array of database rows
* @param $opts FormOptions
*/
public function webOutput( $rows, $opts ) {
- global $wgOut, $wgUser, $wgRCShowWatchingUsers, $wgShowUpdatedMarker;
- global $wgAllowCategorizedRecentChanges;
+ global $wgRCShowWatchingUsers, $wgShowUpdatedMarker, $wgAllowCategorizedRecentChanges;
$limit = $opts['limit'];
@@ -394,43 +466,47 @@ class SpecialRecentChanges extends IncludableSpecialPage {
}
// And now for the content
- $wgOut->setFeedAppendQuery( $this->getFeedQuery() );
+ $this->getOutput()->setFeedAppendQuery( $this->getFeedQuery() );
if( $wgAllowCategorizedRecentChanges ) {
$this->filterByCategories( $rows, $opts );
}
- $showWatcherCount = $wgRCShowWatchingUsers && $wgUser->getOption( 'shownumberswatching' );
+ $showWatcherCount = $wgRCShowWatchingUsers && $this->getUser()->getOption( 'shownumberswatching' );
$watcherCache = array();
$dbr = wfGetDB( DB_SLAVE );
$counter = 1;
- $list = ChangesList::newFromUser( $wgUser );
+ $list = ChangesList::newFromContext( $this->getContext() );
$s = $list->beginRecentChangesList();
foreach( $rows as $obj ) {
- if( $limit == 0 ) break;
+ if( $limit == 0 ) {
+ break;
+ }
$rc = RecentChange::newFromRow( $obj );
$rc->counter = $counter++;
# Check if the page has been updated since the last visit
- if( $wgShowUpdatedMarker && !empty($obj->wl_notificationtimestamp) ) {
- $rc->notificationtimestamp = ($obj->rc_timestamp >= $obj->wl_notificationtimestamp);
+ if( $wgShowUpdatedMarker && !empty( $obj->wl_notificationtimestamp ) ) {
+ $rc->notificationtimestamp = ( $obj->rc_timestamp >= $obj->wl_notificationtimestamp );
} else {
$rc->notificationtimestamp = false; // Default
}
# Check the number of users watching the page
$rc->numberofWatchingusers = 0; // Default
if( $showWatcherCount && $obj->rc_namespace >= 0 ) {
- if( !isset($watcherCache[$obj->rc_namespace][$obj->rc_title]) ) {
+ if( !isset( $watcherCache[$obj->rc_namespace][$obj->rc_title] ) ) {
$watcherCache[$obj->rc_namespace][$obj->rc_title] =
- $dbr->selectField( 'watchlist',
+ $dbr->selectField(
+ 'watchlist',
'COUNT(*)',
array(
'wl_namespace' => $obj->rc_namespace,
'wl_title' => $obj->rc_title,
),
- __METHOD__ . '-watchers' );
+ __METHOD__ . '-watchers'
+ );
}
$rc->numberofWatchingusers = $watcherCache[$obj->rc_namespace][$obj->rc_title];
}
@@ -438,7 +514,7 @@ class SpecialRecentChanges extends IncludableSpecialPage {
--$limit;
}
$s .= $list->endRecentChangesList();
- $wgOut->addHTML( $s );
+ $this->getOutput()->addHTML( $s );
}
/**
@@ -456,14 +532,16 @@ class SpecialRecentChanges extends IncludableSpecialPage {
* @return String: XHTML
*/
public function doHeader( $opts ) {
- global $wgScript, $wgOut;
+ global $wgScript;
- $this->setTopText( $wgOut, $opts );
+ $this->setTopText( $opts );
$defaults = $opts->getAllValues();
$nondefaults = $opts->getChangedValues();
- $opts->consumeValues( array( 'namespace', 'invert', 'tagfilter',
- 'categories', 'categories_any' ) );
+ $opts->consumeValues( array(
+ 'namespace', 'invert', 'associated', 'tagfilter',
+ 'categories', 'categories_any'
+ ) );
$panel = array();
$panel[] = $this->optionsPanel( $defaults, $nondefaults );
@@ -502,11 +580,11 @@ class SpecialRecentChanges extends IncludableSpecialPage {
$panel[] = $form;
$panelString = implode( "\n", $panel );
- $wgOut->addHTML(
+ $this->getOutput()->addHTML(
Xml::fieldset( wfMsg( 'recentchanges-legend' ), $panelString, array( 'class' => 'rcoptions' ) )
);
- $this->setBottomText( $wgOut, $opts );
+ $this->setBottomText( $opts );
}
/**
@@ -515,7 +593,7 @@ class SpecialRecentChanges extends IncludableSpecialPage {
* @param $opts FormOptions
* @return Array
*/
- function getExtraOptions( $opts ){
+ function getExtraOptions( $opts ) {
$extraOpts = array();
$extraOpts['namespace'] = $this->namespaceFilterForm( $opts );
@@ -525,8 +603,9 @@ class SpecialRecentChanges extends IncludableSpecialPage {
}
$tagFilter = ChangeTags::buildTagFilterSelector( $opts['tagfilter'] );
- if ( count($tagFilter) )
+ if ( count( $tagFilter ) ) {
$extraOpts['tagfilter'] = $tagFilter;
+ }
wfRunHooks( 'SpecialRecentChangesPanel', array( &$extraOpts, $opts ) );
return $extraOpts;
@@ -535,33 +614,41 @@ class SpecialRecentChanges extends IncludableSpecialPage {
/**
* Send the text to be displayed above the options
*
- * @param $out OutputPage
* @param $opts FormOptions
*/
- function setTopText( OutputPage $out, FormOptions $opts ){
- $out->addWikiText( wfMsgForContentNoTrans( 'recentchangestext' ) );
+ function setTopText( FormOptions $opts ) {
+ $this->getOutput()->addWikiText( wfMsgForContentNoTrans( 'recentchangestext' ) );
}
/**
* Send the text to be displayed after the options, for use in
* Recentchangeslinked
*
- * @param $out OutputPage
* @param $opts FormOptions
*/
- function setBottomText( OutputPage $out, FormOptions $opts ){}
+ function setBottomText( FormOptions $opts ) {}
/**
* Creates the choose namespace selection
*
+ * @todo Uses radio buttons (HASHAR)
* @param $opts FormOptions
* @return String
*/
protected function namespaceFilterForm( FormOptions $opts ) {
$nsSelect = Xml::namespaceSelector( $opts['namespace'], '' );
- $nsLabel = Xml::label( wfMsg('namespace'), 'namespace' );
- $invert = Xml::checkLabel( wfMsg('invert'), 'invert', 'nsinvert', $opts['invert'] );
- return array( $nsLabel, "$nsSelect $invert" );
+ $nsLabel = Xml::label( wfMsg( 'namespace' ), 'namespace' );
+ $invert = Xml::checkLabel(
+ wfMsg( 'invert' ), 'invert', 'nsinvert',
+ $opts['invert'],
+ array( 'title' => wfMsg( 'tooltip-invert' ) )
+ );
+ $associated = Xml::checkLabel(
+ wfMsg( 'namespace_association' ), 'associated', 'nsassociated',
+ $opts['associated'],
+ array( 'title' => wfMsg( 'tooltip-namespace_association' ) )
+ );
+ return array( $nsLabel, "$nsSelect $invert $associated" );
}
/**
@@ -571,10 +658,10 @@ class SpecialRecentChanges extends IncludableSpecialPage {
* @return Array
*/
protected function categoryFilterForm( FormOptions $opts ) {
- list( $label, $input ) = Xml::inputLabelSep( wfMsg('rc_categories'),
+ list( $label, $input ) = Xml::inputLabelSep( wfMsg( 'rc_categories' ),
'categories', 'mw-categories', false, $opts['categories'] );
- $input .= ' ' . Xml::checkLabel( wfMsg('rc_categories_any'),
+ $input .= ' ' . Xml::checkLabel( wfMsg( 'rc_categories_any' ),
'categories_any', 'mw-categories_any', $opts['categories_any'] );
return array( $label, $input );
@@ -597,7 +684,9 @@ class SpecialRecentChanges extends IncludableSpecialPage {
$cats = array();
foreach( $categories as $cat ) {
$cat = trim( $cat );
- if( $cat == '' ) continue;
+ if( $cat == '' ) {
+ continue;
+ }
$cats[] = $cat;
}
@@ -605,10 +694,12 @@ class SpecialRecentChanges extends IncludableSpecialPage {
$articles = array();
$a2r = array();
$rowsarr = array();
- foreach( $rows AS $k => $r ) {
+ foreach( $rows as $k => $r ) {
$nt = Title::makeTitle( $r->rc_namespace, $r->rc_title );
$id = $nt->getArticleID();
- if( $id == 0 ) continue; # Page might have been deleted...
+ if( $id == 0 ) {
+ continue; # Page might have been deleted...
+ }
if( !in_array( $id, $articles ) ) {
$articles[] = $id;
}
@@ -620,18 +711,19 @@ class SpecialRecentChanges extends IncludableSpecialPage {
}
# Shortcut?
- if( !count( $articles ) || !count( $cats ) )
- return ;
+ if( !count( $articles ) || !count( $cats ) ) {
+ return;
+ }
# Look up
$c = new Categoryfinder;
- $c->seed( $articles, $cats, $opts['categories_any'] ? "OR" : "AND" ) ;
+ $c->seed( $articles, $cats, $opts['categories_any'] ? 'OR' : 'AND' );
$match = $c->run();
# Filter
$newrows = array();
- foreach( $match AS $id ) {
- foreach( $a2r[$id] AS $rev ) {
+ foreach( $match as $id ) {
+ foreach( $a2r[$id] as $rev ) {
$k = $rev;
$newrows[$k] = $rowsarr[$k];
}
@@ -648,15 +740,12 @@ class SpecialRecentChanges extends IncludableSpecialPage {
* @param $active Boolean: whether to show the link in bold
*/
function makeOptionsLink( $title, $override, $options, $active = false ) {
- global $wgUser;
- $sk = $wgUser->getSkin();
$params = $override + $options;
+ $text = htmlspecialchars( $title );
if ( $active ) {
- return $sk->link( $this->getTitle(), '<strong>' . htmlspecialchars( $title ) . '</strong>',
- array(), $params, array( 'known' ) );
- } else {
- return $sk->link( $this->getTitle(), htmlspecialchars( $title ), array() , $params, array( 'known' ) );
+ $text = '<strong>' . $text . '</strong>';
}
+ return Linker::linkKnown( $this->getTitle(), $text, array(), $params );
}
/**
@@ -666,20 +755,21 @@ class SpecialRecentChanges extends IncludableSpecialPage {
* @param $nondefaults Array
*/
function optionsPanel( $defaults, $nondefaults ) {
- global $wgLang, $wgUser, $wgRCLinkLimits, $wgRCLinkDays;
+ global $wgRCLinkLimits, $wgRCLinkDays;
$options = $nondefaults + $defaults;
$note = '';
- if( !wfEmptyMsg( 'rclegend', wfMsg('rclegend') ) ) {
- $note .= '<div class="mw-rclegend">' . wfMsgExt( 'rclegend', array('parseinline') ) . "</div>\n";
+ if( !wfEmptyMsg( 'rclegend' ) ) {
+ $note .= '<div class="mw-rclegend">' .
+ wfMsgExt( 'rclegend', array( 'parseinline' ) ) . "</div>\n";
}
if( $options['from'] ) {
$note .= wfMsgExt( 'rcnotefrom', array( 'parseinline' ),
- $wgLang->formatNum( $options['limit'] ),
- $wgLang->timeanddate( $options['from'], true ),
- $wgLang->date( $options['from'], true ),
- $wgLang->time( $options['from'], true ) ) . '<br />';
+ $this->getLang()->formatNum( $options['limit'] ),
+ $this->getLang()->timeanddate( $options['from'], true ),
+ $this->getLang()->date( $options['from'], true ),
+ $this->getLang()->time( $options['from'], true ) ) . '<br />';
}
# Sort data for display and make sure it's unique after we've added user data.
@@ -692,50 +782,63 @@ class SpecialRecentChanges extends IncludableSpecialPage {
// limit links
foreach( $wgRCLinkLimits as $value ) {
- $cl[] = $this->makeOptionsLink( $wgLang->formatNum( $value ),
- array( 'limit' => $value ), $nondefaults, $value == $options['limit'] ) ;
+ $cl[] = $this->makeOptionsLink( $this->getLang()->formatNum( $value ),
+ array( 'limit' => $value ), $nondefaults, $value == $options['limit'] );
}
- $cl = $wgLang->pipeList( $cl );
+ $cl = $this->getLang()->pipeList( $cl );
// day links, reset 'from' to none
foreach( $wgRCLinkDays as $value ) {
- $dl[] = $this->makeOptionsLink( $wgLang->formatNum( $value ),
- array( 'days' => $value, 'from' => '' ), $nondefaults, $value == $options['days'] ) ;
+ $dl[] = $this->makeOptionsLink( $this->getLang()->formatNum( $value ),
+ array( 'days' => $value, 'from' => '' ), $nondefaults, $value == $options['days'] );
}
- $dl = $wgLang->pipeList( $dl );
+ $dl = $this->getLang()->pipeList( $dl );
// show/hide links
$showhide = array( wfMsg( 'show' ), wfMsg( 'hide' ) );
- $minorLink = $this->makeOptionsLink( $showhide[1-$options['hideminor']],
- array( 'hideminor' => 1-$options['hideminor'] ), $nondefaults);
- $botLink = $this->makeOptionsLink( $showhide[1-$options['hidebots']],
- array( 'hidebots' => 1-$options['hidebots'] ), $nondefaults);
- $anonsLink = $this->makeOptionsLink( $showhide[ 1 - $options['hideanons'] ],
- array( 'hideanons' => 1 - $options['hideanons'] ), $nondefaults );
- $liuLink = $this->makeOptionsLink( $showhide[1-$options['hideliu']],
- array( 'hideliu' => 1-$options['hideliu'] ), $nondefaults);
- $patrLink = $this->makeOptionsLink( $showhide[1-$options['hidepatrolled']],
- array( 'hidepatrolled' => 1-$options['hidepatrolled'] ), $nondefaults);
- $myselfLink = $this->makeOptionsLink( $showhide[1-$options['hidemyself']],
- array( 'hidemyself' => 1-$options['hidemyself'] ), $nondefaults);
-
- $links[] = wfMsgHtml( 'rcshowhideminor', $minorLink );
- $links[] = wfMsgHtml( 'rcshowhidebots', $botLink );
- $links[] = wfMsgHtml( 'rcshowhideanons', $anonsLink );
- $links[] = wfMsgHtml( 'rcshowhideliu', $liuLink );
- if( $wgUser->useRCPatrol() )
- $links[] = wfMsgHtml( 'rcshowhidepatr', $patrLink );
- $links[] = wfMsgHtml( 'rcshowhidemine', $myselfLink );
- $hl = $wgLang->pipeList( $links );
+ $filters = array(
+ 'hideminor' => 'rcshowhideminor',
+ 'hidebots' => 'rcshowhidebots',
+ 'hideanons' => 'rcshowhideanons',
+ 'hideliu' => 'rcshowhideliu',
+ 'hidepatrolled' => 'rcshowhidepatr',
+ 'hidemyself' => 'rcshowhidemine'
+ );
+ foreach ( $this->customFilters as $key => $params ) {
+ $filters[$key] = $params['msg'];
+ }
+ // Disable some if needed
+ if ( !$this->getUser()->useRCPatrol() ) {
+ unset( $filters['hidepatrolled'] );
+ }
+
+ $links = array();
+ foreach ( $filters as $key => $msg ) {
+ $link = $this->makeOptionsLink( $showhide[1 - $options[$key]],
+ array( $key => 1-$options[$key] ), $nondefaults );
+ $links[] = wfMsgHtml( $msg, $link );
+ }
// show from this onward link
- $now = $wgLang->timeanddate( wfTimestampNow(), true );
- $tl = $this->makeOptionsLink( $now, array( 'from' => wfTimestampNow() ), $nondefaults );
+ $timestamp = wfTimestampNow();
+ $now = $this->getLang()->timeanddate( $timestamp, true );
+ $tl = $this->makeOptionsLink(
+ $now, array( 'from' => $timestamp ), $nondefaults
+ );
$rclinks = wfMsgExt( 'rclinks', array( 'parseinline', 'replaceafter' ),
- $cl, $dl, $hl );
+ $cl, $dl, $this->getLang()->pipeList( $links ) );
$rclistfrom = wfMsgExt( 'rclistfrom', array( 'parseinline', 'replaceafter' ), $tl );
return "{$note}$rclinks<br />$rclistfrom";
}
+
+ /**
+ * add javascript specific to the [[Special:RecentChanges]] page
+ */
+ function addRecentChangesJS() {
+ $this->getOutput()->addModules( array(
+ 'mediawiki.special.recentchanges',
+ ) );
+ }
}
diff --git a/includes/specials/SpecialRecentchangeslinked.php b/includes/specials/SpecialRecentchangeslinked.php
index db0f554d..8b8369b5 100644
--- a/includes/specials/SpecialRecentchangeslinked.php
+++ b/includes/specials/SpecialRecentchangeslinked.php
@@ -46,9 +46,8 @@ class SpecialRecentchangeslinked extends SpecialRecentChanges {
}
public function feedSetup() {
- global $wgRequest;
$opts = parent::feedSetup();
- $opts['target'] = $wgRequest->getVal( 'target' );
+ $opts['target'] = $this->getRequest()->getVal( 'target' );
return $opts;
}
@@ -56,14 +55,13 @@ class SpecialRecentchangeslinked extends SpecialRecentChanges {
$feed = new ChangesFeed( $feedFormat, false );
$feedObj = $feed->getFeedObject(
wfMsgForContent( 'recentchangeslinked-title', $this->getTargetTitle()->getPrefixedText() ),
- wfMsgForContent( 'recentchangeslinked-feed' )
+ wfMsgForContent( 'recentchangeslinked-feed' ),
+ $this->getTitle()->getFullUrl()
);
return array( $feed, $feedObj );
}
public function doMainQuery( $conds, $opts ) {
- global $wgUser, $wgOut;
-
$target = $opts['target'];
$showlinkedto = $opts['showlinkedto'];
$limit = $opts['limit'];
@@ -73,11 +71,11 @@ class SpecialRecentchangeslinked extends SpecialRecentChanges {
}
$title = Title::newFromURL( $target );
if( !$title || $title->getInterwiki() != '' ){
- $wgOut->wrapWikiMsg( "<div class=\"errorbox\">\n$1\n</div><br style=\"clear: both\" />", 'allpagesbadtitle' );
+ $this->getOutput()->wrapWikiMsg( "<div class=\"errorbox\">\n$1\n</div><br style=\"clear: both\" />", 'allpagesbadtitle' );
return false;
}
- $wgOut->setPageTitle( wfMsg( 'recentchangeslinked-title', $title->getPrefixedText() ) );
+ $this->getOutput()->setPageTitle( wfMsg( 'recentchangeslinked-title', $title->getPrefixedText() ) );
/*
* Ordinary links are in the pagelinks table, while transclusions are
@@ -99,13 +97,13 @@ class SpecialRecentchangeslinked extends SpecialRecentChanges {
$query_options = array();
// left join with watchlist table to highlight watched rows
- $uid = $wgUser->getId();
+ $uid = $this->getUser()->getId();
if( $uid ) {
$tables[] = 'watchlist';
$select[] = 'wl_user';
$join_conds['watchlist'] = array( 'LEFT JOIN', "wl_user={$uid} AND wl_title=rc_title AND wl_namespace=rc_namespace" );
}
- if ( $wgUser->isAllowed( 'rollback' ) ) {
+ if ( $this->getUser()->isAllowed( 'rollback' ) ) {
$tables[] = 'page';
$join_conds['page'] = array('LEFT JOIN', 'rc_cur_id=page_id');
$select[] = 'page_latest';
@@ -143,7 +141,7 @@ class SpecialRecentchangeslinked extends SpecialRecentChanges {
// imagelinks and categorylinks tables have no xx_namespace field, and have xx_to instead of xx_title
if( $link_table == 'imagelinks' ) $link_ns = NS_FILE;
- else if( $link_table == 'categorylinks' ) $link_ns = NS_CATEGORY;
+ elseif( $link_table == 'categorylinks' ) $link_ns = NS_CATEGORY;
else $link_ns = 0;
if( $showlinkedto ) {
@@ -171,16 +169,16 @@ class SpecialRecentchangeslinked extends SpecialRecentChanges {
else
$order = array();
-
- $query = $dbr->selectSQLText(
- array_merge( $tables, array( $link_table ) ),
- $select,
+
+ $query = $dbr->selectSQLText(
+ array_merge( $tables, array( $link_table ) ),
+ $select,
$conds + $subconds,
- __METHOD__,
+ __METHOD__,
$order + $query_options,
$join_conds + array( $link_table => array( 'INNER JOIN', $subjoin ) )
);
-
+
if( $dbr->unionSupportsOrderAndLimit())
$query = $dbr->limitResult( $query, $limit );
@@ -196,7 +194,7 @@ class SpecialRecentchangeslinked extends SpecialRecentChanges {
$sql = $dbr->unionQueries($subsql, false).' ORDER BY rc_timestamp DESC';
$sql = $dbr->limitResult($sql, $limit, false);
}
-
+
$res = $dbr->query( $sql, __METHOD__ );
if( $res->numRows() == 0 )
@@ -204,7 +202,7 @@ class SpecialRecentchangeslinked extends SpecialRecentChanges {
return $res;
}
-
+
function getExtraOptions( $opts ){
$opts->consumeValues( array( 'showlinkedto', 'target', 'tagfilter' ) );
$extraOpts = array();
@@ -219,6 +217,9 @@ class SpecialRecentchangeslinked extends SpecialRecentChanges {
return $extraOpts;
}
+ /**
+ * @return Title
+ */
function getTargetTitle() {
if ( $this->rclTargetTitle === null ) {
$opts = $this->getOptions();
@@ -231,13 +232,12 @@ class SpecialRecentchangeslinked extends SpecialRecentChanges {
return $this->rclTargetTitle;
}
- function setTopText( OutputPage $out, FormOptions $opts ) {
- global $wgUser;
- $skin = $wgUser->getSkin();
+ function setTopText( FormOptions $opts ) {
$target = $this->getTargetTitle();
- if( $target )
- $out->setSubtitle( wfMsg( 'recentchangeslinked-backlink', $skin->link( $target,
+ if( $target ) {
+ $this->getOutput()->setSubtitle( wfMsg( 'recentchangeslinked-backlink', Linker::link( $target,
$target->getPrefixedText(), array(), array( 'redirect' => 'no' ) ) ) );
+ }
}
public function getFeedQuery() {
@@ -249,9 +249,9 @@ class SpecialRecentchangeslinked extends SpecialRecentChanges {
}
}
- function setBottomText( OutputPage $out, FormOptions $opts ) {
- if( isset( $this->mResultEmpty ) && $this->mResultEmpty ){
- $out->addWikiMsg( 'recentchangeslinked-noresult' );
+ function setBottomText( FormOptions $opts ) {
+ if( isset( $this->mResultEmpty ) && $this->mResultEmpty ) {
+ $this->getOutput()->addWikiMsg( 'recentchangeslinked-noresult' );
}
}
}
diff --git a/includes/specials/SpecialRevisiondelete.php b/includes/specials/SpecialRevisiondelete.php
index f77fc347..3c643253 100644
--- a/includes/specials/SpecialRevisiondelete.php
+++ b/includes/specials/SpecialRevisiondelete.php
@@ -28,9 +28,6 @@
* @ingroup SpecialPage
*/
class SpecialRevisionDelete extends UnlistedSpecialPage {
- /** Skin object */
- var $skin;
-
/** True if the submit button was clicked, and the form was posted */
var $submitClicked;
@@ -64,39 +61,39 @@ class SpecialRevisionDelete extends UnlistedSpecialPage {
*/
static $allowedTypes = array(
'revision' => array(
- 'check-label' => 'revdelete-hide-text',
+ 'check-label' => 'revdelete-hide-text',
'deletion-bits' => Revision::DELETED_TEXT,
- 'success' => 'revdelete-success',
- 'failure' => 'revdelete-failure',
- 'list-class' => 'RevDel_RevisionList',
+ 'success' => 'revdelete-success',
+ 'failure' => 'revdelete-failure',
+ 'list-class' => 'RevDel_RevisionList',
),
'archive' => array(
- 'check-label' => 'revdelete-hide-text',
+ 'check-label' => 'revdelete-hide-text',
'deletion-bits' => Revision::DELETED_TEXT,
- 'success' => 'revdelete-success',
- 'failure' => 'revdelete-failure',
- 'list-class' => 'RevDel_ArchiveList',
+ 'success' => 'revdelete-success',
+ 'failure' => 'revdelete-failure',
+ 'list-class' => 'RevDel_ArchiveList',
),
'oldimage'=> array(
- 'check-label' => 'revdelete-hide-image',
+ 'check-label' => 'revdelete-hide-image',
'deletion-bits' => File::DELETED_FILE,
- 'success' => 'revdelete-success',
- 'failure' => 'revdelete-failure',
- 'list-class' => 'RevDel_FileList',
+ 'success' => 'revdelete-success',
+ 'failure' => 'revdelete-failure',
+ 'list-class' => 'RevDel_FileList',
),
'filearchive' => array(
- 'check-label' => 'revdelete-hide-image',
+ 'check-label' => 'revdelete-hide-image',
'deletion-bits' => File::DELETED_FILE,
- 'success' => 'revdelete-success',
- 'failure' => 'revdelete-failure',
- 'list-class' => 'RevDel_ArchivedFileList',
+ 'success' => 'revdelete-success',
+ 'failure' => 'revdelete-failure',
+ 'list-class' => 'RevDel_ArchivedFileList',
),
'logging' => array(
- 'check-label' => 'revdelete-hide-name',
+ 'check-label' => 'revdelete-hide-name',
'deletion-bits' => LogPage::DELETED_ACTION,
- 'success' => 'logdelete-success',
- 'failure' => 'logdelete-failure',
- 'list-class' => 'RevDel_LogList',
+ 'success' => 'logdelete-success',
+ 'failure' => 'logdelete-failure',
+ 'list-class' => 'RevDel_LogList',
),
);
@@ -114,43 +111,46 @@ class SpecialRevisionDelete extends UnlistedSpecialPage {
}
public function execute( $par ) {
- global $wgOut, $wgUser, $wgRequest;
- if( !$wgUser->isAllowed( 'deletedhistory' ) ) {
- $wgOut->permissionRequired( 'deletedhistory' );
+ $output = $this->getOutput();
+ $user = $this->getUser();
+ if( !$user->isAllowed( 'deletedhistory' ) ) {
+ $output->permissionRequired( 'deletedhistory' );
return;
- } else if( wfReadOnly() ) {
- $wgOut->readOnlyPage();
+ } elseif( wfReadOnly() ) {
+ $output->readOnlyPage();
return;
}
- $this->mIsAllowed = $wgUser->isAllowed('deleterevision'); // for changes
- $this->skin = $wgUser->getSkin();
+ $this->mIsAllowed = $user->isAllowed('deleterevision'); // for changes
$this->setHeaders();
$this->outputHeader();
- $this->submitClicked = $wgRequest->wasPosted() && $wgRequest->getBool( 'wpSubmit' );
+ $request = $this->getRequest();
+ $this->submitClicked = $request->wasPosted() && $request->getBool( 'wpSubmit' );
# Handle our many different possible input types.
- $ids = $wgRequest->getVal( 'ids' );
+ $ids = $request->getVal( 'ids' );
if ( !is_null( $ids ) ) {
# Allow CSV, for backwards compatibility, or a single ID for show/hide links
$this->ids = explode( ',', $ids );
} else {
# Array input
- $this->ids = array_keys( $wgRequest->getArray('ids',array()) );
+ $this->ids = array_keys( $request->getArray('ids',array()) );
}
// $this->ids = array_map( 'intval', $this->ids );
$this->ids = array_unique( array_filter( $this->ids ) );
- if ( $wgRequest->getVal( 'action' ) == 'historysubmit' ) {
- # For show/hide form submission from history page
- $this->targetObj = $GLOBALS['wgTitle'];
+ if ( $request->getVal( 'action' ) == 'historysubmit' ) {
+ // For show/hide form submission from history page
+ // Since we are access through index.php?title=XXX&action=historysubmit
+ // getFullTitle() will contain the target title and not our title
+ $this->targetObj = $this->getFullTitle();
$this->typeName = 'revision';
} else {
- $this->typeName = $wgRequest->getVal( 'type' );
- $this->targetObj = Title::newFromText( $wgRequest->getText( 'target' ) );
+ $this->typeName = $request->getVal( 'type' );
+ $this->targetObj = Title::newFromText( $request->getText( 'target' ) );
}
# For reviewing deleted files...
- $this->archiveName = $wgRequest->getVal( 'file' );
- $this->token = $wgRequest->getVal( 'token' );
+ $this->archiveName = $request->getVal( 'file' );
+ $this->token = $request->getVal( 'token' );
if ( $this->archiveName && $this->targetObj ) {
$this->tryShowFile( $this->archiveName );
return;
@@ -162,23 +162,23 @@ class SpecialRevisionDelete extends UnlistedSpecialPage {
# No targets?
if( !isset( self::$allowedTypes[$this->typeName] ) || count( $this->ids ) == 0 ) {
- $wgOut->showErrorPage( 'revdelete-nooldid-title', 'revdelete-nooldid-text' );
+ $output->showErrorPage( 'revdelete-nooldid-title', 'revdelete-nooldid-text' );
return;
}
$this->typeInfo = self::$allowedTypes[$this->typeName];
# If we have revisions, get the title from the first one
- # since they should all be from the same page. This allows
+ # since they should all be from the same page. This allows
# for more flexibility with page moves...
if( $this->typeName == 'revision' ) {
$rev = Revision::newFromId( $this->ids[0] );
$this->targetObj = $rev ? $rev->getTitle() : $this->targetObj;
}
-
- $this->otherReason = $wgRequest->getVal( 'wpReason' );
+
+ $this->otherReason = $request->getVal( 'wpReason' );
# We need a target page!
if( is_null($this->targetObj) ) {
- $wgOut->addWikiMsg( 'undelete-header' );
+ $output->addWikiMsg( 'undelete-header' );
return;
}
# Give a link to the logs/hist for this page
@@ -190,27 +190,27 @@ class SpecialRevisionDelete extends UnlistedSpecialPage {
array( 'revdelete-hide-comment', 'wpHideComment', Revision::DELETED_COMMENT ),
array( 'revdelete-hide-user', 'wpHideUser', Revision::DELETED_USER )
);
- if( $wgUser->isAllowed('suppressrevision') ) {
+ if( $user->isAllowed('suppressrevision') ) {
$this->checks[] = array( 'revdelete-hide-restricted',
'wpHideRestricted', Revision::DELETED_RESTRICTED );
}
# Either submit or create our form
if( $this->mIsAllowed && $this->submitClicked ) {
- $this->submit( $wgRequest );
+ $this->submit( $request );
} else {
$this->showForm();
}
-
+
$qc = $this->getLogQueryCond();
# Show relevant lines from the deletion log
- $wgOut->addHTML( "<h2>" . htmlspecialchars( LogPage::logName( 'delete' ) ) . "</h2>\n" );
- LogEventsList::showLogExtract( $wgOut, 'delete',
+ $output->addHTML( "<h2>" . htmlspecialchars( LogPage::logName( 'delete' ) ) . "</h2>\n" );
+ LogEventsList::showLogExtract( $output, 'delete',
$this->targetObj->getPrefixedText(), '', array( 'lim' => 25, 'conds' => $qc ) );
# Show relevant lines from the suppression log
- if( $wgUser->isAllowed( 'suppressionlog' ) ) {
- $wgOut->addHTML( "<h2>" . htmlspecialchars( LogPage::logName( 'suppress' ) ) . "</h2>\n" );
- LogEventsList::showLogExtract( $wgOut, 'suppress',
+ if( $user->isAllowed( 'suppressionlog' ) ) {
+ $output->addHTML( "<h2>" . htmlspecialchars( LogPage::logName( 'suppress' ) ) . "</h2>\n" );
+ LogEventsList::showLogExtract( $output, 'suppress',
$this->targetObj->getPrefixedText(), '', array( 'lim' => 25, 'conds' => $qc ) );
}
}
@@ -219,11 +219,10 @@ class SpecialRevisionDelete extends UnlistedSpecialPage {
* Show some useful links in the subtitle
*/
protected function showConvenienceLinks() {
- global $wgOut, $wgUser, $wgLang;
# Give a link to the logs/hist for this page
if( $this->targetObj ) {
$links = array();
- $links[] = $this->skin->linkKnown(
+ $links[] = Linker::linkKnown(
SpecialPage::getTitleFor( 'Log' ),
wfMsgHtml( 'viewpagelogs' ),
array(),
@@ -231,16 +230,16 @@ class SpecialRevisionDelete extends UnlistedSpecialPage {
);
if ( $this->targetObj->getNamespace() != NS_SPECIAL ) {
# Give a link to the page history
- $links[] = $this->skin->linkKnown(
+ $links[] = Linker::linkKnown(
$this->targetObj,
wfMsgHtml( 'pagehist' ),
array(),
array( 'action' => 'history' )
);
# Link to deleted edits
- if( $wgUser->isAllowed('undelete') ) {
+ if( $this->getUser()->isAllowed('undelete') ) {
$undelete = SpecialPage::getTitleFor( 'Undelete' );
- $links[] = $this->skin->linkKnown(
+ $links[] = Linker::linkKnown(
$undelete,
wfMsgHtml( 'deletedhist' ),
array(),
@@ -249,7 +248,7 @@ class SpecialRevisionDelete extends UnlistedSpecialPage {
}
}
# Logs themselves don't have histories or archived revisions
- $wgOut->setSubtitle( '<p>' . $wgLang->pipeList( $links ) . '</p>' );
+ $this->getOutput()->setSubtitle( '<p>' . $this->getLang()->pipeList( $links ) . '</p>' );
}
}
@@ -259,7 +258,7 @@ class SpecialRevisionDelete extends UnlistedSpecialPage {
protected function getLogQueryCond() {
$conds = array();
// Revision delete logs for these item
- $conds['log_type'] = array('delete','suppress');
+ $conds['log_type'] = array( 'delete', 'suppress' );
$conds['log_action'] = $this->getList()->getLogAction();
$conds['ls_field'] = RevisionDeleter::getRelationType( $this->typeName );
$conds['ls_value'] = $this->ids;
@@ -271,36 +270,34 @@ class SpecialRevisionDelete extends UnlistedSpecialPage {
* TODO Mostly copied from Special:Undelete. Refactor.
*/
protected function tryShowFile( $archiveName ) {
- global $wgOut, $wgRequest, $wgUser, $wgLang;
-
$repo = RepoGroup::singleton()->getLocalRepo();
$oimage = $repo->newFromArchiveName( $this->targetObj, $archiveName );
$oimage->load();
// Check if user is allowed to see this file
if ( !$oimage->exists() ) {
- $wgOut->addWikiMsg( 'revdelete-no-file' );
+ $this->getOutput()->addWikiMsg( 'revdelete-no-file' );
return;
}
if( !$oimage->userCan(File::DELETED_FILE) ) {
if( $oimage->isDeleted( File::DELETED_RESTRICTED ) ) {
- $wgOut->permissionRequired( 'suppressrevision' );
+ $this->getOutput()->permissionRequired( 'suppressrevision' );
} else {
- $wgOut->permissionRequired( 'deletedtext' );
+ $this->getOutput()->permissionRequired( 'deletedtext' );
}
return;
}
- if ( !$wgUser->matchEditToken( $this->token, $archiveName ) ) {
- $wgOut->addWikiMsg( 'revdelete-show-file-confirm',
+ if ( !$this->getUser()->matchEditToken( $this->token, $archiveName ) ) {
+ $this->getOutput()->addWikiMsg( 'revdelete-show-file-confirm',
$this->targetObj->getText(),
- $wgLang->date( $oimage->getTimestamp() ),
- $wgLang->time( $oimage->getTimestamp() ) );
- $wgOut->addHTML(
+ $this->getLang()->date( $oimage->getTimestamp() ),
+ $this->getLang()->time( $oimage->getTimestamp() ) );
+ $this->getOutput()->addHTML(
Xml::openElement( 'form', array(
'method' => 'POST',
'action' => $this->getTitle()->getLocalUrl(
'target=' . urlencode( $oimage->getName() ) .
'&file=' . urlencode( $archiveName ) .
- '&token=' . urlencode( $wgUser->editToken( $archiveName ) ) )
+ '&token=' . urlencode( $this->getUser()->editToken( $archiveName ) ) )
)
) .
Xml::submitButton( wfMsg( 'revdelete-show-file-submit' ) ) .
@@ -308,14 +305,14 @@ class SpecialRevisionDelete extends UnlistedSpecialPage {
);
return;
}
- $wgOut->disable();
+ $this->getOutput()->disable();
# We mustn't allow the output to be Squid cached, otherwise
# if an admin previews a deleted image, and it's cached, then
# a user without appropriate permissions can toddle off and
# nab the image, and Squid will serve it
- $wgRequest->response()->header( 'Expires: ' . gmdate( 'D, d M Y H:i:s', 0 ) . ' GMT' );
- $wgRequest->response()->header( 'Cache-Control: no-cache, no-store, max-age=0, must-revalidate' );
- $wgRequest->response()->header( 'Pragma: no-cache' );
+ $this->getRequest()->response()->header( 'Expires: ' . gmdate( 'D, d M Y H:i:s', 0 ) . ' GMT' );
+ $this->getRequest()->response()->header( 'Cache-Control: no-cache, no-store, max-age=0, must-revalidate' );
+ $this->getRequest()->response()->header( 'Pragma: no-cache' );
# Stream the file to the client
global $IP;
@@ -331,27 +328,26 @@ class SpecialRevisionDelete extends UnlistedSpecialPage {
protected function getList() {
if ( is_null( $this->list ) ) {
$class = $this->typeInfo['list-class'];
- $this->list = new $class( $this, $this->targetObj, $this->ids );
+ $this->list = new $class( $this->getContext(), $this->targetObj, $this->ids );
}
return $this->list;
}
/**
- * Show a list of items that we will operate on, and show a form with checkboxes
+ * Show a list of items that we will operate on, and show a form with checkboxes
* which will allow the user to choose new visibility settings.
*/
protected function showForm() {
- global $wgOut, $wgUser, $wgLang;
$UserAllowed = true;
if ( $this->typeName == 'logging' ) {
- $wgOut->addWikiMsg( 'logdelete-selected', $wgLang->formatNum( count($this->ids) ) );
+ $this->getOutput()->addWikiMsg( 'logdelete-selected', $this->getLang()->formatNum( count($this->ids) ) );
} else {
- $wgOut->addWikiMsg( 'revdelete-selected',
+ $this->getOutput()->addWikiMsg( 'revdelete-selected',
$this->targetObj->getPrefixedText(), count( $this->ids ) );
}
- $wgOut->addHTML( "<ul>" );
+ $this->getOutput()->addHTML( "<ul>" );
$numRevisions = 0;
// Live revisions...
@@ -360,21 +356,21 @@ class SpecialRevisionDelete extends UnlistedSpecialPage {
$item = $list->current();
if ( !$item->canView() ) {
if( !$this->submitClicked ) {
- $wgOut->permissionRequired( 'suppressrevision' );
+ $this->getOutput()->permissionRequired( 'suppressrevision' );
return;
}
$UserAllowed = false;
}
$numRevisions++;
- $wgOut->addHTML( $item->getHTML() );
+ $this->getOutput()->addHTML( $item->getHTML() );
}
if( !$numRevisions ) {
- $wgOut->showErrorPage( 'revdelete-nooldid-title', 'revdelete-nooldid-text' );
+ $this->getOutput()->showErrorPage( 'revdelete-nooldid-title', 'revdelete-nooldid-text' );
return;
}
-
- $wgOut->addHTML( "</ul>" );
+
+ $this->getOutput()->addHTML( "</ul>" );
// Explanation text
$this->addUsageText();
@@ -384,7 +380,7 @@ class SpecialRevisionDelete extends UnlistedSpecialPage {
// Show form if the user can submit
if( $this->mIsAllowed ) {
$out = Xml::openElement( 'form', array( 'method' => 'post',
- 'action' => $this->getTitle()->getLocalUrl( array( 'action' => 'submit' ) ),
+ 'action' => $this->getTitle()->getLocalUrl( array( 'action' => 'submit' ) ),
'id' => 'mw-revdel-form-revisions' ) ) .
Xml::fieldset( wfMsg( 'revdelete-legend' ) ) .
$this->buildCheckBoxes() .
@@ -404,7 +400,7 @@ class SpecialRevisionDelete extends UnlistedSpecialPage {
Xml::label( wfMsg( 'revdelete-otherreason' ), 'wpReason' ) .
'</td>' .
'<td class="mw-input">' .
- Xml::input( 'wpReason', 60, $this->otherReason, array( 'id' => 'wpReason' ) ) .
+ Xml::input( 'wpReason', 60, $this->otherReason, array( 'id' => 'wpReason', 'maxlength' => 100 ) ) .
'</td>' .
"</tr><tr>\n" .
'<td></td>' .
@@ -414,7 +410,7 @@ class SpecialRevisionDelete extends UnlistedSpecialPage {
'</td>' .
"</tr>\n" .
Xml::closeElement( 'table' ) .
- Html::hidden( 'wpEditToken', $wgUser->editToken() ) .
+ Html::hidden( 'wpEditToken', $this->getUser()->editToken() ) .
Html::hidden( 'target', $this->targetObj->getPrefixedText() ) .
Html::hidden( 'type', $this->typeName ) .
Html::hidden( 'ids', implode( ',', $this->ids ) ) .
@@ -425,9 +421,9 @@ class SpecialRevisionDelete extends UnlistedSpecialPage {
if( $this->mIsAllowed ) {
$out .= Xml::closeElement( 'form' ) . "\n";
// Show link to edit the dropdown reasons
- if( $wgUser->isAllowed( 'editinterface' ) ) {
+ if( $this->getUser()->isAllowed( 'editinterface' ) ) {
$title = Title::makeTitle( NS_MEDIAWIKI, 'revdelete-reason-dropdown' );
- $link = $wgUser->getSkin()->link(
+ $link = Linker::link(
$title,
wfMsgHtml( 'revdelete-edit-reasonlist' ),
array(),
@@ -436,30 +432,27 @@ class SpecialRevisionDelete extends UnlistedSpecialPage {
$out .= Xml::tags( 'p', array( 'class' => 'mw-revdel-editreasons' ), $link ) . "\n";
}
}
- $wgOut->addHTML( $out );
+ $this->getOutput()->addHTML( $out );
}
/**
* Show some introductory text
- * FIXME Wikimedia-specific policy text
+ * @todo FIXME: Wikimedia-specific policy text
*/
protected function addUsageText() {
- global $wgOut, $wgUser;
- $wgOut->addWikiMsg( 'revdelete-text' );
- if( $wgUser->isAllowed( 'suppressrevision' ) ) {
- $wgOut->addWikiMsg( 'revdelete-suppress-text' );
+ $this->getOutput()->addWikiMsg( 'revdelete-text' );
+ if( $this->getUser()->isAllowed( 'suppressrevision' ) ) {
+ $this->getOutput()->addWikiMsg( 'revdelete-suppress-text' );
}
if( $this->mIsAllowed ) {
- $wgOut->addWikiMsg( 'revdelete-confirm' );
+ $this->getOutput()->addWikiMsg( 'revdelete-confirm' );
}
}
-
+
/**
* @return String: HTML
*/
protected function buildCheckBoxes() {
- global $wgRequest;
-
$html = '<table>';
// If there is just one item, use checkboxes
$list = $this->getList();
@@ -467,7 +460,7 @@ class SpecialRevisionDelete extends UnlistedSpecialPage {
$list->reset();
$bitfield = $list->current()->getBits(); // existing field
if( $this->submitClicked ) {
- $bitfield = $this->extractBitfield( $this->extractBitParams($wgRequest), $bitfield );
+ $bitfield = $this->extractBitfield( $this->extractBitParams(), $bitfield );
}
foreach( $this->checks as $item ) {
list( $message, $name, $field ) = $item;
@@ -488,7 +481,7 @@ class SpecialRevisionDelete extends UnlistedSpecialPage {
list( $message, $name, $field ) = $item;
// If there are several items, use third state by default...
if( $this->submitClicked ) {
- $selected = $wgRequest->getInt( $name, 0 /* unchecked */ );
+ $selected = $this->getRequest()->getInt( $name, 0 /* unchecked */ );
} else {
$selected = -1; // use existing field
}
@@ -503,24 +496,23 @@ class SpecialRevisionDelete extends UnlistedSpecialPage {
$html .= "<tr>$line</tr>\n";
}
}
-
+
$html .= '</table>';
return $html;
}
/**
* UI entry point for form submission.
- * @param $request WebRequest
*/
- protected function submit( $request ) {
- global $wgUser, $wgOut;
+ protected function submit() {
# Check edit token on submission
- if( $this->submitClicked && !$wgUser->matchEditToken( $request->getVal('wpEditToken') ) ) {
- $wgOut->addWikiMsg( 'sessionfailure' );
+ $token = $this->getRequest()->getVal('wpEditToken');
+ if( $this->submitClicked && !$this->getUser()->matchEditToken( $token ) ) {
+ $this->getOutput()->addWikiMsg( 'sessionfailure' );
return false;
}
- $bitParams = $this->extractBitParams( $request );
- $listReason = $request->getText( 'wpRevDeleteReasonList', 'other' ); // from dropdown
+ $bitParams = $this->extractBitParams();
+ $listReason = $this->getRequest()->getText( 'wpRevDeleteReasonList', 'other' ); // from dropdown
$comment = $listReason;
if( $comment != 'other' && $this->otherReason != '' ) {
// Entry from drop down menu + additional comment
@@ -529,8 +521,8 @@ class SpecialRevisionDelete extends UnlistedSpecialPage {
$comment = $this->otherReason;
}
# Can the user set this field?
- if( $bitParams[Revision::DELETED_RESTRICTED]==1 && !$wgUser->isAllowed('suppressrevision') ) {
- $wgOut->permissionRequired( 'suppressrevision' );
+ if( $bitParams[Revision::DELETED_RESTRICTED]==1 && !$this->getUser()->isAllowed('suppressrevision') ) {
+ $this->getOutput()->permissionRequired( 'suppressrevision' );
return false;
}
# If the save went through, go to success message...
@@ -549,9 +541,8 @@ class SpecialRevisionDelete extends UnlistedSpecialPage {
* Report that the submit operation succeeded
*/
protected function success() {
- global $wgOut;
- $wgOut->setPagetitle( wfMsg( 'actioncomplete' ) );
- $wgOut->wrapWikiMsg( "<span class=\"success\">\n$1\n</span>", $this->typeInfo['success'] );
+ $this->getOutput()->setPagetitle( wfMsg( 'actioncomplete' ) );
+ $this->getOutput()->wrapWikiMsg( "<span class=\"success\">\n$1\n</span>", $this->typeInfo['success'] );
$this->list->reloadFromMaster();
$this->showForm();
}
@@ -560,22 +551,21 @@ class SpecialRevisionDelete extends UnlistedSpecialPage {
* Report that the submit operation failed
*/
protected function failure( $status ) {
- global $wgOut;
- $wgOut->setPagetitle( wfMsg( 'actionfailed' ) );
- $wgOut->addWikiText( $status->getWikiText( $this->typeInfo['failure'] ) );
+ $this->getOutput()->setPagetitle( wfMsg( 'actionfailed' ) );
+ $this->getOutput()->addWikiText( $status->getWikiText( $this->typeInfo['failure'] ) );
$this->showForm();
}
/**
* Put together an array that contains -1, 0, or the *_deleted const for each bit
- * @param $request WebRequest
+ *
* @return array
*/
- protected function extractBitParams( $request ) {
+ protected function extractBitParams() {
$bitfield = array();
foreach( $this->checks as $item ) {
list( /* message */ , $name, $field ) = $item;
- $val = $request->getInt( $name, 0 /* unchecked */ );
+ $val = $this->getRequest()->getInt( $name, 0 /* unchecked */ );
if( $val < -1 || $val > 1) {
$val = -1; // -1 for existing value
}
@@ -586,7 +576,7 @@ class SpecialRevisionDelete extends UnlistedSpecialPage {
}
return $bitfield;
}
-
+
/**
* Put together a rev_deleted bitfield
* @param $bitPars array extractBitParams() params
@@ -599,7 +589,7 @@ class SpecialRevisionDelete extends UnlistedSpecialPage {
foreach( $bitPars as $const => $val ) {
if( $val == 1 ) {
$newBits |= $const; // $const is the *_deleted const
- } else if( $val == -1 ) {
+ } elseif( $val == -1 ) {
$newBits |= ($oldfield & $const); // use existing
}
}
diff --git a/includes/specials/SpecialSearch.php b/includes/specials/SpecialSearch.php
index fd6e858e..ba9d378a 100644
--- a/includes/specials/SpecialSearch.php
+++ b/includes/specials/SpecialSearch.php
@@ -24,35 +24,66 @@
*/
/**
- * Entry point
- *
- * @param $par String: (default '')
- */
-function wfSpecialSearch( $par = '' ) {
- global $wgRequest, $wgUser, $wgOut;
- $wgOut->allowClickjacking();
-
- // Strip underscores from title parameter; most of the time we'll want
- // text form here. But don't strip underscores from actual text params!
- $titleParam = str_replace( '_', ' ', $par );
- // Fetch the search term
- $search = str_replace( "\n", " ", $wgRequest->getText( 'search', $titleParam ) );
- $searchPage = new SpecialSearch( $wgRequest, $wgUser );
- if( $wgRequest->getVal( 'fulltext' )
- || !is_null( $wgRequest->getVal( 'offset' ))
- || !is_null( $wgRequest->getVal( 'searchx' )) )
- {
- $searchPage->showResults( $search );
- } else {
- $searchPage->goResult( $search );
- }
-}
-
-/**
* implements Special:Search - Run text & title search and display the output
* @ingroup SpecialPage
*/
-class SpecialSearch {
+class SpecialSearch extends SpecialPage {
+ /**
+ * Current search profile. Search profile is just a name that identifies
+ * the active search tab on the search page (content, help, discussions...)
+ * For users tt replaces the set of enabled namespaces from the query
+ * string when applicable. Extensions can add new profiles with hooks
+ * with custom search options just for that profile.
+ * null|string
+ */
+ protected $profile;
+
+ /// Search engine
+ protected $searchEngine;
+
+ /// For links
+ protected $extraParams = array();
+
+ /// No idea, apparently used by some other classes
+ protected $mPrefix;
+
+ const NAMESPACES_CURRENT = 'sense';
+
+ public function __construct() {
+ parent::__construct( 'Search' );
+ }
+
+ /**
+ * Entry point
+ *
+ * @param $par String or null
+ */
+ public function execute( $par ) {
+ global $wgRequest, $wgUser, $wgOut;
+
+ $this->setHeaders();
+ $this->outputHeader();
+ $wgOut->allowClickjacking();
+ $wgOut->addModuleStyles( 'mediawiki.special' );
+
+ // Strip underscores from title parameter; most of the time we'll want
+ // text form here. But don't strip underscores from actual text params!
+ $titleParam = str_replace( '_', ' ', $par );
+
+ // Fetch the search term
+ $search = str_replace( "\n", " ", $wgRequest->getText( 'search', $titleParam ) );
+
+ $this->load( $wgRequest, $wgUser );
+
+ if ( $wgRequest->getVal( 'fulltext' )
+ || !is_null( $wgRequest->getVal( 'offset' ) )
+ || !is_null( $wgRequest->getVal( 'searchx' ) ) )
+ {
+ $this->showResults( $search );
+ } else {
+ $this->goResult( $search );
+ }
+ }
/**
* Set up basic search parameters from the request and user settings.
@@ -61,18 +92,44 @@ class SpecialSearch {
* @param $request WebRequest
* @param $user User
*/
- public function __construct( &$request, &$user ) {
+ public function load( &$request, &$user ) {
list( $this->limit, $this->offset ) = $request->getLimitOffset( 20, 'searchlimit' );
- $this->mPrefix = $request->getVal('prefix', '');
- # Extract requested namespaces
- $this->namespaces = $this->powerSearch( $request );
- if( empty( $this->namespaces ) ) {
- $this->namespaces = SearchEngine::userNamespaces( $user );
+ $this->mPrefix = $request->getVal( 'prefix', '' );
+
+
+ # Extract manually requested namespaces
+ $nslist = $this->powerSearch( $request );
+ $this->profile = $profile = $request->getVal( 'profile', null );
+ $profiles = $this->getSearchProfiles();
+ if ( $profile === null) {
+ // BC with old request format
+ $this->profile = 'advanced';
+ if ( count( $nslist ) ) {
+ foreach( $profiles as $key => $data ) {
+ if ( $nslist === $data['namespaces'] && $key !== 'advanced') {
+ $this->profile = $key;
+ }
+ }
+ $this->namespaces = $nslist;
+ } else {
+ $this->namespaces = SearchEngine::userNamespaces( $user );
+ }
+ } elseif ( $profile === 'advanced' ) {
+ $this->namespaces = $nslist;
+ } else {
+ if ( isset( $profiles[$profile]['namespaces'] ) ) {
+ $this->namespaces = $profiles[$profile]['namespaces'];
+ } else {
+ // Unknown profile requested
+ $this->profile = 'default';
+ $this->namespaces = $profiles['default']['namespaces'];
+ }
}
- $this->searchRedirects = $request->getCheck( 'redirs' );
- $this->searchAdvanced = $request->getVal( 'advanced' );
- $this->active = 'advanced';
- $this->sk = $user->getSkin();
+
+ // Redirects defaults to true, but we don't know whether it was ticked of or just missing
+ $default = $request->getBool( 'profile' ) ? 0 : 1;
+ $this->searchRedirects = $request->getBool( 'redirs', $default ) ? 1 : 0;
+ $this->sk = $this->getSkin();
$this->didYouMeanHtml = ''; # html of did you mean... link
$this->fulltext = $request->getVal('fulltext');
}
@@ -93,12 +150,12 @@ class SpecialSearch {
}
# If there's an exact or very near match, jump right there.
$t = SearchEngine::getNearMatch( $term );
-
+
if ( !wfRunHooks( 'SpecialSearchGo', array( &$t, &$term ) ) ) {
# Hook requested termination
return;
}
-
+
if( !is_null( $t ) ) {
$wgOut->redirect( $t->getFullURL() );
return;
@@ -123,19 +180,21 @@ class SpecialSearch {
* @param $term String
*/
public function showResults( $term ) {
- global $wgOut, $wgUser, $wgDisableTextSearch, $wgContLang, $wgScript;
+ global $wgOut, $wgDisableTextSearch, $wgContLang, $wgScript;
wfProfileIn( __METHOD__ );
- $sk = $wgUser->getSkin();
+ $sk = $this->getSkin();
- $this->searchEngine = SearchEngine::create();
- $search =& $this->searchEngine;
+ $search = $this->getSearchEngine();
$search->setLimitOffset( $this->limit, $this->offset );
$search->setNamespaces( $this->namespaces );
- $search->showRedirects = $this->searchRedirects;
+ $search->showRedirects = $this->searchRedirects; // BC
+ $search->setFeatureData( 'list-redirects', $this->searchRedirects );
$search->prefix = $this->mPrefix;
$term = $search->transformSearchTerm($term);
+ wfRunHooks( 'SpecialSearchSetupEngine', array( $this, $this->profile, $search ) );
+
$this->setupPage( $term );
if( $wgDisableTextSearch ) {
@@ -146,14 +205,13 @@ class SpecialSearch {
wfProfileOut( __METHOD__ );
return;
}
- global $wgInputEncoding;
$wgOut->addHTML(
Xml::openElement( 'fieldset' ) .
Xml::element( 'legend', null, wfMsg( 'search-external' ) ) .
Xml::element( 'p', array( 'class' => 'mw-searchdisabled' ), wfMsg( 'searchdisabled' ) ) .
wfMsg( 'googlesearch',
htmlspecialchars( $term ),
- htmlspecialchars( $wgInputEncoding ),
+ htmlspecialchars( 'UTF-8' ),
htmlspecialchars( wfMsg( 'searchbutton' ) )
) .
Xml::closeElement( 'fieldset' )
@@ -205,7 +263,7 @@ class SpecialSearch {
Xml::openElement(
'form',
array(
- 'id' => ( $this->searchAdvanced ? 'powersearch' : 'search' ),
+ 'id' => ( $this->profile === 'advanced' ? 'powersearch' : 'search' ),
'method' => 'get',
'action' => $wgScript
)
@@ -214,7 +272,7 @@ class SpecialSearch {
$wgOut->addHtml(
Xml::openElement( 'table', array( 'id'=>'mw-search-top-table', 'border'=>0, 'cellpadding'=>0, 'cellspacing'=>0 ) ) .
Xml::openElement( 'tr' ) .
- Xml::openElement( 'td' ) . "\n" .
+ Xml::openElement( 'td' ) . "\n" .
$this->shortDialog( $term ) .
Xml::closeElement('td') .
Xml::closeElement('tr') .
@@ -223,17 +281,15 @@ class SpecialSearch {
// Sometimes the search engine knows there are too many hits
if( $titleMatches instanceof SearchResultTooMany ) {
- $wgOut->addWikiText( '==' . wfMsg( 'toomanymatches' ) . "==\n" );
+ $wgOut->wrapWikiMsg( "==$1==\n", 'toomanymatches' );
wfProfileOut( __METHOD__ );
return;
}
$filePrefix = $wgContLang->getFormattedNsText(NS_FILE).':';
if( trim( $term ) === '' || $filePrefix === trim( $term ) ) {
- $wgOut->addHTML( $this->formHeader($term, 0, 0));
- if( $this->searchAdvanced ) {
- $wgOut->addHTML( $this->powerSearchBox( $term ) );
- }
+ $wgOut->addHTML( $this->formHeader( $term, 0, 0 ) );
+ $wgOut->addHtml( $this->getProfileForm( $this->profile, $term ) );
$wgOut->addHTML( '</form>' );
// Empty query -- straight view of search form
wfProfileOut( __METHOD__ );
@@ -245,7 +301,7 @@ class SpecialSearch {
$textMatchesNum = $textMatches ? $textMatches->numRows() : 0;
// Total initial query matches (possible false positives)
$num = $titleMatchesNum + $textMatchesNum;
-
+
// Get total actual results (after second filtering, if any)
$numTitleMatches = $titleMatches && !is_null( $titleMatches->getTotalHits() ) ?
$titleMatches->getTotalHits() : $titleMatchesNum;
@@ -258,13 +314,12 @@ class SpecialSearch {
$totalRes += $titleMatches->getTotalHits();
if($textMatches && !is_null( $textMatches->getTotalHits() ))
$totalRes += $textMatches->getTotalHits();
-
+
// show number of results and current offset
- $wgOut->addHTML( $this->formHeader($term, $num, $totalRes));
- if( $this->searchAdvanced ) {
- $wgOut->addHTML( $this->powerSearchBox( $term ) );
- }
-
+ $wgOut->addHTML( $this->formHeader( $term, $num, $totalRes ) );
+ $wgOut->addHtml( $this->getProfileForm( $this->profile, $term ) );
+
+
$wgOut->addHtml( Xml::closeElement( 'form' ) );
$wgOut->addHtml( "<div class='searchresults'>" );
@@ -281,8 +336,9 @@ class SpecialSearch {
wfRunHooks( 'SpecialSearchResults', array( $term, &$titleMatches, &$textMatches ) );
} else {
wfRunHooks( 'SpecialSearchNoResults', array( $term ) );
- }
+ }
+ $wgOut->parserOptions()->setEditSection( false );
if( $titleMatches ) {
if( $numTitleMatches > 0 ) {
$wgOut->wrapWikiMsg( "==$1==\n", 'titlematches' );
@@ -321,23 +377,33 @@ class SpecialSearch {
}
wfProfileOut( __METHOD__ );
}
-
+
protected function showCreateLink( $t ) {
global $wgOut;
-
+
// show direct page/create link if applicable
- $messageName = null;
- if( !is_null($t) ) {
- if( $t->isKnown() ) {
- $messageName = 'searchmenu-exists';
- } elseif( $t->userCan( 'create' ) ) {
- $messageName = 'searchmenu-new';
- } else {
- $messageName = 'searchmenu-new-nocreate';
- }
- }
+
+ // Check DBkey !== '' in case of fragment link only.
+ if( is_null( $t ) || $t->getDBkey() === '' ) {
+ // invalid title
+ // preserve the paragraph for margins etc...
+ $this->getOutput()->addHtml( '<p></p>' );
+ return;
+ }
+ $messageName = '';
+ if( $t->isKnown() ) {
+ $messageName = 'searchmenu-exists';
+ } elseif( $t->userCan( 'create' ) ) {
+ $messageName = 'searchmenu-new';
+ } else {
+ $messageName = 'searchmenu-new-nocreate';
+ }
+ $params = array( $messageName, wfEscapeWikiText( $t->getPrefixedText() ) );
+ wfRunHooks( 'SpecialSearchCreateLink', array( $t, &$params ) );
+
+ // Extensions using the hook might still return an empty $messageName
if( $messageName ) {
- $wgOut->wrapWikiMsg( "<p class=\"mw-search-createlink\">\n$1</p>", array( $messageName, wfEscapeWikiText( $t->getPrefixedText() ) ) );
+ $this->getOutput()->wrapWikiMsg( "<p class=\"mw-search-createlink\">\n$1</p>", $params );
} else {
// preserve the paragraph for margins etc...
$wgOut->addHtml( '<p></p>' );
@@ -349,28 +415,14 @@ class SpecialSearch {
*/
protected function setupPage( $term ) {
global $wgOut;
- // Figure out the active search profile header
- if( $this->searchAdvanced ) {
- $this->active = 'advanced';
- } else {
- $profiles = $this->getSearchProfiles();
-
- foreach( $profiles as $key => $data ) {
- if ( $this->namespaces == $data['namespaces'] && $key != 'advanced')
- $this->active = $key;
- }
-
- }
+
# Should advanced UI be used?
- $this->searchAdvanced = ($this->active === 'advanced');
- if( !empty( $term ) ) {
+ $this->searchAdvanced = ($this->profile === 'advanced');
+ if( strval( $term ) !== '' ) {
$wgOut->setPageTitle( wfMsg( 'searchresults') );
$wgOut->setHTMLTitle( wfMsg( 'pagetitle', wfMsg( 'searchresults-title', $term ) ) );
}
- $wgOut->setArticleRelated( false );
- $wgOut->setRobotPolicy( 'noindex,nofollow' );
// add javascript specific to special:search
- $wgOut->addModules( 'mediawiki.legacy.search' );
$wgOut->addModules( 'mediawiki.special.search' );
}
@@ -388,6 +440,7 @@ class SpecialSearch {
$arr[] = $ns;
}
}
+
return $arr;
}
@@ -398,14 +451,15 @@ class SpecialSearch {
*/
protected function powerSearchOptions() {
$opt = array();
- foreach( $this->namespaces as $n ) {
- $opt['ns' . $n] = 1;
- }
$opt['redirs'] = $this->searchRedirects ? 1 : 0;
- if( $this->searchAdvanced ) {
- $opt['advanced'] = $this->searchAdvanced;
+ if( $this->profile !== 'advanced' ) {
+ $opt['profile'] = $this->profile;
+ } else {
+ foreach( $this->namespaces as $n ) {
+ $opt['ns' . $n] = 1;
+ }
}
- return $opt;
+ return $opt + $this->extraParams;
}
/**
@@ -443,7 +497,7 @@ class SpecialSearch {
* @param $terms Array: terms to highlight
*/
protected function showHit( $result, $terms ) {
- global $wgLang, $wgUser;
+ global $wgLang;
wfProfileIn( __METHOD__ );
if( $result->isBrokenTitle() ) {
@@ -451,16 +505,16 @@ class SpecialSearch {
return "<!-- Broken link in search result -->\n";
}
- $sk = $wgUser->getSkin();
+ $sk = $this->getSkin();
$t = $result->getTitle();
$titleSnippet = $result->getTitleSnippet($terms);
if( $titleSnippet == '' )
$titleSnippet = null;
-
+
$link_t = clone $t;
-
+
wfRunHooks( 'ShowSearchHitTitle',
array( &$link_t, &$titleSnippet, $result, $terms, $this ) );
@@ -509,7 +563,6 @@ class SpecialSearch {
$section = '';
-
if( !is_null($sectionTitle) ) {
if( $sectionText == '' )
$sectionText = null;
@@ -544,7 +597,7 @@ class SpecialSearch {
$size = wfMsgExt(
'search-result-size',
array( 'parsemag', 'escape' ),
- $this->sk->formatSize( $byteSize ),
+ $wgLang->formatSize( $byteSize ),
$wgLang->formatNum( $wordCount )
);
@@ -706,13 +759,13 @@ class SpecialSearch {
$out = "";
// display project name
if(is_null($lastInterwiki) || $lastInterwiki != $t->getInterwiki()) {
- if( key_exists($t->getInterwiki(),$customCaptions) )
+ if( array_key_exists($t->getInterwiki(),$customCaptions) ) {
// captions from 'search-interwiki-custom'
$caption = $customCaptions[$t->getInterwiki()];
- else{
+ } else {
// default is to show the hostname of the other wiki which might suck
// if there are many wikis on one hostname
- $parsed = parse_url($t->getFullURL());
+ $parsed = wfParseUrl( $t->getFullURL() );
$caption = wfMsg('search-interwiki-default', $parsed['host']);
}
// "more results" link (special page stuff could be localized, but we might not know target lang)
@@ -735,14 +788,28 @@ class SpecialSearch {
return $out;
}
+ protected function getProfileForm( $profile, $term ) {
+ // Hidden stuff
+ $opts = array();
+ $opts['redirs'] = $this->searchRedirects;
+ $opts['profile'] = $this->profile;
+
+ if ( $profile === 'advanced' ) {
+ return $this->powerSearchBox( $term, $opts );
+ } else {
+ $form = '';
+ wfRunHooks( 'SpecialSearchProfileForm', array( $this, &$form, $profile, $term, $opts ) );
+ return $form;
+ }
+ }
/**
- * Generates the power search box at bottom of [[Special:Search]]
+ * Generates the power search box at [[Special:Search]]
*
* @param $term String: search term
* @return String: HTML form
*/
- protected function powerSearchBox( $term ) {
+ protected function powerSearchBox( $term, $opts ) {
// Groups namespaces into rows according to subject
$rows = array();
foreach( SearchEngine::searchableNamespaces() as $namespace => $name ) {
@@ -768,7 +835,7 @@ class SpecialSearch {
}
$rows = array_values( $rows );
$numRows = count( $rows );
-
+
// Lays out namespaces in multiple floating two-column tables so they'll
// be arranged nicely while still accommodating different screen widths
$namespaceTables = '';
@@ -782,15 +849,21 @@ class SpecialSearch {
}
$namespaceTables .= Xml::closeElement( 'table' );
}
+
+ $showSections = array( 'namespaceTables' => $namespaceTables );
+
// Show redirects check only if backend supports it
- $redirects = '';
- if( $this->searchEngine->acceptListRedirects() ) {
- $redirects =
- Xml::check(
- 'redirs', $this->searchRedirects, array( 'value' => '1', 'id' => 'redirs' )
- ) .
- ' ' .
- Xml::label( wfMsg( 'powersearch-redir' ), 'redirs' );
+ if( $this->getSearchEngine()->supports( 'list-redirects' ) ) {
+ $showSections['redirects'] =
+ Xml::checkLabel( wfMsg( 'powersearch-redir' ), 'redirs', 'redirs', $this->searchRedirects );
+ }
+
+ wfRunHooks( 'SpecialSearchPowerBox', array( &$showSections, $term, $opts ) );
+
+ $hidden = '';
+ unset( $opts['redirs'] );
+ foreach( $opts as $key => $value ) {
+ $hidden .= Html::hidden( $key, $value );
}
// Return final output
return
@@ -809,7 +882,6 @@ class SpecialSearch {
array(
'type'=>'button',
'id' => 'mw-search-toggleall',
- 'onclick' => 'mwToggleSearchCheckboxes("all");',
'value' => wfMsg( 'powersearch-toggleall' )
)
) .
@@ -818,25 +890,20 @@ class SpecialSearch {
array(
'type'=>'button',
'id' => 'mw-search-togglenone',
- 'onclick' => 'mwToggleSearchCheckboxes("none");',
'value' => wfMsg( 'powersearch-togglenone' )
)
)
) .
Xml::element( 'div', array( 'class' => 'divider' ), '', false ) .
- $namespaceTables .
- Xml::element( 'div', array( 'class' => 'divider' ), '', false ) .
- $redirects .
- Html::hidden( 'title', SpecialPage::getTitleFor( 'Search' )->getPrefixedText() ) .
- Html::hidden( 'advanced', $this->searchAdvanced ) .
- Html::hidden( 'fulltext', 'Advanced search' ) .
+ implode( Xml::element( 'div', array( 'class' => 'divider' ), '', false ), $showSections ) .
+ $hidden .
Xml::closeElement( 'fieldset' );
}
-
+
protected function getSearchProfiles() {
// Builds list of Search Types (profiles)
$nsAllSet = array_keys( SearchEngine::searchableNamespaces() );
-
+
$profiles = array(
'default' => array(
'message' => 'searchprofile-articles',
@@ -867,25 +934,25 @@ class SpecialSearch {
'advanced' => array(
'message' => 'searchprofile-advanced',
'tooltip' => 'searchprofile-advanced-tooltip',
- 'namespaces' => $this->namespaces,
- 'parameters' => array( 'advanced' => 1 ),
+ 'namespaces' => self::NAMESPACES_CURRENT,
)
);
-
+
wfRunHooks( 'SpecialSearchProfiles', array( &$profiles ) );
foreach( $profiles as &$data ) {
- sort($data['namespaces']);
+ if ( !is_array( $data['namespaces'] ) ) continue;
+ sort( $data['namespaces'] );
}
-
+
return $profiles;
}
protected function formHeader( $term, $resultsShown, $totalNum ) {
global $wgLang;
-
+
$out = Xml::openElement('div', array( 'class' => 'mw-search-formheader' ) );
-
+
$bareterm = $term;
if( $this->startsWithImage( $term ) ) {
// Deletes prefixes
@@ -893,24 +960,29 @@ class SpecialSearch {
}
$profiles = $this->getSearchProfiles();
-
+
// Outputs XML for Search Types
$out .= Xml::openElement( 'div', array( 'class' => 'search-types' ) );
$out .= Xml::openElement( 'ul' );
foreach ( $profiles as $id => $profile ) {
+ if ( !isset( $profile['parameters'] ) ) {
+ $profile['parameters'] = array();
+ }
+ $profile['parameters']['profile'] = $id;
+
$tooltipParam = isset( $profile['namespace-messages'] ) ?
$wgLang->commaList( $profile['namespace-messages'] ) : null;
$out .= Xml::tags(
'li',
array(
- 'class' => $this->active == $id ? 'current' : 'normal'
+ 'class' => $this->profile === $id ? 'current' : 'normal'
),
$this->makeSearchLink(
$bareterm,
- $profile['namespaces'],
+ array(),
wfMsg( $profile['message'] ),
wfMsg( $profile['tooltip'], $tooltipParam ),
- isset( $profile['parameters'] ) ? $profile['parameters'] : array()
+ $profile['parameters']
)
);
}
@@ -930,60 +1002,54 @@ class SpecialSearch {
} elseif ( $resultsShown >= $this->limit ) {
$top = wfShowingResults( $this->offset, $this->limit );
} else {
- $top = wfShowingResultsNum( $this->offset, $this->limit, $resultsShown );
+ $top = wfMsgExt( 'showingresultsnum', array( 'parseinline' ),
+ $wgLang->formatNum( $this->limit ),
+ $wgLang->formatNum( $this->offset + 1 ),
+ $wgLang->formatNum( $resultsShown )
+ );
}
$out .= Xml::tags( 'div', array( 'class' => 'results-info' ),
Xml::tags( 'ul', null, Xml::tags( 'li', null, $top ) )
);
}
-
+
$out .= Xml::element( 'div', array( 'style' => 'clear:both' ), '', false );
$out .= Xml::closeElement('div');
-
- // Adds hidden namespace fields
- if ( !$this->searchAdvanced ) {
- foreach( $this->namespaces as $ns ) {
- $out .= Html::hidden( "ns{$ns}", '1' );
- }
- }
-
+
return $out;
}
protected function shortDialog( $term ) {
- $searchTitle = SpecialPage::getTitleFor( 'Search' );
- $out = Html::hidden( 'title', $searchTitle->getPrefixedText() ) . "\n";
- // Keep redirect setting
- $out .= Html::hidden( "redirs", (int)$this->searchRedirects ) . "\n";
+ $out = Html::hidden( 'title', $this->getTitle()->getPrefixedText() );
+ $out .= Html::hidden( 'profile', $this->profile ) . "\n";
// Term box
$out .= Html::input( 'search', $term, 'search', array(
- 'id' => $this->searchAdvanced ? 'powerSearchText' : 'searchText',
+ 'id' => $this->profile === 'advanced' ? 'powerSearchText' : 'searchText',
'size' => '50',
'autofocus'
) ) . "\n";
$out .= Html::hidden( 'fulltext', 'Search' ) . "\n";
$out .= Xml::submitButton( wfMsg( 'searchbutton' ) ) . "\n";
- return $out . $this->didYouMeanHtml;
+ return $out . $this->didYouMeanHtml;
}
/**
* Make a search link with some target namespaces
*
* @param $term String
- * @param $namespaces Array
+ * @param $namespaces Array ignored
* @param $label String: link's text
* @param $tooltip String: link's tooltip
* @param $params Array: query string parameters
* @return String: HTML fragment
*/
- protected function makeSearchLink( $term, $namespaces, $label, $tooltip, $params=array() ) {
+ protected function makeSearchLink( $term, $namespaces, $label, $tooltip, $params = array() ) {
$opt = $params;
foreach( $namespaces as $n ) {
$opt['ns' . $n] = 1;
}
- $opt['redirs'] = $this->searchRedirects ? 1 : 0;
+ $opt['redirs'] = $this->searchRedirects;
- $st = SpecialPage::getTitleFor( 'Search' );
$stParams = array_merge(
array(
'search' => $term,
@@ -995,10 +1061,8 @@ class SpecialSearch {
return Xml::element(
'a',
array(
- 'href' => $st->getLocalURL( $stParams ),
- 'title' => $tooltip,
- 'onmousedown' => 'mwSearchHeaderClick(this);',
- 'onkeydown' => 'mwSearchHeaderClick(this);'),
+ 'href' => $this->getTitle()->getLocalURL( $stParams ),
+ 'title' => $tooltip),
$label
);
}
@@ -1018,7 +1082,7 @@ class SpecialSearch {
}
return false;
}
-
+
/**
* Check if query starts with all: prefix
*
@@ -1028,12 +1092,32 @@ class SpecialSearch {
protected function startsWithAll( $term ) {
$allkeyword = wfMsgForContent('searchall');
-
+
$p = explode( ':', $term );
if( count( $p ) > 1 ) {
return $p[0] == $allkeyword;
}
return false;
}
-}
+ /**
+ * @since 1.18
+ */
+ public function getSearchEngine() {
+ if ( $this->searchEngine === null ) {
+ $this->searchEngine = SearchEngine::create();
+ }
+ return $this->searchEngine;
+ }
+
+ /**
+ * Users of hook SpecialSearchSetupEngine can use this to
+ * add more params to links to not lose selection when
+ * user navigates search results.
+ * @since 1.18
+ */
+ public function setExtraParam( $key, $value ) {
+ $this->extraParams[$key] = $value;
+ }
+
+}
diff --git a/includes/specials/SpecialShortpages.php b/includes/specials/SpecialShortpages.php
index 989e4c07..3b785018 100644
--- a/includes/specials/SpecialShortpages.php
+++ b/includes/specials/SpecialShortpages.php
@@ -29,10 +29,11 @@
*/
class ShortPagesPage extends QueryPage {
- function getName() {
- return 'Shortpages';
+ function __construct( $name = 'Shortpages' ) {
+ parent::__construct( $name );
}
+ // inexpensive?
/**
* This query is indexed as of 1.5
*/
@@ -44,29 +45,27 @@ class ShortPagesPage extends QueryPage {
return false;
}
- function getSQL() {
- global $wgContentNamespaces;
-
- $dbr = wfGetDB( DB_SLAVE );
- $page = $dbr->tableName( 'page' );
- $name = $dbr->addQuotes( $this->getName() );
-
- $forceindex = $dbr->useIndexClause("page_len");
-
- if ($wgContentNamespaces)
- $nsclause = "page_namespace IN (" . $dbr->makeList($wgContentNamespaces) . ")";
- else
- $nsclause = "page_namespace = " . NS_MAIN;
+ function getQueryInfo() {
+ return array (
+ 'tables' => array ( 'page' ),
+ 'fields' => array ( 'page_namespace AS namespace',
+ 'page_title AS title',
+ 'page_len AS value' ),
+ 'conds' => array ( 'page_namespace' => MWNamespace::getContentNamespaces(),
+ 'page_is_redirect' => 0 ),
+ 'options' => array ( 'USE INDEX' => 'page_len' )
+ );
+ }
- return
- "SELECT $name as type,
- page_namespace as namespace,
- page_title as title,
- page_len AS value
- FROM $page $forceindex
- WHERE $nsclause AND page_is_redirect=0";
+ function getOrderFields() {
+ return array( 'page_len' );
}
+ /**
+ * @param $db DatabaseBase
+ * @param $res
+ * @return void
+ */
function preprocessResults( $db, $res ) {
# There's no point doing a batch check if we aren't caching results;
# the page must exist for it to have been pulled out of the table
@@ -87,10 +86,10 @@ class ShortPagesPage extends QueryPage {
}
function formatResult( $skin, $result ) {
- global $wgLang, $wgContLang;
- $dm = $wgContLang->getDirMark();
+ global $wgLang;
+ $dm = $wgLang->getDirMark();
- $title = Title::makeTitleSafe( $result->namespace, $result->title );
+ $title = Title::makeTitle( $result->namespace, $result->title );
if ( !$title ) {
return '<!-- Invalid title ' . htmlspecialchars( "{$result->namespace}:{$result->title}" ). '-->';
}
@@ -110,14 +109,3 @@ class ShortPagesPage extends QueryPage {
: "<del>({$hlink}) {$dm}{$plink} {$dm}[{$size}]</del>";
}
}
-
-/**
- * constructor
- */
-function wfSpecialShortpages() {
- list( $limit, $offset ) = wfCheckLimits();
-
- $spp = new ShortPagesPage();
-
- return $spp->doQuery( $offset, $limit );
-}
diff --git a/includes/specials/SpecialSpecialpages.php b/includes/specials/SpecialSpecialpages.php
index 19bc6b00..13bc4c2b 100644
--- a/includes/specials/SpecialSpecialpages.php
+++ b/includes/specials/SpecialSpecialpages.php
@@ -33,10 +33,11 @@ class SpecialSpecialpages extends UnlistedSpecialPage {
}
function execute( $par ) {
- global $wgOut;
+ $out = $this->getOutput();
$this->setHeaders();
$this->outputHeader();
- $wgOut->allowClickjacking();
+ $out->allowClickjacking();
+ $out->addModuleStyles( 'mediawiki.special' );
$groups = $this->getPageGroups();
@@ -50,7 +51,7 @@ class SpecialSpecialpages extends UnlistedSpecialPage {
private function getPageGroups() {
global $wgSortSpecialPages;
- $pages = SpecialPage::getUsablePages();
+ $pages = SpecialPageFactory::getUsablePages();
if( !count( $pages ) ) {
# Yeah, that was pointless. Thanks for coming.
@@ -61,11 +62,11 @@ class SpecialSpecialpages extends UnlistedSpecialPage {
$groups = array();
foreach ( $pages as $page ) {
if ( $page->isListed() ) {
- $group = SpecialPage::getGroup( $page );
+ $group = SpecialPageFactory::getGroup( $page );
if( !isset( $groups[$group] ) ) {
$groups[$group] = array();
}
- $groups[$group][$page->getDescription()] = array( $page->getTitle(), $page->isRestricted() );
+ $groups[$group][$page->getDescription()] = array( $page->getTitle(), $page->isRestricted(), $page->isExpensive() );
}
}
@@ -87,52 +88,59 @@ class SpecialSpecialpages extends UnlistedSpecialPage {
}
private function outputPageList( $groups ) {
- global $wgUser, $wgOut;
+ global $wgMiserMode;
+ $out = $this->getOutput();
- $sk = $wgUser->getSkin();
$includesRestrictedPages = false;
+ $includesCachedPages = false;
foreach ( $groups as $group => $sortedPages ) {
$middle = ceil( count( $sortedPages )/2 );
$total = count( $sortedPages );
$count = 0;
- $wgOut->wrapWikiMsg( "<h4 class=\"mw-specialpagesgroup\" id=\"mw-specialpagesgroup-$group\">$1</h4>\n", "specialpages-group-$group" );
- $wgOut->addHTML(
+ $out->wrapWikiMsg( "<h2 class=\"mw-specialpagesgroup\" id=\"mw-specialpagesgroup-$group\">$1</h2>\n", "specialpages-group-$group" );
+ $out->addHTML(
Html::openElement( 'table', array( 'style' => 'width:100%;', 'class' => 'mw-specialpages-table' ) ) ."\n" .
Html::openElement( 'tr' ) . "\n" .
Html::openElement( 'td', array( 'style' => 'width:30%;vertical-align:top' ) ) . "\n" .
Html::openElement( 'ul' ) . "\n"
);
foreach( $sortedPages as $desc => $specialpage ) {
- list( $title, $restricted ) = $specialpage;
- $link = $sk->linkKnown( $title , htmlspecialchars( $desc ) );
+ list( $title, $restricted, $expensive) = $specialpage;
+
+ $pageClasses = array();
+ if ( $expensive && $wgMiserMode ){
+ $includesCachedPages = true;
+ $pageClasses[] = 'mw-specialpagecached';
+ }
if( $restricted ) {
$includesRestrictedPages = true;
- $wgOut->addHTML( Html::rawElement( 'li', array( 'class' => 'mw-specialpages-page mw-specialpagerestricted' ), Html::rawElement( 'strong', array(), $link ) ) . "\n" );
- } else {
- $wgOut->addHTML( Html::rawElement( 'li', array(), $link ) . "\n" );
+ $pageClasses[] = 'mw-specialpagerestricted';
}
+ $link = Linker::linkKnown( $title , htmlspecialchars( $desc ) );
+ $out->addHTML( Html::rawElement( 'li', array( 'class' => implode( ' ', $pageClasses ) ), $link ) . "\n" );
+
# Split up the larger groups
$count++;
if( $total > 3 && $count == $middle ) {
- $wgOut->addHTML(
+ $out->addHTML(
Html::closeElement( 'ul' ) . Html::closeElement( 'td' ) .
Html::element( 'td', array( 'style' => 'width:10%' ), '' ) .
Html::openElement( 'td', array( 'style' => 'width:30%' ) ) . Html::openElement( 'ul' ) . "\n"
);
}
}
- $wgOut->addHTML(
+ $out->addHTML(
Html::closeElement( 'ul' ) . Html::closeElement( 'td' ) .
Html::element( 'td', array( 'style' => 'width:30%' ), '' ) .
Html::closeElement( 'tr' ) . Html::closeElement( 'table' ) . "\n"
);
}
- if ( $includesRestrictedPages ) {
- $wgOut->wrapWikiMsg( "<div class=\"mw-specialpages-notes\">\n$1\n</div>", 'specialpages-note' );
+ if ( $includesRestrictedPages || $includesCachedPages ) {
+ $out->wrapWikiMsg( "<div class=\"mw-specialpages-notes\">\n$1\n</div>", 'specialpages-note' );
}
}
}
diff --git a/includes/specials/SpecialStatistics.php b/includes/specials/SpecialStatistics.php
index b0d0246e..5def4da5 100644
--- a/includes/specials/SpecialStatistics.php
+++ b/includes/specials/SpecialStatistics.php
@@ -28,20 +28,20 @@
* @ingroup SpecialPage
*/
class SpecialStatistics extends SpecialPage {
-
+
private $views, $edits, $good, $images, $total, $users,
- $activeUsers, $admins = 0;
-
+ $activeUsers = 0;
+
public function __construct() {
parent::__construct( 'Statistics' );
}
-
+
public function execute( $par ) {
- global $wgOut, $wgMemc;
- global $wgDisableCounters, $wgMiserMode;
-
+ global $wgMemc, $wgDisableCounters, $wgMiserMode;
+
$this->setHeaders();
-
+ $this->getOutput()->addModuleStyles( 'mediawiki.special' );
+
$this->views = SiteStats::views();
$this->edits = SiteStats::edits();
$this->good = SiteStats::articles();
@@ -49,15 +49,14 @@ class SpecialStatistics extends SpecialPage {
$this->total = SiteStats::pages();
$this->users = SiteStats::users();
$this->activeUsers = SiteStats::activeUsers();
- $this->admins = SiteStats::numberingroup('sysop');
$this->hook = '';
-
+
# Staticic - views
$viewsStats = '';
if( !$wgDisableCounters ) {
$viewsStats = $this->getViewsStats();
}
-
+
# Set active user count
if( !$wgMiserMode ) {
$key = wfMemcKey( 'sitestats', 'activeusers-updated' );
@@ -88,7 +87,7 @@ class SpecialStatistics extends SpecialPage {
if( !$wgDisableCounters && !$wgMiserMode ) {
$text .= $this->getMostViewedPages();
}
-
+
# Statistic - other
$extraStats = array();
if( wfRunHooks( 'SpecialStatsAddExtra', array( &$extraStats ) ) ) {
@@ -98,12 +97,12 @@ class SpecialStatistics extends SpecialPage {
$text .= Xml::closeElement( 'table' );
# Customizable footer
- $footer = wfMsgExt( 'statistics-footer', array('parseinline') );
- if( !wfEmptyMsg( 'statistics-footer', $footer ) && $footer != '' ) {
- $text .= "\n" . $footer;
+ $footer = wfMessage( 'statistics-footer' );
+ if ( !$footer->isBlank() ) {
+ $text .= "\n" . $footer->parse();
}
- $wgOut->addHTML( $text );
+ $this->getOutput()->addHTML( $text );
}
/**
@@ -117,80 +116,72 @@ class SpecialStatistics extends SpecialPage {
*/
private function formatRow( $text, $number, $trExtraParams = array(), $descMsg = '', $descMsgParam = '' ) {
if( $descMsg ) {
- $descriptionText = wfMsgExt( $descMsg, array( 'parseinline' ), $descMsgParam );
- if ( !wfEmptyMsg( $descMsg, $descriptionText ) ) {
- $descriptionText = " ($descriptionText)";
- $text .= "<br />" . Xml::element( 'small', array( 'class' => 'mw-statistic-desc'),
- $descriptionText );
+ $msg = wfMessage( $descMsg, $descMsgParam );
+ if ( $msg->exists() ) {
+ $descriptionText = $msg->parse();
+ $text .= "<br />" . Xml::element( 'small', array( 'class' => 'mw-statistic-desc'),
+ " ($descriptionText)" );
}
}
- return
- Html::rawElement( 'tr', $trExtraParams,
+ return Html::rawElement( 'tr', $trExtraParams,
Html::rawElement( 'td', array(), $text ) .
Html::rawElement( 'td', array( 'class' => 'mw-statistics-numbers' ), $number )
);
}
-
+
/**
* Each of these methods is pretty self-explanatory, get a particular
* row for the table of statistics
* @return string
*/
private function getPageStats() {
- global $wgLang;
return Xml::openElement( 'tr' ) .
Xml::tags( 'th', array( 'colspan' => '2' ), wfMsgExt( 'statistics-header-pages', array( 'parseinline' ) ) ) .
Xml::closeElement( 'tr' ) .
$this->formatRow( wfMsgExt( 'statistics-articles', array( 'parseinline' ) ),
- $wgLang->formatNum( $this->good ),
+ $this->getLang()->formatNum( $this->good ),
array( 'class' => 'mw-statistics-articles' ) ) .
$this->formatRow( wfMsgExt( 'statistics-pages', array( 'parseinline' ) ),
- $wgLang->formatNum( $this->total ),
+ $this->getLang()->formatNum( $this->total ),
array( 'class' => 'mw-statistics-pages' ),
'statistics-pages-desc' ) .
$this->formatRow( wfMsgExt( 'statistics-files', array( 'parseinline' ) ),
- $wgLang->formatNum( $this->images ),
+ $this->getLang()->formatNum( $this->images ),
array( 'class' => 'mw-statistics-files' ) );
}
private function getEditStats() {
- global $wgLang;
return Xml::openElement( 'tr' ) .
Xml::tags( 'th', array( 'colspan' => '2' ), wfMsgExt( 'statistics-header-edits', array( 'parseinline' ) ) ) .
Xml::closeElement( 'tr' ) .
$this->formatRow( wfMsgExt( 'statistics-edits', array( 'parseinline' ) ),
- $wgLang->formatNum( $this->edits ),
+ $this->getLang()->formatNum( $this->edits ),
array( 'class' => 'mw-statistics-edits' ) ) .
$this->formatRow( wfMsgExt( 'statistics-edits-average', array( 'parseinline' ) ),
- $wgLang->formatNum( sprintf( '%.2f', $this->total ? $this->edits / $this->total : 0 ) ),
+ $this->getLang()->formatNum( sprintf( '%.2f', $this->total ? $this->edits / $this->total : 0 ) ),
array( 'class' => 'mw-statistics-edits-average' ) );
}
private function getUserStats() {
- global $wgLang, $wgUser, $wgActiveUserDays;
- $sk = $wgUser->getSkin();
+ global $wgActiveUserDays;
return Xml::openElement( 'tr' ) .
Xml::tags( 'th', array( 'colspan' => '2' ), wfMsgExt( 'statistics-header-users', array( 'parseinline' ) ) ) .
Xml::closeElement( 'tr' ) .
$this->formatRow( wfMsgExt( 'statistics-users', array( 'parseinline' ) ),
- $wgLang->formatNum( $this->users ),
+ $this->getLang()->formatNum( $this->users ),
array( 'class' => 'mw-statistics-users' ) ) .
$this->formatRow( wfMsgExt( 'statistics-users-active', array( 'parseinline' ) ) . ' ' .
- $sk->link(
+ Linker::linkKnown(
SpecialPage::getTitleFor( 'Activeusers' ),
- wfMsgHtml( 'listgrouprights-members' ),
- array(),
- array(),
- 'known'
+ wfMsgHtml( 'listgrouprights-members' )
),
- $wgLang->formatNum( $this->activeUsers ),
+ $this->getLang()->formatNum( $this->activeUsers ),
array( 'class' => 'mw-statistics-users-active' ),
'statistics-users-active-desc',
- $wgLang->formatNum( $wgActiveUserDays ) );
+ $this->getLang()->formatNum( $wgActiveUserDays ) );
}
private function getGroupStats() {
- global $wgGroupPermissions, $wgImplicitGroups, $wgLang, $wgUser;
- $sk = $wgUser->getSkin();
+ global $wgGroupPermissions, $wgImplicitGroups;
$text = '';
foreach( $wgGroupPermissions as $group => $permissions ) {
# Skip generic * and implicit groups
@@ -198,29 +189,28 @@ class SpecialStatistics extends SpecialPage {
continue;
}
$groupname = htmlspecialchars( $group );
- $msg = wfMsg( 'group-' . $groupname );
- if ( wfEmptyMsg( 'group-' . $groupname, $msg ) || $msg == '' ) {
+ $msg = wfMessage( 'group-' . $groupname );
+ if ( $msg->isBlank() ) {
$groupnameLocalized = $groupname;
} else {
- $groupnameLocalized = $msg;
+ $groupnameLocalized = $msg->text();
}
- $msg = wfMsgForContent( 'grouppage-' . $groupname );
- if ( wfEmptyMsg( 'grouppage-' . $groupname, $msg ) || $msg == '' ) {
+ $msg = wfMessage( 'grouppage-' . $groupname )->inContentLanguage();
+ if ( $msg->isBlank() ) {
$grouppageLocalized = MWNamespace::getCanonicalName( NS_PROJECT ) . ':' . $groupname;
} else {
- $grouppageLocalized = $msg;
+ $grouppageLocalized = $msg->text();
}
$linkTarget = Title::newFromText( $grouppageLocalized );
- $grouppage = $sk->link(
+ $grouppage = Linker::link(
$linkTarget,
htmlspecialchars( $groupnameLocalized )
);
- $grouplink = $sk->link(
+ $grouplink = Linker::linkKnown(
SpecialPage::getTitleFor( 'Listusers' ),
wfMsgHtml( 'listgrouprights-members' ),
array(),
- array( 'group' => $group ),
- 'known'
+ array( 'group' => $group )
);
# Add a class when a usergroup contains no members to allow hiding these rows
$classZero = '';
@@ -229,31 +219,28 @@ class SpecialStatistics extends SpecialPage {
$classZero = ' statistics-group-zero';
}
$text .= $this->formatRow( $grouppage . ' ' . $grouplink,
- $wgLang->formatNum( $countUsers ),
+ $this->getLang()->formatNum( $countUsers ),
array( 'class' => 'statistics-group-' . Sanitizer::escapeClass( $group ) . $classZero ) );
}
return $text;
}
private function getViewsStats() {
- global $wgLang;
return Xml::openElement( 'tr' ) .
Xml::tags( 'th', array( 'colspan' => '2' ), wfMsgExt( 'statistics-header-views', array( 'parseinline' ) ) ) .
Xml::closeElement( 'tr' ) .
$this->formatRow( wfMsgExt( 'statistics-views-total', array( 'parseinline' ) ),
- $wgLang->formatNum( $this->views ),
+ $this->getLang()->formatNum( $this->views ),
array ( 'class' => 'mw-statistics-views-total' ), 'statistics-views-total-desc' ) .
$this->formatRow( wfMsgExt( 'statistics-views-peredit', array( 'parseinline' ) ),
- $wgLang->formatNum( sprintf( '%.2f', $this->edits ?
+ $this->getLang()->formatNum( sprintf( '%.2f', $this->edits ?
$this->views / $this->edits : 0 ) ),
array ( 'class' => 'mw-statistics-views-peredit' ) );
}
private function getMostViewedPages() {
- global $wgLang, $wgUser;
$text = '';
$dbr = wfGetDB( DB_SLAVE );
- $sk = $wgUser->getSkin();
$res = $dbr->select(
'page',
array(
@@ -278,9 +265,9 @@ class SpecialStatistics extends SpecialPage {
foreach ( $res as $row ) {
$title = Title::makeTitleSafe( $row->page_namespace, $row->page_title );
if( $title instanceof Title ) {
- $text .= $this->formatRow( $sk->link( $title ),
- $wgLang->formatNum( $row->page_counter ) );
-
+ $text .= $this->formatRow( Linker::link( $title ),
+ $this->getLang()->formatNum( $row->page_counter ) );
+
}
}
$res->free();
@@ -289,22 +276,20 @@ class SpecialStatistics extends SpecialPage {
}
private function getOtherStats( $stats ) {
- global $wgLang;
-
if ( !count( $stats ) )
return '';
$return = Xml::openElement( 'tr' ) .
Xml::tags( 'th', array( 'colspan' => '2' ), wfMsgExt( 'statistics-header-hooks', array( 'parseinline' ) ) ) .
Xml::closeElement( 'tr' );
-
+
foreach( $stats as $name => $number ) {
$name = htmlspecialchars( $name );
$number = htmlspecialchars( $number );
-
- $return .= $this->formatRow( $name, $wgLang->formatNum( $number ), array( 'class' => 'mw-statistics-hook' ) );
+
+ $return .= $this->formatRow( $name, $this->getLang()->formatNum( $number ), array( 'class' => 'mw-statistics-hook' ) );
}
-
+
return $return;
}
}
diff --git a/includes/specials/SpecialTags.php b/includes/specials/SpecialTags.php
index c2aecf47..66a89e94 100644
--- a/includes/specials/SpecialTags.php
+++ b/includes/specials/SpecialTags.php
@@ -48,7 +48,8 @@ class SpecialTags extends SpecialPage {
Xml::tags( 'th', null, wfMsgExt( 'tags-hitcount-header', 'parseinline' ) )
);
$dbr = wfGetDB( DB_SLAVE );
- $res = $dbr->select( 'change_tag', array( 'ct_tag', 'count(*) as hitcount' ), array(), __METHOD__, array( 'GROUP BY' => 'ct_tag', 'ORDER BY' => 'hitcount DESC' ) );
+ $res = $dbr->select( 'change_tag', array( 'ct_tag', 'count(*) AS hitcount' ),
+ array(), __METHOD__, array( 'GROUP BY' => 'ct_tag', 'ORDER BY' => 'hitcount DESC' ) );
foreach ( $res as $row ) {
$html .= $this->doTagRow( $row->ct_tag, $row->hitcount );
@@ -62,10 +63,9 @@ class SpecialTags extends SpecialPage {
}
function doTagRow( $tag, $hitcount ) {
- static $sk=null, $doneTags=array();
- if (!$sk) {
- global $wgUser;
- $sk = $wgUser->getSkin();
+ static $sk = null, $doneTags = array();
+ if ( !$sk ) {
+ $sk = $this->getSkin();
}
if ( in_array( $tag, $doneTags ) ) {
@@ -73,7 +73,7 @@ class SpecialTags extends SpecialPage {
}
global $wgLang;
-
+
$newRow = '';
$newRow .= Xml::tags( 'td', null, Xml::element( 'tt', null, $tag ) );
@@ -81,8 +81,8 @@ class SpecialTags extends SpecialPage {
$disp .= ' (' . $sk->link( Title::makeTitle( NS_MEDIAWIKI, "Tag-$tag" ), wfMsgHtml( 'tags-edit' ) ) . ')';
$newRow .= Xml::tags( 'td', null, $disp );
- $desc = wfMsgExt( "tag-$tag-description", 'parseinline' );
- $desc = wfEmptyMsg( "tag-$tag-description", $desc ) ? '' : $desc;
+ $msg = wfMessage( "tag-$tag-description" );
+ $desc = !$msg->exists() ? '' : $msg->parse();
$desc .= ' (' . $sk->link( Title::makeTitle( NS_MEDIAWIKI, "Tag-$tag-description" ), wfMsgHtml( 'tags-edit' ) ) . ')';
$newRow .= Xml::tags( 'td', null, $desc );
diff --git a/includes/specials/SpecialUnblock.php b/includes/specials/SpecialUnblock.php
new file mode 100644
index 00000000..521c1775
--- /dev/null
+++ b/includes/specials/SpecialUnblock.php
@@ -0,0 +1,209 @@
+<?php
+/**
+ * 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.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup SpecialPage
+ */
+
+/**
+ * A special page for unblocking users
+ *
+ * @ingroup SpecialPage
+ */
+class SpecialUnblock extends SpecialPage {
+
+ protected $target;
+ protected $type;
+ protected $block;
+
+ public function __construct(){
+ parent::__construct( 'Unblock', 'block' );
+ }
+
+ public function execute( $par ){
+ global $wgUser, $wgOut, $wgRequest;
+
+ # Check permissions
+ if( !$this->userCanExecute( $wgUser ) ) {
+ $this->displayRestrictionError();
+ return;
+ }
+
+ # Check for database lock
+ if( wfReadOnly() ) {
+ throw new ReadOnlyError;
+ }
+
+ list( $this->target, $this->type ) = SpecialBlock::getTargetAndType( $par, $wgRequest );
+ $this->block = Block::newFromTarget( $this->target );
+
+ # bug 15810: blocked admins should have limited access here. This won't allow sysops
+ # to remove autoblocks on themselves, but they should have ipblock-exempt anyway
+ $status = SpecialBlock::checkUnblockSelf( $this->target );
+ if ( $status !== true ) {
+ throw new ErrorPageError( 'badaccess', $status );
+ }
+
+ $wgOut->setPageTitle( wfMsg( 'unblockip' ) );
+ $wgOut->addModules( 'mediawiki.special' );
+
+ $form = new HTMLForm( $this->getFields(), $this->getContext() );
+ $form->setWrapperLegend( wfMsg( 'unblockip' ) );
+ $form->setSubmitCallback( array( __CLASS__, 'processUnblock' ) );
+ $form->setSubmitText( wfMsg( 'ipusubmit' ) );
+ $form->addPreText( wfMsgExt( 'unblockiptext', 'parse' ) );
+
+ if( $form->show() ){
+ switch( $this->type ){
+ case Block::TYPE_USER:
+ case Block::TYPE_IP:
+ $wgOut->addWikiMsg( 'unblocked', $this->target );
+ break;
+ case Block::TYPE_RANGE:
+ $wgOut->addWikiMsg( 'unblocked-range', $this->target );
+ break;
+ case Block::TYPE_ID:
+ case Block::TYPE_AUTO:
+ $wgOut->addWikiMsg( 'unblocked-id', $this->target );
+ break;
+ }
+ }
+ }
+
+ protected function getFields(){
+ $fields = array(
+ 'Target' => array(
+ 'type' => 'text',
+ 'label-message' => 'ipadressorusername',
+ 'tabindex' => '1',
+ 'size' => '45',
+ 'required' => true,
+ ),
+ 'Name' => array(
+ 'type' => 'info',
+ 'label-message' => 'ipadressorusername',
+ ),
+ 'Reason' => array(
+ 'type' => 'text',
+ 'label-message' => 'ipbreason',
+ )
+ );
+
+ if( $this->block instanceof Block ){
+ list( $target, $type ) = $this->block->getTargetAndType();
+
+ # Autoblocks are logged as "autoblock #123 because the IP was recently used by
+ # User:Foo, and we've just got any block, auto or not, that applies to a target
+ # the user has specified. Someone could be fishing to connect IPs to autoblocks,
+ # so don't show any distinction between unblocked IPs and autoblocked IPs
+ if( $type == Block::TYPE_AUTO && $this->type == Block::TYPE_IP ){
+ $fields['Target']['default'] = $this->target;
+ unset( $fields['Name'] );
+
+ } else {
+ $fields['Target']['default'] = $target;
+ $fields['Target']['type'] = 'hidden';
+ switch( $type ){
+ case Block::TYPE_USER:
+ case Block::TYPE_IP:
+ $skin = $this->getSkin();
+ $fields['Name']['default'] = $skin->link(
+ $target->getUserPage(),
+ $target->getName()
+ );
+ $fields['Name']['raw'] = true;
+ break;
+
+ case Block::TYPE_RANGE:
+ $fields['Name']['default'] = $target;
+ break;
+
+ case Block::TYPE_AUTO:
+ $fields['Name']['default'] = $this->block->getRedactedName();
+ $fields['Name']['raw'] = true;
+ # Don't expose the real target of the autoblock
+ $fields['Target']['default'] = "#{$this->target}";
+ break;
+ }
+ }
+
+ } else {
+ $fields['Target']['default'] = $this->target;
+ unset( $fields['Name'] );
+ }
+ return $fields;
+ }
+
+ /**
+ * Process the form
+ * @return Array( Array(message key, parameters) ) on failure, True on success
+ */
+ public static function processUnblock( array $data ){
+ global $wgUser;
+
+ $target = $data['Target'];
+ $block = Block::newFromTarget( $data['Target'] );
+
+ if( !$block instanceof Block ){
+ return array( array( 'ipb_cant_unblock', $target ) );
+ }
+
+ # If the specified IP is a single address, and the block is a range block, don't
+ # unblock the whole range.
+ list( $target, $type ) = SpecialBlock::getTargetAndType( $target );
+ if( $block->getType() == Block::TYPE_RANGE && $type == Block::TYPE_IP ) {
+ $range = $block->getTarget();
+ return array( array( 'ipb_blocked_as_range', $target, $range ) );
+ }
+
+ # If the name was hidden and the blocking user cannot hide
+ # names, then don't allow any block removals...
+ if( !$wgUser->isAllowed( 'hideuser' ) && $block->mHideName ) {
+ return array( 'unblock-hideuser' );
+ }
+
+ # Delete block
+ if ( !$block->delete() ) {
+ return array( 'ipb_cant_unblock', htmlspecialchars( $block->getTarget() ) );
+ }
+
+ # Unset _deleted fields as needed
+ if( $block->mHideName ) {
+ # Something is deeply FUBAR if this is not a User object, but who knows?
+ $id = $block->getTarget() instanceof User
+ ? $block->getTarget()->getID()
+ : User::idFromName( $block->getTarget() );
+
+ RevisionDeleteUser::unsuppressUserName( $block->getTarget(), $id );
+ }
+
+ # Redact the name (IP address) for autoblocks
+ if ( $block->getType() == Block::TYPE_AUTO ) {
+ $page = Title::makeTitle( NS_USER, '#' . $block->getId() );
+ } else {
+ $page = $block->getTarget() instanceof User
+ ? $block->getTarget()->getUserpage()
+ : Title::makeTitle( NS_USER, $block->getTarget() );
+ }
+
+ # Make log entry
+ $log = new LogPage( 'block' );
+ $log->addEntry( 'unblock', $page, $data['Reason'] );
+
+ return true;
+ }
+}
diff --git a/includes/specials/SpecialUncategorizedcategories.php b/includes/specials/SpecialUncategorizedcategories.php
index 9574af70..70d98df9 100644
--- a/includes/specials/SpecialUncategorizedcategories.php
+++ b/includes/specials/SpecialUncategorizedcategories.php
@@ -27,22 +27,8 @@
* @ingroup SpecialPage
*/
class UncategorizedCategoriesPage extends UncategorizedPagesPage {
- function __construct() {
+ function __construct( $name = 'Uncategorizedcategories' ) {
+ parent::__construct( $name );
$this->requestedNamespace = NS_CATEGORY;
}
-
- function getName() {
- return "Uncategorizedcategories";
- }
-}
-
-/**
- * constructor
- */
-function wfSpecialUncategorizedcategories() {
- list( $limit, $offset ) = wfCheckLimits();
-
- $lpp = new UncategorizedCategoriesPage();
-
- return $lpp->doQuery( $offset, $limit );
}
diff --git a/includes/specials/SpecialUncategorizedimages.php b/includes/specials/SpecialUncategorizedimages.php
index c4254039..3efed747 100644
--- a/includes/specials/SpecialUncategorizedimages.php
+++ b/includes/specials/SpecialUncategorizedimages.php
@@ -27,10 +27,11 @@
*
* @ingroup SpecialPage
*/
+// @todo FIXME: Use an instance of UncategorizedPagesPage or something
class UncategorizedImagesPage extends ImageQueryPage {
- function getName() {
- return 'Uncategorizedimages';
+ function __construct( $name = 'Uncategorizedimages' ) {
+ parent::__construct( $name );
}
function sortDescending() {
@@ -45,21 +46,18 @@ class UncategorizedImagesPage extends ImageQueryPage {
return false;
}
- function getSQL() {
- $dbr = wfGetDB( DB_SLAVE );
- list( $page, $categorylinks ) = $dbr->tableNamesN( 'page', 'categorylinks' );
- $ns = NS_FILE;
-
- return "SELECT 'Uncategorizedimages' AS type, page_namespace AS namespace,
- page_title AS title, page_title AS value
- FROM {$page} LEFT JOIN {$categorylinks} ON page_id = cl_from
- WHERE cl_from IS NULL AND page_namespace = {$ns} AND page_is_redirect = 0";
+ function getQueryInfo() {
+ return array (
+ 'tables' => array( 'page', 'categorylinks' ),
+ 'fields' => array( 'page_namespace AS namespace',
+ 'page_title AS title',
+ 'page_title AS value' ),
+ 'conds' => array( 'cl_from IS NULL',
+ 'page_namespace' => NS_FILE,
+ 'page_is_redirect' => 0 ),
+ 'join_conds' => array( 'categorylinks' => array(
+ 'LEFT JOIN', 'cl_from=page_id' ) )
+ );
}
}
-
-function wfSpecialUncategorizedimages() {
- $uip = new UncategorizedImagesPage();
- list( $limit, $offset ) = wfCheckLimits();
- return $uip->doQuery( $offset, $limit );
-}
diff --git a/includes/specials/SpecialUncategorizedpages.php b/includes/specials/SpecialUncategorizedpages.php
index c7fef5d2..08a69448 100644
--- a/includes/specials/SpecialUncategorizedpages.php
+++ b/includes/specials/SpecialUncategorizedpages.php
@@ -26,11 +26,12 @@
*
* @ingroup SpecialPage
*/
+// @todo FIXME: Make $requestedNamespace selectable, unify all subclasses into one
class UncategorizedPagesPage extends PageQueryPage {
- var $requestedNamespace = NS_MAIN;
+ protected $requestedNamespace = false;
- function getName() {
- return "Uncategorizedpages";
+ function __construct( $name = 'Uncategorizedpages' ) {
+ parent::__construct( $name );
}
function sortDescending() {
@@ -42,32 +43,27 @@ class UncategorizedPagesPage extends PageQueryPage {
}
function isSyndicated() { return false; }
- function getSQL() {
- $dbr = wfGetDB( DB_SLAVE );
- list( $page, $categorylinks ) = $dbr->tableNamesN( 'page', 'categorylinks' );
- $name = $dbr->addQuotes( $this->getName() );
-
- return
- "
- SELECT
- $name as type,
- page_namespace AS namespace,
- page_title AS title,
- page_title AS value
- FROM $page
- LEFT JOIN $categorylinks ON page_id=cl_from
- WHERE cl_from IS NULL AND page_namespace={$this->requestedNamespace} AND page_is_redirect=0
- ";
+ function getQueryInfo() {
+ return array (
+ 'tables' => array ( 'page', 'categorylinks' ),
+ 'fields' => array ( 'page_namespace AS namespace',
+ 'page_title AS title',
+ 'page_title AS value' ),
+ // default for page_namespace is all content namespaces (if requestedNamespace is false)
+ // otherwise, page_namespace is requestedNamespace
+ 'conds' => array ( 'cl_from IS NULL',
+ 'page_namespace' => ( $this->requestedNamespace!==false ? $this->requestedNamespace : MWNamespace::getContentNamespaces() ),
+ 'page_is_redirect' => 0 ),
+ 'join_conds' => array ( 'categorylinks' => array (
+ 'LEFT JOIN', 'cl_from = page_id' ) )
+ );
}
-}
-/**
- * constructor
- */
-function wfSpecialUncategorizedpages() {
- list( $limit, $offset ) = wfCheckLimits();
-
- $lpp = new UncategorizedPagesPage();
-
- return $lpp->doQuery( $offset, $limit );
+ function getOrderFields() {
+ // For some crazy reason ordering by a constant
+ // causes a filesort
+ if( $this->requestedNamespace === false && count( MWNamespace::getContentNamespaces() ) > 1 )
+ return array( 'page_namespace', 'page_title' );
+ return array( 'page_title' );
+ }
}
diff --git a/includes/specials/SpecialUncategorizedtemplates.php b/includes/specials/SpecialUncategorizedtemplates.php
index aa4e979d..af038fa8 100644
--- a/includes/specials/SpecialUncategorizedtemplates.php
+++ b/includes/specials/SpecialUncategorizedtemplates.php
@@ -29,20 +29,8 @@
* @ingroup SpecialPage
*/
class UncategorizedTemplatesPage extends UncategorizedPagesPage {
-
- var $requestedNamespace = NS_TEMPLATE;
-
- public function getName() {
- return 'Uncategorizedtemplates';
+ public function __construct( $name = 'Uncategorizedtemplates' ) {
+ parent::__construct( $name );
+ $this->requestedNamespace = NS_TEMPLATE;
}
-
-}
-
-/**
- * Main execution point
- */
-function wfSpecialUncategorizedtemplates() {
- list( $limit, $offset ) = wfCheckLimits();
- $utp = new UncategorizedTemplatesPage();
- $utp->doQuery( $offset, $limit );
}
diff --git a/includes/specials/SpecialUndelete.php b/includes/specials/SpecialUndelete.php
index 1cf61d26..d4636e74 100644
--- a/includes/specials/SpecialUndelete.php
+++ b/includes/specials/SpecialUndelete.php
@@ -27,6 +27,10 @@
* @ingroup SpecialPage
*/
class PageArchive {
+
+ /**
+ * @var Title
+ */
protected $title;
var $fileStatus;
@@ -76,6 +80,11 @@ class PageArchive {
return self::listPages( $dbr, $conds );
}
+ /**
+ * @param $dbr DatabaseBase
+ * @param $condition
+ * @return bool|ResultWrapper
+ */
protected static function listPages( $dbr, $condition ) {
return $dbr->resultObject(
$dbr->select(
@@ -105,9 +114,12 @@ class PageArchive {
function listRevisions() {
$dbr = wfGetDB( DB_SLAVE );
$res = $dbr->select( 'archive',
- array( 'ar_minor_edit', 'ar_timestamp', 'ar_user', 'ar_user_text', 'ar_comment', 'ar_len', 'ar_deleted' ),
+ array(
+ 'ar_minor_edit', 'ar_timestamp', 'ar_user', 'ar_user_text',
+ 'ar_comment', 'ar_len', 'ar_deleted', 'ar_rev_id'
+ ),
array( 'ar_namespace' => $this->title->getNamespace(),
- 'ar_title' => $this->title->getDBkey() ),
+ 'ar_title' => $this->title->getDBkey() ),
'PageArchive::listRevisions',
array( 'ORDER BY' => 'ar_timestamp DESC' ) );
$ret = $dbr->resultObject( $res );
@@ -155,19 +167,6 @@ class PageArchive {
}
/**
- * Fetch (and decompress if necessary) the stored text for the deleted
- * revision of the page with the given timestamp.
- *
- * @param $timestamp String
- * @return String
- * @deprecated Use getRevision() for more flexible information
- */
- function getRevisionText( $timestamp ) {
- $rev = $this->getRevision( $timestamp );
- return $rev ? $rev->getText() : null;
- }
-
- /**
* Return a Revision object containing data for the deleted revision.
* Note that the result *may* or *may not* have a null page ID.
*
@@ -190,8 +189,8 @@ class PageArchive {
'ar_deleted',
'ar_len' ),
array( 'ar_namespace' => $this->title->getNamespace(),
- 'ar_title' => $this->title->getDBkey(),
- 'ar_timestamp' => $dbr->timestamp( $timestamp ) ),
+ 'ar_title' => $this->title->getDBkey(),
+ 'ar_timestamp' => $dbr->timestamp( $timestamp ) ),
__METHOD__ );
if( $row ) {
return Revision::newFromArchiveRow( $row, array( 'page' => $this->title->getArticleId() ) );
@@ -217,8 +216,8 @@ class PageArchive {
$row = $dbr->selectRow( 'archive',
'ar_timestamp',
array( 'ar_namespace' => $this->title->getNamespace(),
- 'ar_title' => $this->title->getDBkey(),
- 'ar_timestamp < ' .
+ 'ar_title' => $this->title->getDBkey(),
+ 'ar_timestamp < ' .
$dbr->addQuotes( $dbr->timestamp( $timestamp ) ) ),
__METHOD__,
array(
@@ -263,7 +262,7 @@ class PageArchive {
if( is_null( $row->ar_text_id ) ) {
// An old row from MediaWiki 1.4 or previous.
// Text is embedded in this row in classic compression format.
- return Revision::getRevisionText( $row, "ar_" );
+ return Revision::getRevisionText( $row, 'ar_' );
} else {
// New-style: keyed to the text storage backend.
$dbr = wfGetDB( DB_SLAVE );
@@ -275,7 +274,6 @@ class PageArchive {
}
}
-
/**
* Fetch (and decompress if necessary) the stored text of the most
* recently edited deleted revision of the page.
@@ -289,7 +287,7 @@ class PageArchive {
$row = $dbr->selectRow( 'archive',
array( 'ar_text', 'ar_flags', 'ar_text_id' ),
array( 'ar_namespace' => $this->title->getNamespace(),
- 'ar_title' => $this->title->getDBkey() ),
+ 'ar_title' => $this->title->getDBkey() ),
__METHOD__,
array( 'ORDER BY' => 'ar_timestamp DESC' ) );
if( $row ) {
@@ -308,8 +306,8 @@ class PageArchive {
$dbr = wfGetDB( DB_SLAVE );
$n = $dbr->selectField( 'archive', 'COUNT(ar_title)',
array( 'ar_namespace' => $this->title->getNamespace(),
- 'ar_title' => $this->title->getDBkey() ) );
- return ($n > 0);
+ 'ar_title' => $this->title->getDBkey() ) );
+ return ( $n > 0 );
}
/**
@@ -336,6 +334,9 @@ class PageArchive {
if( $restoreFiles && $this->title->getNamespace() == NS_FILE ) {
$img = wfLocalFile( $this->title );
$this->fileStatus = $img->restore( $fileVersions, $unsuppress );
+ if ( !$this->fileStatus->isOk() ) {
+ return false;
+ }
$filesRestored = $this->fileStatus->successCount;
} else {
$filesRestored = 0;
@@ -343,8 +344,9 @@ class PageArchive {
if( $restoreText ) {
$textRestored = $this->undeleteRevisions( $timestamps, $unsuppress, $comment );
- if($textRestored === false) // It must be one of UNDELETE_*
+ if( $textRestored === false ) { // It must be one of UNDELETE_*
return false;
+ }
} else {
$textRestored = 0;
}
@@ -368,11 +370,12 @@ class PageArchive {
return false;
}
- if( trim( $comment ) != '' )
+ if( trim( $comment ) != '' ) {
$reason .= wfMsgForContent( 'colon-separator' ) . $comment;
+ }
$log->addEntry( 'restore', $this->title, $reason );
- return array($textRestored, $filesRestored, $reason);
+ return array( $textRestored, $filesRestored, $reason );
}
/**
@@ -387,19 +390,24 @@ class PageArchive {
* @return Mixed: number of revisions restored or false on failure
*/
private function undeleteRevisions( $timestamps, $unsuppress = false, $comment = '' ) {
- if ( wfReadOnly() )
+ if ( wfReadOnly() ) {
return false;
+ }
$restoreAll = empty( $timestamps );
$dbw = wfGetDB( DB_MASTER );
# Does this page already exist? We'll have to update it...
$article = new Article( $this->title );
+ # Load latest data for the current page (bug 31179)
+ $article->loadPageData( 'fromdbmaster' );
+ $oldcountable = $article->isCountable();
+
$options = 'FOR UPDATE'; // lock page
$page = $dbw->selectRow( 'page',
array( 'page_id', 'page_latest' ),
array( 'page_namespace' => $this->title->getNamespace(),
- 'page_title' => $this->title->getDBkey() ),
+ 'page_title' => $this->title->getDBkey() ),
__METHOD__,
$options
);
@@ -463,7 +471,7 @@ class PageArchive {
$ret = $dbw->resultObject( $result );
$rev_count = $dbw->numRows( $result );
if( !$rev_count ) {
- wfDebug( __METHOD__.": no revisions to restore\n" );
+ wfDebug( __METHOD__ . ": no revisions to restore\n" );
return false; // ???
}
@@ -473,7 +481,7 @@ class PageArchive {
if( $makepage ) {
// Check the state of the newest to-be version...
- if( !$unsuppress && ($row->ar_deleted & Revision::DELETED_TEXT) ) {
+ if( !$unsuppress && ( $row->ar_deleted & Revision::DELETED_TEXT ) ) {
return false; // we can't leave the current revision like this!
}
// Safe to insert now...
@@ -483,7 +491,7 @@ class PageArchive {
// Check if a deleted revision will become the current revision...
if( $row->ar_timestamp > $previousTimestamp ) {
// Check the state of the newest to-be version...
- if( !$unsuppress && ($row->ar_deleted & Revision::DELETED_TEXT) ) {
+ if( !$unsuppress && ( $row->ar_deleted & Revision::DELETED_TEXT ) ) {
return false; // we can't leave the current revision like this!
}
}
@@ -495,8 +503,11 @@ class PageArchive {
foreach ( $ret as $row ) {
// Check for key dupes due to shitty archive integrity.
if( $row->ar_rev_id ) {
- $exists = $dbw->selectField( 'revision', '1', array('rev_id' => $row->ar_rev_id), __METHOD__ );
- if( $exists ) continue; // don't throw DB errors
+ $exists = $dbw->selectField( 'revision', '1',
+ array( 'rev_id' => $row->ar_rev_id ), __METHOD__ );
+ if( $exists ) {
+ continue; // don't throw DB errors
+ }
}
// Insert one revision at a time...maintaining deletion status
// unless we are specifically removing all restrictions...
@@ -520,38 +531,33 @@ class PageArchive {
__METHOD__ );
// Was anything restored at all?
- if( $restored == 0 )
+ if ( $restored == 0 ) {
return 0;
+ }
- if( $revision ) {
- // Attach the latest revision to the page...
- $wasnew = $article->updateIfNewerOn( $dbw, $revision, $previousRevId );
- if( $newid || $wasnew ) {
- // Update site stats, link tables, etc
- $article->createUpdates( $revision );
- }
+ $created = (bool)$newid;
- if( $newid ) {
- wfRunHooks( 'ArticleUndelete', array( &$this->title, true, $comment ) );
- Article::onArticleCreate( $this->title );
- } else {
- wfRunHooks( 'ArticleUndelete', array( &$this->title, false, $comment ) );
- Article::onArticleEdit( $this->title );
- }
+ // Attach the latest revision to the page...
+ $wasnew = $article->updateIfNewerOn( $dbw, $revision, $previousRevId );
+ if ( $created || $wasnew ) {
+ // Update site stats, link tables, etc
+ $user = User::newFromName( $revision->getRawUserText(), false );
+ $article->doEditUpdates( $revision, $user, array( 'created' => $created, 'oldcountable' => $oldcountable ) );
+ }
- if( $this->title->getNamespace() == NS_FILE ) {
- $update = new HTMLCacheUpdate( $this->title, 'imagelinks' );
- $update->doUpdate();
- }
- } else {
- // Revision couldn't be created. This is very weird
- wfDebug( "Undelete: unknown error...\n" );
- return false;
+ wfRunHooks( 'ArticleUndelete', array( &$this->title, $created, $comment ) );
+
+ if( $this->title->getNamespace() == NS_FILE ) {
+ $update = new HTMLCacheUpdate( $this->title, 'imagelinks' );
+ $update->doUpdate();
}
return $restored;
}
+ /**
+ * @return Status
+ */
function getFileStatus() { return $this->fileStatus; }
}
@@ -561,47 +567,47 @@ class PageArchive {
*
* @ingroup SpecialPage
*/
-class UndeleteForm extends SpecialPage {
- var $mAction, $mTarget, $mTimestamp, $mRestore, $mInvert, $mTargetObj;
- var $mTargetTimestamp, $mAllowed, $mCanView, $mComment, $mToken, $mRequest;
+class SpecialUndelete extends SpecialPage {
+ var $mAction, $mTarget, $mTimestamp, $mRestore, $mInvert, $mFilename;
+ var $mTargetTimestamp, $mAllowed, $mCanView, $mComment, $mToken;
- function __construct( $request = null ) {
- parent::__construct( 'Undelete', 'deletedhistory' );
+ /**
+ * @var Title
+ */
+ var $mTargetObj;
- if ( $request === null ) {
- global $wgRequest;
- $this->mRequest = $wgRequest;
- } else {
- $this->mRequest = $request;
- }
+ function __construct() {
+ parent::__construct( 'Undelete', 'deletedhistory' );
}
function loadRequest() {
- global $wgUser;
- $this->mAction = $this->mRequest->getVal( 'action' );
- $this->mTarget = $this->mRequest->getVal( 'target' );
- $this->mSearchPrefix = $this->mRequest->getText( 'prefix' );
- $time = $this->mRequest->getVal( 'timestamp' );
+ $request = $this->getRequest();
+ $user = $this->getUser();
+
+ $this->mAction = $request->getVal( 'action' );
+ $this->mTarget = $request->getVal( 'target' );
+ $this->mSearchPrefix = $request->getText( 'prefix' );
+ $time = $request->getVal( 'timestamp' );
$this->mTimestamp = $time ? wfTimestamp( TS_MW, $time ) : '';
- $this->mFile = $this->mRequest->getVal( 'file' );
-
- $posted = $this->mRequest->wasPosted() &&
- $wgUser->matchEditToken( $this->mRequest->getVal( 'wpEditToken' ) );
- $this->mRestore = $this->mRequest->getCheck( 'restore' ) && $posted;
- $this->mInvert = $this->mRequest->getCheck( 'invert' ) && $posted;
- $this->mPreview = $this->mRequest->getCheck( 'preview' ) && $posted;
- $this->mDiff = $this->mRequest->getCheck( 'diff' );
- $this->mComment = $this->mRequest->getText( 'wpComment' );
- $this->mUnsuppress = $this->mRequest->getVal( 'wpUnsuppress' ) && $wgUser->isAllowed( 'suppressrevision' );
- $this->mToken = $this->mRequest->getVal( 'token' );
-
- if ( $wgUser->isAllowed( 'undelete' ) && !$wgUser->isBlocked() ) {
+ $this->mFilename = $request->getVal( 'file' );
+
+ $posted = $request->wasPosted() &&
+ $user->matchEditToken( $request->getVal( 'wpEditToken' ) );
+ $this->mRestore = $request->getCheck( 'restore' ) && $posted;
+ $this->mInvert = $request->getCheck( 'invert' ) && $posted;
+ $this->mPreview = $request->getCheck( 'preview' ) && $posted;
+ $this->mDiff = $request->getCheck( 'diff' );
+ $this->mComment = $request->getText( 'wpComment' );
+ $this->mUnsuppress = $request->getVal( 'wpUnsuppress' ) && $user->isAllowed( 'suppressrevision' );
+ $this->mToken = $request->getVal( 'token' );
+
+ if ( $user->isAllowed( 'undelete' ) && !$user->isBlocked() ) {
$this->mAllowed = true; // user can restore
$this->mCanView = true; // user can view content
- } elseif ( $wgUser->isAllowed( 'deletedtext' ) ) {
+ } elseif ( $user->isAllowed( 'deletedtext' ) ) {
$this->mAllowed = false; // user cannot restore
$this->mCanView = true; // user can view content
- } else { // user can only view the list of revisions
+ } else { // user can only view the list of revisions
$this->mAllowed = false;
$this->mCanView = false;
$this->mTimestamp = '';
@@ -611,7 +617,7 @@ class UndeleteForm extends SpecialPage {
if( $this->mRestore || $this->mInvert ) {
$timestamps = array();
$this->mFileVersions = array();
- foreach( $_REQUEST as $key => $val ) {
+ foreach( $request->getValues() as $key => $val ) {
$matches = array();
if( preg_match( '/^ts(\d{14})$/', $key, $matches ) ) {
array_push( $timestamps, $matches[1] );
@@ -627,10 +633,8 @@ class UndeleteForm extends SpecialPage {
}
function execute( $par ) {
- global $wgOut, $wgUser;
-
$this->setHeaders();
- if ( !$this->userCanExecute( $wgUser ) ) {
+ if ( !$this->userCanExecute( $this->getUser() ) ) {
$this->displayRestrictionError();
return;
}
@@ -638,10 +642,12 @@ class UndeleteForm extends SpecialPage {
$this->loadRequest();
+ $out = $this->getOutput();
+
if ( $this->mAllowed ) {
- $wgOut->setPagetitle( wfMsg( "undeletepage" ) );
+ $out->setPageTitle( wfMsg( 'undeletepage' ) );
} else {
- $wgOut->setPagetitle( wfMsg( "viewdeletedpage" ) );
+ $out->setPageTitle( wfMsg( 'viewdeletedpage' ) );
}
if( $par != '' ) {
@@ -649,13 +655,14 @@ class UndeleteForm extends SpecialPage {
}
if ( $this->mTarget !== '' ) {
$this->mTargetObj = Title::newFromURL( $this->mTarget );
+ $this->getSkin()->setRelevantTitle( $this->mTargetObj );
} else {
$this->mTargetObj = null;
}
if( is_null( $this->mTargetObj ) ) {
- # Not all users can just browse every deleted page from the list
- if( $wgUser->isAllowed( 'browsearchive' ) ) {
+ # Not all users can just browse every deleted page from the list
+ if( $this->getUser()->isAllowed( 'browsearchive' ) ) {
$this->showSearchForm();
# List undeletable articles
@@ -664,52 +671,53 @@ class UndeleteForm extends SpecialPage {
$this->showList( $result );
}
} else {
- $wgOut->addWikiMsg( 'undelete-header' );
+ $out->addWikiMsg( 'undelete-header' );
}
return;
}
if( $this->mTimestamp !== '' ) {
return $this->showRevision( $this->mTimestamp );
}
- if( $this->mFile !== null ) {
- $file = new ArchivedFile( $this->mTargetObj, '', $this->mFile );
+ if( $this->mFilename !== null ) {
+ $file = new ArchivedFile( $this->mTargetObj, '', $this->mFilename );
// Check if user is allowed to see this file
if ( !$file->exists() ) {
- $wgOut->addWikiMsg( 'filedelete-nofile', $this->mFile );
+ $out->addWikiMsg( 'filedelete-nofile', $this->mFilename );
return;
- } else if( !$file->userCan( File::DELETED_FILE ) ) {
+ } elseif( !$file->userCan( File::DELETED_FILE ) ) {
if( $file->isDeleted( File::DELETED_RESTRICTED ) ) {
- $wgOut->permissionRequired( 'suppressrevision' );
+ $out->permissionRequired( 'suppressrevision' );
} else {
- $wgOut->permissionRequired( 'deletedtext' );
+ $out->permissionRequired( 'deletedtext' );
}
return false;
- } elseif ( !$wgUser->matchEditToken( $this->mToken, $this->mFile ) ) {
- $this->showFileConfirmationForm( $this->mFile );
+ } elseif ( !$this->getUser()->matchEditToken( $this->mToken, $this->mFilename ) ) {
+ $this->showFileConfirmationForm( $this->mFilename );
return false;
} else {
- return $this->showFile( $this->mFile );
+ return $this->showFile( $this->mFilename );
}
}
- if( $this->mRestore && $this->mAction == "submit" ) {
+ if( $this->mRestore && $this->mAction == 'submit' ) {
global $wgUploadMaintenance;
if( $wgUploadMaintenance && $this->mTargetObj && $this->mTargetObj->getNamespace() == NS_FILE ) {
- $wgOut->wrapWikiMsg( "<div class='error'>\n$1\n</div>\n", array( 'filedelete-maintenance' ) );
+ $out->wrapWikiMsg( "<div class='error'>\n$1\n</div>\n", array( 'filedelete-maintenance' ) );
return;
}
return $this->undelete();
}
- if( $this->mInvert && $this->mAction == "submit" ) {
- return $this->showHistory( );
+ if( $this->mInvert && $this->mAction == 'submit' ) {
+ return $this->showHistory();
}
return $this->showHistory();
}
function showSearchForm() {
- global $wgOut, $wgScript;
- $wgOut->addWikiMsg( 'undelete-header' );
+ global $wgScript;
+
+ $this->getOutput()->addWikiMsg( 'undelete-header' );
- $wgOut->addHTML(
+ $this->getOutput()->addHTML(
Xml::openElement( 'form', array(
'method' => 'get',
'action' => $wgScript ) ) .
@@ -725,23 +733,27 @@ class UndeleteForm extends SpecialPage {
);
}
- // Generic list of deleted pages
+ /**
+ * Generic list of deleted pages
+ *
+ * @param $result ResultWrapper
+ * @return bool
+ */
private function showList( $result ) {
- global $wgLang, $wgUser, $wgOut;
+ $out = $this->getOutput();
if( $result->numRows() == 0 ) {
- $wgOut->addWikiMsg( 'undelete-no-results' );
+ $out->addWikiMsg( 'undelete-no-results' );
return;
}
- $wgOut->addWikiMsg( 'undeletepagetext', $wgLang->formatNum( $result->numRows() ) );
+ $out->addWikiMsg( 'undeletepagetext', $this->getLang()->formatNum( $result->numRows() ) );
- $sk = $wgUser->getSkin();
$undelete = $this->getTitle();
- $wgOut->addHTML( "<ul>\n" );
+ $out->addHTML( "<ul>\n" );
foreach ( $result as $row ) {
$title = Title::makeTitleSafe( $row->ar_namespace, $row->ar_title );
- $link = $sk->linkKnown(
+ $link = Linker::linkKnown(
$undelete,
htmlspecialchars( $title->getPrefixedText() ),
array(),
@@ -749,111 +761,102 @@ class UndeleteForm extends SpecialPage {
);
$revs = wfMsgExt( 'undeleterevisions',
array( 'parseinline' ),
- $wgLang->formatNum( $row->count ) );
- $wgOut->addHTML( "<li>{$link} ({$revs})</li>\n" );
+ $this->getLang()->formatNum( $row->count ) );
+ $out->addHTML( "<li>{$link} ({$revs})</li>\n" );
}
$result->free();
- $wgOut->addHTML( "</ul>\n" );
+ $out->addHTML( "</ul>\n" );
return true;
}
private function showRevision( $timestamp ) {
- global $wgLang, $wgUser, $wgOut;
-
- $skin = $wgUser->getSkin();
+ $out = $this->getOutput();
- if(!preg_match("/[0-9]{14}/",$timestamp)) return 0;
+ if( !preg_match( '/[0-9]{14}/', $timestamp ) ) {
+ return 0;
+ }
$archive = new PageArchive( $this->mTargetObj );
+ wfRunHooks( 'UndeleteForm::showRevision', array( &$archive, $this->mTargetObj ) );
$rev = $archive->getRevision( $timestamp );
if( !$rev ) {
- $wgOut->addWikiMsg( 'undeleterevision-missing' );
+ $out->addWikiMsg( 'undeleterevision-missing' );
return;
}
- if( $rev->isDeleted(Revision::DELETED_TEXT) ) {
- if( !$rev->userCan(Revision::DELETED_TEXT) ) {
- $wgOut->wrapWikiMsg( "<div class='mw-warning plainlinks'>\n$1\n</div>\n", 'rev-deleted-text-permission' );
+ if( $rev->isDeleted( Revision::DELETED_TEXT ) ) {
+ if( !$rev->userCan( Revision::DELETED_TEXT ) ) {
+ $out->wrapWikiMsg( "<div class='mw-warning plainlinks'>\n$1\n</div>\n", 'rev-deleted-text-permission' );
return;
} else {
- $wgOut->wrapWikiMsg( "<div class='mw-warning plainlinks'>\n$1\n</div>\n", 'rev-deleted-text-view' );
- $wgOut->addHTML( '<br />' );
+ $out->wrapWikiMsg( "<div class='mw-warning plainlinks'>\n$1\n</div>\n", 'rev-deleted-text-view' );
+ $out->addHTML( '<br />' );
// and we are allowed to see...
}
}
- $wgOut->setPageTitle( wfMsg( 'undeletepage' ) );
-
- $link = $skin->linkKnown(
- $this->getTitle( $this->mTargetObj->getPrefixedDBkey() ),
- htmlspecialchars( $this->mTargetObj->getPrefixedText() )
- );
+ $out->setPageTitle( wfMsg( 'undeletepage' ) );
if( $this->mDiff ) {
$previousRev = $archive->getPreviousRevision( $timestamp );
if( $previousRev ) {
$this->showDiff( $previousRev, $rev );
- if( $wgUser->getOption( 'diffonly' ) ) {
+ if( $this->getUser()->getOption( 'diffonly' ) ) {
return;
} else {
- $wgOut->addHTML( '<hr />' );
+ $out->addHTML( '<hr />' );
}
} else {
- $wgOut->addWikiMsg( 'undelete-nodiff' );
+ $out->addWikiMsg( 'undelete-nodiff' );
}
}
+ $link = Linker::linkKnown(
+ $this->getTitle( $this->mTargetObj->getPrefixedDBkey() ),
+ htmlspecialchars( $this->mTargetObj->getPrefixedText() )
+ );
+
// date and time are separate parameters to facilitate localisation.
// $time is kept for backward compat reasons.
- $time = htmlspecialchars( $wgLang->timeAndDate( $timestamp, true ) );
- $d = htmlspecialchars( $wgLang->date( $timestamp, true ) );
- $t = htmlspecialchars( $wgLang->time( $timestamp, true ) );
- $user = $skin->revUserTools( $rev );
+ $time = $this->getLang()->timeAndDate( $timestamp, true );
+ $d = $this->getLang()->date( $timestamp, true );
+ $t = $this->getLang()->time( $timestamp, true );
+ $user = Linker::revUserTools( $rev );
if( $this->mPreview ) {
$openDiv = '<div id="mw-undelete-revision" class="mw-warning">';
} else {
$openDiv = '<div id="mw-undelete-revision">';
}
+ $out->addHTML( $openDiv );
// Revision delete links
- $canHide = $wgUser->isAllowed( 'deleterevision' );
- if( $this->mDiff ) {
- $revdlink = ''; // diffs already have revision delete links
- } else if( $canHide || ($rev->getVisibility() && $wgUser->isAllowed('deletedhistory')) ) {
- if( !$rev->userCan(Revision::DELETED_RESTRICTED ) ) {
- $revdlink = $skin->revDeleteLinkDisabled( $canHide ); // revision was hidden from sysops
- } else {
- $query = array(
- 'type' => 'archive',
- 'target' => $this->mTargetObj->getPrefixedDBkey(),
- 'ids' => $rev->getTimestamp()
- );
- $revdlink = $skin->revDeleteLink( $query,
- $rev->isDeleted( File::DELETED_RESTRICTED ), $canHide );
+ if ( !$this->mDiff ) {
+ $revdel = $this->revDeleteLink( $rev );
+ if ( $revdel ) {
+ $out->addHTML( $revdel );
}
- } else {
- $revdlink = '';
}
- $wgOut->addHTML( $openDiv . $revdlink . wfMsgWikiHtml( 'undelete-revision', $link, $time, $user, $d, $t ) . '</div>' );
+ $out->addHTML( wfMessage( 'undelete-revision' )->rawParams( $link )->params(
+ $time )->rawParams( $user )->params( $d, $t )->parse() . '</div>' );
wfRunHooks( 'UndeleteShowRevision', array( $this->mTargetObj, $rev ) );
if( $this->mPreview ) {
- //Hide [edit]s
- $popts = $wgOut->parserOptions();
+ // Hide [edit]s
+ $popts = $out->parserOptions();
$popts->setEditSection( false );
- $wgOut->parserOptions( $popts );
- $wgOut->addWikiTextTitleTidy( $rev->getText( Revision::FOR_THIS_USER ), $this->mTargetObj, true );
+ $out->parserOptions( $popts );
+ $out->addWikiTextTitleTidy( $rev->getText( Revision::FOR_THIS_USER ), $this->mTargetObj, true );
}
- $wgOut->addHTML(
+ $out->addHTML(
Xml::element( 'textarea', array(
'readonly' => 'readonly',
- 'cols' => intval( $wgUser->getOption( 'cols' ) ),
- 'rows' => intval( $wgUser->getOption( 'rows' ) ) ),
+ 'cols' => intval( $this->getUser()->getOption( 'cols' ) ),
+ 'rows' => intval( $this->getUser()->getOption( 'rows' ) ) ),
$rev->getText( Revision::FOR_THIS_USER ) . "\n" ) .
Xml::openElement( 'div' ) .
Xml::openElement( 'form', array(
@@ -870,7 +873,7 @@ class UndeleteForm extends SpecialPage {
Xml::element( 'input', array(
'type' => 'hidden',
'name' => 'wpEditToken',
- 'value' => $wgUser->editToken() ) ) .
+ 'value' => $this->getUser()->editToken() ) ) .
Xml::element( 'input', array(
'type' => 'submit',
'name' => 'preview',
@@ -884,6 +887,48 @@ class UndeleteForm extends SpecialPage {
}
/**
+ * Get a revision-deletion link, or disabled link, or nothing, depending
+ * on user permissions & the settings on the revision.
+ *
+ * Will use forward-compatible revision ID in the Special:RevDelete link
+ * if possible, otherwise the timestamp-based ID which may break after
+ * undeletion.
+ *
+ * @param Revision $rev
+ * @return string HTML fragment
+ */
+ function revDeleteLink( $rev ) {
+ $canHide = $this->getUser()->isAllowed( 'deleterevision' );
+ if( $canHide || ( $rev->getVisibility() && $this->getUser()->isAllowed( 'deletedhistory' ) ) ) {
+ if( !$rev->userCan( Revision::DELETED_RESTRICTED ) ) {
+ $revdlink = Linker::revDeleteLinkDisabled( $canHide ); // revision was hidden from sysops
+ } else {
+ if ( $rev->getId() ) {
+ // RevDelete links using revision ID are stable across
+ // page deletion and undeletion; use when possible.
+ $query = array(
+ 'type' => 'revision',
+ 'target' => $this->mTargetObj->getPrefixedDBkey(),
+ 'ids' => $rev->getId()
+ );
+ } else {
+ // Older deleted entries didn't save a revision ID.
+ // We have to refer to these by timestamp, ick!
+ $query = array(
+ 'type' => 'archive',
+ 'target' => $this->mTargetObj->getPrefixedDBkey(),
+ 'ids' => $rev->getTimestamp()
+ );
+ }
+ return Linker::revDeleteLink( $query,
+ $rev->isDeleted( File::DELETED_RESTRICTED ), $canHide );
+ }
+ } else {
+ return '';
+ }
+ }
+
+ /**
* Build a diff display between this and the previous either deleted
* or non-deleted edit.
*
@@ -892,11 +937,9 @@ class UndeleteForm extends SpecialPage {
* @return String: HTML
*/
function showDiff( $previousRev, $currentRev ) {
- global $wgOut;
-
$diffEngine = new DifferenceEngine( $previousRev->getTitle() );
$diffEngine->showDiffStyle();
- $wgOut->addHTML(
+ $this->getOutput()->addHTML(
"<div>" .
"<table border='0' width='98%' cellpadding='0' cellspacing='4' class='diff'>" .
"<col class='diff-marker' />" .
@@ -918,59 +961,47 @@ class UndeleteForm extends SpecialPage {
);
}
+ /**
+ * @param $rev Revision
+ * @param $prefix
+ * @return string
+ */
private function diffHeader( $rev, $prefix ) {
- global $wgUser, $wgLang;
- $sk = $wgUser->getSkin();
$isDeleted = !( $rev->getId() && $rev->getTitle() );
if( $isDeleted ) {
- /// @todo Fixme: $rev->getTitle() is null for deleted revs...?
+ /// @todo FIXME: $rev->getTitle() is null for deleted revs...?
$targetPage = $this->getTitle();
$targetQuery = array(
'target' => $this->mTargetObj->getPrefixedText(),
'timestamp' => wfTimestamp( TS_MW, $rev->getTimestamp() )
);
} else {
- /// @todo Fixme getId() may return non-zero for deleted revs...
+ /// @todo FIXME: getId() may return non-zero for deleted revs...
$targetPage = $rev->getTitle();
$targetQuery = array( 'oldid' => $rev->getId() );
}
// Add show/hide deletion links if available
- $canHide = $wgUser->isAllowed( 'deleterevision' );
- if( $canHide || ($rev->getVisibility() && $wgUser->isAllowed('deletedhistory')) ) {
- $del = ' ';
- if( !$rev->userCan( Revision::DELETED_RESTRICTED ) ) {
- $del .= $sk->revDeleteLinkDisabled( $canHide ); // revision was hidden from sysops
- } else {
- $query = array(
- 'type' => 'archive',
- 'target' => $this->mTargetObj->getPrefixedDbkey(),
- 'ids' => $rev->getTimestamp()
- );
- $del .= $sk->revDeleteLink( $query,
- $rev->isDeleted( Revision::DELETED_RESTRICTED ), $canHide );
- }
- } else {
- $del = '';
- }
+ $del = $this->revDeleteLink( $rev );
return
- '<div id="mw-diff-'.$prefix.'title1"><strong>' .
- $sk->link(
+ '<div id="mw-diff-' . $prefix . 'title1"><strong>' .
+ Linker::link(
$targetPage,
- wfMsgHtml(
+ wfMsgExt(
'revisionasof',
- htmlspecialchars( $wgLang->timeanddate( $rev->getTimestamp(), true ) ),
- htmlspecialchars( $wgLang->date( $rev->getTimestamp(), true ) ),
- htmlspecialchars( $wgLang->time( $rev->getTimestamp(), true ) )
+ array( 'escape' ),
+ $this->getLang()->timeanddate( $rev->getTimestamp(), true ),
+ $this->getLang()->date( $rev->getTimestamp(), true ),
+ $this->getLang()->time( $rev->getTimestamp(), true )
),
array(),
$targetQuery
) .
'</strong></div>' .
'<div id="mw-diff-'.$prefix.'title2">' .
- $sk->revUserTools( $rev ) . '<br />' .
+ Linker::revUserTools( $rev ) . '<br />' .
'</div>' .
'<div id="mw-diff-'.$prefix.'title3">' .
- $sk->revComment( $rev ) . $del . '<br />' .
+ Linker::revComment( $rev ) . $del . '<br />' .
'</div>';
}
@@ -978,19 +1009,18 @@ class UndeleteForm extends SpecialPage {
* Show a form confirming whether a tokenless user really wants to see a file
*/
private function showFileConfirmationForm( $key ) {
- global $wgOut, $wgUser, $wgLang;
- $file = new ArchivedFile( $this->mTargetObj, '', $this->mFile );
- $wgOut->addWikiMsg( 'undelete-show-file-confirm',
+ $file = new ArchivedFile( $this->mTargetObj, '', $this->mFilename );
+ $this->getOutput()->addWikiMsg( 'undelete-show-file-confirm',
$this->mTargetObj->getText(),
- $wgLang->date( $file->getTimestamp() ),
- $wgLang->time( $file->getTimestamp() ) );
- $wgOut->addHTML(
+ $this->getLang()->date( $file->getTimestamp() ),
+ $this->getLang()->time( $file->getTimestamp() ) );
+ $this->getOutput()->addHTML(
Xml::openElement( 'form', array(
'method' => 'POST',
- 'action' => $this->getTitle()->getLocalUrl(
+ 'action' => $this->getTitle()->getLocalURL(
'target=' . urlencode( $this->mTarget ) .
'&file=' . urlencode( $key ) .
- '&token=' . urlencode( $wgUser->editToken( $key ) ) )
+ '&token=' . urlencode( $this->getUser()->editToken( $key ) ) )
)
) .
Xml::submitButton( wfMsg( 'undelete-show-file-submit' ) ) .
@@ -1002,16 +1032,16 @@ class UndeleteForm extends SpecialPage {
* Show a deleted file version requested by the visitor.
*/
private function showFile( $key ) {
- global $wgOut, $wgRequest;
- $wgOut->disable();
+ $this->getOutput()->disable();
# We mustn't allow the output to be Squid cached, otherwise
# if an admin previews a deleted image, and it's cached, then
# a user without appropriate permissions can toddle off and
# nab the image, and Squid will serve it
- $wgRequest->response()->header( 'Expires: ' . gmdate( 'D, d M Y H:i:s', 0 ) . ' GMT' );
- $wgRequest->response()->header( 'Cache-Control: no-cache, no-store, max-age=0, must-revalidate' );
- $wgRequest->response()->header( 'Pragma: no-cache' );
+ $response = $this->getRequest()->response();
+ $response->header( 'Expires: ' . gmdate( 'D, d M Y H:i:s', 0 ) . ' GMT' );
+ $response->header( 'Cache-Control: no-cache, no-store, max-age=0, must-revalidate' );
+ $response->header( 'Pragma: no-cache' );
global $IP;
require_once( "$IP/includes/StreamFile.php" );
@@ -1020,34 +1050,36 @@ class UndeleteForm extends SpecialPage {
wfStreamFile( $path );
}
- private function showHistory( ) {
- global $wgUser, $wgOut;
-
- $sk = $wgUser->getSkin();
+ private function showHistory() {
+ $out = $this->getOutput();
if( $this->mAllowed ) {
- $wgOut->setPagetitle( wfMsg( "undeletepage" ) );
+ $out->addModules( 'mediawiki.special.undelete' );
+ $out->setPageTitle( wfMsg( 'undeletepage' ) );
} else {
- $wgOut->setPagetitle( wfMsg( 'viewdeletedpage' ) );
+ $out->setPageTitle( wfMsg( 'viewdeletedpage' ) );
}
-
- $wgOut->wrapWikiMsg( "<div class='mw-undelete-pagetitle'>\n$1\n</div>\n", array ( 'undeletepagetitle', $this->mTargetObj->getPrefixedText() ) );
+ $out->wrapWikiMsg(
+ "<div class='mw-undelete-pagetitle'>\n$1\n</div>\n",
+ array( 'undeletepagetitle', $this->mTargetObj->getPrefixedText() )
+ );
$archive = new PageArchive( $this->mTargetObj );
+ wfRunHooks( 'UndeleteForm::showHistory', array( &$archive, $this->mTargetObj ) );
/*
$text = $archive->getLastRevisionText();
if( is_null( $text ) ) {
- $wgOut->addWikiMsg( "nohistory" );
+ $out->addWikiMsg( 'nohistory' );
return;
}
*/
- $wgOut->addHTML( '<div class="mw-undelete-history">' );
+ $out->addHTML( '<div class="mw-undelete-history">' );
if ( $this->mAllowed ) {
- $wgOut->addWikiMsg( "undeletehistory" );
- $wgOut->addWikiMsg( "undeleterevdel" );
+ $out->addWikiMsg( 'undeletehistory' );
+ $out->addWikiMsg( 'undeleterevdel' );
} else {
- $wgOut->addWikiMsg( "undeletehistorynoadmin" );
+ $out->addWikiMsg( 'undeletehistorynoadmin' );
}
- $wgOut->addHTML( '</div>' );
+ $out->addHTML( '</div>' );
# List all stored revisions
$revisions = $archive->listRevisions();
@@ -1080,39 +1112,39 @@ class UndeleteForm extends SpecialPage {
$action = $this->getTitle()->getLocalURL( array( 'action' => 'submit' ) );
# Start the form here
$top = Xml::openElement( 'form', array( 'method' => 'post', 'action' => $action, 'id' => 'undelete' ) );
- $wgOut->addHTML( $top );
+ $out->addHTML( $top );
}
# Show relevant lines from the deletion log:
- $wgOut->addHTML( Xml::element( 'h2', null, LogPage::logName( 'delete' ) ) . "\n" );
- LogEventsList::showLogExtract( $wgOut, 'delete', $this->mTargetObj->getPrefixedText() );
+ $out->addHTML( Xml::element( 'h2', null, LogPage::logName( 'delete' ) ) . "\n" );
+ LogEventsList::showLogExtract( $out, 'delete', $this->mTargetObj->getPrefixedText() );
# Show relevant lines from the suppression log:
- if( $wgUser->isAllowed( 'suppressionlog' ) ) {
- $wgOut->addHTML( Xml::element( 'h2', null, LogPage::logName( 'suppress' ) ) . "\n" );
- LogEventsList::showLogExtract( $wgOut, 'suppress', $this->mTargetObj->getPrefixedText() );
+ if( $this->getUser()->isAllowed( 'suppressionlog' ) ) {
+ $out->addHTML( Xml::element( 'h2', null, LogPage::logName( 'suppress' ) ) . "\n" );
+ LogEventsList::showLogExtract( $out, 'suppress', $this->mTargetObj->getPrefixedText() );
}
if( $this->mAllowed && ( $haveRevisions || $haveFiles ) ) {
# Format the user-visible controls (comment field, submission button)
# in a nice little table
- if( $wgUser->isAllowed( 'suppressrevision' ) ) {
+ if( $this->getUser()->isAllowed( 'suppressrevision' ) ) {
$unsuppressBox =
"<tr>
<td>&#160;</td>
<td class='mw-input'>" .
- Xml::checkLabel( wfMsg('revdelete-unsuppress'), 'wpUnsuppress',
+ Xml::checkLabel( wfMsg( 'revdelete-unsuppress' ), 'wpUnsuppress',
'mw-undelete-unsuppress', $this->mUnsuppress ).
"</td>
</tr>";
} else {
- $unsuppressBox = "";
+ $unsuppressBox = '';
}
$table =
Xml::fieldset( wfMsg( 'undelete-fieldset-title' ) ) .
Xml::openElement( 'table', array( 'id' => 'mw-undelete-table' ) ) .
"<tr>
<td colspan='2' class='mw-undelete-extrahelp'>" .
- wfMsgWikiHtml( 'undeleteextrahelp' ) .
+ wfMsgExt( 'undeleteextrahelp', 'parse' ) .
"</td>
</tr>
<tr>
@@ -1127,7 +1159,6 @@ class UndeleteForm extends SpecialPage {
<td>&#160;</td>
<td class='mw-submit'>" .
Xml::submitButton( wfMsg( 'undeletebtn' ), array( 'name' => 'restore', 'id' => 'mw-undelete-submit' ) ) . ' ' .
- Xml::element( 'input', array( 'type' => 'reset', 'value' => wfMsg( 'undeletereset' ), 'id' => 'mw-undelete-reset' ) ) . ' ' .
Xml::submitButton( wfMsg( 'undeleteinvert' ), array( 'name' => 'invert', 'id' => 'mw-undelete-invert' ) ) .
"</td>
</tr>" .
@@ -1135,51 +1166,49 @@ class UndeleteForm extends SpecialPage {
Xml::closeElement( 'table' ) .
Xml::closeElement( 'fieldset' );
- $wgOut->addHTML( $table );
+ $out->addHTML( $table );
}
- $wgOut->addHTML( Xml::element( 'h2', null, wfMsg( 'history' ) ) . "\n" );
+ $out->addHTML( Xml::element( 'h2', null, wfMsg( 'history' ) ) . "\n" );
if( $haveRevisions ) {
# The page's stored (deleted) history:
- $wgOut->addHTML("<ul>");
+ $out->addHTML( '<ul>' );
$remaining = $revisions->numRows();
$earliestLiveTime = $this->mTargetObj->getEarliestRevTime();
foreach ( $revisions as $row ) {
$remaining--;
- $wgOut->addHTML( $this->formatRevisionRow( $row, $earliestLiveTime, $remaining, $sk ) );
+ $out->addHTML( $this->formatRevisionRow( $row, $earliestLiveTime, $remaining ) );
}
$revisions->free();
- $wgOut->addHTML("</ul>");
+ $out->addHTML( '</ul>' );
} else {
- $wgOut->addWikiMsg( "nohistory" );
+ $out->addWikiMsg( 'nohistory' );
}
if( $haveFiles ) {
- $wgOut->addHTML( Xml::element( 'h2', null, wfMsg( 'filehist' ) ) . "\n" );
- $wgOut->addHTML( "<ul>" );
+ $out->addHTML( Xml::element( 'h2', null, wfMsg( 'filehist' ) ) . "\n" );
+ $out->addHTML( '<ul>' );
foreach ( $files as $row ) {
- $wgOut->addHTML( $this->formatFileRow( $row, $sk ) );
+ $out->addHTML( $this->formatFileRow( $row ) );
}
$files->free();
- $wgOut->addHTML( "</ul>" );
+ $out->addHTML( '</ul>' );
}
if ( $this->mAllowed ) {
# Slip in the hidden controls here
$misc = Html::hidden( 'target', $this->mTarget );
- $misc .= Html::hidden( 'wpEditToken', $wgUser->editToken() );
+ $misc .= Html::hidden( 'wpEditToken', $this->getUser()->editToken() );
$misc .= Xml::closeElement( 'form' );
- $wgOut->addHTML( $misc );
+ $out->addHTML( $misc );
}
return true;
}
- private function formatRevisionRow( $row, $earliestLiveTime, $remaining, $sk ) {
- global $wgUser, $wgLang;
-
+ private function formatRevisionRow( $row, $earliestLiveTime, $remaining ) {
$rev = Revision::newFromArchiveRow( $row,
array( 'page' => $this->mTargetObj->getArticleId() ) );
$stxt = '';
@@ -1188,7 +1217,7 @@ class UndeleteForm extends SpecialPage {
if( $this->mAllowed ) {
if( $this->mInvert ) {
if( in_array( $ts, $this->mTargetTimestamp ) ) {
- $checkBox = Xml::check( "ts$ts");
+ $checkBox = Xml::check( "ts$ts" );
} else {
$checkBox = Xml::check( "ts$ts", true );
}
@@ -1203,13 +1232,13 @@ class UndeleteForm extends SpecialPage {
$titleObj = $this->getTitle();
# Last link
if( !$rev->userCan( Revision::DELETED_TEXT ) ) {
- $pageLink = htmlspecialchars( $wgLang->timeanddate( $ts, true ) );
- $last = wfMsgHtml('diff');
- } else if( $remaining > 0 || ($earliestLiveTime && $ts > $earliestLiveTime) ) {
- $pageLink = $this->getPageLink( $rev, $titleObj, $ts, $sk );
- $last = $sk->linkKnown(
+ $pageLink = htmlspecialchars( $this->getLang()->timeanddate( $ts, true ) );
+ $last = wfMsgHtml( 'diff' );
+ } elseif( $remaining > 0 || ( $earliestLiveTime && $ts > $earliestLiveTime ) ) {
+ $pageLink = $this->getPageLink( $rev, $titleObj, $ts );
+ $last = Linker::linkKnown(
$titleObj,
- wfMsgHtml('diff'),
+ wfMsgHtml( 'diff' ),
array(),
array(
'target' => $this->mTargetObj->getPrefixedText(),
@@ -1218,77 +1247,61 @@ class UndeleteForm extends SpecialPage {
)
);
} else {
- $pageLink = $this->getPageLink( $rev, $titleObj, $ts, $sk );
- $last = wfMsgHtml('diff');
+ $pageLink = $this->getPageLink( $rev, $titleObj, $ts );
+ $last = wfMsgHtml( 'diff' );
}
} else {
- $pageLink = htmlspecialchars( $wgLang->timeanddate( $ts, true ) );
- $last = wfMsgHtml('diff');
+ $pageLink = htmlspecialchars( $this->getLang()->timeanddate( $ts, true ) );
+ $last = wfMsgHtml( 'diff' );
}
// User links
- $userLink = $sk->revUserTools( $rev );
+ $userLink = Linker::revUserTools( $rev );
// Revision text size
- if( !is_null($size = $row->ar_len) ) {
- $stxt = $sk->formatRevisionSize( $size );
+ $size = $row->ar_len;
+ if( !is_null( $size ) ) {
+ $stxt = Linker::formatRevisionSize( $size );
}
// Edit summary
- $comment = $sk->revComment( $rev );
+ $comment = Linker::revComment( $rev );
// Revision delete links
- $canHide = $wgUser->isAllowed( 'deleterevision' );
- if( $canHide || ($rev->getVisibility() && $wgUser->isAllowed('deletedhistory')) ) {
- if( !$rev->userCan( Revision::DELETED_RESTRICTED ) ) {
- $revdlink = $sk->revDeleteLinkDisabled( $canHide ); // revision was hidden from sysops
- } else {
- $query = array(
- 'type' => 'archive',
- 'target' => $this->mTargetObj->getPrefixedDBkey(),
- 'ids' => $ts
- );
- $revdlink = $sk->revDeleteLink( $query,
- $rev->isDeleted( Revision::DELETED_RESTRICTED ), $canHide );
- }
- } else {
- $revdlink = '';
- }
+ $revdlink = $this->revDeleteLink( $rev );
return "<li>$checkBox $revdlink ($last) $pageLink . . $userLink $stxt $comment</li>";
}
- private function formatFileRow( $row, $sk ) {
- global $wgUser, $wgLang;
-
+ private function formatFileRow( $row ) {
$file = ArchivedFile::newFromRow( $row );
$ts = wfTimestamp( TS_MW, $row->fa_timestamp );
if( $this->mAllowed && $row->fa_storage_key ) {
- $checkBox = Xml::check( "fileid" . $row->fa_id );
+ $checkBox = Xml::check( 'fileid' . $row->fa_id );
$key = urlencode( $row->fa_storage_key );
- $pageLink = $this->getFileLink( $file, $this->getTitle(), $ts, $key, $sk );
+ $pageLink = $this->getFileLink( $file, $this->getTitle(), $ts, $key );
} else {
$checkBox = '';
- $pageLink = $wgLang->timeanddate( $ts, true );
+ $pageLink = $this->getLang()->timeanddate( $ts, true );
}
- $userLink = $this->getFileUser( $file, $sk );
+ $userLink = $this->getFileUser( $file );
$data =
wfMsg( 'widthheight',
- $wgLang->formatNum( $row->fa_width ),
- $wgLang->formatNum( $row->fa_height ) ) .
+ $this->getLang()->formatNum( $row->fa_width ),
+ $this->getLang()->formatNum( $row->fa_height ) ) .
' (' .
- wfMsg( 'nbytes', $wgLang->formatNum( $row->fa_size ) ) .
+ wfMsg( 'nbytes', $this->getLang()->formatNum( $row->fa_size ) ) .
')';
$data = htmlspecialchars( $data );
- $comment = $this->getFileComment( $file, $sk );
+ $comment = $this->getFileComment( $file );
// Add show/hide deletion links if available
- $canHide = $wgUser->isAllowed( 'deleterevision' );
- if( $canHide || ($file->getVisibility() && $wgUser->isAllowed('deletedhistory')) ) {
- if( !$file->userCan(File::DELETED_RESTRICTED ) ) {
- $revdlink = $sk->revDeleteLinkDisabled( $canHide ); // revision was hidden from sysops
+ $canHide = $this->getUser()->isAllowed( 'deleterevision' );
+ if( $canHide || ( $file->getVisibility() && $this->getUser()->isAllowed( 'deletedhistory' ) ) ) {
+ if( !$file->userCan( File::DELETED_RESTRICTED ) ) {
+ $revdlink = Linker::revDeleteLinkDisabled( $canHide ); // revision was hidden from sysops
} else {
$query = array(
'type' => 'filearchive',
'target' => $this->mTargetObj->getPrefixedDBkey(),
'ids' => $row->fa_id
);
- $revdlink = $sk->revDeleteLink( $query,
+ $revdlink = Linker::revDeleteLink( $query,
$file->isDeleted( File::DELETED_RESTRICTED ), $canHide );
}
} else {
@@ -1299,17 +1312,17 @@ class UndeleteForm extends SpecialPage {
/**
* Fetch revision text link if it's available to all users
+ *
+ * @param $rev Revision
* @return string
*/
- function getPageLink( $rev, $titleObj, $ts, $sk ) {
- global $wgLang;
-
- $time = htmlspecialchars( $wgLang->timeanddate( $ts, true ) );
+ function getPageLink( $rev, $titleObj, $ts ) {
+ $time = htmlspecialchars( $this->getLang()->timeanddate( $ts, true ) );
- if( !$rev->userCan(Revision::DELETED_TEXT) ) {
+ if( !$rev->userCan( Revision::DELETED_TEXT ) ) {
return '<span class="history-deleted">' . $time . '</span>';
} else {
- $link = $sk->linkKnown(
+ $link = Linker::linkKnown(
$titleObj,
$time,
array(),
@@ -1318,8 +1331,9 @@ class UndeleteForm extends SpecialPage {
'timestamp' => $ts
)
);
- if( $rev->isDeleted(Revision::DELETED_TEXT) )
+ if( $rev->isDeleted( Revision::DELETED_TEXT ) ) {
$link = '<span class="history-deleted">' . $link . '</span>';
+ }
return $link;
}
}
@@ -1327,26 +1341,26 @@ class UndeleteForm extends SpecialPage {
/**
* Fetch image view link if it's available to all users
*
+ * @param $file File
* @return String: HTML fragment
*/
- function getFileLink( $file, $titleObj, $ts, $key, $sk ) {
- global $wgLang, $wgUser;
-
- if( !$file->userCan(File::DELETED_FILE) ) {
- return '<span class="history-deleted">' . $wgLang->timeanddate( $ts, true ) . '</span>';
+ function getFileLink( $file, $titleObj, $ts, $key ) {
+ if( !$file->userCan( File::DELETED_FILE ) ) {
+ return '<span class="history-deleted">' . $this->getLang()->timeanddate( $ts, true ) . '</span>';
} else {
- $link = $sk->linkKnown(
+ $link = Linker::linkKnown(
$titleObj,
- $wgLang->timeanddate( $ts, true ),
+ $this->getLang()->timeanddate( $ts, true ),
array(),
array(
'target' => $this->mTargetObj->getPrefixedText(),
'file' => $key,
- 'token' => $wgUser->editToken( $key )
+ 'token' => $this->getUser()->editToken( $key )
)
);
- if( $file->isDeleted(File::DELETED_FILE) )
+ if( $file->isDeleted( File::DELETED_FILE ) ) {
$link = '<span class="history-deleted">' . $link . '</span>';
+ }
return $link;
}
}
@@ -1354,16 +1368,18 @@ class UndeleteForm extends SpecialPage {
/**
* Fetch file's user id if it's available to this user
*
+ * @param $file File
* @return String: HTML fragment
*/
- function getFileUser( $file, $sk ) {
- if( !$file->userCan(File::DELETED_USER) ) {
+ function getFileUser( $file ) {
+ if( !$file->userCan( File::DELETED_USER ) ) {
return '<span class="history-deleted">' . wfMsgHtml( 'rev-deleted-user' ) . '</span>';
} else {
- $link = $sk->userLink( $file->getRawUser(), $file->getRawUserText() ) .
- $sk->userToolLinks( $file->getRawUser(), $file->getRawUserText() );
- if( $file->isDeleted(File::DELETED_USER) )
+ $link = Linker::userLink( $file->getRawUser(), $file->getRawUserText() ) .
+ Linker::userToolLinks( $file->getRawUser(), $file->getRawUserText() );
+ if( $file->isDeleted( File::DELETED_USER ) ) {
$link = '<span class="history-deleted">' . $link . '</span>';
+ }
return $link;
}
}
@@ -1371,54 +1387,57 @@ class UndeleteForm extends SpecialPage {
/**
* Fetch file upload comment if it's available to this user
*
+ * @param $file File
* @return String: HTML fragment
*/
- function getFileComment( $file, $sk ) {
- if( !$file->userCan(File::DELETED_COMMENT) ) {
- return '<span class="history-deleted"><span class="comment">' . wfMsgHtml( 'rev-deleted-comment' ) . '</span></span>';
+ function getFileComment( $file ) {
+ if( !$file->userCan( File::DELETED_COMMENT ) ) {
+ return '<span class="history-deleted"><span class="comment">' .
+ wfMsgHtml( 'rev-deleted-comment' ) . '</span></span>';
} else {
- $link = $sk->commentBlock( $file->getRawDescription() );
- if( $file->isDeleted(File::DELETED_COMMENT) )
+ $link = Linker::commentBlock( $file->getRawDescription() );
+ if( $file->isDeleted( File::DELETED_COMMENT ) ) {
$link = '<span class="history-deleted">' . $link . '</span>';
+ }
return $link;
}
}
function undelete() {
- global $wgOut, $wgUser;
if ( wfReadOnly() ) {
- $wgOut->readOnlyPage();
- return;
+ throw new ReadOnlyError;
}
+
if( !is_null( $this->mTargetObj ) ) {
$archive = new PageArchive( $this->mTargetObj );
+ wfRunHooks( 'UndeleteForm::undelete', array( &$archive, $this->mTargetObj ) );
$ok = $archive->undelete(
$this->mTargetTimestamp,
$this->mComment,
$this->mFileVersions,
$this->mUnsuppress );
- if( is_array($ok) ) {
- if ( $ok[1] ) // Undeleted file count
+ if( is_array( $ok ) ) {
+ if ( $ok[1] ) { // Undeleted file count
wfRunHooks( 'FileUndeleteComplete', array(
$this->mTargetObj, $this->mFileVersions,
- $wgUser, $this->mComment) );
+ $this->getUser(), $this->mComment ) );
+ }
- $skin = $wgUser->getSkin();
- $link = $skin->linkKnown( $this->mTargetObj );
- $wgOut->addHTML( wfMsgWikiHtml( 'undeletedpage', $link ) );
+ $link = Linker::linkKnown( $this->mTargetObj );
+ $this->getOutput()->addHTML( wfMessage( 'undeletedpage' )->rawParams( $link )->parse() );
} else {
- $wgOut->showFatalError( wfMsg( "cannotundelete" ) );
- $wgOut->addHTML( '<p>' . wfMsgHtml( "undeleterevdel" ) . '</p>' );
+ $this->getOutput()->showFatalError( wfMsg( 'cannotundelete' ) );
+ $this->getOutput()->addWikiMsg( 'undeleterevdel' );
}
// Show file deletion warnings and errors
$status = $archive->getFileStatus();
if( $status && !$status->isGood() ) {
- $wgOut->addWikiText( $status->getWikiText( 'undelete-error-short', 'undelete-error-long' ) );
+ $this->getOutput()->addWikiText( $status->getWikiText( 'undelete-error-short', 'undelete-error-long' ) );
}
} else {
- $wgOut->showFatalError( wfMsg( "cannotundelete" ) );
+ $this->getOutput()->showFatalError( wfMsg( 'cannotundelete' ) );
}
return false;
}
diff --git a/includes/specials/SpecialUnlockdb.php b/includes/specials/SpecialUnlockdb.php
index c71b554b..95ad0bf5 100644
--- a/includes/specials/SpecialUnlockdb.php
+++ b/includes/specials/SpecialUnlockdb.php
@@ -33,12 +33,13 @@ class SpecialUnlockdb extends SpecialPage {
}
public function execute( $par ) {
- global $wgUser, $wgOut, $wgRequest;
+ global $wgUser, $wgRequest;
$this->setHeaders();
- if( !$wgUser->isAllowed( 'siteadmin' ) ) {
- $wgOut->permissionRequired( 'siteadmin' );
+ # Permission check
+ if( !$this->userCanExecute( $wgUser ) ) {
+ $this->displayRestrictionError();
return;
}
@@ -48,7 +49,7 @@ class SpecialUnlockdb extends SpecialPage {
if ( $action == 'success' ) {
$this->showSuccess();
- } else if ( $action == 'submit' && $wgRequest->wasPosted() &&
+ } elseif ( $action == 'submit' && $wgRequest->wasPosted() &&
$wgUser->matchEditToken( $wgRequest->getVal( 'wpEditToken' ) ) ) {
$this->doSubmit();
} else {
@@ -104,7 +105,12 @@ class SpecialUnlockdb extends SpecialPage {
$this->showForm( wfMsg( 'locknoconfirm' ) );
return;
}
- if ( @!unlink( $wgReadOnlyFile ) ) {
+
+ wfSuppressWarnings();
+ $res = unlink( $wgReadOnlyFile );
+ wfRestoreWarnings();
+
+ if ( !$res ) {
$wgOut->showFileDeleteError( $wgReadOnlyFile );
return;
}
diff --git a/includes/specials/SpecialUnusedcategories.php b/includes/specials/SpecialUnusedcategories.php
index ff2a66e1..e4b8e544 100644
--- a/includes/specials/SpecialUnusedcategories.php
+++ b/includes/specials/SpecialUnusedcategories.php
@@ -28,25 +28,26 @@ class UnusedCategoriesPage extends QueryPage {
function isExpensive() { return true; }
- function getName() {
- return 'Unusedcategories';
+ function __construct( $name = 'Unusedcategories' ) {
+ parent::__construct( $name );
}
function getPageHeader() {
return wfMsgExt( 'unusedcategoriestext', array( 'parse' ) );
}
- function getSQL() {
- $NScat = NS_CATEGORY;
- $dbr = wfGetDB( DB_SLAVE );
- list( $categorylinks, $page ) = $dbr->tableNamesN( 'categorylinks', 'page' );
- return "SELECT 'Unusedcategories' as type,
- {$NScat} as namespace, page_title as title, page_title as value
- FROM $page
- LEFT JOIN $categorylinks ON page_title=cl_to
- WHERE cl_from IS NULL
- AND page_namespace = {$NScat}
- AND page_is_redirect = 0";
+ function getQueryInfo() {
+ return array (
+ 'tables' => array ( 'page', 'categorylinks' ),
+ 'fields' => array ( 'page_namespace AS namespace',
+ 'page_title AS title',
+ 'page_title AS value' ),
+ 'conds' => array ( 'cl_from IS NULL',
+ 'page_namespace' => NS_CATEGORY,
+ 'page_is_redirect' => 0 ),
+ 'join_conds' => array ( 'categorylinks' => array (
+ 'LEFT JOIN', 'cl_to = page_title' ) )
+ );
}
/**
@@ -61,10 +62,3 @@ class UnusedCategoriesPage extends QueryPage {
return $skin->link( $title, $title->getText() );
}
}
-
-/** constructor */
-function wfSpecialUnusedCategories() {
- list( $limit, $offset ) = wfCheckLimits();
- $uc = new UnusedCategoriesPage();
- return $uc->doQuery( $offset, $limit );
-}
diff --git a/includes/specials/SpecialUnusedimages.php b/includes/specials/SpecialUnusedimages.php
index 091ec3a3..6407de44 100644
--- a/includes/specials/SpecialUnusedimages.php
+++ b/includes/specials/SpecialUnusedimages.php
@@ -27,41 +27,53 @@
* @ingroup SpecialPage
*/
class UnusedimagesPage extends ImageQueryPage {
+ function __construct( $name = 'Unusedimages' ) {
+ parent::__construct( $name );
+ }
- function isExpensive() { return true; }
-
- function getName() {
- return 'Unusedimages';
+ function isExpensive() {
+ return true;
}
function sortDescending() {
return false;
}
- function isSyndicated() { return false; }
-
- function getSQL() {
- global $wgCountCategorizedImagesAsUsed;
- $dbr = wfGetDB( DB_SLAVE );
+ function isSyndicated() {
+ return false;
+ }
- $epoch = $dbr->unixTimestamp( 'img_timestamp' );
+ function getQueryInfo() {
+ global $wgCountCategorizedImagesAsUsed;
+ $retval = array (
+ 'tables' => array ( 'image', 'imagelinks' ),
+ 'fields' => array ( "'" . NS_FILE . "' AS namespace",
+ 'img_name AS title',
+ 'img_timestamp AS value',
+ 'img_user', 'img_user_text',
+ 'img_description' ),
+ 'conds' => array ( 'il_to IS NULL' ),
+ 'join_conds' => array ( 'imagelinks' => array (
+ 'LEFT JOIN', 'il_to = img_name' ) )
+ );
if ( $wgCountCategorizedImagesAsUsed ) {
- list( $page, $image, $imagelinks, $categorylinks ) = $dbr->tableNamesN( 'page', 'image', 'imagelinks', 'categorylinks' );
-
- return "SELECT 'Unusedimages' as type, 6 as namespace, img_name as title, $epoch as value,
- img_user, img_user_text, img_description
- FROM ((($page AS I LEFT JOIN $categorylinks AS L ON I.page_id = L.cl_from)
- LEFT JOIN $imagelinks AS P ON I.page_title = P.il_to)
- INNER JOIN $image AS G ON I.page_title = G.img_name)
- WHERE I.page_namespace = ".NS_FILE." AND L.cl_from IS NULL AND P.il_to IS NULL";
- } else {
- list( $image, $imagelinks ) = $dbr->tableNamesN( 'image','imagelinks' );
-
- return "SELECT 'Unusedimages' as type, 6 as namespace, img_name as title, $epoch as value,
- img_user, img_user_text, img_description
- FROM $image LEFT JOIN $imagelinks ON img_name=il_to WHERE il_to IS NULL ";
+ // Order is significant
+ $retval['tables'] = array ( 'image', 'page', 'categorylinks',
+ 'imagelinks' );
+ $retval['conds']['page_namespace'] = NS_FILE;
+ $retval['conds'][] = 'cl_from IS NULL';
+ $retval['conds'][] = 'img_name = page_title';
+ $retval['join_conds']['categorylinks'] = array (
+ 'LEFT JOIN', 'cl_from = page_id' );
+ $retval['join_conds']['imagelinks'] = array (
+ 'LEFT JOIN', 'il_to = page_title' );
}
+ return $retval;
+ }
+
+ function usesTimestamps() {
+ return true;
}
function getPageHeader() {
@@ -69,13 +81,3 @@ class UnusedimagesPage extends ImageQueryPage {
}
}
-
-/**
- * Entry point
- */
-function wfSpecialUnusedimages() {
- list( $limit, $offset ) = wfCheckLimits();
- $uip = new UnusedimagesPage();
-
- return $uip->doQuery( $offset, $limit );
-}
diff --git a/includes/specials/SpecialUnusedtemplates.php b/includes/specials/SpecialUnusedtemplates.php
index 68bf95a2..da501605 100644
--- a/includes/specials/SpecialUnusedtemplates.php
+++ b/includes/specials/SpecialUnusedtemplates.php
@@ -31,24 +31,34 @@
*/
class UnusedtemplatesPage extends QueryPage {
- function getName() { return( 'Unusedtemplates' ); }
+ function __construct( $name = 'Unusedtemplates' ) {
+ parent::__construct( $name );
+ }
+
function isExpensive() { return true; }
function isSyndicated() { return false; }
function sortDescending() { return false; }
- function getSQL() {
- $dbr = wfGetDB( DB_SLAVE );
- list( $page, $templatelinks) = $dbr->tableNamesN( 'page', 'templatelinks' );
- $sql = "SELECT 'Unusedtemplates' AS type, page_title AS title,
- page_namespace AS namespace, 0 AS value
- FROM $page
- LEFT JOIN $templatelinks
- ON page_namespace = tl_namespace AND page_title = tl_title
- WHERE page_namespace = 10 AND tl_from IS NULL
- AND page_is_redirect = 0";
- return $sql;
+ function getQueryInfo() {
+ return array (
+ 'tables' => array ( 'page', 'templatelinks' ),
+ 'fields' => array ( 'page_namespace AS namespace',
+ 'page_title AS title',
+ 'page_title AS value' ),
+ 'conds' => array ( 'page_namespace' => NS_TEMPLATE,
+ 'tl_from IS NULL',
+ 'page_is_redirect' => 0 ),
+ 'join_conds' => array ( 'templatelinks' => array (
+ 'LEFT JOIN', array ( 'tl_title = page_title',
+ 'tl_namespace = page_namespace' ) ) )
+ );
}
+ /**
+ * @param $skin Skin
+ * @param $result
+ * @return string
+ */
function formatResult( $skin, $result ) {
$title = Title::makeTitle( NS_TEMPLATE, $result->title );
$pageLink = $skin->linkKnown(
@@ -72,8 +82,3 @@ class UnusedtemplatesPage extends QueryPage {
}
-function wfSpecialUnusedtemplates() {
- list( $limit, $offset ) = wfCheckLimits();
- $utp = new UnusedtemplatesPage();
- $utp->doQuery( $offset, $limit );
-}
diff --git a/includes/specials/SpecialUnwatchedpages.php b/includes/specials/SpecialUnwatchedpages.php
index ecd62cb7..0f11140b 100644
--- a/includes/specials/SpecialUnwatchedpages.php
+++ b/includes/specials/SpecialUnwatchedpages.php
@@ -31,62 +31,58 @@
*/
class UnwatchedpagesPage extends QueryPage {
- function getName() { return 'Unwatchedpages'; }
+ function __construct( $name = 'Unwatchedpages' ) {
+ parent::__construct( $name, 'unwatchedpages' );
+ }
+
function isExpensive() { return true; }
function isSyndicated() { return false; }
- function getSQL() {
- $dbr = wfGetDB( DB_SLAVE );
- list( $page, $watchlist ) = $dbr->tableNamesN( 'page', 'watchlist' );
- $mwns = NS_MEDIAWIKI;
- return
- "
- SELECT
- 'Unwatchedpages' as type,
- page_namespace as namespace,
- page_title as title,
- page_namespace as value
- FROM $page
- LEFT JOIN $watchlist ON wl_namespace = page_namespace AND page_title = wl_title
- WHERE wl_title IS NULL AND page_is_redirect = 0 AND page_namespace<>$mwns
- ";
+ function getQueryInfo() {
+ return array (
+ 'tables' => array ( 'page', 'watchlist' ),
+ 'fields' => array ( 'page_namespace AS namespace',
+ 'page_title AS title',
+ 'page_namespace AS value' ),
+ 'conds' => array ( 'wl_title IS NULL',
+ 'page_is_redirect' => 0,
+ "page_namespace != '" . NS_MEDIAWIKI .
+ "'" ),
+ 'join_conds' => array ( 'watchlist' => array (
+ 'LEFT JOIN', array ( 'wl_title = page_title',
+ 'wl_namespace = page_namespace' ) ) )
+ );
}
function sortDescending() { return false; }
+ function getOrderFields() {
+ return array( 'page_namespace', 'page_title' );
+ }
+
+ /**
+ * @param $skin Skin
+ * @param $result
+ * @return string
+ */
function formatResult( $skin, $result ) {
global $wgContLang;
$nt = Title::makeTitle( $result->namespace, $result->title );
$text = $wgContLang->convert( $nt->getPrefixedText() );
- $plink = $skin->linkKnown(
+ $plink = Linker::linkKnown(
$nt,
htmlspecialchars( $text )
);
- $wlink = $skin->linkKnown(
+ $token = WatchAction::getWatchToken( $nt, $this->getUser() );
+ $wlink = Linker::linkKnown(
$nt,
wfMsgHtml( 'watch' ),
array(),
- array( 'action' => 'watch' )
+ array( 'action' => 'watch', 'token' => $token )
);
return wfSpecialList( $plink, $wlink );
}
}
-
-/**
- * constructor
- */
-function wfSpecialUnwatchedpages() {
- global $wgUser, $wgOut;
-
- if ( ! $wgUser->isAllowed( 'unwatchedpages' ) )
- return $wgOut->permissionRequired( 'unwatchedpages' );
-
- list( $limit, $offset ) = wfCheckLimits();
-
- $wpp = new UnwatchedpagesPage();
-
- $wpp->doQuery( $offset, $limit );
-}
diff --git a/includes/specials/SpecialUpload.php b/includes/specials/SpecialUpload.php
index 893e4be2..8eeca5d5 100644
--- a/includes/specials/SpecialUpload.php
+++ b/includes/specials/SpecialUpload.php
@@ -45,7 +45,15 @@ class SpecialUpload extends SpecialPage {
/** Misc variables **/
public $mRequest; // The WebRequest or FauxRequest this form is supposed to handle
public $mSourceType;
+
+ /**
+ * @var UploadBase
+ */
public $mUpload;
+
+ /**
+ * @var LocalFile
+ */
public $mLocalFile;
public $mUploadClicked;
@@ -71,6 +79,8 @@ class SpecialUpload extends SpecialPage {
public $uploadFormTextTop;
public $uploadFormTextAfterSummary;
+ public $mWatchthis;
+
/**
* Initialize instance variables from request and create an Upload handler
*
@@ -105,7 +115,7 @@ class SpecialUpload extends SpecialPage {
$this->mForReUpload = $request->getBool( 'wpForReUpload' ); // updating a file
$this->mCancelUpload = $request->getCheck( 'wpCancelUpload' )
- || $request->getCheck( 'wpReUpload' ); // b/w compat
+ || $request->getCheck( 'wpReUpload' ); // b/w compat
// If it was posted check for the token (no remote POST'ing with user credentials)
$token = $request->getVal( 'wpEditToken' );
@@ -130,7 +140,7 @@ class SpecialUpload extends SpecialPage {
* @param $user User object
* @return Boolean
*/
- public function userCanExecute( $user ) {
+ public function userCanExecute( User $user ) {
return UploadBase::isEnabled() && parent::userCanExecute( $user );
}
@@ -196,7 +206,7 @@ class SpecialUpload extends SpecialPage {
wfDebug( "Hook 'UploadForm:initial' broke output of the upload form" );
return;
}
-
+
$this->showUploadForm( $this->getUploadForm() );
}
@@ -214,7 +224,7 @@ class SpecialUpload extends SpecialPage {
*/
protected function showUploadForm( $form ) {
# Add links if file was previously deleted
- if ( !$this->mDesiredDestName ) {
+ if ( $this->mDesiredDestName ) {
$this->showViewDeletedLinks();
}
@@ -267,7 +277,7 @@ class SpecialUpload extends SpecialPage {
$desiredTitleObj = Title::makeTitleSafe( NS_FILE, $this->mDesiredDestName );
$delNotice = ''; // empty by default
if ( $desiredTitleObj instanceof Title && !$desiredTitleObj->exists() ) {
- LogEventsList::showLogExtract( $delNotice, array( 'delete', 'move' ),
+ LogEventsList::showLogExtract( $delNotice, array( 'delete', 'move' ),
$desiredTitleObj->getPrefixedText(),
'', array( 'lim' => 10,
'conds' => array( "log_action != 'revision'" ),
@@ -278,17 +288,17 @@ class SpecialUpload extends SpecialPage {
$form->addPreText( $delNotice );
# Add text to form
- $form->addPreText( '<div id="uploadtext">' .
- wfMsgExt( 'uploadtext', 'parse', array( $this->mDesiredDestName ) ) .
+ $form->addPreText( '<div id="uploadtext">' .
+ wfMsgExt( 'uploadtext', 'parse', array( $this->mDesiredDestName ) ) .
'</div>' );
# Add upload error message
$form->addPreText( $message );
# Add footer to form
- $uploadFooter = wfMsgNoTrans( 'uploadfooter' );
- if ( $uploadFooter != '-' && !wfEmptyMsg( 'uploadfooter', $uploadFooter ) ) {
+ $uploadFooter = wfMessage( 'uploadfooter' );
+ if ( !$uploadFooter->isDisabled() ) {
$form->addPostText( '<div id="mw-upload-footer-message">'
- . $wgOut->parse( $uploadFooter ) . "</div>\n" );
+ . $wgOut->parse( $uploadFooter->plain() ) . "</div>\n" );
}
return $form;
@@ -309,7 +319,7 @@ class SpecialUpload extends SpecialPage {
$link = wfMsgExt(
$wgUser->isAllowed( 'delete' ) ? 'thisisdeleted' : 'viewdeleted',
array( 'parse', 'replaceafter' ),
- $wgUser->getSkin()->linkKnown(
+ $this->getSkin()->linkKnown(
SpecialPage::getTitleFor( 'Undelete', $title->getPrefixedText() ),
wfMsgExt( 'restorelink', array( 'parsemag', 'escape' ), $count )
)
@@ -317,11 +327,6 @@ class SpecialUpload extends SpecialPage {
$wgOut->addHTML( "<div id=\"contentSub2\">{$link}</div>" );
}
}
-
- // Show the relevant lines from deletion log (for still deleted files only)
- if( $title instanceof Title && $title->isDeletedQuick() && !$title->exists() ) {
- $this->showDeletionLog( $wgOut, $title->getPrefixedText() );
- }
}
/**
@@ -337,7 +342,7 @@ class SpecialUpload extends SpecialPage {
*/
protected function showRecoverableUploadError( $message ) {
$sessionKey = $this->mUpload->stashSession();
- $message = '<h2>' . wfMsgHtml( 'uploadwarning' ) . "</h2>\n" .
+ $message = '<h2>' . wfMsgHtml( 'uploaderror' ) . "</h2>\n" .
'<div class="error">' . $message . "</div>\n";
$form = $this->getUploadForm( $message, $sessionKey );
@@ -357,8 +362,8 @@ class SpecialUpload extends SpecialPage {
# mDestWarningAck is set when some javascript has shown the warning
# to the user. mForReUpload is set when the user clicks the "upload a
# new version" link.
- if ( !$warnings || ( count( $warnings ) == 1 &&
- isset( $warnings['exists'] ) &&
+ if ( !$warnings || ( count( $warnings ) == 1 &&
+ isset( $warnings['exists'] ) &&
( $this->mDestWarningAck || $this->mForReUpload ) ) )
{
return false;
@@ -436,16 +441,15 @@ class SpecialUpload extends SpecialPage {
return;
}
-
// Upload verification
$details = $this->mUpload->verifyUpload();
if ( $details['status'] != UploadBase::OK ) {
$this->processVerificationError( $details );
return;
}
-
+
// Verify permissions for this title
- $permErrors = $this->mUpload->verifyPermissions( $wgUser );
+ $permErrors = $this->mUpload->verifyTitlePermissions( $wgUser );
if( $permErrors !== true ) {
$code = array_shift( $permErrors[0] );
$this->showRecoverableUploadError( wfMsgExt( $code,
@@ -574,6 +578,10 @@ class SpecialUpload extends SpecialPage {
$this->showRecoverableUploadError( wfMsgExt( 'filetype-missing',
'parseinline' ) );
break;
+ case UploadBase::WINDOWS_NONASCII_FILENAME:
+ $this->showRecoverableUploadError( wfMsgExt( 'windows-nonascii-filename',
+ 'parseinline' ) );
+ break;
/** Statuses that require reuploading **/
case UploadBase::EMPTY_FILE:
@@ -583,18 +591,25 @@ class SpecialUpload extends SpecialPage {
$this->showUploadError( wfMsgHtml( 'largefileserver' ) );
break;
case UploadBase::FILETYPE_BADTYPE:
- $finalExt = $details['finalExt'];
- $this->showUploadError(
- wfMsgExt( 'filetype-banned-type',
- array( 'parseinline' ),
- htmlspecialchars( $finalExt ),
- implode(
- wfMsgExt( 'comma-separator', array( 'escapenoentities' ) ),
- $wgFileExtensions
- ),
- $wgLang->formatNum( count( $wgFileExtensions ) )
- )
- );
+ $msg = wfMessage( 'filetype-banned-type' );
+ if ( isset( $details['blacklistedExt'] ) ) {
+ $msg->params( $wgLang->commaList( $details['blacklistedExt'] ) );
+ } else {
+ $msg->params( $details['finalExt'] );
+ }
+ $msg->params( $wgLang->commaList( $wgFileExtensions ),
+ count( $wgFileExtensions ) );
+
+ // Add PLURAL support for the first parameter. This results
+ // in a bit unlogical parameter sequence, but does not break
+ // old translations
+ if ( isset( $details['blacklistedExt'] ) ) {
+ $msg->params( count( $details['blacklistedExt'] ) );
+ } else {
+ $msg->params( 1 );
+ }
+
+ $this->showUploadError( $msg->parse() );
break;
case UploadBase::VERIFICATION_ERROR:
unset( $details['status'] );
@@ -690,7 +705,7 @@ class SpecialUpload extends SpecialPage {
'page' => $filename
)
);
- $warning = wfMsgWikiHtml( 'filewasdeleted', $llink );
+ $warning = wfMsgExt( 'filewasdeleted', array( 'parse', 'replaceafter' ), $llink );
}
return $warning;
@@ -761,6 +776,8 @@ class UploadForm extends HTMLForm {
protected $mSourceIds;
+ protected $mMaxFileSize = array();
+
public function __construct( $options = array() ) {
$this->mWatch = !empty( $options['watch'] );
$this->mForReUpload = !empty( $options['forreupload'] );
@@ -777,7 +794,7 @@ class UploadForm extends HTMLForm {
? $options['texttop'] : '';
$this->mTextAfterSummary = isset( $options['textaftersummary'] )
- ? $options['textaftersummary'] : '';
+ ? $options['textaftersummary'] : '';
$sourceDescriptor = $this->getSourceSection();
$descriptor = $sourceDescriptor
@@ -812,7 +829,6 @@ class UploadForm extends HTMLForm {
*/
protected function getSourceSection() {
global $wgLang, $wgUser, $wgRequest;
- global $wgMaxUploadSize;
if ( $this->mSessionKey ) {
return array(
@@ -841,6 +857,14 @@ class UploadForm extends HTMLForm {
);
}
+ $this->mMaxUploadSize['file'] = UploadBase::getMaxUploadSize( 'file' );
+ # Limit to upload_max_filesize unless we are running under HipHop and
+ # that setting doesn't exist
+ if ( !wfIsHipHop() ) {
+ $this->mMaxUploadSize['file'] = min( $this->mMaxUploadSize['file'],
+ wfShorthandToInteger( ini_get( 'upload_max_filesize' ) ) );
+ }
+
$descriptor['UploadFile'] = array(
'class' => 'UploadSourceField',
'section' => 'source',
@@ -851,17 +875,12 @@ class UploadForm extends HTMLForm {
'radio' => &$radio,
'help' => wfMsgExt( 'upload-maxfilesize',
array( 'parseinline', 'escapenoentities' ),
- $wgLang->formatSize(
- wfShorthandToInteger( min(
- wfShorthandToInteger(
- ini_get( 'upload_max_filesize' )
- ), $wgMaxUploadSize
- ) )
- )
+ $wgLang->formatSize( $this->mMaxUploadSize['file'] )
) . ' ' . wfMsgHtml( 'upload_source_file' ),
'checked' => $selectedSourceType == 'file',
);
if ( $canUploadByUrl ) {
+ $this->mMaxUploadSize['url'] = UploadBase::getMaxUploadSize( 'url' );
$descriptor['UploadFileURL'] = array(
'class' => 'UploadSourceField',
'section' => 'source',
@@ -871,7 +890,7 @@ class UploadForm extends HTMLForm {
'radio' => &$radio,
'help' => wfMsgExt( 'upload-maxfilesize',
array( 'parseinline', 'escapenoentities' ),
- $wgLang->formatSize( $wgMaxUploadSize )
+ $wgLang->formatSize( $this->mMaxUploadSize['url'] )
) . ' ' . wfMsgHtml( 'upload_source_url' ),
'checked' => $selectedSourceType == 'url',
);
@@ -903,16 +922,16 @@ class UploadForm extends HTMLForm {
# Everything not permitted is banned
$extensionsList =
'<div id="mw-upload-permitted">' .
- wfMsgWikiHtml( 'upload-permitted', $wgLang->commaList( $wgFileExtensions ) ) .
+ wfMsgExt( 'upload-permitted', 'parse', $wgLang->commaList( $wgFileExtensions ) ) .
"</div>\n";
} else {
# We have to list both preferred and prohibited
$extensionsList =
'<div id="mw-upload-preferred">' .
- wfMsgWikiHtml( 'upload-preferred', $wgLang->commaList( $wgFileExtensions ) ) .
+ wfMsgExt( 'upload-preferred', 'parse', $wgLang->commaList( $wgFileExtensions ) ) .
"</div>\n" .
'<div id="mw-upload-prohibited">' .
- wfMsgWikiHtml( 'upload-prohibited', $wgLang->commaList( $wgFileBlacklist ) ) .
+ wfMsgExt( 'upload-prohibited', 'parse', $wgLang->commaList( $wgFileBlacklist ) ) .
"</div>\n";
}
} else {
@@ -931,6 +950,26 @@ class UploadForm extends HTMLForm {
protected function getDescriptionSection() {
global $wgUser;
+ if ( $this->mSessionKey ) {
+ $stash = RepoGroup::singleton()->getLocalRepo()->getUploadStash();
+ try {
+ $file = $stash->getFile( $this->mSessionKey );
+ } catch ( MWException $e ) {
+ $file = null;
+ }
+ if ( $file ) {
+ global $wgContLang;
+
+ $mto = $file->transform( array( 'width' => 120 ) );
+ $this->addHeaderText(
+ '<div class="thumb t' . $wgContLang->alignEnd() . '">' .
+ Html::element( 'img', array(
+ 'src' => $mto->getUrl(),
+ 'class' => 'thumbimage',
+ ) ) . '</div>', 'description' );
+ }
+ }
+
$descriptor = array(
'DestFile' => array(
'type' => 'text',
@@ -939,7 +978,7 @@ class UploadForm extends HTMLForm {
'label-message' => 'destfilename',
'size' => 60,
'default' => $this->mDestFile,
- # FIXME: hack to work around poor handling of the 'default' option in HTMLForm
+ # @todo FIXME: Hack to work around poor handling of the 'default' option in HTMLForm
'nodata' => strval( $this->mDestFile ) !== '',
),
'UploadDescription' => array(
@@ -967,6 +1006,7 @@ class UploadForm extends HTMLForm {
'EditTools' => array(
'type' => 'edittools',
'section' => 'description',
+ 'message' => 'edittools-upload',
)
);
@@ -1035,7 +1075,7 @@ class UploadForm extends HTMLForm {
'id' => 'wpDestFileWarningAck',
'default' => $this->mDestWarningAck ? '1' : '',
);
-
+
if ( $this->mForReUpload ) {
$descriptor['ForReUpload'] = array(
'type' => 'hidden',
@@ -1064,6 +1104,7 @@ class UploadForm extends HTMLForm {
$useAjaxDestCheck = $wgUseAjax && $wgAjaxUploadDestCheck;
$useAjaxLicensePreview = $wgUseAjax && $wgAjaxLicensePreview && $wgEnableAPI;
+ $this->mMaxUploadSize['*'] = UploadBase::getMaxUploadSize();
$scriptVars = array(
'wgAjaxUploadDestCheck' => $useAjaxDestCheck,
@@ -1075,12 +1116,17 @@ class UploadForm extends HTMLForm {
'wgUploadSourceIds' => $this->mSourceIds,
'wgStrictFileExtensions' => $wgStrictFileExtensions,
'wgCapitalizeUploads' => MWNamespace::isCapitalized( NS_FILE ),
+ 'wgMaxUploadSize' => $this->mMaxUploadSize,
);
$wgOut->addScript( Skin::makeVariablesScript( $scriptVars ) );
- // For <charinsert> support
- $wgOut->addModules( array( 'mediawiki.legacy.edit', 'mediawiki.legacy.upload' ) );
+
+ $wgOut->addModules( array(
+ 'mediawiki.action.edit', // For <charinsert> support
+ 'mediawiki.legacy.upload', // Old form stuff...
+ 'mediawiki.special.upload', // Newer extras for thumbnail preview.
+ ) );
}
/**
diff --git a/includes/specials/SpecialUploadStash.php b/includes/specials/SpecialUploadStash.php
index 48a41a5e..20a37f0b 100644
--- a/includes/specials/SpecialUploadStash.php
+++ b/includes/specials/SpecialUploadStash.php
@@ -20,13 +20,7 @@ class SpecialUploadStash extends UnlistedSpecialPage {
// UploadStash
private $stash;
- // is the edit request authorized? boolean
- private $isEditAuthorized;
-
- // did the user request us to clear the stash? boolean
- private $requestedClear;
-
- // Since we are directly writing the file to STDOUT,
+ // Since we are directly writing the file to STDOUT,
// we should not be reading in really big files and serving them out.
//
// We also don't want people using this as a file drop, even if they
@@ -34,19 +28,15 @@ class SpecialUploadStash extends UnlistedSpecialPage {
//
// This service is really for thumbnails and other such previews while
// uploading.
- const MAX_SERVE_BYTES = 262144; // 256K
-
- public function __construct( $request = null ) {
- global $wgRequest;
+ const MAX_SERVE_BYTES = 1048576; // 1MB
+ public function __construct() {
parent::__construct( 'UploadStash', 'upload' );
try {
$this->stash = RepoGroup::singleton()->getLocalRepo()->getUploadStash();
} catch ( UploadStashNotAvailableException $e ) {
return null;
}
-
- $this->loadRequest( is_null( $request ) ? $wgRequest : $request );
}
/**
@@ -91,7 +81,7 @@ class SpecialUploadStash extends UnlistedSpecialPage {
return $this->outputLocalFile( $params['file'] );
}
} catch( UploadStashFileNotFoundException $e ) {
- $code = 404;
+ $code = 404;
$message = $e->getMessage();
} catch( UploadStashZeroLengthFileException $e ) {
$code = 500;
@@ -107,15 +97,15 @@ class SpecialUploadStash extends UnlistedSpecialPage {
$message = $e->getMessage();
}
- wfHttpError( $code, OutputPage::getStatusMessage( $code ), $message );
+ wfHttpError( $code, HttpStatus::getMessage( $code ), $message );
return false;
}
-
+
/**
- * Parse the key passed to the SpecialPage. Returns an array containing
- * the associated file object, the type ('file' or 'thumb') and if
+ * Parse the key passed to the SpecialPage. Returns an array containing
+ * the associated file object, the type ('file' or 'thumb') and if
* application the transform parameters
- *
+ *
* @param string $key
* @return array
*/
@@ -132,28 +122,27 @@ class SpecialUploadStash extends UnlistedSpecialPage {
$srcNamePos = strrpos( $thumbPart, $fileName );
if ( $srcNamePos === false || $srcNamePos < 1 ) {
throw new UploadStashBadPathException( 'Unrecognized thumb name' );
- }
+ }
$paramString = substr( $thumbPart, 0, $srcNamePos - 1 );
-
+
$handler = $file->getHandler();
- $params = $handler->parseParamString( $paramString );
- return array( 'file' => $file, 'type' => $type, 'params' => $params );
+ $params = $handler->parseParamString( $paramString );
+ return array( 'file' => $file, 'type' => $type, 'params' => $params );
}
-
+
return array( 'file' => $file, 'type' => $type );
}
-
-
-
/**
* Get a thumbnail for file, either generated locally or remotely, and stream it out
- * @param String $key: key for the file in the stash
- * @param int $width: width of desired thumbnail
- * @return boolean success
- */
+ *
+ * @param $file
+ * @param $params array
+ *
+ * @return boolean success
+ */
private function outputThumbFromStash( $file, $params ) {
-
+
// this global, if it exists, points to a "scaler", as you might find in the Wikimedia Foundation cluster. See outputRemoteScaledThumb()
// this is part of our horrible NFS-based system, we create a file on a mount point here, but fetch the scaled file from somewhere else that
// happens to share it over NFS
@@ -165,16 +154,13 @@ class SpecialUploadStash extends UnlistedSpecialPage {
} else {
$this->outputLocallyScaledThumb( $file, $params, $flags );
}
-
-
}
-
/**
* Scale a file (probably with a locally installed imagemagick, or similar) and output it to STDOUT.
- * @param $file: File object
+ * @param $file: File object
* @param $params: scaling parameters ( e.g. array( width => '50' ) );
- * @param $flags: scaling flags ( see File:: constants )
+ * @param $flags: scaling flags ( see File:: constants )
* @throws MWException
* @return boolean success
*/
@@ -182,7 +168,7 @@ class SpecialUploadStash extends UnlistedSpecialPage {
// n.b. this is stupid, we insist on re-transforming the file every time we are invoked. We rely
// on HTTP caching to ensure this doesn't happen.
-
+
$flags |= File::RENDER_NOW;
$thumbnailImage = $file->transform( $params, $flags );
@@ -203,41 +189,47 @@ class SpecialUploadStash extends UnlistedSpecialPage {
}
return $this->outputLocalFile( $thumbFile );
-
+
}
-
+
/**
* Scale a file with a remote "scaler", as exists on the Wikimedia Foundation cluster, and output it to STDOUT.
- * Note: unlike the usual thumbnail process, the web client never sees the cluster URL; we do the whole HTTP transaction to the scaler ourselves
+ * Note: unlike the usual thumbnail process, the web client never sees the cluster URL; we do the whole HTTP transaction to the scaler ourselves
* and cat the results out.
- * Note: We rely on NFS to have propagated the file contents to the scaler. However, we do not rely on the thumbnail being created in NFS and then
- * propagated back to our filesystem. Instead we take the results of the HTTP request instead.
+ * Note: We rely on NFS to have propagated the file contents to the scaler. However, we do not rely on the thumbnail being created in NFS and then
+ * propagated back to our filesystem. Instead we take the results of the HTTP request instead.
* Note: no caching is being done here, although we are instructing the client to cache it forever.
- * @param $file: File object
+ * @param $file: File object
* @param $params: scaling parameters ( e.g. array( width => '50' ) );
- * @param $flags: scaling flags ( see File:: constants )
+ * @param $flags: scaling flags ( see File:: constants )
* @throws MWException
* @return boolean success
*/
private function outputRemoteScaledThumb( $file, $params, $flags ) {
-
+
// this global probably looks something like 'http://upload.wikimedia.org/wikipedia/test/thumb/temp'
// do not use trailing slash
global $wgUploadStashScalerBaseUrl;
- $scalerThumbName = $file->getParamThumbName( $file->name, $params );
- $scalerThumbUrl = $wgUploadStashScalerBaseUrl . '/' . $file->getRel() . '/' . $scalerThumbName;
-
+ // We need to use generateThumbName() instead of thumbName(), because
+ // the suffix needs to match the file name for the remote thumbnailer
+ // to work
+ $scalerThumbName = $file->generateThumbName( $file->getName(), $params );
+ $scalerThumbUrl = $wgUploadStashScalerBaseUrl . '/' . $file->getUrlRel() .
+ '/' . rawurlencode( $scalerThumbName );
+
// make a curl call to the scaler to create a thumbnail
- $httpOptions = array(
+ $httpOptions = array(
'method' => 'GET',
'timeout' => 'default'
);
$req = MWHttpRequest::factory( $scalerThumbUrl, $httpOptions );
$status = $req->execute();
if ( ! $status->isOK() ) {
- $errors = $status->getErrorsArray();
- throw new MWException( "Fetching thumbnail failed: " . join( ", ", $errors ) );
+ $errors = $status->getErrorsArray();
+ $errorStr = "Fetching thumbnail failed: " . print_r( $errors, 1 );
+ $errorStr .= "\nurl = $scalerThumbUrl\n";
+ throw new MWException( $errorStr );
}
$contentType = $req->getResponseHeader( "content-type" );
if ( ! $contentType ) {
@@ -257,13 +249,13 @@ class SpecialUploadStash extends UnlistedSpecialPage {
private function outputLocalFile( $file ) {
if ( $file->getSize() > self::MAX_SERVE_BYTES ) {
throw new SpecialUploadStashTooLargeException();
- }
+ }
self::outputFileHeaders( $file->getMimeType(), $file->getSize() );
readfile( $file->getPath() );
return true;
}
- /**
+ /**
* Output HTTP response of raw content
* Side effect: writes HTTP response to STDOUT.
* @param String $content: content
@@ -275,11 +267,11 @@ class SpecialUploadStash extends UnlistedSpecialPage {
throw new SpecialUploadStashTooLargeException();
}
self::outputFileHeaders( $contentType, $size );
- print $content;
+ print $content;
return true;
}
- /**
+ /**
* Output headers for streaming
* XXX unsure about encoding as binary; if we received from HTTP perhaps we should use that encoding, concatted with semicolon to mimeType as it usually is.
* Side effect: preps PHP to write headers to STDOUT.
@@ -290,38 +282,20 @@ class SpecialUploadStash extends UnlistedSpecialPage {
header( "Content-Type: $contentType", true );
header( 'Content-Transfer-Encoding: binary', true );
header( 'Expires: Sun, 17-Jan-2038 19:14:07 GMT', true );
- header( "Content-Length: $size", true );
- }
-
-
- /**
- * Initialize authorization & actions to take, from the request
- * @param $request: WebRequest
- */
- private function loadRequest( $request ) {
- global $wgUser;
- if ( $request->wasPosted() ) {
-
- $token = $request->getVal( 'wpEditToken' );
- $this->isEditAuthorized = $wgUser->matchEditToken( $token );
-
- $this->requestedClear = $request->getBool( 'clear' );
-
- }
+ header( "Content-Length: $size", true );
}
/**
- * Static callback for the HTMLForm in showUploads, to process
+ * Static callback for the HTMLForm in showUploads, to process
* Note the stash has to be recreated since this is being called in a static context.
* This works, because there really is only one stash per logged-in user, despite appearances.
*
* @return Status
- */
+ */
public static function tryClearStashedUploads( $formData ) {
- wfDebug( __METHOD__ . " form data : " . print_r( $formData, 1 ) );
- if ( isset( $formData['clear'] ) and $formData['clear'] ) {
- $stash = new UploadStash();
- wfDebug( "stash has: " . print_r( $stash->listFiles(), 1 ) );
+ if ( isset( $formData['Clear'] ) ) {
+ $stash = RepoGroup::singleton()->getLocalRepo()->getUploadStash();
+ wfDebug( "stash has: " . print_r( $stash->listFiles(), true ) );
if ( ! $stash->clear() ) {
return Status::newFatal( 'uploadstash-errclear' );
}
@@ -333,7 +307,7 @@ class SpecialUploadStash extends UnlistedSpecialPage {
* Default action when we don't have a subpage -- just show links to the uploads we have,
* Also show a button to clear stashed files
* @param Status : $status - the result of processRequest
- */
+ */
private function showUploads( $status = null ) {
global $wgOut;
if ( $status === null ) {
@@ -344,49 +318,49 @@ class SpecialUploadStash extends UnlistedSpecialPage {
$this->setHeaders();
$this->outputHeader();
-
// create the form, which will also be used to execute a callback to process incoming form data
// this design is extremely dubious, but supposedly HTMLForm is our standard now?
- $form = new HTMLForm( array(
- 'Clear' => array(
- 'type' => 'hidden',
+ $form = new HTMLForm( array(
+ 'Clear' => array(
+ 'type' => 'hidden',
'default' => true,
'name' => 'clear',
- )
+ )
), 'clearStashedUploads' );
- $form->setSubmitCallback( array( __CLASS__, 'tryClearStashedUploads' ) );
+ $form->setSubmitCallback( array( __CLASS__ , 'tryClearStashedUploads' ) );
$form->setTitle( $this->getTitle() );
- $form->addHiddenField( 'clear', true, array( 'type' => 'boolean' ) );
$form->setSubmitText( wfMsg( 'uploadstash-clear' ) );
- $form->prepareForm();
- $formResult = $form->tryAuthorizedSubmit();
-
+ $form->prepareForm();
+ $formResult = $form->tryAuthorizedSubmit();
// show the files + form, if there are any, or just say there are none
- $refreshHtml = Html::element( 'a', array( 'href' => $this->getTitle()->getLocalURL() ), wfMsg( 'uploadstash-refresh' ) );
+ $refreshHtml = Html::element( 'a',
+ array( 'href' => $this->getTitle()->getLocalURL() ),
+ wfMsg( 'uploadstash-refresh' ) );
$files = $this->stash->listFiles();
if ( count( $files ) ) {
sort( $files );
$fileListItemsHtml = '';
foreach ( $files as $file ) {
+ // TODO: Use Linker::link or even construct the list in plain wikitext
$fileListItemsHtml .= Html::rawElement( 'li', array(),
- Html::element( 'a', array( 'href' =>
+ Html::element( 'a', array( 'href' =>
$this->getTitle( "file/$file" )->getLocalURL() ), $file )
);
}
$wgOut->addHtml( Html::rawElement( 'ul', array(), $fileListItemsHtml ) );
- $form->displayForm( $formResult );
+ $form->displayForm( $formResult );
$wgOut->addHtml( Html::rawElement( 'p', array(), $refreshHtml ) );
} else {
- $wgOut->addHtml( Html::rawElement( 'p', array(),
+ $wgOut->addHtml( Html::rawElement( 'p', array(),
Html::element( 'span', array(), wfMsg( 'uploadstash-nofiles' ) )
- . ' '
+ . ' '
. $refreshHtml
) );
}
-
+
return true;
}
}
diff --git a/includes/specials/SpecialUserlogin.php b/includes/specials/SpecialUserlogin.php
index ccace79d..01dc9a1c 100644
--- a/includes/specials/SpecialUserlogin.php
+++ b/includes/specials/SpecialUserlogin.php
@@ -22,24 +22,11 @@
*/
/**
- * Constructor
- */
-function wfSpecialUserlogin( $par = '' ) {
- global $wgRequest;
- if( session_id() == '' ) {
- wfSetupSession();
- }
-
- $form = new LoginForm( $wgRequest, $par );
- $form->execute();
-}
-
-/**
* Implements Special:UserLogin
*
* @ingroup SpecialPage
*/
-class LoginForm {
+class LoginForm extends SpecialPage {
const SUCCESS = 0;
const NO_NAME = 1;
@@ -56,23 +43,42 @@ class LoginForm {
const NEED_TOKEN = 12;
const WRONG_TOKEN = 13;
- var $mName, $mPassword, $mRetype, $mReturnTo, $mCookieCheck, $mPosted;
- var $mAction, $mCreateaccount, $mCreateaccountMail, $mMailmypassword;
+ var $mUsername, $mPassword, $mRetype, $mReturnTo, $mCookieCheck, $mPosted;
+ var $mAction, $mCreateaccount, $mCreateaccountMail;
var $mLoginattempt, $mRemember, $mEmail, $mDomain, $mLanguage;
var $mSkipCookieCheck, $mReturnToQuery, $mToken, $mStickHTTPS;
+ var $mType, $mReason, $mRealName;
+ var $mAbortLoginErrorMsg = 'login-abort-generic';
+ /**
+ * @var ExternalUser
+ */
private $mExtUser = null;
/**
- * Constructor
- * @param $request WebRequest: a WebRequest object passed by reference
- * @param $par String: subpage parameter
+ * @param WebRequest $request
+ */
+ public function __construct( $request = null ) {
+ parent::__construct( 'Userlogin' );
+
+ if ( $request === null ) {
+ global $wgRequest;
+ $this->load( $wgRequest );
+ } else {
+ $this->load( $request );
+ }
+ }
+
+ /**
+ * Loader
+ *
+ * @param $request WebRequest object
*/
- function __construct( &$request, $par = '' ) {
+ function load( $request ) {
global $wgAuth, $wgHiddenPrefs, $wgEnableEmail, $wgRedirectOnLogin;
- $this->mType = ( $par == 'signup' ) ? $par : $request->getText( 'type' ); # Check for [[Special:Userlogin/signup]]
- $this->mName = $request->getText( 'wpName' );
+ $this->mType = $request->getText( 'type' );
+ $this->mUsername = $request->getText( 'wpName' );
$this->mPassword = $request->getText( 'wpPassword' );
$this->mRetype = $request->getText( 'wpRetype' );
$this->mDomain = $request->getText( 'wpDomain' );
@@ -83,9 +89,7 @@ class LoginForm {
$this->mPosted = $request->wasPosted();
$this->mCreateaccount = $request->getCheck( 'wpCreateaccount' );
$this->mCreateaccountMail = $request->getCheck( 'wpCreateaccountMail' )
- && $wgEnableEmail;
- $this->mMailmypassword = $request->getCheck( 'wpMailmypassword' )
- && $wgEnableEmail;
+ && $wgEnableEmail;
$this->mLoginattempt = $request->getCheck( 'wpLoginattempt' );
$this->mAction = $request->getVal( 'action' );
$this->mRemember = $request->getCheck( 'wpRemember' );
@@ -105,9 +109,9 @@ class LoginForm {
$this->mEmail = '';
}
if( !in_array( 'realname', $wgHiddenPrefs ) ) {
- $this->mRealName = $request->getText( 'wpRealName' );
+ $this->mRealName = $request->getText( 'wpRealName' );
} else {
- $this->mRealName = '';
+ $this->mRealName = '';
}
if( !$wgAuth->validDomain( $this->mDomain ) ) {
@@ -123,7 +127,15 @@ class LoginForm {
}
}
- function execute() {
+ public function execute( $par ) {
+ if ( session_id() == '' ) {
+ wfSetupSession();
+ }
+
+ if ( $par == 'signup' ) { # Check for [[Special:Userlogin/signup]]
+ $this->mType = 'signup';
+ }
+
if ( !is_null( $this->mCookieCheck ) ) {
$this->onCookieRedirectCheck( $this->mCookieCheck );
return;
@@ -132,8 +144,6 @@ class LoginForm {
return $this->addNewAccount();
} elseif ( $this->mCreateaccountMail ) {
return $this->addNewAccountMailPassword();
- } elseif ( $this->mMailmypassword ) {
- return $this->mailPassword();
} elseif ( ( 'submitlogin' == $this->mAction ) || $this->mLoginattempt ) {
return $this->processLogin();
}
@@ -167,8 +177,6 @@ class LoginForm {
$u->addNewUserLogEntry( true, $this->mReason );
$wgOut->setPageTitle( wfMsg( 'accmailtitle' ) );
- $wgOut->setRobotPolicy( 'noindex,nofollow' );
- $wgOut->setArticleRelated( false );
if( !$result->isGood() ) {
$this->mainLoginForm( wfMsg( 'mailerror', $result->getWikiText() ) );
@@ -198,7 +206,7 @@ class LoginForm {
}
# Send out an email authentication message if needed
- if( $wgEmailAuthentication && User::isValidEmailAddr( $u->getEmail() ) ) {
+ if( $wgEmailAuthentication && Sanitizer::validateEmail( $u->getEmail() ) ) {
$status = $u->sendConfirmationMail();
if( $status->isGood() ) {
$wgOut->addWikiMsg( 'confirmemail_oncreate' );
@@ -216,6 +224,10 @@ class LoginForm {
if( $wgUser->isAnon() ) {
$wgUser = $u;
$wgUser->setCookies();
+ // This should set it for OutputPage and the Skin
+ // which is needed or the personal links will be
+ // wrong.
+ RequestContext::getMain()->setUser( $u );
wfRunHooks( 'AddNewAccount', array( $wgUser, false ) );
$wgUser->addNewUserLogEntry();
if( $this->hasSessionCookie() ) {
@@ -227,9 +239,7 @@ class LoginForm {
# Confirm that the account was created
$self = SpecialPage::getTitleFor( 'Userlogin' );
$wgOut->setPageTitle( wfMsgHtml( 'accountcreated' ) );
- $wgOut->setArticleRelated( false );
- $wgOut->setRobotPolicy( 'noindex,nofollow' );
- $wgOut->addHTML( wfMsgWikiHtml( 'accountcreatedtext', $u->getName() ) );
+ $wgOut->addWikiMsg( 'accountcreatedtext', $u->getName() );
$wgOut->returnToMain( false, $self );
wfRunHooks( 'AddNewAccount', array( $u, false ) );
$u->addNewUserLogEntry( false, $this->mReason );
@@ -258,7 +268,8 @@ class LoginForm {
// create a local account and login as any domain user). We only need
// to check this for domains that aren't local.
if( 'local' != $this->mDomain && $this->mDomain != '' ) {
- if( !$wgAuth->canCreateAccounts() && ( !$wgAuth->userExists( $this->mName ) || !$wgAuth->authenticate( $this->mName, $this->mPassword ) ) ) {
+ if( !$wgAuth->canCreateAccounts() && ( !$wgAuth->userExists( $this->mUsername )
+ || !$wgAuth->authenticate( $this->mUsername, $this->mPassword ) ) ) {
$this->mainLoginForm( wfMsg( 'wrongpassword' ) );
return false;
}
@@ -272,7 +283,7 @@ class LoginForm {
# Request forgery checks.
if ( !self::getCreateaccountToken() ) {
self::setCreateaccountToken();
- $this->mainLoginForm( wfMsgExt( 'nocookiesnew', array( 'parseinline' ) ) );
+ $this->mainLoginForm( wfMsgExt( 'nocookiesfornew', array( 'parseinline' ) ) );
return false;
}
@@ -293,7 +304,7 @@ class LoginForm {
$wgOut->permissionRequired( 'createaccount' );
return false;
} elseif ( $wgUser->isBlockedFromCreateAccount() ) {
- $this->userBlockedMessage();
+ $this->userBlockedMessage( $wgUser->isBlockedFromCreateAccount() );
return false;
}
@@ -304,7 +315,7 @@ class LoginForm {
}
# Now create a dummy user ($u) and check if it is valid
- $name = trim( $this->mName );
+ $name = trim( $this->mUsername );
$u = User::newFromName( $name, 'creatable' );
if ( !is_object( $u ) ) {
$this->mainLoginForm( wfMsg( 'noname' ) );
@@ -325,7 +336,14 @@ class LoginForm {
$valid = $u->getPasswordValidity( $this->mPassword );
if ( $valid !== true ) {
if ( !$this->mCreateaccountMail ) {
- $this->mainLoginForm( wfMsgExt( $valid, array( 'parsemag' ), $wgMinimalPasswordLength ) );
+ if ( is_array( $valid ) ) {
+ $message = array_shift( $valid );
+ $params = $valid;
+ } else {
+ $message = $valid;
+ $params = array( $wgMinimalPasswordLength );
+ }
+ $this->mainLoginForm( wfMsgExt( $message, array( 'parsemag' ), $params ) );
return false;
} else {
# do not force a password for account creation by email
@@ -341,7 +359,7 @@ class LoginForm {
return false;
}
- if( !empty( $this->mEmail ) && !User::isValidEmailAddr( $this->mEmail ) ) {
+ if( !empty( $this->mEmail ) && !Sanitizer::validateEmail( $this->mEmail ) ) {
$this->mainLoginForm( wfMsg( 'invalidemailaddress' ) );
return false;
}
@@ -431,9 +449,9 @@ class LoginForm {
* creation.
*/
public function authenticateUserData() {
- global $wgUser, $wgAuth, $wgMemc;
+ global $wgUser, $wgAuth;
- if ( $this->mName == '' ) {
+ if ( $this->mUsername == '' ) {
return self::NO_NAME;
}
@@ -452,22 +470,9 @@ class LoginForm {
return self::NEED_TOKEN;
}
- global $wgPasswordAttemptThrottle;
-
- $throttleCount = 0;
- if ( is_array( $wgPasswordAttemptThrottle ) ) {
- $throttleKey = wfMemcKey( 'password-throttle', wfGetIP(), md5( $this->mName ) );
- $count = $wgPasswordAttemptThrottle['count'];
- $period = $wgPasswordAttemptThrottle['seconds'];
-
- $throttleCount = $wgMemc->get( $throttleKey );
- if ( !$throttleCount ) {
- $wgMemc->add( $throttleKey, 1, $period ); // start counter
- } elseif ( $throttleCount < $count ) {
- $wgMemc->incr( $throttleKey );
- } elseif ( $throttleCount >= $count ) {
- return self::THROTTLED;
- }
+ $throttleCount = self::incLoginThrottle( $this->mUsername );
+ if ( $throttleCount === true ) {
+ return self::THROTTLED;
}
// Validate the login token
@@ -481,16 +486,16 @@ class LoginForm {
// creates the user in the database. Until we load $wgUser, checking
// for user existence using User::newFromName($name)->getId() below
// will effectively be using stale data.
- if ( $wgUser->getName() === $this->mName ) {
- wfDebug( __METHOD__ . ": already logged in as {$this->mName}\n" );
+ if ( $wgUser->getName() === $this->mUsername ) {
+ wfDebug( __METHOD__ . ": already logged in as {$this->mUsername}\n" );
return self::SUCCESS;
}
- $this->mExtUser = ExternalUser::newFromName( $this->mName );
+ $this->mExtUser = ExternalUser::newFromName( $this->mUsername );
# TODO: Allow some magic here for invalid external names, e.g., let the
# user choose a different wiki name.
- $u = User::newFromName( $this->mName );
+ $u = User::newFromName( $this->mUsername );
if( !( $u instanceof User ) || !User::isUsableName( $u->getName() ) ) {
return self::ILLEGAL;
}
@@ -518,7 +523,7 @@ class LoginForm {
// Give general extensions, such as a captcha, a chance to abort logins
$abort = self::ABORTED;
- if( !wfRunHooks( 'AbortLogin', array( $u, $this->mPassword, &$abort ) ) ) {
+ if( !wfRunHooks( 'AbortLogin', array( $u, $this->mPassword, &$abort, &$this->mAbortLoginErrorMsg ) ) ) {
return $abort;
}
@@ -559,10 +564,14 @@ class LoginForm {
} else {
$wgAuth->updateUser( $u );
$wgUser = $u;
+ // This should set it for OutputPage and the Skin
+ // which is needed or the personal links will be
+ // wrong.
+ RequestContext::getMain()->setUser( $u );
// Please reset throttle for successful logins, thanks!
- if( $throttleCount ) {
- $wgMemc->delete( $throttleKey );
+ if ( $throttleCount ) {
+ self::clearLoginThrottle( $this->mUsername );
}
if ( $isAutoCreated ) {
@@ -576,9 +585,52 @@ class LoginForm {
return $retval;
}
+ /*
+ * Increment the login attempt throttle hit count for the (username,current IP)
+ * tuple unless the throttle was already reached.
+ * @param $username string The user name
+ * @return Bool|Integer The integer hit count or True if it is already at the limit
+ */
+ public static function incLoginThrottle( $username ) {
+ global $wgPasswordAttemptThrottle, $wgMemc;
+
+ $throttleCount = 0;
+ if ( is_array( $wgPasswordAttemptThrottle ) ) {
+ $throttleKey = wfMemcKey( 'password-throttle', wfGetIP(), md5( $username ) );
+ $count = $wgPasswordAttemptThrottle['count'];
+ $period = $wgPasswordAttemptThrottle['seconds'];
+
+ $throttleCount = $wgMemc->get( $throttleKey );
+ if ( !$throttleCount ) {
+ $wgMemc->add( $throttleKey, 1, $period ); // start counter
+ } elseif ( $throttleCount < $count ) {
+ $wgMemc->incr( $throttleKey );
+ } elseif ( $throttleCount >= $count ) {
+ return true;
+ }
+ }
+
+ return $throttleCount;
+ }
+
+ /*
+ * Clear the login attempt throttle hit count for the (username,current IP) tuple.
+ * @param $username string The user name
+ * @return void
+ */
+ public static function clearLoginThrottle( $username ) {
+ global $wgMemc;
+
+ $throttleKey = wfMemcKey( 'password-throttle', wfGetIP(), md5( $username ) );
+ $wgMemc->delete( $throttleKey );
+ }
+
/**
* Attempt to automatically create a user on login. Only succeeds if there
* is an external authentication method which allows it.
+ *
+ * @param $user User
+ *
* @return integer Status code
*/
function attemptAutoCreate( $user ) {
@@ -618,6 +670,14 @@ class LoginForm {
}
}
+ $abortError = '';
+ if( !wfRunHooks( 'AbortAutoAccount', array( $user, &$abortError ) ) ) {
+ // Hook point to add extra creation throttles and blocks
+ wfDebug( "LoginForm::attemptAutoCreate: a hook blocked creation: $abortError\n" );
+ $this->mAbortLoginErrorMsg = $abortError;
+ return self::ABORTED;
+ }
+
wfDebug( __METHOD__ . ": creating account\n" );
$this->initUser( $user, true );
return self::SUCCESS;
@@ -639,7 +699,7 @@ class LoginForm {
self::clearLoginToken();
// Reset the throttle
- $key = wfMemcKey( 'password-throttle', wfGetIP(), md5( $this->mName ) );
+ $key = wfMemcKey( 'password-throttle', wfGetIP(), md5( $this->mUsername ) );
global $wgMemc;
$wgMemc->delete( $key );
@@ -657,7 +717,7 @@ class LoginForm {
break;
case self::NEED_TOKEN:
- $this->mainLoginForm( wfMsgExt( 'nocookieslogin', array( 'parseinline' ) ) );
+ $this->mainLoginForm( wfMsgExt( 'nocookiesforlogin', array( 'parseinline' ) ) );
break;
case self::WRONG_TOKEN:
$this->mainLoginForm( wfMsg( 'sessionfailure' ) );
@@ -671,9 +731,11 @@ class LoginForm {
break;
case self::NOT_EXISTS:
if( $wgUser->isAllowed( 'createaccount' ) ) {
- $this->mainLoginForm( wfMsgWikiHtml( 'nosuchuser', htmlspecialchars( $this->mName ) ) );
+ $this->mainLoginForm( wfMsgExt( 'nosuchuser', 'parseinline',
+ wfEscapeWikiText( $this->mUsername ) ) );
} else {
- $this->mainLoginForm( wfMsg( 'nosuchusershort', htmlspecialchars( $this->mName ) ) );
+ $this->mainLoginForm( wfMsg( 'nosuchusershort',
+ wfEscapeWikiText( $this->mUsername ) ) );
}
break;
case self::WRONG_PASS:
@@ -686,14 +748,17 @@ class LoginForm {
$this->resetLoginForm( wfMsg( 'resetpass_announce' ) );
break;
case self::CREATE_BLOCKED:
- $this->userBlockedMessage();
+ $this->userBlockedMessage( $wgUser->mBlock );
break;
case self::THROTTLED:
$this->mainLoginForm( wfMsg( 'login-throttled' ) );
break;
case self::USER_BLOCKED:
$this->mainLoginForm( wfMsgExt( 'login-userblocked',
- array( 'parsemag', 'escape' ), $this->mName ) );
+ array( 'parsemag', 'escape' ), $this->mUsername ) );
+ break;
+ case self::ABORTED:
+ $this->mainLoginForm( wfMsg( $this->mAbortLoginErrorMsg ) );
break;
default:
throw new MWException( 'Unhandled case value' );
@@ -703,100 +768,11 @@ class LoginForm {
function resetLoginForm( $error ) {
global $wgOut;
$wgOut->addHTML( Xml::element('p', array( 'class' => 'error' ), $error ) );
- $reset = new SpecialResetpass();
+ $reset = new SpecialChangePassword();
$reset->execute( null );
}
/**
- * @private
- */
- function mailPassword() {
- global $wgUser, $wgOut, $wgAuth;
-
- if ( wfReadOnly() ) {
- $wgOut->readOnlyPage();
- return false;
- }
-
- if( !$wgAuth->allowPasswordChange() ) {
- $this->mainLoginForm( wfMsg( 'resetpass_forbidden' ) );
- return;
- }
-
- # Check against blocked IPs so blocked users can't flood admins
- # with password resets
- if( $wgUser->isBlocked() ) {
- $this->mainLoginForm( wfMsg( 'blocked-mailpassword' ) );
- return;
- }
-
- # Check for hooks
- $error = null;
- if ( !wfRunHooks( 'UserLoginMailPassword', array( $this->mName, &$error ) ) ) {
- $this->mainLoginForm( $error );
- return;
- }
-
- # If the user doesn't have a login token yet, set one.
- if ( !self::getLoginToken() ) {
- self::setLoginToken();
- $this->mainLoginForm( wfMsg( 'sessionfailure' ) );
- return;
- }
-
- # If the user didn't pass a login token, tell them we need one
- if ( !$this->mToken ) {
- $this->mainLoginForm( wfMsg( 'sessionfailure' ) );
- return;
- }
-
- # Check against the rate limiter
- if( $wgUser->pingLimiter( 'mailpassword' ) ) {
- $wgOut->rateLimited();
- return;
- }
-
- if ( $this->mName == '' ) {
- $this->mainLoginForm( wfMsg( 'noname' ) );
- return;
- }
- $u = User::newFromName( $this->mName );
- if( !$u instanceof User ) {
- $this->mainLoginForm( wfMsg( 'noname' ) );
- return;
- }
- if ( 0 == $u->getID() ) {
- $this->mainLoginForm( wfMsgWikiHtml( 'nosuchuser', htmlspecialchars( $u->getName() ) ) );
- return;
- }
-
- # Validate the login token
- if ( $this->mToken !== self::getLoginToken() ) {
- $this->mainLoginForm( wfMsg( 'sessionfailure' ) );
- return;
- }
-
- # Check against password throttle
- if ( $u->isPasswordReminderThrottled() ) {
- global $wgPasswordReminderResendTime;
- # Round the time in hours to 3 d.p., in case someone is specifying
- # minutes or seconds.
- $this->mainLoginForm( wfMsgExt( 'throttled-mailpassword', array( 'parsemag' ),
- round( $wgPasswordReminderResendTime, 3 ) ) );
- return;
- }
-
- $result = $this->mailPasswordInternal( $u, true, 'passwordremindertitle', 'passwordremindertext' );
- if( $result->isGood() ) {
- $this->mainLoginForm( wfMsg( 'passwordsent', $u->getName() ), 'success' );
- self::clearLoginToken();
- } else {
- $this->mainLoginForm( $result->getWikiText( 'mailerror' ) );
- }
- }
-
-
- /**
* @param $u User object
* @param $throttle Boolean
* @param $emailTitle String: message name of email title
@@ -872,9 +848,14 @@ class LoginForm {
global $wgUser;
# Run any hooks; display injected HTML
$injected_html = '';
+ $welcome_creation_msg = 'welcomecreation';
+
wfRunHooks( 'UserLoginComplete', array( &$wgUser, &$injected_html ) );
- $this->displaySuccessfulLogin( 'welcomecreation', $injected_html );
+ //let any extensions change what message is shown
+ wfRunHooks( 'BeforeWelcomeCreation', array( &$welcome_creation_msg, &$injected_html ) );
+
+ $this->displaySuccessfulLogin( $welcome_creation_msg, $injected_html );
}
/**
@@ -884,9 +865,10 @@ class LoginForm {
global $wgOut, $wgUser;
$wgOut->setPageTitle( wfMsg( 'loginsuccesstitle' ) );
- $wgOut->setRobotPolicy( 'noindex,nofollow' );
- $wgOut->setArticleRelated( false );
- $wgOut->addWikiMsg( $msgname, $wgUser->getName() );
+ if( $msgname ){
+ $wgOut->addWikiMsg( $msgname, wfEscapeWikiText( $wgUser->getName() ) );
+ }
+
$wgOut->addHTML( $injected_html );
if ( !empty( $this->mReturnTo ) ) {
@@ -896,9 +878,15 @@ class LoginForm {
}
}
- /** */
- function userBlockedMessage() {
- global $wgOut, $wgUser;
+ /**
+ * Output a message that informs the user that they cannot create an account because
+ * there is a block on them or their IP which prevents account creation. Note that
+ * User::isBlockedFromCreateAccount(), which gets this block, ignores the 'hardblock'
+ * setting on blocks (bug 13611).
+ * @param $block Block the block causing this error
+ */
+ function userBlockedMessage( Block $block ) {
+ global $wgOut;
# Let's be nice about this, it's likely that this feature will be used
# for blocking large numbers of innocent people, e.g. range blocks on
@@ -909,17 +897,19 @@ class LoginForm {
# out.
$wgOut->setPageTitle( wfMsg( 'cantcreateaccounttitle' ) );
- $wgOut->setRobotPolicy( 'noindex,nofollow' );
- $wgOut->setArticleRelated( false );
-
- $ip = wfGetIP();
- $blocker = User::whoIs( $wgUser->mBlock->mBy );
- $block_reason = $wgUser->mBlock->mReason;
+ $block_reason = $block->mReason;
if ( strval( $block_reason ) === '' ) {
$block_reason = wfMsg( 'blockednoreason' );
}
- $wgOut->addWikiMsg( 'cantcreateaccount-text', $ip, $block_reason, $blocker );
+
+ $wgOut->addWikiMsg(
+ 'cantcreateaccount-text',
+ $block->getTarget(),
+ $block_reason,
+ $block->getBlocker()->getName()
+ );
+
$wgOut->returnToMain( false );
}
@@ -927,10 +917,11 @@ class LoginForm {
* @private
*/
function mainLoginForm( $msg, $msgtype = 'error' ) {
- global $wgUser, $wgOut, $wgHiddenPrefs, $wgEnableEmail;
+ global $wgUser, $wgOut, $wgHiddenPrefs;
+ global $wgEnableEmail, $wgEnableUserEmail;
global $wgRequest, $wgLoginLanguageSelector;
global $wgAuth, $wgEmailConfirmToEdit, $wgCookieExpiration;
- global $wgSecureLogin;
+ global $wgSecureLogin, $wgPasswordResetRoutes;
$titleObj = SpecialPage::getTitleFor( 'Userlogin' );
@@ -942,7 +933,7 @@ class LoginForm {
$wgOut->readOnlyPage();
return;
} elseif ( $wgUser->isBlockedFromCreateAccount() ) {
- $this->userBlockedMessage();
+ $this->userBlockedMessage( $wgUser->isBlockedFromCreateAccount() );
return;
} elseif ( count( $permErrors = $titleObj->getUserPermissionsErrors( 'createaccount', $wgUser, true ) )>0 ) {
$wgOut->showPermissionsErrorPage( $permErrors, 'createaccount' );
@@ -950,11 +941,11 @@ class LoginForm {
}
}
- if ( $this->mName == '' ) {
+ if ( $this->mUsername == '' ) {
if ( $wgUser->isLoggedIn() ) {
- $this->mName = $wgUser->getName();
+ $this->mUsername = $wgUser->getName();
} else {
- $this->mName = $wgRequest->getCookie( 'UserName' );
+ $this->mUsername = $wgRequest->getCookie( 'UserName' );
}
}
@@ -996,8 +987,12 @@ class LoginForm {
$template->set( 'link', '' );
}
+ $resetLink = $this->mType == 'signup'
+ ? null
+ : is_array( $wgPasswordResetRoutes ) && in_array( true, array_values( $wgPasswordResetRoutes ) );
+
$template->set( 'header', '' );
- $template->set( 'name', $this->mName );
+ $template->set( 'name', $this->mUsername );
$template->set( 'password', $this->mPassword );
$template->set( 'retype', $this->mRetype );
$template->set( 'email', $this->mEmail );
@@ -1012,7 +1007,9 @@ class LoginForm {
$template->set( 'userealname', !in_array( 'realname', $wgHiddenPrefs ) );
$template->set( 'useemail', $wgEnableEmail );
$template->set( 'emailrequired', $wgEmailConfirmToEdit );
+ $template->set( 'emailothers', $wgEnableUserEmail );
$template->set( 'canreset', $wgAuth->allowPasswordChange() );
+ $template->set( 'resetlink', $resetLink );
$template->set( 'canremember', ( $wgCookieExpiration > 0 ) );
$template->set( 'usereason', $wgUser->isLoggedIn() );
$template->set( 'remember', $wgUser->getOption( 'rememberpassword' ) || $this->mRemember );
@@ -1037,6 +1034,22 @@ class LoginForm {
if( $this->mLanguage )
$template->set( 'uselang', $this->mLanguage );
}
+
+ // Use loginend-https for HTTPS requests if it's not blank, loginend otherwise
+ // Ditto for signupend
+ $usingHTTPS = WebRequest::detectProtocol() == 'https';
+ $loginendHTTPS = wfMessage( 'loginend-https' );
+ $signupendHTTPS = wfMessage( 'signupend-https' );
+ if ( $usingHTTPS && !$loginendHTTPS->isBlank() ) {
+ $template->set( 'loginend', $loginendHTTPS->parse() );
+ } else {
+ $template->set( 'loginend', wfMessage( 'loginend' )->parse() );
+ }
+ if ( $usingHTTPS && !$signupendHTTPS->isBlank() ) {
+ $template->set( 'signupend', $signupendHTTPS->parse() );
+ } else {
+ $template->set( 'signupend', wfMessage( 'signupend' )->parse() );
+ }
// Give authentication and captcha plugins a chance to modify the form
$wgAuth->modifyUITemplate( $template, $this->mType );
@@ -1053,22 +1066,24 @@ class LoginForm {
$wgOut->setPageTitle( wfMsg( 'userloginnocreate' ) );
}
- $wgOut->setRobotPolicy( 'noindex,nofollow' );
- $wgOut->setArticleRelated( false );
$wgOut->disallowUserJs(); // just in case...
$wgOut->addTemplate( $template );
}
/**
* @private
+ *
+ * @param $user User
+ *
+ * @return Boolean
*/
function showCreateOrLoginLink( &$user ) {
if( $this->mType == 'signup' ) {
- return( true );
+ return true;
} elseif( $user->isAllowed( 'createaccount' ) ) {
- return( true );
+ return true;
} else {
- return( false );
+ return false;
}
}
@@ -1186,15 +1201,15 @@ class LoginForm {
function makeLanguageSelector() {
global $wgLang;
- $msg = wfMsgForContent( 'loginlanguagelinks' );
- if( $msg != '' && !wfEmptyMsg( 'loginlanguagelinks', $msg ) ) {
- $langs = explode( "\n", $msg );
+ $msg = wfMessage( 'loginlanguagelinks' )->inContentLanguage();
+ if( !$msg->isBlank() ) {
+ $langs = explode( "\n", $msg->text() );
$links = array();
foreach( $langs as $lang ) {
$lang = trim( $lang, '* ' );
$parts = explode( '|', $lang );
if ( count( $parts ) >= 2 ) {
- $links[] = $this->makeLanguageSelectorLink( $parts[0], $parts[1] );
+ $links[] = $this->makeLanguageSelectorLink( $parts[0], trim( $parts[1] ) );
}
}
return count( $links ) > 0 ? wfMsgHtml( 'loginlanguagelabel', $wgLang->pipeList( $links ) ) : '';
@@ -1211,7 +1226,6 @@ class LoginForm {
* @param $lang Language code
*/
function makeLanguageSelectorLink( $text, $lang ) {
- global $wgUser;
$self = SpecialPage::getTitleFor( 'Userlogin' );
$attr = array( 'uselang' => $lang );
if( $this->mType == 'signup' ) {
@@ -1220,8 +1234,7 @@ class LoginForm {
if( $this->mReturnTo ) {
$attr['returnto'] = $this->mReturnTo;
}
- $skin = $wgUser->getSkin();
- return $skin->linkKnown(
+ return Linker::linkKnown(
$self,
htmlspecialchars( $text ),
array(),
diff --git a/includes/specials/SpecialUserrights.php b/includes/specials/SpecialUserrights.php
index 6ea8668b..4de048c0 100644
--- a/includes/specials/SpecialUserrights.php
+++ b/includes/specials/SpecialUserrights.php
@@ -41,7 +41,7 @@ class UserrightsPage extends SpecialPage {
return true;
}
- public function userCanExecute( $user ) {
+ public function userCanExecute( User $user ) {
return $this->userCanChangeRights( $user, false );
}
@@ -98,7 +98,7 @@ class UserrightsPage extends SpecialPage {
}
if( !$this->userCanChangeRights( $wgUser, true ) ) {
- // fixme... there may be intermediate groups we can mention.
+ // @todo FIXME: There may be intermediate groups we can mention.
$wgOut->showPermissionsErrorPage( array( array(
$wgUser->isAnon()
? 'userrights-nologin'
@@ -112,7 +112,7 @@ class UserrightsPage extends SpecialPage {
}
$this->outputHeader();
-
+ $wgOut->addModuleStyles( 'mediawiki.special' );
$this->setHeaders();
// show the general form
@@ -222,7 +222,7 @@ class UserrightsPage extends SpecialPage {
$user->removeGroup( $group );
}
}
- if( $add ) {
+ if( $add ) {
$newGroups = array_merge( $newGroups, $add );
foreach( $add as $group ) {
$user->addGroup( $group );
@@ -317,7 +317,7 @@ class UserrightsPage extends SpecialPage {
return Status::newFatal( 'nouserspecified' );
}
- if( $name{0} == '#' ) {
+ if( $name[0] == '#' ) {
// Numeric ID can be specified...
// We'll do a lookup for the name internally.
$id = intval( substr( $name, 1 ) );
@@ -414,7 +414,7 @@ class UserrightsPage extends SpecialPage {
* @param $groups Array: Array of groups the user is in
*/
protected function showEditUserGroupsForm( $user, $groups ) {
- global $wgOut, $wgUser, $wgLang;
+ global $wgOut, $wgUser, $wgLang, $wgRequest;
$list = array();
foreach( $groups as $group ) {
@@ -429,12 +429,14 @@ class UserrightsPage extends SpecialPage {
}
$grouplist = '';
- if( count( $list ) > 0 ) {
- $grouplist = wfMsgHtml( 'userrights-groupsmember' );
+ $count = count( $list );
+ if( $count > 0 ) {
+ $grouplist = wfMessage( 'userrights-groupsmember', $count)->parse();
$grouplist = '<p>' . $grouplist . ' ' . $wgLang->listToText( $list ) . "</p>\n";
}
- if( count( $autolist ) > 0 ) {
- $autogrouplistintro = wfMsgHtml( 'userrights-groupsmember-auto' );
+ $count = count( $autolist );
+ if( $count > 0 ) {
+ $autogrouplistintro = wfMessage( 'userrights-groupsmember-auto', $count)->parse();
$grouplist .= '<p>' . $autogrouplistintro . ' ' . $wgLang->listToText( $autolist ) . "</p>\n";
}
$wgOut->addHTML(
@@ -453,14 +455,15 @@ class UserrightsPage extends SpecialPage {
Xml::label( wfMsg( 'userrights-reason' ), 'wpReason' ) .
"</td>
<td class='mw-input'>" .
- Xml::input( 'user-reason', 60, false, array( 'id' => 'wpReason', 'maxlength' => 255 ) ) .
+ Xml::input( 'user-reason', 60, $wgRequest->getVal( 'user-reason', false ),
+ array( 'id' => 'wpReason', 'maxlength' => 255 ) ) .
"</td>
</tr>
<tr>
<td></td>
<td class='mw-submit'>" .
Xml::submitButton( wfMsg( 'saveusergroups' ),
- array( 'name' => 'saveusergroups' ) + $wgUser->getSkin()->tooltipAndAccessKeyAttribs( 'userrights-set' ) ) .
+ array( 'name' => 'saveusergroups' ) + Linker::tooltipAndAccesskeyAttribs( 'userrights-set' ) ) .
"</td>
</tr>" .
Xml::closeElement( 'table' ) . "\n" .
@@ -534,7 +537,7 @@ class UserrightsPage extends SpecialPage {
foreach( $columns as $name => $column ) {
if( $column === array() )
continue;
- $ret .= Xml::element( 'th', null, wfMsg( 'userrights-' . $name . '-col' ) );
+ $ret .= Xml::element( 'th', null, wfMessage( 'userrights-' . $name . '-col', count( $column ) )->text() );
}
$ret.= "</tr>\n<tr>\n";
foreach( $columns as $column ) {
diff --git a/includes/specials/SpecialVersion.php b/includes/specials/SpecialVersion.php
index 101823db..0331f056 100644
--- a/includes/specials/SpecialVersion.php
+++ b/includes/specials/SpecialVersion.php
@@ -29,15 +29,15 @@
* @ingroup SpecialPage
*/
class SpecialVersion extends SpecialPage {
-
+
protected $firstExtOpened = false;
protected static $extensionTypes = false;
-
+
protected static $viewvcUrls = array(
'svn+ssh://svn.wikimedia.org/svnroot/mediawiki' => 'http://svn.wikimedia.org/viewvc/mediawiki',
'http://svn.wikimedia.org/svnroot/mediawiki' => 'http://svn.wikimedia.org/viewvc/mediawiki',
- # Doesn't work at the time of writing but maybe some day:
+ # Doesn't work at the time of writing but maybe some day:
'https://svn.wikimedia.org/viewvc/mediawiki' => 'http://svn.wikimedia.org/viewvc/mediawiki',
);
@@ -49,30 +49,33 @@ class SpecialVersion extends SpecialPage {
* main()
*/
public function execute( $par ) {
- global $wgOut, $wgSpecialVersionShowHooks, $wgContLang;
-
+ global $wgOut, $wgSpecialVersionShowHooks, $wgRequest;
+
$this->setHeaders();
$this->outputHeader();
$wgOut->allowClickjacking();
- $wgOut->addHTML( Xml::openElement( 'div',
- array( 'dir' => $wgContLang->getDir() ) ) );
- $text =
+ $text =
$this->getMediaWikiCredits() .
$this->softwareInformation() .
$this->getExtensionCredits();
if ( $wgSpecialVersionShowHooks ) {
$text .= $this->getWgHooks();
}
-
+
$wgOut->addWikiText( $text );
$wgOut->addHTML( $this->IPInfo() );
- $wgOut->addHTML( '</div>' );
+
+ if ( $wgRequest->getVal( 'easteregg' ) ) {
+ if ( $this->showEasterEgg() ) {
+ // TODO: put something interesting here
+ }
+ }
}
/**
* Returns wiki text showing the license information.
- *
+ *
* @return string
*/
private static function getMediaWikiCredits() {
@@ -113,7 +116,7 @@ class SpecialVersion extends SpecialPage {
/**
* Returns wiki text showing the third party software versions (apache, php, mysql).
- *
+ *
* @return string
*/
static function softwareInformation() {
@@ -136,14 +139,14 @@ class SpecialVersion extends SpecialPage {
<th>" . wfMsg( 'version-software-product' ) . "</th>
<th>" . wfMsg( 'version-software-version' ) . "</th>
</tr>\n";
-
+
foreach( $software as $name => $version ) {
$out .= "<tr>
<td>" . $name . "</td>
- <td>" . $version . "</td>
+ <td class=\"ltr\">" . $version . "</td>
</tr>\n";
}
-
+
return $out . Xml::closeElement( 'table' );
}
@@ -163,8 +166,8 @@ class SpecialVersion extends SpecialPage {
$version = "$wgVersion (r{$info['checkout-rev']})";
} else {
$version = $wgVersion . ' ' .
- wfMsg(
- 'version-svn-revision',
+ wfMsg(
+ 'version-svn-revision',
isset( $info['directory-rev'] ) ? $info['directory-rev'] : '',
$info['checkout-rev']
);
@@ -173,7 +176,7 @@ class SpecialVersion extends SpecialPage {
wfProfileOut( __METHOD__ );
return $version;
}
-
+
/**
* Return a wikitext-formatted string of the MediaWiki version with a link to
* the SVN revision if available.
@@ -183,16 +186,16 @@ class SpecialVersion extends SpecialPage {
public static function getVersionLinked() {
global $wgVersion, $IP;
wfProfileIn( __METHOD__ );
-
+
$info = self::getSvnInfo( $IP );
-
+
if ( isset( $info['checkout-rev'] ) ) {
$linkText = wfMsg(
'version-svn-revision',
isset( $info['directory-rev'] ) ? $info['directory-rev'] : '',
$info['checkout-rev']
);
-
+
if ( isset( $info['viewvc-url'] ) ) {
$version = "$wgVersion [{$info['viewvc-url']} $linkText]";
} else {
@@ -201,7 +204,7 @@ class SpecialVersion extends SpecialPage {
} else {
$version = $wgVersion;
}
-
+
wfProfileOut( __METHOD__ );
return $version;
}
@@ -209,13 +212,13 @@ class SpecialVersion extends SpecialPage {
/**
* Returns an array with the base extension types.
* Type is stored as array key, the message as array value.
- *
+ *
* TODO: ideally this would return all extension types, including
* those added by SpecialVersionExtensionTypes. This is not possible
* since this hook is passing along $this though.
- *
+ *
* @since 1.17
- *
+ *
* @return array
*/
public static function getExtensionTypes() {
@@ -225,44 +228,46 @@ class SpecialVersion extends SpecialPage {
'parserhook' => wfMsg( 'version-parserhooks' ),
'variable' => wfMsg( 'version-variables' ),
'media' => wfMsg( 'version-mediahandlers' ),
+ 'antispam' => wfMsg( 'version-antispam' ),
'skin' => wfMsg( 'version-skins' ),
+ 'api' => wfMsg( 'version-api' ),
'other' => wfMsg( 'version-other' ),
);
-
+
wfRunHooks( 'ExtensionTypes', array( &self::$extensionTypes ) );
}
-
+
return self::$extensionTypes;
}
-
+
/**
* Returns the internationalized name for an extension type.
- *
+ *
* @since 1.17
- *
+ *
* @param $type String
- *
+ *
* @return string
*/
public static function getExtensionTypeName( $type ) {
$types = self::getExtensionTypes();
return isset( $types[$type] ) ? $types[$type] : $types['other'];
}
-
+
/**
* Generate wikitext showing extensions name, URL, author and description.
*
* @return String: Wikitext
*/
function getExtensionCredits() {
- global $wgExtensionCredits, $wgExtensionFunctions, $wgParser, $wgSkinExtensionFunctions;
+ global $wgExtensionCredits, $wgExtensionFunctions, $wgParser;
- if ( !count( $wgExtensionCredits ) && !count( $wgExtensionFunctions ) && !count( $wgSkinExtensionFunctions ) ) {
+ if ( !count( $wgExtensionCredits ) && !count( $wgExtensionFunctions ) ) {
return '';
}
$extensionTypes = self::getExtensionTypes();
-
+
/**
* @deprecated as of 1.17, use hook ExtensionTypes instead.
*/
@@ -271,25 +276,25 @@ class SpecialVersion extends SpecialPage {
$out = Xml::element( 'h2', array( 'id' => 'mw-version-ext' ), wfMsg( 'version-extensions' ) ) .
Xml::openElement( 'table', array( 'class' => 'wikitable', 'id' => 'sv-ext' ) );
- // Make sure the 'other' type is set to an array.
+ // Make sure the 'other' type is set to an array.
if ( !array_key_exists( 'other', $wgExtensionCredits ) ) {
$wgExtensionCredits['other'] = array();
}
-
+
// Find all extensions that do not have a valid type and give them the type 'other'.
foreach ( $wgExtensionCredits as $type => $extensions ) {
if ( !array_key_exists( $type, $extensionTypes ) ) {
$wgExtensionCredits['other'] = array_merge( $wgExtensionCredits['other'], $extensions );
}
}
-
+
// Loop through the extension categories to display their extensions in the list.
foreach ( $extensionTypes as $type => $message ) {
if ( $type != 'other' ) {
$out .= $this->getExtensionCategory( $type, $message );
}
}
-
+
// We want the 'other' type to be last in the list.
$out .= $this->getExtensionCategory( 'other', $extensionTypes['other'] );
@@ -309,36 +314,32 @@ class SpecialVersion extends SpecialPage {
$out .= '<tr><td colspan="4">' . $this->listToText( $tags ). "</td></tr>\n";
}
- if( count( $fhooks = $wgParser->getFunctionHooks() ) ) {
+ $fhooks = $wgParser->getFunctionHooks();
+ if( count( $fhooks ) ) {
$out .= $this->openExtType( wfMsg( 'version-parser-function-hooks' ), 'parser-function-hooks' );
$out .= '<tr><td colspan="4">' . $this->listToText( $fhooks ) . "</td></tr>\n";
}
- if ( count( $wgSkinExtensionFunctions ) ) {
- $out .= $this->openExtType( wfMsg( 'version-skin-extension-functions' ), 'skin-extension-functions' );
- $out .= '<tr><td colspan="4">' . $this->listToText( $wgSkinExtensionFunctions ) . "</td></tr>\n";
- }
-
$out .= Xml::closeElement( 'table' );
-
+
return $out;
}
-
+
/**
* Creates and returns the HTML for a single extension category.
- *
+ *
* @since 1.17
- *
+ *
* @param $type String
* @param $message String
- *
+ *
* @return string
*/
protected function getExtensionCategory( $type, $message ) {
- global $wgExtensionCredits;
-
+ global $wgExtensionCredits;
+
$out = '';
-
+
if ( array_key_exists( $type, $wgExtensionCredits ) && count( $wgExtensionCredits[$type] ) > 0 ) {
$out .= $this->openExtType( $message, 'credits-' . $type );
@@ -350,7 +351,7 @@ class SpecialVersion extends SpecialPage {
}
return $out;
- }
+ }
/**
* Callback to sort extensions by type.
@@ -368,14 +369,14 @@ class SpecialVersion extends SpecialPage {
/**
* Creates and formats the creidts for a single extension and returns this.
- *
+ *
* @param $extension Array
- *
+ *
* @return string
*/
function getCreditsForExtension( array $extension ) {
$name = isset( $extension['name'] ) ? $extension['name'] : '[no name]';
-
+
if ( isset( $extension['path'] ) ) {
$svnInfo = self::getSvnInfo( dirname($extension['path']) );
$directoryRev = isset( $svnInfo['directory-rev'] ) ? $svnInfo['directory-rev'] : null;
@@ -393,10 +394,10 @@ class SpecialVersion extends SpecialPage {
} else {
$mainLink = $name;
}
-
+
if ( isset( $extension['version'] ) ) {
- $versionText = '<span class="mw-version-ext-version">' .
- wfMsg( 'version-version', $extension['version'] ) .
+ $versionText = '<span class="mw-version-ext-version">' .
+ wfMsg( 'version-version', $extension['version'] ) .
'</span>';
} else {
$versionText = '';
@@ -412,22 +413,19 @@ class SpecialVersion extends SpecialPage {
# Make description text.
$description = isset ( $extension['description'] ) ? $extension['description'] : '';
-
+
if( isset ( $extension['descriptionmsg'] ) ) {
# Look for a localized description.
$descriptionMsg = $extension['descriptionmsg'];
-
+
if( is_array( $descriptionMsg ) ) {
$descriptionMsgKey = $descriptionMsg[0]; // Get the message key
array_shift( $descriptionMsg ); // Shift out the message key to get the parameters only
array_map( "htmlspecialchars", $descriptionMsg ); // For sanity
- $msg = wfMsg( $descriptionMsgKey, $descriptionMsg );
+ $description = wfMsg( $descriptionMsgKey, $descriptionMsg );
} else {
- $msg = wfMsg( $descriptionMsg );
+ $description = wfMsg( $descriptionMsg );
}
- if ( !wfEmptyMsg( $descriptionMsg, $msg ) && $msg != '' ) {
- $description = $msg;
- }
}
if ( $svnText !== false ) {
@@ -438,12 +436,12 @@ class SpecialVersion extends SpecialPage {
$extNameVer = "<tr>
<td colspan=\"2\"><em>$mainLink $versionText</em></td>";
}
-
+
$author = isset ( $extension['author'] ) ? $extension['author'] : array();
$extDescAuthor = "<td>$description</td>
- <td>" . $this->listToText( (array)$author, false ) . "</td>
+ <td>" . $this->listAuthors( $author, false ) . "</td>
</tr>\n";
-
+
return $extNameVer . $extDescAuthor;
}
@@ -466,11 +464,12 @@ class SpecialVersion extends SpecialPage {
<th>" . wfMsg( 'version-hook-subscribedby' ) . "</th>
</tr>\n";
- foreach ( $myWgHooks as $hook => $hooks )
+ foreach ( $myWgHooks as $hook => $hooks ) {
$ret .= "<tr>
<td>$hook</td>
<td>" . $this->listToText( $hooks ) . "</td>
</tr>\n";
+ }
$ret .= Xml::closeElement( 'table' );
return $ret;
@@ -487,13 +486,13 @@ class SpecialVersion extends SpecialPage {
$out .= '<tr class="sv-space">' . Html::element( 'td', $opt ) . "</tr>\n";
}
$this->firstExtOpened = true;
-
+
if( $name ) {
$opt['id'] = "sv-$name";
}
$out .= "<tr>" . Xml::element( 'th', $opt, $text ) . "</tr>\n";
-
+
return $out;
}
@@ -509,11 +508,29 @@ class SpecialVersion extends SpecialPage {
}
/**
+ * Return a formatted unsorted list of authors
+ *
+ * @param $authors mixed: string or array of strings
+ * @return String: HTML fragment
+ */
+ function listAuthors( $authors ) {
+ $list = array();
+ foreach( (array)$authors as $item ) {
+ if( $item == '...' ) {
+ $list[] = wfMsg( 'version-poweredby-others' );
+ } else {
+ $list[] = $item;
+ }
+ }
+ return $this->listToText( $list, false );
+ }
+
+ /**
* Convert an array of items into a list for display.
*
* @param $list Array of elements to display
* @param $sort Boolean: whether to sort the items in $list
- *
+ *
* @return String
*/
function listToText( $list, $sort = true ) {
@@ -538,29 +555,31 @@ class SpecialVersion extends SpecialPage {
*
* @param $list Mixed: will convert an array to string if given and return
* the paramater unaltered otherwise
- *
+ *
* @return Mixed
*/
- static function arrayToString( $list ) {
- if( is_array( $list ) && count( $list ) == 1 )
+ public static function arrayToString( $list ) {
+ if( is_array( $list ) && count( $list ) == 1 ) {
$list = $list[0];
+ }
if( is_object( $list ) ) {
$class = get_class( $list );
return "($class)";
} elseif ( !is_array( $list ) ) {
return $list;
} else {
- if( is_object( $list[0] ) )
+ if( is_object( $list[0] ) ) {
$class = get_class( $list[0] );
- else
+ } else {
$class = $list[0];
+ }
return "($class, {$list[1]})";
}
}
/**
- * Get an associative array of information about a given path, from its .svn
- * subdirectory. Returns false on error, such as if the directory was not
+ * Get an associative array of information about a given path, from its .svn
+ * subdirectory. Returns false on error, such as if the directory was not
* checked out with subversion.
*
* Returned keys are:
@@ -608,7 +627,7 @@ class SpecialVersion extends SpecialPage {
}
}
}
-
+
return false;
}
@@ -616,26 +635,26 @@ class SpecialVersion extends SpecialPage {
if ( count( $lines ) < 11 ) {
return false;
}
-
+
$info = array(
'checkout-rev' => intval( trim( $lines[3] ) ),
'url' => trim( $lines[4] ),
'repo-url' => trim( $lines[5] ),
'directory-rev' => intval( trim( $lines[10] ) )
);
-
+
if ( isset( self::$viewvcUrls[$info['repo-url']] ) ) {
- $viewvc = str_replace(
- $info['repo-url'],
+ $viewvc = str_replace(
+ $info['repo-url'],
self::$viewvcUrls[$info['repo-url']],
$info['url']
);
-
+
$viewvc .= '/?pathrev=';
$viewvc .= urlencode( $info['checkout-rev'] );
$info['viewvc-url'] = $viewvc;
}
-
+
return $info;
}
@@ -643,12 +662,12 @@ class SpecialVersion extends SpecialPage {
* Retrieve the revision number of a Subversion working directory.
*
* @param $dir String: directory of the svn checkout
- *
+ *
* @return Integer: revision number as int
*/
public static function getSvnRevision( $dir ) {
$info = self::getSvnInfo( $dir );
-
+
if ( $info === false ) {
return false;
} elseif ( isset( $info['checkout-rev'] ) ) {
@@ -658,4 +677,108 @@ class SpecialVersion extends SpecialPage {
}
}
+ function showEasterEgg() {
+ $rx = $rp = $xe = '';
+ $alpha = array("", "kbQW", "\$\n()");
+ $beta = implode( "', '", $alpha);
+ $juliet = 'echo $delta + strrev($foxtrot) - $alfa + $wgVersion . base64_decode($bravo) * $charlie';
+ for ( $i = 1; $i <= 4; $i++ ) {
+ $rx .= '([^j]*)J';
+ $rp .= "+(\\$i)";
+ }
+
+ $rx = "/$rx/Sei";
+ $O = substr("$alpha')", 1);
+ for ( $i = 1; $i <= strlen( $rx ) / 3; $i++ ) {
+ $rx[$i-1] = strtolower( $rx[$i-1] );
+ }
+ $ry = ".*?(.((.)(.))).{1,3}(.)(.{1,$i})(\\4.\\3)(.).*";
+ $ry = "/$ry/Sei";
+ $O = substr("$beta')", 1);
+ preg_match_all('/(?<=\$)[[:alnum:]]*/',substr($juliet, 0, $i<<1), $charlie);
+ foreach( $charlie[0] as $bravo ) {
+ $$bravo =& $xe;
+ }
+ $xe = 'xe=<<<mo/./hfromowoxv=<<<m
+쵍潅旅𞗎왎캎𐺆ߨ趥䲀쫥𒯡𚦄𚬀Ꝍ螃䤎꤯溃𔱢櫅褡䞠⽬✡栠迤⾏𐵥쾃𜜧줏袏浣।궇䬃꼁꿤𘐧
+𞛁윥桯䦎䵎Ꞅ𚠣涁쭀讀撠蝠讄伣𞫡枮ⵇ𚥣𐡃𐭏沢𞜄𞴏𞻧⠤쳯蒣䮎𒵬컡豣ۅ𐯥⦇𐫁漅蛁꼤从楆
+⥀䡦𚭅沢⠬輁䲯좡梇䟇伄육较촅䥃要𞝄迯쟠꺃ⶥ栆궀撠満ꐣ𞦇좧𐠅𞫠𐠧𚮣讇輤亀➏欣첡쮧⽬
+氀쮧跧𐫥䪀⬬⾅𞼀ⵏ괬ত櫤䭀楦𚫃𐣂괥챣𐥇楀귧읠죯쒡ۅ𐾤䳄䤄𞽀괬躏譇䮄搥𚬁䯄津䶮⾅𐫅
+𐴂௧쮯궣輥ߡ亀𞪀氀诤𐯢⿅諃⫤𞦁䮣⦬죄椎貧𞛄ඇ쿇亏跤⦌术থۏ仆䛇枡䪄𐵇곁謠𞿯ⶏⶃ䞣
+궥螏蝁ꤣ⟬极涇𞴧伢𞼯ଅ𚣡즡⡌浣䯇쿃ⳇ궏ས⢃曦⦥蛧갠컡楧𘬧袏⦏⢠䳠챤⽧𚠧⬣⼀潧⭅椤
+𞟯軁종쵃䬆𞮀𞮅꤇𞣅溎楯곡⢡꾥첥쫧Ⱨ균檏辀䭮⡄𐞯쿁䱤𐠠柅迠웏𚟯⾅豠𐡀𐡅䱀轡⾯쥃⥁溆
+䢣䞮柄ꠌⶡ𞒯𐳣𞳅蛤椏𞯀✠귬ຄ𐷡𞜠䶃𞭀毥𞡯桥ꐥ❣쳀𞾧⡧𖥢꽧죄ത𖴧ޥ歠ແ위䯎撯쬁䮣浅
+쾇泮𐢁켄𞧧𞦏䦯꾯迡𞐯曎䢦쿣杦궯⡀䤦䷢𐭢쟁쯯⧤蟯䡏氇𒭯𔜧𞢣𞱏蝤𒬧궧ߢ𐭆䛃찃쭣沠𚬀𞿏
+䴃𐣣䣎𐺃ꥅ轃⣄蟧⦡𒛧蟃毣洇䞎Ҡ潄仆𐲃𞧥철䢤俎譯泠쮄␥栏쾯ⳏ짡𞾯⥡𚠬߂𚥯ކ澥䲀ⵀ𞻃
+ⵡ𚦣𒯣✬𐟯𞥥輄䱀굡榏❡첄⦄ꡥⶣ𞡤⺁𞞡ݣ𐢅𒷤⤡꿄蝡𞱁ⴄ贁𒛬氃𞞇𞶡ޅ짣߁𞱃𐫄ۥ𞰣𐱅欤
+梢蝡柧䥏仏撣𐳣𞠅좇𞐣蒣䰤྅𚪏࿂ಇ濤䞦쮅𚬁𚭧𚬬𒴯𐵣𚥌沮潁좤澅𐻯杣棦ꤤ洯𐳃𚭀콅궧쭠𔥢
+𞱠桎䝆겡쭄𞵁겯䥂ⶀ𐥂𚧬⽬䠇쳄❬Ⰼ𞵀䐦⿌웃𒿠첏𐛡浣涆𒯌⢤অ䭎𚜧갣𞾏䴮⡃꤯죠䰀쬯༄䫏
+𐱂ꢅ䬦賧𐯡유辇➥佃仮귣젏𒴯⭅ꢡ각컄⒤⻠讁涅䠃跥袏佄𞝄𐳇泄껧𚮡𞱏棇满གྷ𐻯輤괅𚠬❥겠
+𒐧䣂ꤏ襃𞼧𜰧伎襡웅𞳧걯䳣𚟡켁쭄洠컥❅⿏亂𚯧𚯯쯅𞮅⢁𐠦𒮠𚯣𞞥诤꣏辀𖥢椯겇毣濢𞝣𚢀➠
+䮮浥겁沣졣䜦泇歏𐾄搯曯柆ۇۇ䞀泆𐾧武𚭠況꽌𐧢ꝅ軀⬠쾣𞡀榧𞣏𚦤Ⱡ䠦Ⲥ𞰯𞻥쿇䬄貃柅涢
+갏⼁𐿧ݏౠ𐿣褀涡𘼧𞮏༅𞵡𐥆䮄𐮥➇ꝣݥ䡏䯎梢𚟇輇ꤠ䫣䵀ण漂𞬯⢡軀𚭅𐯆௦𚠤襁쫇⾡濧沤
+䜇伢ۇ汧첏䤎잤䛯Ⰱ俇𞵃ꢧ殂궏榮ޣ𞼧涂氏𞬇滦즤蜀⠥𐺏쐣⾏껬콇漯Ꝡ柦櫇읁梠仇장滦⟠꿯
+쮁搥櫢𐫣ꠏ𒮬椥𐛤誅栮朥迣⺄ඇ𞣣⿏䬂쾏⫠⒧✏궇襤⡁𞯇濃𚣠Ⱐ𚫤歯䛠𒛥𞫇쮠𞟤컃𞢯⬣濡䦣
+衏貣柂𞳁森챏ಇ고𚫠蟄䤏젯𒮡⫯楀䞄䳣쮅궤轧껯𞥤𐪃𞶡潇ބ𚥣𐵇浣𐬀蝤⽧쐣쾇➣𞝀𐡦䮠䤣𐠄
+Ꝡ𐾁蠤𞛡𞵀䬦覯搦⥯쥏梂걯𐾧ⵁ೦챁𚣌躄轡𐯣𞻥䢦𐝂財䲧𐦁䬎첁棏␣౦잧棆젥襁젃䤏⢏榀ⵁ
+螅赡𒿯ⶣ赧꾤𚬅濁𒛏涆𐴂ॡ䳦ߢ赁䯇䢃ꠌ泄柠泡찇𐛢𞰏䪂𐝢櫇𚰧漥𐣄𞜤𐥁⟤淣ഡ䳮த谀ཡ𞾧
+➁血꽧蟧辧게⻣𚣣쳏ഡ䠄杮𞣠죃汦諤య毠蝅𐦄謄殯𞱄䳀ⳏ𞶁쟇ආ𐻢잏𐿡䳃ۂ𞭥䝇䦇⥌켏쥯춏
+𖽢𐳃𒷡𚫥𚟇𐿧𚦧𐝢䥦𚯀棇潡⥄歡찁朆⻠䤆𖤧漢𜐧ꡅ⽄쾠𐥣衏𚥠𐥆䤣অ𞛇䤣𐡡𐢏䞦𖐧ߣ裏𚫁𐵤
+ཅۄ춁䲃欆귬𐺀诀滁𞫇𐯇䝃𞧡챃첥𞭤꺏쫅𞫡䱮𞼤અ𒭤견Ф𐫁𐾧佣𖱢澢쿏𞛧⽅侮榅𐾄य쥏蜏䣣
+𚥌𐫏쵥𚥡➤跡殃䰣䯤𞳥읤ⴏ굄𚬧⥇줡걬০켃𜼧𚧯첣䜂𞵇𚟀찃궀谀Ɽ伎䢮𒛄𚦀ꤥ⾣𐭁沅䬇䧠𐱇
+沀濡ठ𞰄쟠𐺅ꐣ𐴂躄佇⦇毄计賀䢎澡𒮌䲄𒠧캀䟣𐷧褀𞻅蠤൯棏蜃𞮤澄❧⾥撦⽬ⶥ𐪄ய𔼧ބ躄
+䬎챯𚫇⽯𐾠𞛠𚛧䬎Ꞅ굥𐢂𚠣⠥䝧朄𞧥࿏웥꽬གྷ浅⦁❬𐺆侢栦⧠𞛯궠ඦ𚭧趤谥此𐲂𐬃軠𚪅𐞦𞷤
+蛄俧袥补榏읠⤁⠀豇俢쮯꤇➏𐴁ⶤ涮찣𒮇읁榠跣𜤧⦅ໃಆ𞛯䵣谠𞰅ꢯ⡧淯柤궡✠䮎괯𒮣❅朎
+⥅웣䯮첀𚫣꒤𐣠쭏洀蛡楆𚮣ൡ䮮ү氠𐜏濆䜢䷯潣歃䷯𞣡웁쭄椥䟂➅𒯣𒯤ૡༀ䭧ܣ죅𐯠ए軯䧣
+Ⱔ䐢⬥檂䠮⫤䛠꜡䛆讠𚭄✠꿏欣蠡𐵆켏豣譄𞣇춣𒭯𐻢䠃䰠撦朅䮄榦溃貀𒯅䶇⾁𞬧澡𐻦䲮榀𞯧
+𐪄䢆侄𞾏朦꜇𐮢ཏ𐯣췧꺁𞱃枠櫧桠괬枇ꜯ곇𐰂𘜧𐦄컡濦汥줠𞲡輀𞫃𐠣쥇⣃𞴏䳂⟤漇쯣껃𐾀衃
+𚮄쯇𒼧𐝄浥洄楠৯춥蒧⾯𐫆༂ꤌ毮䤆⺄༠०袀䢂죃ⴣ𐿯梇溄毦𞼄螄櫤쳃栅満걌毠𞞏ⱌ𚮡꒧䢆
+ꥁ泎𞭅仧궀辯諯웅𞳇津趃অ꿏伏𐵤캁⠃𐦂𐶀ꝣ䛂贤济杧𐝁撠䱤殥歡躇楄꒧꽧𞽧䡣쵧𒯃𐱆ꜯ위
+ཀ谠諃𐬃軅␥𞰇贠撣߅꽤⠥ಡ𐝀궥윁𞳁Ⰴܯ즡歎𞷥ⵅഏ蝁𞟇구ꝧ܅䱦껡䛦߅蒯俧콣𚭅梧䛠ꡇ
+ݧ𚮏웥Т⬠䬦榀𐢂貤𞰅𚭠謣䱦⒡췧𐥀濇⧣⤀좯殧𞬣줤⣀楏楎굏ݤ滁ۇ𘐧𚯯䒯Ⰰ𞼤ҡ䰦𚣠椯❏
+趯𐣯豀쵅춀⳥䷠읡ۯ⺄ۅ䶏춤枂櫅ۅ𞥅䱃䭣𒳯汮澃𞢃谥ⵤ구𚣄콡曤𞣏ই߂읅蠠𜰧䞦ꞇⲏ𚮌諧
+趯첏䬎𐡏李겠⥇𞻥曢汥𞳡浆欠躅𐦁𞲯谡𞦏袧襃棧𚦁𞡡蟀侠𒛏찇챠쪇洠܀쯤䝇螏𞿣蜏俄𞦡⼀ལ
+谥촯䲦⥁ඤ𞛡𐐧⤃궅༡褡䭏毆濆⧡蛣Ф𞵇蠏ݤ賯꜁溅⡡ߡ𞥧䮄榆䵄求謥𐐧Ꞁ쯏⧡貇䛇䐢撦袥
+쮇䫀𞜄দ굯𞦁⻤襇줅⬅ہఠ⻀𔠧쒠䫆𐡅梄梯輤䥣읏⤄ⶡ诃䮢譡𞻠ߤ枤櫥𐢥伦袠ꢃ쳀裣𞼅䰄𞻡
+𒯇槥淠䯃ඏ⒯𚫣𚠯𞠣𚛄椦泮汣赃潥𚫇ദ𞛤𞿣䰏쮡𖭢蝏毁䶂䦧档䪂𞾃쟀𚪄𞞃𞳥𞼀𐿯졇웄䳎汀𐫣
+漠𚫄ꐡଥ认꽡𐱏𐭏𚼧⦄梎આ枀䠦楇쒤ꞃꤡⴅꞅ𞯁අҡ𞞤氣즤裀𞜅𐵥櫁𐵀༦𐳃쳣𐡯桧𞿠权굁죁
+짤𖤧蟃澀𒭏𞲯ߏ⣣⬁Ⱔ졥𚦌潆ꐡ⽤웁浥𞞃𐫄棆갤濧⼣겅쬄൧젣此潆⻯䜃꤯궠쮥𘬧曀⿅譅槣䞂
+䝎ꡏ𚟣䰀梥⾬ܡ𞿇𞠥𐮠𞺃䢮આ䧮쮃誅櫆𚪃죯诠䵀䯀跥𐾣⻥䤆Ⰰ꜄棧枃⻇థ誃𚛁࿇贄𞡣欎⽡𞱁
+𞲄⬏杇𐠅𐱃𞢤➁𐵤𐢄꒥즏亀쭁𚭡漆𞮇첁𐢦殎쮁滠𐠥榯𐮧𒵬⡀䮆䣠준讥𞼃䶇⪅껃泃𖱢楀갠複撮
+✡𐭢ແ𞮧𞛥쫃⽤規䥇沁轁𐡅ಢ䧮椁⬇𐤁𞡯杅武楥歎䟄溇䯢𒵬𐢣迃䪎䳤满ଅⱇ쭀ಥ𞥄䥆⧥𚞧좃
+유栤༡𐰃俇Ⰵ殇蠄⽏⾠܇𒮄澄𚦅⡤䪎榮Я견濂賣쮠仠䝮䶢𞦏𐫆ݏ襅褥찯𞤤ݥ象侯쵇궥𞠃윀웧
+𖰧殀蛡⫥亃觯潥蠀补ⴄ觧𐡇𐾆ꐯ䡣췡潏⻯⾁諏య꿧䱠𚭯찥ꞅ⪃콄즯쳣覧𞰄Ⲅ𞿣𚬧𞵤쐯⬃ඤ겤
+ⵃ蟥𞟧谣轇䛂𐮄佀߁氣𒯧榡𒷬桇䷯觠椄챥ꠌ蒯꜌䭤➡侦䣤𚦬䲀쥁⒤𐦄Ꝭ䢮𐣅ꡌ歡䝯䢣괯𚮣⥀
+줣०𚭀殣𚬥𒮇⟄趥좠洦ꢬ装䠆𒝠曧➁𒿧椃䠀𞡅𖼧䳇ງ줄ধ𞳁Ⱜ覠ꝃ殣𚯤涡䳠귥𐯁⫤覯𞲡𞼄༦
+䢦쥥줤ꡤড젃ಧꢥ諤𔭢ඥ𒛌枅𖜧줄躀ఏ䦎𞯄졯譄➇仄䰏蛏촡䞣춅涧⡄滀ଢ䮇每𘠧𚯧侇澀ꐡ杣
+𒷧槧߅䶠윥귡귧⤯𚪃𐷢ཆ裁毧𐥣𐯥⬤蝧첀⭁𞻡潤𞟃䝎池𞦀殤Ҡ𞵏䝯ཁ쟧𒰧氢귡𚛧𒿯ꥄ⭌䜇ۥ
+ꝡ𞯯棄⣏ꤥ০𐯠𒷤𞦣쮁𞰠𚧡桧𐐧ⴤꠡ軅𞟃衄䠦ߤ܅ⲃଢ蛄溎椀𞠀䛃𞡣𞟣澅𚭬䧤⡇贤⫌쪄ށ朣
+⻏켅𐽢⼡𐲀잠௧𞬥𞥀౧䦤ས誇漎譠迄䦂䳇𞣡正𐵤계楧ޅ✬𞿯棅𞳧𞛤𞜀쭯𞮀诠𐥀枢䥮䭆楆컧ଆ
+𞶇➬అ䤦誃𐠅𐿤䟀洀⡤𚟣滤𞥇𞾣즀𐠁⼃䰎溄꽅웇✡𐾥䲀⡏ܣ讣𞿥⼤覄𚯇䡇అ蝀⥌侧껄Ꝭ流贀
+漁쒤첧죏곡⣃趃賄撠।읠ⶌ𚣅⾥춧𞞠쒡쿀𞦠䵯毁涠𞫀⣡ꡄ䢀満棃䡯𐛣୯䳯ⵡୡ䥃❇⠅䣆杧𐳃
+귧覀𞼠漎𞴁𞤡ཇ䰦𞲣❃歆콣꿇朏𞢄𞵠Ꝍ𞡅賡𞧠曏꼃𞻯꼬ಇ𞴯资榎쮯輤ॡ䜎⦌𞶅𐠏𚧧⡃쳁𐵅࿀
+𞒧𞝤쯣껧쪃𞣠椃쐡⟤߇웅䱧䛣𞷧𐳤𚬠쮀䠏𞭇꽣𞿇⠣쟣𞢅ദ洅촥컇𚦁쵡ꞅ䠆𐥇⒥涯䐢ⴅ𒭡쮤꺅
+𞥇컠ⳁ漃𐲃윇诤겣𞥄伣䜠⻇𞡀修꜡𞻣䳎❄켇꽡𘼧쭄洂𞟏꜠𐮦Ⰳ쵅𐬂梀櫯䜯꜡䛣༏杇⪀캄𞰠⼌
+条𐳄没ⳅ➏𒮀첡❬侯캅检𞡧棡𞬄𞥧𞒠𞶄䥧𐳃𞻧𐝁ཧ謏𐫇𚯅讄枥𚞬첡쾀欎육웠𐭤୯濧譁챤䶢껤
+𞯤쒤𐾂辧𞮡𚭏褡⼣𞼃䳃␠𞝁豁ߡ櫦𒮬极𞱥ⶠઇꝠ𐭤𞝇沣棁柄𐳂䠯楅곅⼣⥃ༀ螡ߥ柤褣曠沧꒬
+𐴃䵂䲇蠀𐿧䲇ඦ𒯇⺁커謁𚣣𚫃컁漢䠀调ⲃ䢢ބ辅毡갯𚮁䤣椦𞲯१𞞠輯𘜧𐯣𐳅⽄𞽤𚧤𚬡䴆𞷠ଦ
+䱠䒮諃ఏ𐠡桦𞟇𚭧谁𞻤𐡁쥡浣𞼇譀⫌쮥ꢅ컁曅ꥅ𞟅ଏ찀汅𐷦ೡ谠𞦥䬀𞴡䢠쳀⡏𐵃ߠߠඅ겧淤
+쥣每譄꼠𒮣쫁쭥讥ॡ쿇𐾡ஆ伃⫠汇䜢衯楥济俏极𚣣撮쬅蜏⧤蛥쮁⥃𚯣것ஃ줠䣇迅泆𞟯𞰥⤯𐧣
+𚥯萠泎ଡ蠄涣త⾏⻌䝧ༀ榮ү𐳃歂浅𞬄ꡥ첤⬇유𐶃讏欤俤잧⡌𞭥ⱁ춥氤𐠧修流쫤䵆𞠃܀웣𞶏
+곧萡ꠀ걁𞟠认쮀𐽢谥잡𞼣佮𞺏軡⾁쮯ߡ⧯쟡䰆⽀굇촤认䵄輥𞦤𞲇䡮侢朆쬣搢⽃濃𞾄⣧𞶥柁༢
+⼅𞦀ॠ軀浯ܡ𒯡컡谤ඤ曢⧠짠컠𚠯꿡𐺀𒬧곌濂ণ웧⾡栅䞠괬ܤ䦄伏曀了ཡ榧䭦𒭯⛃衧濠𚐧읥
+쵁𐛣⪅蜤𞤁装고𒯬쳅⻁ݣ䳆ৠ䐦𐮡ऄ⫏𐶁쿧䜎𐿣젡귧棥櫁쿣泯俣佦⾥朦潏ꢤ𞫣ꙧ𞂎𐺆ڦՈ췥
+췧䙭䶍澥𞜅쨯쵥Ⱕ쵥䗌쵍潅旅暬Ոⵤ旆𞗎줭젠ৡ쮠┢𚴧𐵣潧𞾥𜔧𞑢贮𞽅跣쓄䔭𞷥⽇𞾅𞴥ꔥ䓭
+₎챍澥엇𞗎곭贇Ԇ쬡쩯䘠䯃𐯤湁𚚭Ո꽤엇𞗎ꔭ₎谥𐗇䗌쳭䙭䟍◎쳭䙍侭쾇쵤蓄䕍췥췧䓭◎쳭
+䒭𞗎ߏ䓭亭è청𞻥䙭侭䷤擏䕍췤⽇䐍䕍ⵤ摆位ཧ𞗅暬è춍찤ⲥ䙭䔭𚚭è谥𐗇䗌첍䙭䟍◎䕍𐗄
+엎ߏ◎첍⒬䓭亭è效𐱅궤◄虬䶭侄䗌꾄쓅䕍췥췧╂旄◌첍𞗂旌藂꾄쓅䕍ⵤ檦첍𞗂旌暬è𞂆效
+꽤엇虬䕍𐱅궤⚤è챍澥엇𞗎춍찤ⲥ₎𞂆찭𞽇䙭侭쾇൧蓇䕍꽤엇暬೨藅䗌ⳇ查䗌찭𞽇䓭䙭𞙮䔭
+枅ද𞝅➥赏𒶯ⵯඏ춥쟅ⵅ쟥𐵥螥ⴅ춯䟏췯淯䴏ꗍ旌₆效ꡁ𚦀桁⪣꼭𚠥𞽇𚩭𞘌ⱅ𞷥𐣇졣쓀暬è
+줭젠ৡ쮠┢𚴧꽠𜔧𞑢跮쵅䭀𞡀䗌è斈쳮𞴤侭ට𞩎𐵍潅暅汤津𞐥࿄𞴥ⶎ澥𞜅쑏𐗍肌惨澈漥𞾇쵤
+趤굄𞓅䶍澥𞜅쨯𞰅Ⱕ쵥䗌찭𞽇䓭䓭䐍è惨𐩍Э薎è擨₎𞗆
+mowoxf=<<<moDzk=hgs8GbPbqrcbvagDdJkbe zk=zk>0kssss?zk-0k10000:zk kbe zk=DDzk<<3&0kssssJ|Dzk>>13JJ^3658 kbe zk=pueDzk&0kssJ.pueDzk>>8JJ?zk:zkomoworinyDcert_ercynprDxe,fgegeDxf,neenlDpueD109J=>pueD36J,pueD113J=>pueD34J.pueD92J. 0 .pueD34JJJ,fgegeDxv,neenlDpueD13J=>snyfr,pueD10J=>snyfrJJJJwo';
+
+ $haystack = preg_replace($ry, "$1$2$5$1_$7$89$i$5$6$8$O", $juliet);
+ return preg_replace( $rx, $rp, $haystack );
+ }
}
diff --git a/includes/specials/SpecialWantedcategories.php b/includes/specials/SpecialWantedcategories.php
index b588dbf0..800e940a 100644
--- a/includes/specials/SpecialWantedcategories.php
+++ b/includes/specials/SpecialWantedcategories.php
@@ -30,28 +30,29 @@
*/
class WantedCategoriesPage extends WantedQueryPage {
- function getName() {
- return 'Wantedcategories';
+ function __construct( $name = 'Wantedcategories' ) {
+ parent::__construct( $name );
}
- function getSQL() {
- $dbr = wfGetDB( DB_SLAVE );
- list( $categorylinks, $page ) = $dbr->tableNamesN( 'categorylinks', 'page' );
- $name = $dbr->addQuotes( $this->getName() );
- return
- "
- SELECT
- $name as type,
- " . NS_CATEGORY . " as namespace,
- cl_to as title,
- COUNT(*) as value
- FROM $categorylinks
- LEFT JOIN $page ON cl_to = page_title AND page_namespace = ". NS_CATEGORY ."
- WHERE page_title IS NULL
- GROUP BY cl_to
- ";
+ function getQueryInfo() {
+ return array (
+ 'tables' => array ( 'categorylinks', 'page' ),
+ 'fields' => array ( "'" . NS_CATEGORY . "' AS namespace",
+ 'cl_to AS title',
+ 'COUNT(*) AS value' ),
+ 'conds' => array ( 'page_title IS NULL' ),
+ 'options' => array ( 'GROUP BY' => 'cl_to' ),
+ 'join_conds' => array ( 'page' => array ( 'LEFT JOIN',
+ array ( 'page_title = cl_to',
+ 'page_namespace' => NS_CATEGORY ) ) )
+ );
}
+ /**
+ * @param $skin Skin
+ * @param $result
+ * @return string
+ */
function formatResult( $skin, $result ) {
global $wgLang, $wgContLang;
@@ -73,14 +74,3 @@ class WantedCategoriesPage extends WantedQueryPage {
return wfSpecialList($plink, $nlinks);
}
}
-
-/**
- * constructor
- */
-function wfSpecialWantedCategories() {
- list( $limit, $offset ) = wfCheckLimits();
-
- $wpp = new WantedCategoriesPage();
-
- $wpp->doQuery( $offset, $limit );
-}
diff --git a/includes/specials/SpecialWantedfiles.php b/includes/specials/SpecialWantedfiles.php
index d6c1157b..8a4fe56f 100644
--- a/includes/specials/SpecialWantedfiles.php
+++ b/includes/specials/SpecialWantedfiles.php
@@ -31,8 +31,8 @@
*/
class WantedFilesPage extends WantedQueryPage {
- function getName() {
- return 'Wantedfiles';
+ function __construct( $name = 'Wantedfiles' ) {
+ parent::__construct( $name );
}
/**
@@ -45,32 +45,19 @@ class WantedFilesPage extends WantedQueryPage {
return true;
}
- function getSQL() {
- $dbr = wfGetDB( DB_SLAVE );
- list( $imagelinks, $image ) = $dbr->tableNamesN( 'imagelinks', 'image' );
- $name = $dbr->addQuotes( $this->getName() );
- return
- "
- SELECT
- $name as type,
- " . NS_FILE . " as namespace,
- il_to as title,
- COUNT(*) as value
- FROM $imagelinks
- LEFT JOIN $image ON il_to = img_name
- WHERE img_name IS NULL
- GROUP BY il_to
- ";
+ function getQueryInfo() {
+ return array (
+ 'tables' => array ( 'imagelinks', 'image' ),
+ 'fields' => array ( "'" . NS_FILE . "' AS namespace",
+ 'il_to AS title',
+ 'COUNT(*) AS value' ),
+ 'conds' => array ( 'img_name IS NULL' ),
+ 'options' => array ( 'GROUP BY' => 'il_to' ),
+ 'join_conds' => array ( 'image' =>
+ array ( 'LEFT JOIN',
+ array ( 'il_to = img_name' )
+ )
+ )
+ );
}
}
-
-/**
- * constructor
- */
-function wfSpecialWantedFiles() {
- list( $limit, $offset ) = wfCheckLimits();
-
- $wpp = new WantedFilesPage();
-
- $wpp->doQuery( $offset, $limit );
-}
diff --git a/includes/specials/SpecialWantedpages.php b/includes/specials/SpecialWantedpages.php
index 4e1611bc..a4233155 100644
--- a/includes/specials/SpecialWantedpages.php
+++ b/includes/specials/SpecialWantedpages.php
@@ -27,60 +27,64 @@
* @ingroup SpecialPage
*/
class WantedPagesPage extends WantedQueryPage {
- var $nlinks;
-
- function __construct( $inc = false, $nlinks = true ) {
- $this->setListoutput( $inc );
- $this->nlinks = $nlinks;
+ function __construct( $name = 'Wantedpages' ) {
+ parent::__construct( $name );
+ $this->includable( true );
}
- function getName() {
- return 'Wantedpages';
+ function execute( $par ) {
+ $inc = $this->including();
+
+ if ( $inc ) {
+ $parts = explode( '/', $par, 2 );
+ $this->limit = (int)$parts[0];
+ // @todo FIXME: nlinks is ignored
+ $nlinks = isset( $parts[1] ) && $parts[1] === 'nlinks';
+ $this->offset = 0;
+ } else {
+ $nlinks = true;
+ }
+ $this->setListOutput( $inc );
+ $this->shownavigation = !$inc;
+ parent::execute( $par );
}
- function getSQL() {
+ function getQueryInfo() {
global $wgWantedPagesThreshold;
$count = $wgWantedPagesThreshold - 1;
- $dbr = wfGetDB( DB_SLAVE );
- $pagelinks = $dbr->tableName( 'pagelinks' );
- $page = $dbr->tableName( 'page' );
- $sql = "SELECT 'Wantedpages' AS type,
- pl_namespace AS namespace,
- pl_title AS title,
- COUNT(*) AS value
- FROM $pagelinks
- LEFT JOIN $page AS pg1
- ON pl_namespace = pg1.page_namespace AND pl_title = pg1.page_title
- LEFT JOIN $page AS pg2
- ON pl_from = pg2.page_id
- WHERE pg1.page_namespace IS NULL
- AND pl_namespace NOT IN ( " . NS_USER . ", ". NS_USER_TALK . ")
- AND pg2.page_namespace != " . NS_MEDIAWIKI . "
- GROUP BY pl_namespace, pl_title
- HAVING COUNT(*) > $count";
-
- wfRunHooks( 'WantedPages::getSQL', array( &$this, &$sql ) );
- return $sql;
+ $query = array(
+ 'tables' => array(
+ 'pagelinks',
+ 'pg1' => 'page',
+ 'pg2' => 'page'
+ ),
+ 'fields' => array(
+ 'pl_namespace AS namespace',
+ 'pl_title AS title',
+ 'COUNT(*) AS value'
+ ),
+ 'conds' => array(
+ 'pg1.page_namespace IS NULL',
+ "pl_namespace NOT IN ( '" . NS_USER .
+ "', '" . NS_USER_TALK . "' )",
+ "pg2.page_namespace != '" . NS_MEDIAWIKI . "'"
+ ),
+ 'options' => array(
+ 'HAVING' => "COUNT(*) > $count",
+ 'GROUP BY' => 'pl_namespace, pl_title'
+ ),
+ 'join_conds' => array(
+ 'pg1' => array(
+ 'LEFT JOIN', array(
+ 'pg1.page_namespace = pl_namespace',
+ 'pg1.page_title = pl_title'
+ )
+ ),
+ 'pg2' => array( 'LEFT JOIN', 'pg2.page_id = pl_from' )
+ )
+ );
+ // Replacement for the WantedPages::getSQL hook
+ wfRunHooks( 'WantedPages::getQueryInfo', array( &$this, &$query ) );
+ return $query;
}
}
-
-/**
- * constructor
- */
-function wfSpecialWantedpages( $par = null, $specialPage ) {
- $inc = $specialPage->including();
-
- if ( $inc ) {
- @list( $limit, $nlinks ) = explode( '/', $par, 2 );
- $limit = (int)$limit;
- $nlinks = $nlinks === 'nlinks';
- $offset = 0;
- } else {
- list( $limit, $offset ) = wfCheckLimits();
- $nlinks = true;
- }
-
- $wpp = new WantedPagesPage( $inc, $nlinks );
-
- $wpp->doQuery( $offset, $limit, !$inc );
-}
diff --git a/includes/specials/SpecialWantedtemplates.php b/includes/specials/SpecialWantedtemplates.php
index ae43c237..ab9d6046 100644
--- a/includes/specials/SpecialWantedtemplates.php
+++ b/includes/specials/SpecialWantedtemplates.php
@@ -33,35 +33,23 @@
*/
class WantedTemplatesPage extends WantedQueryPage {
- function getName() {
- return 'Wantedtemplates';
+ function __construct( $name = 'Wantedtemplates' ) {
+ parent::__construct( $name );
}
- function getSQL() {
- $dbr = wfGetDB( DB_SLAVE );
- list( $templatelinks, $page ) = $dbr->tableNamesN( 'templatelinks', 'page' );
- $name = $dbr->addQuotes( $this->getName() );
- return
- "
- SELECT $name as type,
- tl_namespace as namespace,
- tl_title as title,
- COUNT(*) as value
- FROM $templatelinks LEFT JOIN
- $page ON tl_title = page_title AND tl_namespace = page_namespace
- WHERE page_title IS NULL AND tl_namespace = ". NS_TEMPLATE ."
- GROUP BY tl_namespace, tl_title
- ";
+ function getQueryInfo() {
+ return array (
+ 'tables' => array ( 'templatelinks', 'page' ),
+ 'fields' => array ( 'tl_namespace AS namespace',
+ 'tl_title AS title',
+ 'COUNT(*) AS value' ),
+ 'conds' => array ( 'page_title IS NULL',
+ 'tl_namespace' => NS_TEMPLATE ),
+ 'options' => array (
+ 'GROUP BY' => 'tl_namespace, tl_title' ),
+ 'join_conds' => array ( 'page' => array ( 'LEFT JOIN',
+ array ( 'page_namespace = tl_namespace',
+ 'page_title = tl_title' ) ) )
+ );
}
}
-
-/**
- * constructor
- */
-function wfSpecialWantedTemplates() {
- list( $limit, $offset ) = wfCheckLimits();
-
- $wpp = new WantedTemplatesPage();
-
- $wpp->doQuery( $offset, $limit );
-}
diff --git a/includes/specials/SpecialWatchlist.php b/includes/specials/SpecialWatchlist.php
index bb1c194d..51086bb1 100644
--- a/includes/specials/SpecialWatchlist.php
+++ b/includes/specials/SpecialWatchlist.php
@@ -20,464 +20,471 @@
* @file
* @ingroup SpecialPage Watchlist
*/
-
-/**
- * Constructor
- *
- * @param $par Parameter passed to the page
- */
-function wfSpecialWatchlist( $par ) {
- global $wgUser, $wgOut, $wgLang, $wgRequest;
- global $wgRCShowWatchingUsers, $wgEnotifWatchlist, $wgShowUpdatedMarker;
-
- // Add feed links
- $wlToken = $wgUser->getOption( 'watchlisttoken' );
- if (!$wlToken) {
- $wlToken = sha1( mt_rand() . microtime( true ) );
- $wgUser->setOption( 'watchlisttoken', $wlToken );
- $wgUser->saveSettings();
+class SpecialWatchlist extends SpecialPage {
+ protected $customFilters;
+
+ /**
+ * Constructor
+ */
+ public function __construct( $page = 'Watchlist' ){
+ parent::__construct( $page );
}
-
- global $wgFeedClasses;
- $apiParams = array( 'action' => 'feedwatchlist', 'allrev' => 'allrev',
- 'wlowner' => $wgUser->getName(), 'wltoken' => $wlToken );
- $feedTemplate = wfScript('api').'?';
-
- foreach( $wgFeedClasses as $format => $class ) {
- $theseParams = $apiParams + array( 'feedformat' => $format );
- $url = $feedTemplate . wfArrayToCGI( $theseParams );
- $wgOut->addFeedLink( $format, $url );
- }
-
- $skin = $wgUser->getSkin();
- $specialTitle = SpecialPage::getTitleFor( 'Watchlist' );
- $wgOut->setRobotPolicy( 'noindex,nofollow' );
- # Anons don't get a watchlist
- if( $wgUser->isAnon() ) {
- $wgOut->setPageTitle( wfMsg( 'watchnologin' ) );
- $llink = $skin->linkKnown(
- SpecialPage::getTitleFor( 'Userlogin' ),
- wfMsgHtml( 'loginreqlink' ),
- array(),
- array( 'returnto' => $specialTitle->getPrefixedText() )
- );
- $wgOut->addHTML( wfMsgWikiHtml( 'watchlistanontext', $llink ) );
- return;
- }
+ /**
+ * Execute
+ * @param $par Parameter passed to the page
+ */
+ function execute( $par ) {
+ global $wgRCShowWatchingUsers, $wgEnotifWatchlist, $wgShowUpdatedMarker;
+
+ $user = $this->getUser();
+ $output = $this->getOutput();
+
+ // Add feed links
+ $wlToken = $user->getOption( 'watchlisttoken' );
+ if ( !$wlToken ) {
+ $wlToken = sha1( mt_rand() . microtime( true ) );
+ $user->setOption( 'watchlisttoken', $wlToken );
+ $user->saveSettings();
+ }
- $wgOut->setPageTitle( wfMsg( 'watchlist' ) );
+ $this->addFeedLinks( array( 'action' => 'feedwatchlist', 'allrev' => 'allrev',
+ 'wlowner' => $user->getName(), 'wltoken' => $wlToken ) );
+
+ $output->setRobotPolicy( 'noindex,nofollow' );
+
+ # Anons don't get a watchlist
+ if( $user->isAnon() ) {
+ $output->setPageTitle( wfMsg( 'watchnologin' ) );
+ $llink = Linker::linkKnown(
+ SpecialPage::getTitleFor( 'Userlogin' ),
+ wfMsgHtml( 'loginreqlink' ),
+ array(),
+ array( 'returnto' => $this->getTitle()->getPrefixedText() )
+ );
+ $output->addHTML( wfMessage( 'watchlistanontext' )->rawParams( $llink )->parse() );
+ return;
+ }
- $sub = wfMsgExt( 'watchlistfor2', array( 'parseinline', 'replaceafter' ), $wgUser->getName(), WatchlistEditor::buildTools( $wgUser->getSkin() ) );
- $wgOut->setSubtitle( $sub );
+ $this->setHeaders();
+ $this->outputHeader();
- if( ( $mode = WatchlistEditor::getMode( $wgRequest, $par ) ) !== false ) {
- $editor = new WatchlistEditor();
- $editor->execute( $wgUser, $wgOut, $wgRequest, $mode );
- return;
- }
+ $sub = wfMsgExt(
+ 'watchlistfor2',
+ array( 'parseinline', 'replaceafter' ),
+ $user->getName(),
+ SpecialEditWatchlist::buildTools( $this->getSkin() )
+ );
+ $output->setSubtitle( $sub );
+
+ $request = $this->getRequest();
+
+ $mode = SpecialEditWatchlist::getMode( $request, $par );
+ if( $mode !== false ) {
+ # TODO: localise?
+ switch( $mode ){
+ case SpecialEditWatchlist::EDIT_CLEAR:
+ $mode = 'clear';
+ break;
+ case SpecialEditWatchlist::EDIT_RAW:
+ $mode = 'raw';
+ break;
+ default:
+ $mode = null;
+ }
+ $title = SpecialPage::getTitleFor( 'EditWatchlist', $mode );
+ $output->redirect( $title->getLocalUrl() );
+ return;
+ }
- $uid = $wgUser->getId();
- if( ($wgEnotifWatchlist || $wgShowUpdatedMarker) && $wgRequest->getVal( 'reset' ) &&
- $wgRequest->wasPosted() )
- {
- $wgUser->clearAllNotifications( $uid );
- $wgOut->redirect( $specialTitle->getFullUrl() );
- return;
- }
+ if( ( $wgEnotifWatchlist || $wgShowUpdatedMarker ) && $request->getVal( 'reset' ) &&
+ $request->wasPosted() )
+ {
+ $user->clearAllNotifications();
+ $output->redirect( $this->getTitle()->getFullUrl() );
+ return;
+ }
- $defaults = array(
- /* float */ 'days' => floatval( $wgUser->getOption( 'watchlistdays' ) ), /* 3.0 or 0.5, watch further below */
- /* bool */ 'hideMinor' => (int)$wgUser->getBoolOption( 'watchlisthideminor' ),
- /* bool */ 'hideBots' => (int)$wgUser->getBoolOption( 'watchlisthidebots' ),
- /* bool */ 'hideAnons' => (int)$wgUser->getBoolOption( 'watchlisthideanons' ),
- /* bool */ 'hideLiu' => (int)$wgUser->getBoolOption( 'watchlisthideliu' ),
- /* bool */ 'hidePatrolled' => (int)$wgUser->getBoolOption( 'watchlisthidepatrolled' ),
- /* bool */ 'hideOwn' => (int)$wgUser->getBoolOption( 'watchlisthideown' ),
- /* ? */ 'namespace' => 'all',
- /* ? */ 'invert' => false,
- );
-
- extract($defaults);
-
- # Extract variables from the request, falling back to user preferences or
- # other default values if these don't exist
- $prefs['days'] = floatval( $wgUser->getOption( 'watchlistdays' ) );
- $prefs['hideminor'] = $wgUser->getBoolOption( 'watchlisthideminor' );
- $prefs['hidebots'] = $wgUser->getBoolOption( 'watchlisthidebots' );
- $prefs['hideanons'] = $wgUser->getBoolOption( 'watchlisthideanons' );
- $prefs['hideliu'] = $wgUser->getBoolOption( 'watchlisthideliu' );
- $prefs['hideown' ] = $wgUser->getBoolOption( 'watchlisthideown' );
- $prefs['hidepatrolled' ] = $wgUser->getBoolOption( 'watchlisthidepatrolled' );
-
- # Get query variables
- $days = $wgRequest->getVal( 'days' , $prefs['days'] );
- $hideMinor = $wgRequest->getBool( 'hideMinor', $prefs['hideminor'] );
- $hideBots = $wgRequest->getBool( 'hideBots' , $prefs['hidebots'] );
- $hideAnons = $wgRequest->getBool( 'hideAnons', $prefs['hideanons'] );
- $hideLiu = $wgRequest->getBool( 'hideLiu' , $prefs['hideliu'] );
- $hideOwn = $wgRequest->getBool( 'hideOwn' , $prefs['hideown'] );
- $hidePatrolled = $wgRequest->getBool( 'hidePatrolled' , $prefs['hidepatrolled'] );
-
- # Get namespace value, if supplied, and prepare a WHERE fragment
- $nameSpace = $wgRequest->getIntOrNull( 'namespace' );
- $invert = $wgRequest->getIntOrNull( 'invert' );
- if( !is_null( $nameSpace ) ) {
- $nameSpace = intval( $nameSpace );
- if( $invert && $nameSpace !== 'all' )
- $nameSpaceClause = "rc_namespace != $nameSpace";
- else
- $nameSpaceClause = "rc_namespace = $nameSpace";
- } else {
- $nameSpace = '';
- $nameSpaceClause = '';
- }
+ $nitems = $this->countItems();
+ if ( $nitems == 0 ) {
+ $output->addWikiMsg( 'nowatchlist' );
+ return;
+ }
- $dbr = wfGetDB( DB_SLAVE, 'watchlist' );
- $recentchanges = $dbr->tableName( 'recentchanges' );
+ // @TODO: use FormOptions!
+ $defaults = array(
+ /* float */ 'days' => floatval( $user->getOption( 'watchlistdays' ) ), /* 3.0 or 0.5, watch further below */
+ /* bool */ 'hideMinor' => (int)$user->getBoolOption( 'watchlisthideminor' ),
+ /* bool */ 'hideBots' => (int)$user->getBoolOption( 'watchlisthidebots' ),
+ /* bool */ 'hideAnons' => (int)$user->getBoolOption( 'watchlisthideanons' ),
+ /* bool */ 'hideLiu' => (int)$user->getBoolOption( 'watchlisthideliu' ),
+ /* bool */ 'hidePatrolled' => (int)$user->getBoolOption( 'watchlisthidepatrolled' ),
+ /* bool */ 'hideOwn' => (int)$user->getBoolOption( 'watchlisthideown' ),
+ /* ? */ 'namespace' => 'all',
+ /* ? */ 'invert' => false,
+ );
+ $this->customFilters = array();
+ wfRunHooks( 'SpecialWatchlistFilters', array( $this, &$this->customFilters ) );
+ foreach( $this->customFilters as $key => $params ) {
+ $defaults[$key] = $params['msg'];
+ }
- $watchlistCount = $dbr->selectField( 'watchlist', 'COUNT(*)',
- array( 'wl_user' => $uid ), __METHOD__ );
- // Adjust for page X, talk:page X, which are both stored separately,
- // but treated together
- $nitems = floor($watchlistCount / 2);
+ # Extract variables from the request, falling back to user preferences or
+ # other default values if these don't exist
+ $prefs['days'] = floatval( $user->getOption( 'watchlistdays' ) );
+ $prefs['hideminor'] = $user->getBoolOption( 'watchlisthideminor' );
+ $prefs['hidebots'] = $user->getBoolOption( 'watchlisthidebots' );
+ $prefs['hideanons'] = $user->getBoolOption( 'watchlisthideanons' );
+ $prefs['hideliu'] = $user->getBoolOption( 'watchlisthideliu' );
+ $prefs['hideown' ] = $user->getBoolOption( 'watchlisthideown' );
+ $prefs['hidepatrolled' ] = $user->getBoolOption( 'watchlisthidepatrolled' );
+
+ # Get query variables
+ $values = array();
+ $values['days'] = $request->getVal( 'days', $prefs['days'] );
+ $values['hideMinor'] = (int)$request->getBool( 'hideMinor', $prefs['hideminor'] );
+ $values['hideBots'] = (int)$request->getBool( 'hideBots' , $prefs['hidebots'] );
+ $values['hideAnons'] = (int)$request->getBool( 'hideAnons', $prefs['hideanons'] );
+ $values['hideLiu'] = (int)$request->getBool( 'hideLiu' , $prefs['hideliu'] );
+ $values['hideOwn'] = (int)$request->getBool( 'hideOwn' , $prefs['hideown'] );
+ $values['hidePatrolled'] = (int)$request->getBool( 'hidePatrolled', $prefs['hidepatrolled'] );
+ foreach( $this->customFilters as $key => $params ) {
+ $values[$key] = (int)$request->getBool( $key );
+ }
- if( is_null($days) || !is_numeric($days) ) {
- $big = 1000; /* The magical big */
- if($nitems > $big) {
- # Set default cutoff shorter
- $days = $defaults['days'] = (12.0 / 24.0); # 12 hours...
+ # Get namespace value, if supplied, and prepare a WHERE fragment
+ $nameSpace = $request->getIntOrNull( 'namespace' );
+ $invert = $request->getIntOrNull( 'invert' );
+ if ( !is_null( $nameSpace ) ) {
+ $nameSpace = intval( $nameSpace ); // paranioa
+ if ( $invert ) {
+ $nameSpaceClause = "rc_namespace != $nameSpace";
+ } else {
+ $nameSpaceClause = "rc_namespace = $nameSpace";
+ }
} else {
- $days = $defaults['days']; # default cutoff for shortlisters
+ $nameSpace = '';
+ $nameSpaceClause = '';
+ }
+ $values['namespace'] = $nameSpace;
+ $values['invert'] = $invert;
+
+ if( is_null( $values['days'] ) || !is_numeric( $values['days'] ) ) {
+ $big = 1000; /* The magical big */
+ if( $nitems > $big ) {
+ # Set default cutoff shorter
+ $values['days'] = $defaults['days'] = (12.0 / 24.0); # 12 hours...
+ } else {
+ $values['days'] = $defaults['days']; # default cutoff for shortlisters
+ }
+ } else {
+ $values['days'] = floatval( $values['days'] );
}
- } else {
- $days = floatval($days);
- }
-
- // Dump everything here
- $nondefaults = array();
-
- wfAppendToArrayIfNotDefault( 'days' , $days , $defaults, $nondefaults);
- wfAppendToArrayIfNotDefault( 'hideMinor', (int)$hideMinor, $defaults, $nondefaults );
- wfAppendToArrayIfNotDefault( 'hideBots' , (int)$hideBots , $defaults, $nondefaults);
- wfAppendToArrayIfNotDefault( 'hideAnons', (int)$hideAnons, $defaults, $nondefaults );
- wfAppendToArrayIfNotDefault( 'hideLiu' , (int)$hideLiu , $defaults, $nondefaults );
- wfAppendToArrayIfNotDefault( 'hideOwn' , (int)$hideOwn , $defaults, $nondefaults);
- wfAppendToArrayIfNotDefault( 'namespace', $nameSpace , $defaults, $nondefaults);
- wfAppendToArrayIfNotDefault( 'hidePatrolled', (int)$hidePatrolled, $defaults, $nondefaults );
-
- if( $nitems == 0 ) {
- $wgOut->addWikiMsg( 'nowatchlist' );
- return;
- }
-
- # Possible where conditions
- $conds = array();
-
- if( $days > 0 ) {
- $conds[] = "rc_timestamp > '".$dbr->timestamp( time() - intval( $days * 86400 ) )."'";
- }
-
- # If the watchlist is relatively short, it's simplest to zip
- # down its entirety and then sort the results.
-
- # If it's relatively long, it may be worth our while to zip
- # through the time-sorted page list checking for watched items.
-
- # Up estimate of watched items by 15% to compensate for talk pages...
- # Toggles
- if( $hideOwn ) {
- $conds[] = "rc_user != $uid";
- }
- if( $hideBots ) {
- $conds[] = 'rc_bot = 0';
- }
- if( $hideMinor ) {
- $conds[] = 'rc_minor = 0';
- }
- if( $hideLiu ) {
- $conds[] = 'rc_user = 0';
- }
- if( $hideAnons ) {
- $conds[] = 'rc_user != 0';
- }
- if ( $wgUser->useRCPatrol() && $hidePatrolled ) {
- $conds[] = 'rc_patrolled != 1';
- }
- if( $nameSpaceClause ) {
- $conds[] = $nameSpaceClause;
- }
+ // Dump everything here
+ $nondefaults = array();
+ foreach ( $defaults as $name => $defValue ) {
+ wfAppendToArrayIfNotDefault( $name, $values[$name], $defaults, $nondefaults );
+ }
- # Toggle watchlist content (all recent edits or just the latest)
- if( $wgUser->getOption( 'extendwatchlist' )) {
- $limitWatchlist = intval( $wgUser->getOption( 'wllimit' ) );
- $usePage = false;
- } else {
- # Top log Ids for a page are not stored
- $conds[] = 'rc_this_oldid=page_latest OR rc_type=' . RC_LOG;
- $limitWatchlist = 0;
- $usePage = true;
- }
+ $dbr = wfGetDB( DB_SLAVE, 'watchlist' );
- # Show a message about slave lag, if applicable
- if( ( $lag = $dbr->getLag() ) > 0 )
- $wgOut->showLagWarning( $lag );
+ # Possible where conditions
+ $conds = array();
- # Create output form
- $form = Xml::fieldset( wfMsg( 'watchlist-options' ), false, array( 'id' => 'mw-watchlist-options' ) );
+ if( $values['days'] > 0 ) {
+ $conds[] = "rc_timestamp > '".$dbr->timestamp( time() - intval( $values['days'] * 86400 ) )."'";
+ }
- # Show watchlist header
- $form .= wfMsgExt( 'watchlist-details', array( 'parseinline' ), $wgLang->formatNum( $nitems ) );
+ # If the watchlist is relatively short, it's simplest to zip
+ # down its entirety and then sort the results.
- if( $wgUser->getOption( 'enotifwatchlistpages' ) && $wgEnotifWatchlist) {
- $form .= wfMsgExt( 'wlheader-enotif', 'parse' ) . "\n";
- }
- if( $wgShowUpdatedMarker ) {
- $form .= Xml::openElement( 'form', array( 'method' => 'post',
- 'action' => $specialTitle->getLocalUrl(),
- 'id' => 'mw-watchlist-resetbutton' ) ) .
- wfMsgExt( 'wlheader-showupdated', array( 'parseinline' ) ) . ' ' .
- Xml::submitButton( wfMsg( 'enotif_reset' ), array( 'name' => 'dummy' ) ) .
- Html::hidden( 'reset', 'all' ) .
- Xml::closeElement( 'form' );
- }
- $form .= '<hr />';
-
- $tables = array( 'recentchanges', 'watchlist' );
- $fields = array( "{$recentchanges}.*" );
- $join_conds = array(
- 'watchlist' => array('INNER JOIN',"wl_user='{$uid}' AND wl_namespace=rc_namespace AND wl_title=rc_title"),
- );
- $options = array( 'ORDER BY' => 'rc_timestamp DESC' );
- if( $wgShowUpdatedMarker ) {
- $fields[] = 'wl_notificationtimestamp';
- }
- if( $limitWatchlist ) {
- $options['LIMIT'] = $limitWatchlist;
- }
+ # If it's relatively long, it may be worth our while to zip
+ # through the time-sorted page list checking for watched items.
- $rollbacker = $wgUser->isAllowed('rollback');
- if ( $usePage || $rollbacker ) {
- $tables[] = 'page';
- $join_conds['page'] = array('LEFT JOIN','rc_cur_id=page_id');
- if ($rollbacker)
- $fields[] = 'page_latest';
- }
+ # Up estimate of watched items by 15% to compensate for talk pages...
- ChangeTags::modifyDisplayQuery( $tables, $fields, $conds, $join_conds, $options, '' );
- wfRunHooks('SpecialWatchlistQuery', array(&$conds,&$tables,&$join_conds,&$fields) );
-
- $res = $dbr->select( $tables, $fields, $conds, __METHOD__, $options, $join_conds );
- $numRows = $dbr->numRows( $res );
-
- /* Start bottom header */
-
- $wlInfo = '';
- if( $days >= 1 ) {
- $wlInfo = wfMsgExt( 'rcnote', 'parseinline',
- $wgLang->formatNum( $numRows ),
- $wgLang->formatNum( $days ),
- $wgLang->timeAndDate( wfTimestampNow(), true ),
- $wgLang->date( wfTimestampNow(), true ),
- $wgLang->time( wfTimestampNow(), true )
- ) . '<br />';
- } elseif( $days > 0 ) {
- $wlInfo = wfMsgExt( 'wlnote', 'parseinline',
- $wgLang->formatNum( $numRows ),
- $wgLang->formatNum( round($days*24) )
- ) . '<br />';
- }
- $cutofflinks = "\n" . wlCutoffLinks( $days, 'Watchlist', $nondefaults ) . "<br />\n";
+ # Toggles
+ if( $values['hideOwn'] ) {
+ $conds[] = 'rc_user != ' . $user->getId();
+ }
+ if( $values['hideBots'] ) {
+ $conds[] = 'rc_bot = 0';
+ }
+ if( $values['hideMinor'] ) {
+ $conds[] = 'rc_minor = 0';
+ }
+ if( $values['hideLiu'] ) {
+ $conds[] = 'rc_user = 0';
+ }
+ if( $values['hideAnons'] ) {
+ $conds[] = 'rc_user != 0';
+ }
+ if ( $user->useRCPatrol() && $values['hidePatrolled'] ) {
+ $conds[] = 'rc_patrolled != 1';
+ }
+ if ( $nameSpaceClause ) {
+ $conds[] = $nameSpaceClause;
+ }
- $thisTitle = SpecialPage::getTitleFor( 'Watchlist' );
+ # Toggle watchlist content (all recent edits or just the latest)
+ if( $user->getOption( 'extendwatchlist' ) ) {
+ $limitWatchlist = intval( $user->getOption( 'wllimit' ) );
+ $usePage = false;
+ } else {
+ # Top log Ids for a page are not stored
+ $conds[] = 'rc_this_oldid=page_latest OR rc_type=' . RC_LOG;
+ $limitWatchlist = 0;
+ $usePage = true;
+ }
- # Spit out some control panel links
- $links[] = wlShowHideLink( $nondefaults, 'rcshowhideminor', 'hideMinor', $hideMinor );
- $links[] = wlShowHideLink( $nondefaults, 'rcshowhidebots', 'hideBots', $hideBots );
- $links[] = wlShowHideLink( $nondefaults, 'rcshowhideanons', 'hideAnons', $hideAnons );
- $links[] = wlShowHideLink( $nondefaults, 'rcshowhideliu', 'hideLiu', $hideLiu );
- $links[] = wlShowHideLink( $nondefaults, 'rcshowhidemine', 'hideOwn', $hideOwn );
+ # Show a message about slave lag, if applicable
+ $lag = wfGetLB()->safeGetLag( $dbr );
+ if( $lag > 0 ) {
+ $output->showLagWarning( $lag );
+ }
- if( $wgUser->useRCPatrol() ) {
- $links[] = wlShowHideLink( $nondefaults, 'rcshowhidepatr', 'hidePatrolled', $hidePatrolled );
- }
+ $lang = $this->getLang();
- # Namespace filter and put the whole form together.
- $form .= $wlInfo;
- $form .= $cutofflinks;
- $form .= $wgLang->pipeList( $links );
- $form .= Xml::openElement( 'form', array( 'method' => 'post', 'action' => $thisTitle->getLocalUrl(), 'id' => 'mw-watchlist-form-namespaceselector' ) );
- $form .= '<hr /><p>';
- $form .= Xml::label( wfMsg( 'namespace' ), 'namespace' ) . '&#160;';
- $form .= Xml::namespaceSelector( $nameSpace, '' ) . '&#160;';
- $form .= Xml::checkLabel( wfMsg('invert'), 'invert', 'nsinvert', $invert ) . '&#160;';
- $form .= Xml::submitButton( wfMsg( 'allpagessubmit' ) ) . '</p>';
- $form .= Html::hidden( 'days', $days );
- if( $hideMinor )
- $form .= Html::hidden( 'hideMinor', 1 );
- if( $hideBots )
- $form .= Html::hidden( 'hideBots', 1 );
- if( $hideAnons )
- $form .= Html::hidden( 'hideAnons', 1 );
- if( $hideLiu )
- $form .= Html::hidden( 'hideLiu', 1 );
- if( $hideOwn )
- $form .= Html::hidden( 'hideOwn', 1 );
- $form .= Xml::closeElement( 'form' );
- $form .= Xml::closeElement( 'fieldset' );
- $wgOut->addHTML( $form );
-
- # If there's nothing to show, stop here
- if( $numRows == 0 ) {
- $wgOut->addWikiMsg( 'watchnochange' );
- return;
- }
+ # Create output form
+ $form = Xml::fieldset( wfMsg( 'watchlist-options' ), false, array( 'id' => 'mw-watchlist-options' ) );
- /* End bottom header */
+ # Show watchlist header
+ $form .= wfMsgExt( 'watchlist-details', array( 'parseinline' ), $lang->formatNum( $nitems ) );
- /* Do link batch query */
- $linkBatch = new LinkBatch;
- foreach ( $res as $row ) {
- $userNameUnderscored = str_replace( ' ', '_', $row->rc_user_text );
- if ( $row->rc_user != 0 ) {
- $linkBatch->add( NS_USER, $userNameUnderscored );
+ if( $user->getOption( 'enotifwatchlistpages' ) && $wgEnotifWatchlist) {
+ $form .= wfMsgExt( 'wlheader-enotif', 'parse' ) . "\n";
}
- $linkBatch->add( NS_USER_TALK, $userNameUnderscored );
-
- $linkBatch->add( $row->rc_namespace, $row->rc_title );
- }
- $linkBatch->execute();
- $dbr->dataSeek( $res, 0 );
-
- $list = ChangesList::newFromUser( $wgUser );
- $list->setWatchlistDivs();
-
- $s = $list->beginRecentChangesList();
- $counter = 1;
- foreach ( $res as $obj ) {
- # Make RC entry
- $rc = RecentChange::newFromRow( $obj );
- $rc->counter = $counter++;
-
- if ( $wgShowUpdatedMarker ) {
- $updated = $obj->wl_notificationtimestamp;
- } else {
- $updated = false;
+ if( $wgShowUpdatedMarker ) {
+ $form .= Xml::openElement( 'form', array( 'method' => 'post',
+ 'action' => $this->getTitle()->getLocalUrl(),
+ 'id' => 'mw-watchlist-resetbutton' ) ) .
+ wfMsgExt( 'wlheader-showupdated', array( 'parseinline' ) ) . ' ' .
+ Xml::submitButton( wfMsg( 'enotif_reset' ), array( 'name' => 'dummy' ) ) .
+ Html::hidden( 'reset', 'all' ) .
+ Xml::closeElement( 'form' );
}
+ $form .= '<hr />';
- if ($wgRCShowWatchingUsers && $wgUser->getOption( 'shownumberswatching' )) {
- $rc->numberofWatchingusers = $dbr->selectField( 'watchlist',
- 'COUNT(*)',
- array(
- 'wl_namespace' => $obj->rc_namespace,
- 'wl_title' => $obj->rc_title,
- ),
- __METHOD__ );
- } else {
- $rc->numberofWatchingusers = 0;
+ $tables = array( 'recentchanges', 'watchlist' );
+ $fields = array( $dbr->tableName( 'recentchanges' ) . '.*' );
+ $join_conds = array(
+ 'watchlist' => array('INNER JOIN',"wl_user='{$user->getId()}' AND wl_namespace=rc_namespace AND wl_title=rc_title"),
+ );
+ $options = array( 'ORDER BY' => 'rc_timestamp DESC' );
+ if( $wgShowUpdatedMarker ) {
+ $fields[] = 'wl_notificationtimestamp';
+ }
+ if( $limitWatchlist ) {
+ $options['LIMIT'] = $limitWatchlist;
}
- $s .= $list->recentChangesLine( $rc, $updated, $counter );
- }
- $s .= $list->endRecentChangesList();
-
- $wgOut->addHTML( $s );
-}
+ $rollbacker = $user->isAllowed('rollback');
+ if ( $usePage || $rollbacker ) {
+ $tables[] = 'page';
+ $join_conds['page'] = array('LEFT JOIN','rc_cur_id=page_id');
+ if ( $rollbacker ) {
+ $fields[] = 'page_latest';
+ }
+ }
-function wlShowHideLink( $options, $message, $name, $value ) {
- global $wgUser;
+ ChangeTags::modifyDisplayQuery( $tables, $fields, $conds, $join_conds, $options, '' );
+ wfRunHooks('SpecialWatchlistQuery', array(&$conds,&$tables,&$join_conds,&$fields) );
+
+ $res = $dbr->select( $tables, $fields, $conds, __METHOD__, $options, $join_conds );
+ $numRows = $dbr->numRows( $res );
+
+ /* Start bottom header */
+
+ $wlInfo = '';
+ if( $values['days'] >= 1 ) {
+ $timestamp = wfTimestampNow();
+ $wlInfo = wfMsgExt( 'rcnote', 'parseinline',
+ $lang->formatNum( $numRows ),
+ $lang->formatNum( $values['days'] ),
+ $lang->timeAndDate( $timestamp, true ),
+ $lang->date( $timestamp, true ),
+ $lang->time( $timestamp, true )
+ ) . '<br />';
+ } elseif( $values['days'] > 0 ) {
+ $wlInfo = wfMsgExt( 'wlnote', 'parseinline',
+ $lang->formatNum( $numRows ),
+ $lang->formatNum( round( $values['days'] * 24 ) )
+ ) . '<br />';
+ }
- $showLinktext = wfMsgHtml( 'show' );
- $hideLinktext = wfMsgHtml( 'hide' );
- $title = SpecialPage::getTitleFor( 'Watchlist' );
- $skin = $wgUser->getSkin();
+ $cutofflinks = "\n" . $this->cutoffLinks( $values['days'], $nondefaults ) . "<br />\n";
- $label = $value ? $showLinktext : $hideLinktext;
- $options[$name] = 1 - (int) $value;
+ # Spit out some control panel links
+ $filters = array(
+ 'hideMinor' => 'rcshowhideminor',
+ 'hideBots' => 'rcshowhidebots',
+ 'hideAnons' => 'rcshowhideanons',
+ 'hideLiu' => 'rcshowhideliu',
+ 'hideOwn' => 'rcshowhidemine',
+ 'hidePatrolled' => 'rcshowhidepatr'
+ );
+ foreach ( $this->customFilters as $key => $params ) {
+ $filters[$key] = $params['msg'];
+ }
+ // Disable some if needed
+ if ( !$user->useNPPatrol() ) {
+ unset( $filters['hidePatrolled'] );
+ }
- return wfMsgHtml( $message, $skin->linkKnown( $title, $label, array(), $options ) );
-}
+ $links = array();
+ foreach( $filters as $name => $msg ) {
+ $links[] = $this->showHideLink( $nondefaults, $msg, $name, $values[$name] );
+ }
+ # Namespace filter and put the whole form together.
+ $form .= $wlInfo;
+ $form .= $cutofflinks;
+ $form .= $lang->pipeList( $links );
+ $form .= Xml::openElement( 'form', array( 'method' => 'post', 'action' => $this->getTitle()->getLocalUrl(), 'id' => 'mw-watchlist-form-namespaceselector' ) );
+ $form .= '<hr /><p>';
+ $form .= Xml::label( wfMsg( 'namespace' ), 'namespace' ) . '&#160;';
+ $form .= Xml::namespaceSelector( $nameSpace, '' ) . '&#160;';
+ $form .= Xml::checkLabel( wfMsg('invert'), 'invert', 'nsinvert', $invert ) . '&#160;';
+ $form .= Xml::submitButton( wfMsg( 'allpagessubmit' ) ) . '</p>';
+ $form .= Html::hidden( 'days', $values['days'] );
+ foreach ( $filters as $key => $msg ) {
+ if ( $values[$key] ) {
+ $form .= Html::hidden( $key, 1 );
+ }
+ }
+ $form .= Xml::closeElement( 'form' );
+ $form .= Xml::closeElement( 'fieldset' );
+ $output->addHTML( $form );
+
+ # If there's nothing to show, stop here
+ if( $numRows == 0 ) {
+ $output->addWikiMsg( 'watchnochange' );
+ return;
+ }
-function wlHoursLink( $h, $page, $options = array() ) {
- global $wgUser, $wgLang, $wgContLang;
+ /* End bottom header */
- $sk = $wgUser->getSkin();
- $title = Title::newFromText( $wgContLang->specialPage( $page ) );
- $options['days'] = ($h / 24.0);
+ /* Do link batch query */
+ $linkBatch = new LinkBatch;
+ foreach ( $res as $row ) {
+ $userNameUnderscored = str_replace( ' ', '_', $row->rc_user_text );
+ if ( $row->rc_user != 0 ) {
+ $linkBatch->add( NS_USER, $userNameUnderscored );
+ }
+ $linkBatch->add( NS_USER_TALK, $userNameUnderscored );
- $s = $sk->linkKnown(
- $title,
- $wgLang->formatNum( $h ),
- array(),
- $options
- );
+ $linkBatch->add( $row->rc_namespace, $row->rc_title );
+ }
+ $linkBatch->execute();
+ $dbr->dataSeek( $res, 0 );
+
+ $list = ChangesList::newFromContext( $this->getContext() );
+ $list->setWatchlistDivs();
+
+ $s = $list->beginRecentChangesList();
+ $counter = 1;
+ foreach ( $res as $obj ) {
+ # Make RC entry
+ $rc = RecentChange::newFromRow( $obj );
+ $rc->counter = $counter++;
+
+ if ( $wgShowUpdatedMarker ) {
+ $updated = $obj->wl_notificationtimestamp;
+ } else {
+ $updated = false;
+ }
+
+ if ( $wgRCShowWatchingUsers && $user->getOption( 'shownumberswatching' ) ) {
+ $rc->numberofWatchingusers = $dbr->selectField( 'watchlist',
+ 'COUNT(*)',
+ array(
+ 'wl_namespace' => $obj->rc_namespace,
+ 'wl_title' => $obj->rc_title,
+ ),
+ __METHOD__ );
+ } else {
+ $rc->numberofWatchingusers = 0;
+ }
+
+ $s .= $list->recentChangesLine( $rc, $updated, $counter );
+ }
+ $s .= $list->endRecentChangesList();
- return $s;
-}
+ $output->addHTML( $s );
+ }
-function wlDaysLink( $d, $page, $options = array() ) {
- global $wgUser, $wgLang, $wgContLang;
+ protected function showHideLink( $options, $message, $name, $value ) {
+ $showLinktext = wfMsgHtml( 'show' );
+ $hideLinktext = wfMsgHtml( 'hide' );
- $sk = $wgUser->getSkin();
- $title = Title::newFromText( $wgContLang->specialPage( $page ) );
- $options['days'] = $d;
- $message = ($d ? $wgLang->formatNum( $d ) : wfMsgHtml( 'watchlistall2' ) );
+ $label = $value ? $showLinktext : $hideLinktext;
+ $options[$name] = 1 - (int) $value;
- $s = $sk->linkKnown(
- $title,
- $message,
- array(),
- $options
- );
+ return wfMsgHtml( $message, Linker::linkKnown( $this->getTitle(), $label, array(), $options ) );
+ }
- return $s;
-}
+ protected function hoursLink( $h, $options = array() ) {
+ $options['days'] = ( $h / 24.0 );
-/**
- * Returns html
- */
-function wlCutoffLinks( $days, $page = 'Watchlist', $options = array() ) {
- global $wgLang;
-
- $hours = array( 1, 2, 6, 12 );
- $days = array( 1, 3, 7 );
- $i = 0;
- foreach( $hours as $h ) {
- $hours[$i++] = wlHoursLink( $h, $page, $options );
- }
- $i = 0;
- foreach( $days as $d ) {
- $days[$i++] = wlDaysLink( $d, $page, $options );
+ return Linker::linkKnown(
+ $this->getTitle(),
+ $this->getLang()->formatNum( $h ),
+ array(),
+ $options
+ );
}
- return wfMsgExt('wlshowlast',
- array('parseinline', 'replaceafter'),
- $wgLang->pipeList( $hours ),
- $wgLang->pipeList( $days ),
- wlDaysLink( 0, $page, $options ) );
-}
-/**
- * Count the number of items on a user's watchlist
- *
- * @param $user User object
- * @param $talk Boolean: include talk pages
- * @return Integer
- */
-function wlCountItems( &$user, $talk = true ) {
- $dbr = wfGetDB( DB_SLAVE, 'watchlist' );
+ protected function daysLink( $d, $options = array() ) {
+ $options['days'] = $d;
+ $message = ( $d ? $this->getLang()->formatNum( $d ) : wfMsgHtml( 'watchlistall2' ) );
- # Fetch the raw count
- $res = $dbr->select( 'watchlist', 'COUNT(*) AS count',
- array( 'wl_user' => $user->mId ), 'wlCountItems' );
- $row = $dbr->fetchObject( $res );
- $count = $row->count;
+ return Linker::linkKnown(
+ $this->getTitle(),
+ $message,
+ array(),
+ $options
+ );
+ }
- # Halve to remove talk pages if needed
- if( !$talk )
- $count = floor( $count / 2 );
+ /**
+ * Returns html
+ *
+ * @return string
+ */
+ protected function cutoffLinks( $days, $options = array() ) {
+ $hours = array( 1, 2, 6, 12 );
+ $days = array( 1, 3, 7 );
+ $i = 0;
+ foreach( $hours as $h ) {
+ $hours[$i++] = $this->hoursLink( $h, $options );
+ }
+ $i = 0;
+ foreach( $days as $d ) {
+ $days[$i++] = $this->daysLink( $d, $options );
+ }
+ return wfMsgExt('wlshowlast',
+ array('parseinline', 'replaceafter'),
+ $this->getLang()->pipeList( $hours ),
+ $this->getLang()->pipeList( $days ),
+ $this->daysLink( 0, $options ) );
+ }
- return( $count );
+ /**
+ * Count the number of items on a user's watchlist
+ *
+ * @return Integer
+ */
+ protected function countItems() {
+ $dbr = wfGetDB( DB_SLAVE, 'watchlist' );
+
+ # Fetch the raw count
+ $res = $dbr->select( 'watchlist', 'COUNT(*) AS count',
+ array( 'wl_user' => $this->getUser()->getId() ), __METHOD__ );
+ $row = $dbr->fetchObject( $res );
+ $count = $row->count;
+
+ return floor( $count / 2 );
+ }
}
diff --git a/includes/specials/SpecialWhatlinkshere.php b/includes/specials/SpecialWhatlinkshere.php
index 360f3f68..5cdaad6a 100644
--- a/includes/specials/SpecialWhatlinkshere.php
+++ b/includes/specials/SpecialWhatlinkshere.php
@@ -28,23 +28,27 @@
*/
class SpecialWhatLinksHere extends SpecialPage {
- // Stored objects
- protected $opts, $target, $selfTitle;
+ /**
+ * @var FormOptions
+ */
+ protected $opts;
- // Stored globals
- protected $skin;
+ protected $selfTitle;
+
+ /**
+ * @var Title
+ */
+ protected $target;
protected $limits = array( 20, 50, 100, 250, 500 );
public function __construct() {
parent::__construct( 'Whatlinkshere' );
- global $wgUser;
- $this->skin = $wgUser->getSkin();
}
function execute( $par ) {
- global $wgOut, $wgRequest;
-
+ $out = $this->getOutput();
+
$this->setHeaders();
$opts = new FormOptions();
@@ -59,7 +63,7 @@ class SpecialWhatLinksHere extends SpecialPage {
$opts->add( 'hidelinks', false );
$opts->add( 'hideimages', false );
- $opts->fetchValuesFromRequest( $wgRequest );
+ $opts->fetchValuesFromRequest( $this->getRequest() );
$opts->validateIntBounds( 'limit', 0, 5000 );
// Give precedence to subpage syntax
@@ -72,29 +76,32 @@ class SpecialWhatLinksHere extends SpecialPage {
$this->target = Title::newFromURL( $opts->getValue( 'target' ) );
if( !$this->target ) {
- $wgOut->addHTML( $this->whatlinkshereForm() );
+ $out->addHTML( $this->whatlinkshereForm() );
return;
}
+ $this->getSkin()->setRelevantTitle( $this->target );
+
+
$this->selfTitle = $this->getTitle( $this->target->getPrefixedDBkey() );
- $wgOut->setPageTitle( wfMsg( 'whatlinkshere-title', $this->target->getPrefixedText() ) );
- $wgOut->setSubtitle( wfMsg( 'whatlinkshere-backlink', $this->skin->link( $this->target, $this->target->getPrefixedText(), array(), array( 'redirect' => 'no' ) ) ) );
+ $out->setPageTitle( wfMsg( 'whatlinkshere-title', $this->target->getPrefixedText() ) );
+ $out->setSubtitle( wfMsg( 'whatlinkshere-backlink', Linker::link( $this->target, $this->target->getPrefixedText(), array(), array( 'redirect' => 'no' ) ) ) );
$this->showIndirectLinks( 0, $this->target, $opts->getValue( 'limit' ),
$opts->getValue( 'from' ), $opts->getValue( 'back' ) );
}
/**
- * @param $level int Recursion level
+ * @param $level int Recursion level
* @param $target Title Target title
- * @param $limit int Number of entries to display
- * @param $from Title Display from this article ID
- * @param $back Title Display from this article ID at backwards scrolling
- * @private
+ * @param $limit int Number of entries to display
+ * @param $from Title Display from this article ID
+ * @param $back Title Display from this article ID at backwards scrolling
*/
function showIndirectLinks( $level, $target, $limit, $from = 0, $back = 0 ) {
- global $wgOut, $wgMaxRedirectLinksRetrieved;
+ global $wgMaxRedirectLinksRetrieved;
+ $out = $this->getOutput();
$dbr = wfGetDB( DB_SLAVE );
$options = array();
@@ -171,14 +178,14 @@ class SpecialWhatLinksHere extends SpecialPage {
if( ( !$fetchlinks || !$dbr->numRows($plRes) ) && ( $hidetrans || !$dbr->numRows($tlRes) ) && ( $hideimages || !$dbr->numRows($ilRes) ) ) {
if ( 0 == $level ) {
- $wgOut->addHTML( $this->whatlinkshereForm() );
+ $out->addHTML( $this->whatlinkshereForm() );
// Show filters only if there are links
if( $hidelinks || $hidetrans || $hideredirs || $hideimages )
- $wgOut->addHTML( $this->getFilterPanel() );
+ $out->addHTML( $this->getFilterPanel() );
$errMsg = is_int($namespace) ? 'nolinkshere-ns' : 'nolinkshere';
- $wgOut->addWikiMsg( $errMsg, $this->target->getPrefixedText() );
+ $out->addWikiMsg( $errMsg, $this->target->getPrefixedText() );
}
return;
}
@@ -228,31 +235,31 @@ class SpecialWhatLinksHere extends SpecialPage {
$prevId = $from;
if ( $level == 0 ) {
- $wgOut->addHTML( $this->whatlinkshereForm() );
- $wgOut->addHTML( $this->getFilterPanel() );
- $wgOut->addWikiMsg( 'linkshere', $this->target->getPrefixedText() );
+ $out->addHTML( $this->whatlinkshereForm() );
+ $out->addHTML( $this->getFilterPanel() );
+ $out->addWikiMsg( 'linkshere', $this->target->getPrefixedText() );
$prevnext = $this->getPrevNext( $prevId, $nextId );
- $wgOut->addHTML( $prevnext );
+ $out->addHTML( $prevnext );
}
- $wgOut->addHTML( $this->listStart( $level ) );
+ $out->addHTML( $this->listStart( $level ) );
foreach ( $rows as $row ) {
$nt = Title::makeTitle( $row->page_namespace, $row->page_title );
if ( $row->page_is_redirect && $level < 2 ) {
- $wgOut->addHTML( $this->listItem( $row, $nt, true ) );
+ $out->addHTML( $this->listItem( $row, $nt, true ) );
$this->showIndirectLinks( $level + 1, $nt, $wgMaxRedirectLinksRetrieved );
- $wgOut->addHTML( Xml::closeElement( 'li' ) );
+ $out->addHTML( Xml::closeElement( 'li' ) );
} else {
- $wgOut->addHTML( $this->listItem( $row, $nt ) );
+ $out->addHTML( $this->listItem( $row, $nt ) );
}
}
- $wgOut->addHTML( $this->listEnd() );
+ $out->addHTML( $this->listEnd() );
if( $level == 0 ) {
- $wgOut->addHTML( $prevnext );
+ $out->addHTML( $prevnext );
}
}
@@ -261,6 +268,9 @@ class SpecialWhatLinksHere extends SpecialPage {
}
protected function listItem( $row, $nt, $notClose = false ) {
+ global $wgLang;
+ $dirmark = $wgLang->getDirMark();
+
# local message cache
static $msgcache = null;
if ( $msgcache === null ) {
@@ -278,7 +288,7 @@ class SpecialWhatLinksHere extends SpecialPage {
$query = array();
}
- $link = $this->skin->linkKnown(
+ $link = Linker::linkKnown(
$nt,
null,
array(),
@@ -304,8 +314,8 @@ class SpecialWhatLinksHere extends SpecialPage {
$wlh = Xml::wrapClass( "($wlhLink)", 'mw-whatlinkshere-tools' );
return $notClose ?
- Xml::openElement( 'li' ) . "$link $propsText $wlh\n" :
- Xml::tags( 'li', null, "$link $propsText $wlh" ) . "\n";
+ Xml::openElement( 'li' ) . "$link $propsText $dirmark $wlh\n" :
+ Xml::tags( 'li', null, "$link $propsText $dirmark $wlh" ) . "\n";
}
protected function listEnd() {
@@ -317,7 +327,7 @@ class SpecialWhatLinksHere extends SpecialPage {
if ( $title === null )
$title = $this->getTitle();
- return $this->skin->linkKnown(
+ return Linker::linkKnown(
$title,
$text,
array(),
@@ -326,7 +336,7 @@ class SpecialWhatLinksHere extends SpecialPage {
}
function makeSelfLink( $text, $query ) {
- return $this->skin->linkKnown(
+ return Linker::linkKnown(
$this->selfTitle,
$text,
array(),
@@ -378,7 +388,7 @@ class SpecialWhatLinksHere extends SpecialPage {
# Build up the form
$f = Xml::openElement( 'form', array( 'action' => $wgScript ) );
-
+
# Values that should not be forgotten
$f .= Html::hidden( 'title', $this->getTitle()->getPrefixedText() );
foreach ( $this->opts->getUnconsumedValues() as $name => $value ) {
@@ -410,7 +420,7 @@ class SpecialWhatLinksHere extends SpecialPage {
/**
* Create filter panel
- *
+ *
* @return string HTML fieldset and filter panel with the show/hide links
*/
function getFilterPanel() {
diff --git a/includes/specials/SpecialWithoutinterwiki.php b/includes/specials/SpecialWithoutinterwiki.php
index 90c1f441..9d91b833 100644
--- a/includes/specials/SpecialWithoutinterwiki.php
+++ b/includes/specials/SpecialWithoutinterwiki.php
@@ -30,8 +30,14 @@
class WithoutInterwikiPage extends PageQueryPage {
private $prefix = '';
- function getName() {
- return 'Withoutinterwiki';
+ function __construct( $name = 'Withoutinterwiki' ) {
+ parent::__construct( $name );
+ }
+
+ function execute( $par ) {
+ global $wgRequest;
+ $this->prefix = Title::capitalize( $wgRequest->getVal( 'prefix', $par ), NS_MAIN );
+ parent::execute( $par );
}
function getPageHeader() {
@@ -43,9 +49,9 @@ class WithoutInterwikiPage extends PageQueryPage {
}
$prefix = $this->prefix;
- $t = SpecialPage::getTitleFor( $this->getName() );
+ $t = $this->getTitle();
- return Xml::openElement( 'form', array( 'method' => 'get', 'action' => $wgScript ) ) .
+ return Xml::openElement( 'form', array( 'method' => 'get', 'action' => $wgScript ) ) .
Xml::openElement( 'fieldset' ) .
Xml::element( 'legend', null, wfMsg( 'withoutinterwiki-legend' ) ) .
Html::hidden( 'title', $t->getPrefixedText() ) .
@@ -59,6 +65,10 @@ class WithoutInterwikiPage extends PageQueryPage {
return false;
}
+ function getOrderFields() {
+ return array( 'page_namespace', 'page_title' );
+ }
+
function isExpensive() {
return true;
}
@@ -67,36 +77,22 @@ class WithoutInterwikiPage extends PageQueryPage {
return false;
}
- function getSQL() {
- $dbr = wfGetDB( DB_SLAVE );
- list( $page, $langlinks ) = $dbr->tableNamesN( 'page', 'langlinks' );
- $prefix = $this->prefix ? 'AND page_title' . $dbr->buildLike( $this->prefix , $dbr->anyString() ) : '';
- return
- "SELECT 'Withoutinterwiki' AS type,
- page_namespace AS namespace,
- page_title AS title,
- page_title AS value
- FROM $page
- LEFT JOIN $langlinks
- ON ll_from = page_id
- WHERE ll_title IS NULL
- AND page_namespace=" . NS_MAIN . "
- AND page_is_redirect = 0
- {$prefix}";
- }
-
- function setPrefix( $prefix = '' ) {
- $this->prefix = $prefix;
+ function getQueryInfo() {
+ $query = array (
+ 'tables' => array ( 'page', 'langlinks' ),
+ 'fields' => array ( 'page_namespace AS namespace',
+ 'page_title AS title',
+ 'page_title AS value' ),
+ 'conds' => array ( 'll_title IS NULL',
+ 'page_namespace' => NS_MAIN,
+ 'page_is_redirect' => 0 ),
+ 'join_conds' => array ( 'langlinks' => array (
+ 'LEFT JOIN', 'll_from = page_id' ) )
+ );
+ if ( $this->prefix ) {
+ $dbr = wfGetDB( DB_SLAVE );
+ $query['conds'][] = 'page_title ' . $dbr->buildLike( $this->prefix, $dbr->anyString() );
+ }
+ return $query;
}
-
-}
-
-function wfSpecialWithoutinterwiki() {
- global $wgRequest;
- list( $limit, $offset ) = wfCheckLimits();
- // Only searching the mainspace anyway
- $prefix = Title::capitalize( $wgRequest->getVal( 'prefix' ), NS_MAIN );
- $wip = new WithoutInterwikiPage();
- $wip->setPrefix( $prefix );
- $wip->doQuery( $offset, $limit );
}