From 4ac9fa081a7c045f6a9f1cfc529d82423f485b2e Mon Sep 17 00:00:00 2001 From: Pierre Schmitz Date: Sun, 8 Dec 2013 09:55:49 +0100 Subject: Update to MediaWiki 1.22.0 --- includes/specials/SpecialActiveusers.php | 74 ++- includes/specials/SpecialAllmessages.php | 143 +++-- includes/specials/SpecialAllpages.php | 174 +++--- includes/specials/SpecialAncientpages.php | 22 +- includes/specials/SpecialBlankpage.php | 1 + includes/specials/SpecialBlock.php | 49 +- includes/specials/SpecialBlockList.php | 52 +- includes/specials/SpecialBlockme.php | 66 -- includes/specials/SpecialBooksources.php | 49 +- includes/specials/SpecialBrokenRedirects.php | 12 +- includes/specials/SpecialCachedPage.php | 1 - includes/specials/SpecialCategories.php | 38 +- includes/specials/SpecialChangeEmail.php | 67 +- includes/specials/SpecialChangePassword.php | 134 ++-- includes/specials/SpecialComparePages.php | 11 +- includes/specials/SpecialConfirmemail.php | 101 +-- includes/specials/SpecialContributions.php | 380 +++++++----- includes/specials/SpecialDeadendpages.php | 25 +- includes/specials/SpecialDeletedContributions.php | 179 +++--- includes/specials/SpecialDisambiguations.php | 165 ----- includes/specials/SpecialDoubleRedirects.php | 31 +- includes/specials/SpecialEditWatchlist.php | 174 ++++-- includes/specials/SpecialEmailuser.php | 82 ++- includes/specials/SpecialExport.php | 143 +++-- includes/specials/SpecialFewestrevisions.php | 53 +- includes/specials/SpecialFileDuplicateSearch.php | 51 +- includes/specials/SpecialFilepath.php | 62 +- includes/specials/SpecialImport.php | 245 +++++--- includes/specials/SpecialJavaScriptTest.php | 56 +- includes/specials/SpecialLinkSearch.php | 71 ++- includes/specials/SpecialListfiles.php | 301 +++++++-- includes/specials/SpecialListgrouprights.php | 51 +- includes/specials/SpecialListredirects.php | 34 +- includes/specials/SpecialListusers.php | 113 +++- includes/specials/SpecialLog.php | 79 ++- includes/specials/SpecialLonelypages.php | 48 +- includes/specials/SpecialLongpages.php | 1 - includes/specials/SpecialMIMEsearch.php | 97 ++- includes/specials/SpecialMergeHistory.php | 118 ++-- includes/specials/SpecialMostcategories.php | 48 +- includes/specials/SpecialMostimages.php | 19 +- includes/specials/SpecialMostinterwikis.php | 32 +- includes/specials/SpecialMostlinked.php | 69 ++- includes/specials/SpecialMostlinkedcategories.php | 32 +- includes/specials/SpecialMostlinkedtemplates.php | 39 +- includes/specials/SpecialMovepage.php | 263 ++++---- includes/specials/SpecialNewimages.php | 40 +- includes/specials/SpecialNewpages.php | 156 ++--- includes/specials/SpecialPagesWithProp.php | 32 +- includes/specials/SpecialPasswordReset.php | 94 ++- includes/specials/SpecialPopularpages.php | 34 +- includes/specials/SpecialPreferences.php | 26 +- includes/specials/SpecialPrefixindex.php | 147 +++-- includes/specials/SpecialProtectedpages.php | 169 +++-- includes/specials/SpecialProtectedtitles.php | 80 ++- includes/specials/SpecialRandomInCategory.php | 291 +++++++++ includes/specials/SpecialRandompage.php | 31 +- includes/specials/SpecialRandomredirect.php | 1 - includes/specials/SpecialRecentchanges.php | 410 +++++++------ includes/specials/SpecialRecentchangeslinked.php | 63 +- includes/specials/SpecialRedirect.php | 235 +++++++ includes/specials/SpecialResetTokens.php | 145 +++++ includes/specials/SpecialRevisiondelete.php | 170 ++---- includes/specials/SpecialSearch.php | 198 +++--- includes/specials/SpecialShortpages.php | 18 +- includes/specials/SpecialSpecialpages.php | 17 +- includes/specials/SpecialStatistics.php | 37 +- includes/specials/SpecialTags.php | 69 ++- includes/specials/SpecialUnblock.php | 22 +- .../specials/SpecialUncategorizedcategories.php | 6 +- includes/specials/SpecialUncategorizedimages.php | 2 +- includes/specials/SpecialUncategorizedpages.php | 13 +- includes/specials/SpecialUndelete.php | 680 +++++++++++---------- includes/specials/SpecialUnusedcategories.php | 15 +- includes/specials/SpecialUnusedimages.php | 16 +- includes/specials/SpecialUnusedtemplates.php | 16 +- includes/specials/SpecialUnwatchedpages.php | 16 +- includes/specials/SpecialUpload.php | 126 ++-- includes/specials/SpecialUploadStash.php | 29 +- includes/specials/SpecialUserlogin.php | 369 ++++++----- includes/specials/SpecialUserrights.php | 162 +++-- includes/specials/SpecialVersion.php | 203 ++---- includes/specials/SpecialWantedcategories.php | 18 +- includes/specials/SpecialWantedfiles.php | 16 +- includes/specials/SpecialWantedtemplates.php | 14 +- includes/specials/SpecialWatchlist.php | 192 +++--- includes/specials/SpecialWhatlinkshere.php | 69 ++- includes/specials/SpecialWithoutinterwiki.php | 28 +- 88 files changed, 5128 insertions(+), 3402 deletions(-) delete mode 100644 includes/specials/SpecialBlockme.php delete mode 100644 includes/specials/SpecialDisambiguations.php create mode 100644 includes/specials/SpecialRandomInCategory.php create mode 100644 includes/specials/SpecialRedirect.php create mode 100644 includes/specials/SpecialResetTokens.php (limited to 'includes/specials') diff --git a/includes/specials/SpecialActiveusers.php b/includes/specials/SpecialActiveusers.php index c9c82ada..705dab55 100644 --- a/includes/specials/SpecialActiveusers.php +++ b/includes/specials/SpecialActiveusers.php @@ -62,7 +62,7 @@ class ActiveUsersPager extends UsersPager { $this->requestedUser = ''; if ( $un != '' ) { $username = Title::makeTitleSafe( NS_USER, $un ); - if( !is_null( $username ) ) { + if ( !is_null( $username ) ) { $this->requestedUser = $username->getText(); } } @@ -91,42 +91,62 @@ class ActiveUsersPager extends UsersPager { } function getQueryInfo() { - $dbr = wfGetDB( DB_SLAVE ); + $dbr = $this->getDatabase(); + $conds = array( 'rc_user > 0' ); // Users - no anons - if( !$this->getUser()->isAllowed( 'hideuser' ) ) { - $conds[] = 'ipb_deleted IS NULL OR ipb_deleted = 0'; // don't show hidden names - } $conds[] = 'rc_log_type IS NULL OR rc_log_type != ' . $dbr->addQuotes( 'newusers' ); $conds[] = 'rc_timestamp >= ' . $dbr->addQuotes( - $dbr->timestamp( wfTimestamp( TS_UNIX ) - $this->RCMaxAge*24*3600 ) ); + $dbr->timestamp( wfTimestamp( TS_UNIX ) - $this->RCMaxAge * 24 * 3600 ) ); - if( $this->requestedUser != '' ) { + if ( $this->requestedUser != '' ) { $conds[] = 'rc_user_text >= ' . $dbr->addQuotes( $this->requestedUser ); } + if ( !$this->getUser()->isAllowed( 'hideuser' ) ) { + $conds[] = 'NOT EXISTS (' . $dbr->selectSQLText( + 'ipblocks', '1', array( 'rc_user=ipb_user', 'ipb_deleted' => 1 ) + ) . ')'; + } + return array( - 'tables' => array( 'recentchanges', 'ipblocks' ), + 'tables' => array( 'recentchanges' ), 'fields' => array( 'user_name' => 'rc_user_text', // for Pager inheritance 'rc_user_text', // for Pager - 'user_id' => 'rc_user', - 'recentedits' => 'COUNT(*)', - 'ipb_deleted' => 'MAX(ipb_deleted)' + 'user_id' => 'MAX(rc_user)', // Postgres + 'recentedits' => 'COUNT(*)' ), 'options' => array( - 'GROUP BY' => array( 'rc_user_text', 'user_id' ), + 'GROUP BY' => array( 'rc_user_text' ), 'USE INDEX' => array( 'recentchanges' => 'rc_user_text' ) ), - 'join_conds' => array( // check for suppression blocks - 'ipblocks' => array( 'LEFT JOIN', array( - 'rc_user=ipb_user', - 'ipb_auto' => 0 # avoid duplicate blocks - )), - ), 'conds' => $conds ); } + function doBatchLookups() { + $uids = array(); + foreach ( $this->mResult as $row ) { + $uids[] = $row->user_id; + } + // Fetch the block status of the user for showing "(blocked)" text and for + // striking out names of suppressed users when privileged user views the list. + // Although the first query already hits the block table for un-privileged, this + // is done in two queries to avoid huge quicksorts and to make COUNT(*) correct. + $dbr = $this->getDatabase(); + $res = $dbr->select( 'ipblocks', + array( 'ipb_user', 'MAX(ipb_deleted) AS block_status' ), + array( 'ipb_user' => $uids ), + __METHOD__, + array( 'GROUP BY' => array( 'ipb_user' ) ) + ); + $this->blockStatusByUid = array(); + foreach ( $res as $row ) { + $this->blockStatusByUid[$row->ipb_user] = $row->block_status; // 0 or 1 + } + $this->mResult->seek( 0 ); + } + function formatRow( $row ) { $userName = $row->user_name; @@ -139,7 +159,7 @@ class ActiveUsersPager extends UsersPager { $user = User::newFromId( $row->user_id ); // User right filter - foreach( $this->hideRights as $right ) { + foreach ( $this->hideRights as $right ) { // Calling User::getRights() within the loop so that // if the hideRights() filter is empty, we don't have to // trigger the lazy-init of the big userrights array in the @@ -153,7 +173,7 @@ class ActiveUsersPager extends UsersPager { // Note: This is a different loop than for user rights, // because we're reusing it to build the group links // at the same time - foreach( $user->getGroups() as $group ) { + foreach ( $user->getGroups() as $group ) { if ( in_array( $group, $this->hideGroups ) ) { return ''; } @@ -163,12 +183,14 @@ class ActiveUsersPager extends UsersPager { $groups = $lang->commaList( $list ); $item = $lang->specialList( $ulinks, $groups ); - if( $row->ipb_deleted ) { + + $isBlocked = isset( $this->blockStatusByUid[$row->user_id] ); + if ( $isBlocked && $this->blockStatusByUid[$row->user_id] == 1 ) { $item = "$item"; } $count = $this->msg( 'activeusers-count' )->numParams( $row->recentedits ) ->params( $userName )->numParams( $this->RCMaxAge )->escaped(); - $blocked = !is_null( $row->ipb_deleted ) ? ' ' . $this->msg( 'listusers-blocked', $userName )->escaped() : ''; + $blocked = $isBlocked ? ' ' . $this->msg( 'listusers-blocked', $userName )->escaped() : ''; return Html::rawElement( 'li', array(), "{$item} [{$count}]{$blocked}" ); } @@ -184,15 +206,15 @@ class ActiveUsersPager extends UsersPager { $out .= Html::hidden( 'title', $self->getPrefixedDBkey() ) . $limit . "\n"; $out .= Xml::inputLabel( $this->msg( 'activeusers-from' )->text(), - 'username', 'offset', 20, $this->requestedUser ) . '
';# Username field + 'username', 'offset', 20, $this->requestedUser, array( 'tabindex' => 1 ) ) . '
';# Username field $out .= Xml::checkLabel( $this->msg( 'activeusers-hidebots' )->text(), - 'hidebots', 'hidebots', $this->opts->getValue( 'hidebots' ) ); + 'hidebots', 'hidebots', $this->opts->getValue( 'hidebots' ), array( 'tabindex' => 2 ) ); $out .= Xml::checkLabel( $this->msg( 'activeusers-hidesysops' )->text(), - 'hidesysops', 'hidesysops', $this->opts->getValue( 'hidesysops' ) ) . '
'; + 'hidesysops', 'hidesysops', $this->opts->getValue( 'hidesysops' ), array( 'tabindex' => 3 ) ) . '
'; - $out .= Xml::submitButton( $this->msg( 'allpagessubmit' )->text() ) . "\n";# Submit button and form bottom + $out .= Xml::submitButton( $this->msg( 'allpagessubmit' )->text(), array( 'tabindex' => 4 ) ) . "\n";# Submit button and form bottom $out .= Xml::closeElement( 'fieldset' ); $out .= Xml::closeElement( 'form' ); diff --git a/includes/specials/SpecialAllmessages.php b/includes/specials/SpecialAllmessages.php index a60c8efe..35d6a0c0 100644 --- a/includes/specials/SpecialAllmessages.php +++ b/includes/specials/SpecialAllmessages.php @@ -28,7 +28,6 @@ * @ingroup SpecialPage */ class SpecialAllmessages extends SpecialPage { - /** * @var AllmessagesTablePager */ @@ -53,8 +52,9 @@ class SpecialAllmessages extends SpecialPage { $this->setHeaders(); global $wgUseDatabaseMessages; - if( !$wgUseDatabaseMessages ) { + if ( !$wgUseDatabaseMessages ) { $out->addWikiMsg( 'allmessagesnotsupportedDB' ); + return; } else { $this->outputHeader( 'allmessagestext' ); @@ -74,7 +74,6 @@ class SpecialAllmessages extends SpecialPage { $this->table->getNavigationBar() . $this->table->getBody() . $this->table->getNavigationBar() ); - } protected function getGroupName() { @@ -87,7 +86,6 @@ class SpecialAllmessages extends SpecialPage { * 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; @@ -121,15 +119,15 @@ class AllmessagesTablePager extends TablePager { $request = $this->getRequest(); $this->filter = $request->getVal( 'filter', 'all' ); - if( $this->filter === 'all' ) { + if ( $this->filter === 'all' ) { $this->custom = null; // So won't match in either case } else { - $this->custom = ($this->filter == 'unmodified'); + $this->custom = ( $this->filter == 'unmodified' ); } $prefix = $this->getLanguage()->ucfirst( $request->getVal( 'prefix', '' ) ); $prefix = $prefix != '' ? Title::makeTitleSafe( NS_MEDIAWIKI, $request->getVal( 'prefix', null ) ) : null; - if( $prefix !== null ) { + if ( $prefix !== null ) { $this->displayPrefix = $prefix->getDBkey(); $this->prefix = '/^' . preg_quote( $this->displayPrefix ) . '/i'; } else { @@ -139,7 +137,7 @@ class AllmessagesTablePager extends TablePager { // 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 ) { + if ( $this->foreign ) { $this->suffix = '/' . $this->langcode; } else { $this->suffix = ''; @@ -159,36 +157,36 @@ class AllmessagesTablePager extends TablePager { Xml::openElement( 'table', array( 'class' => 'mw-allmessages-table' ) ) . "\n" . ' ' . - Xml::label( $this->msg( 'allmessages-prefix' )->text(), 'mw-allmessages-form-prefix' ) . - "\n - " . - Xml::input( 'prefix', 20, str_replace( '_', ' ', $this->displayPrefix ), array( 'id' => 'mw-allmessages-form-prefix' ) ) . - "\n + Xml::label( $this->msg( 'allmessages-prefix' )->text(), 'mw-allmessages-form-prefix' ) . + "\n + " . + Xml::input( 'prefix', 20, str_replace( '_', ' ', $this->displayPrefix ), array( 'id' => 'mw-allmessages-form-prefix' ) ) . + "\n \n - " . - $this->msg( 'allmessages-filter' )->escaped() . - "\n + " . + $this->msg( 'allmessages-filter' )->escaped() . + "\n " . - Xml::radioLabel( $this->msg( 'allmessages-filter-unmodified' )->text(), - 'filter', - 'unmodified', - 'mw-allmessages-form-filter-unmodified', - ( $this->filter == 'unmodified' ) - ) . - Xml::radioLabel( $this->msg( 'allmessages-filter-all' )->text(), - 'filter', - 'all', - 'mw-allmessages-form-filter-all', - ( $this->filter == 'all' ) - ) . - Xml::radioLabel( $this->msg( 'allmessages-filter-modified' )->text(), - 'filter', - 'modified', - 'mw-allmessages-form-filter-modified', - ( $this->filter == 'modified' ) - ) . - "\n + Xml::radioLabel( $this->msg( 'allmessages-filter-unmodified' )->text(), + 'filter', + 'unmodified', + 'mw-allmessages-form-filter-unmodified', + ( $this->filter == 'unmodified' ) + ) . + Xml::radioLabel( $this->msg( 'allmessages-filter-all' )->text(), + 'filter', + 'all', + 'mw-allmessages-form-filter-all', + ( $this->filter == 'all' ) + ) . + Xml::radioLabel( $this->msg( 'allmessages-filter-modified' )->text(), + 'filter', + 'modified', + 'mw-allmessages-form-filter-modified', + ( $this->filter == 'modified' ) + ) . + "\n \n " . $langSelect[0] . "\n @@ -197,29 +195,30 @@ class AllmessagesTablePager extends TablePager { ' ' . - Xml::label( $this->msg( 'table_pager_limit_label' )->text(), 'mw-table_pager_limit_label' ) . - ' - ' . - $this->getLimitSelect() . - ' + Xml::label( $this->msg( 'table_pager_limit_label' )->text(), 'mw-table_pager_limit_label' ) . + ' + ' . + $this->getLimitSelect() . + ' ' . - Xml::submitButton( $this->msg( 'allmessages-filter-submit' )->text() ) . - "\n + Xml::submitButton( $this->msg( 'allmessages-filter-submit' )->text() ) . + "\n " . Xml::closeElement( 'table' ) . $this->getHiddenFields( array( 'title', 'prefix', 'filter', 'lang', 'limit' ) ) . Xml::closeElement( 'fieldset' ) . Xml::closeElement( 'form' ); + return $out; } function getAllMessages( $descending ) { wfProfileIn( __METHOD__ ); $messageNames = Language::getLocalisationCache()->getSubitemList( 'en', 'messages' ); - if( $descending ) { + if ( $descending ) { rsort( $messageNames ); } else { asort( $messageNames ); @@ -229,6 +228,7 @@ class AllmessagesTablePager extends TablePager { $messageNames = array_map( array( $this->lang, 'ucfirst' ), $messageNames ); wfProfileOut( __METHOD__ ); + return $messageNames; } @@ -260,18 +260,19 @@ class AllmessagesTablePager extends TablePager { foreach ( $res as $s ) { $exists = false; - if( $foreign ) { + if ( $foreign ) { $title = explode( '/', $s->page_title ); - if( count( $title ) === 2 && $langcode == $title[1] - && isset( $xNames[$title[0]] ) ) { + if ( count( $title ) === 2 && $langcode == $title[1] + && isset( $xNames[$title[0]] ) + ) { $exists = $title[0]; } - } elseif( isset( $xNames[$s->page_title] ) ) { + } elseif ( isset( $xNames[$s->page_title] ) ) { $exists = $s->page_title; } - if( $exists && $s->page_namespace == NS_MEDIAWIKI ) { + if ( $exists && $s->page_namespace == NS_MEDIAWIKI ) { $pageFlags[$exists] = true; - } elseif( $exists && $s->page_namespace == NS_MEDIAWIKI_TALK ) { + } elseif ( $exists && $s->page_namespace == NS_MEDIAWIKI_TALK ) { $talkFlags[$exists] = true; } } @@ -284,6 +285,9 @@ class AllmessagesTablePager extends TablePager { /** * This function normally does a database query to get the results; we need * to make a pretend result using a FakeResultWrapper. + * @param string $offset + * @param int $limit + * @param bool $descending * @return FakeResultWrapper */ function reallyDoQuery( $offset, $limit, $descending ) { @@ -293,27 +297,29 @@ class AllmessagesTablePager extends TablePager { $statuses = self::getCustomisedStatuses( $messageNames, $this->langcode, $this->foreign ); $count = 0; - foreach( $messageNames as $key ) { + foreach ( $messageNames as $key ) { $customised = isset( $statuses['pages'][$key] ); - if( $customised !== $this->custom && + 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' => $actual, - 'am_default' => $default, + 'am_title' => $key, + 'am_actual' => $actual, + 'am_default' => $default, 'am_customised' => $customised, 'am_talk_exists' => isset( $statuses['talks'][$key] ) ); $count++; } - if( $count == $limit ) { + + if ( $count == $limit ) { break; } } + return $result; } @@ -321,26 +327,26 @@ class AllmessagesTablePager extends TablePager { return Xml::openElement( 'table', array( 'class' => 'mw-datatable TablePager', 'id' => 'mw-allmessagestable' ) ) . "\n" . " " . - $this->msg( 'allmessagesname' )->escaped() . " + $this->msg( 'allmessagesname' )->escaped() . " " . - $this->msg( 'allmessagesdefault' )->escaped() . - " + $this->msg( 'allmessagesdefault' )->escaped() . + " \n " . - $this->msg( 'allmessagescurrent' )->escaped() . - " + $this->msg( 'allmessagescurrent' )->escaped() . + " \n"; } function formatValue( $field, $value ) { - switch( $field ) { + switch ( $field ) { case 'am_title' : $title = Title::makeTitle( NS_MEDIAWIKI, $value . $this->suffix ); $talk = Title::makeTitle( NS_MEDIAWIKI_TALK, $value . $this->suffix ); - if( $this->mCurrentRow->am_customised ) { + if ( $this->mCurrentRow->am_customised ) { $title = Linker::linkKnown( $title, $this->getLanguage()->lcfirst( $value ) ); } else { $title = Linker::link( @@ -362,6 +368,7 @@ class AllmessagesTablePager extends TablePager { array( 'broken' ) ); } + return $title . ' ' . $this->msg( 'parentheses' )->rawParams( $talk )->escaped(); case 'am_default' : @@ -376,7 +383,7 @@ class AllmessagesTablePager extends TablePager { $s = parent::formatRow( $row ); // But if there's a customised message, add that too. - if( $row->am_customised ) { + if ( $row->am_customised ) { $s .= Xml::openElement( 'tr', $this->getRowAttrs( $row, true ) ); $formatted = strval( $this->formatValue( 'am_actual', $row->am_actual ) ); if ( $formatted == '' ) { @@ -385,24 +392,26 @@ class AllmessagesTablePager extends TablePager { $s .= Xml::tags( 'td', $this->getCellAttrs( 'am_actual', $row->am_actual ), $formatted ) . "\n"; } + return $s; } function getRowAttrs( $row, $isSecond = false ) { $arr = array(); - if( $row->am_customised ) { + if ( $row->am_customised ) { $arr['class'] = 'allmessages-customised'; } - if( !$isSecond ) { + if ( !$isSecond ) { $arr['id'] = Sanitizer::escapeId( 'msg_' . $this->getLanguage()->lcfirst( $row->am_title ) ); } + return $arr; } function getCellAttrs( $field, $value ) { - if( $this->mCurrentRow->am_customised && $field == 'am_title' ) { + if ( $this->mCurrentRow->am_customised && $field == 'am_title' ) { return array( 'rowspan' => '2', 'class' => $field ); - } elseif( $field == 'am_title' ) { + } elseif ( $field == 'am_title' ) { return array( 'class' => $field ); } else { return array( 'lang' => $this->langcode, 'dir' => $this->lang->getDir(), 'class' => $field ); diff --git a/includes/specials/SpecialAllpages.php b/includes/specials/SpecialAllpages.php index f9cb5cd8..a0820493 100644 --- a/includes/specials/SpecialAllpages.php +++ b/includes/specials/SpecialAllpages.php @@ -71,7 +71,6 @@ class SpecialAllpages extends IncludableSpecialPage { * @param string $par becomes "FOO" when called like Special:Allpages/FOO (default NULL) */ function execute( $par ) { - global $wgContLang; $request = $this->getRequest(); $out = $this->getOutput(); @@ -85,18 +84,18 @@ class SpecialAllpages extends IncludableSpecialPage { $namespace = $request->getInt( 'namespace' ); $hideredirects = $request->getBool( 'hideredirects', false ); - $namespaces = $wgContLang->getNamespaces(); + $namespaces = $this->getContext()->getLanguage()->getNamespaces(); $out->setPageTitle( - ( $namespace > 0 && in_array( $namespace, array_keys( $namespaces) ) ) ? - $this->msg( 'allinnamespace', str_replace( '_', ' ', $namespaces[$namespace] ) ) : - $this->msg( 'allarticles' ) + ( $namespace > 0 && in_array( $namespace, array_keys( $namespaces ) ) ) ? + $this->msg( 'allinnamespace', str_replace( '_', ' ', $namespaces[$namespace] ) ) : + $this->msg( 'allarticles' ) ); $out->addModuleStyles( 'mediawiki.special' ); - if( $par !== null ) { + if ( $par !== null ) { $this->showChunk( $namespace, $par, $to, $hideredirects ); - } elseif( $from !== null && $to === null ) { + } elseif ( $from !== null && $to === null ) { $this->showChunk( $namespace, $from, $to, $hideredirects ); } else { $this->showToplevel( $namespace, $from, $to, $hideredirects ); @@ -160,6 +159,7 @@ class SpecialAllpages extends IncludableSpecialPage { $out .= Xml::closeElement( 'fieldset' ); $out .= Xml::closeElement( 'form' ); $out .= Xml::closeElement( 'div' ); + return $out; } @@ -188,10 +188,13 @@ class SpecialAllpages extends IncludableSpecialPage { $from = ( $from && $from->isLocal() ) ? $from->getDBkey() : null; $to = ( $to && $to->isLocal() ) ? $to->getDBkey() : null; - if( isset( $from ) ) + if ( isset( $from ) ) { $where[] = 'page_title >= ' . $dbr->addQuotes( $from ); - if( isset( $to ) ) + } + + if ( isset( $to ) ) { $where[] = 'page_title <= ' . $dbr->addQuotes( $to ); + } global $wgMemc; $key = wfMemcKey( 'allpages', 'ns', $namespace, sha1( $from ), sha1( $to ) ); @@ -201,7 +204,7 @@ class SpecialAllpages extends IncludableSpecialPage { $maxPerSubpage = intval( $count / $this->maxLineCount ); $maxPerSubpage = max( $maxPerSubpage, $this->maxPerPage ); - if( !is_array( $lines ) ) { + if ( !is_array( $lines ) ) { $options = array( 'LIMIT' => 1 ); $options['ORDER BY'] = 'page_title ASC'; $firstTitle = $dbr->selectField( 'page', 'page_title', $where, __METHOD__, $options ); @@ -210,7 +213,7 @@ class SpecialAllpages extends IncludableSpecialPage { $lines = array( $firstTitle ); # If we are going to show n rows, we need n+1 queries to find the relevant titles. $done = false; - while( !$done ) { + while ( !$done ) { // Fetch the last title of this chunk and the first of the next $chunk = ( $lastTitle === false ) ? array() @@ -223,7 +226,7 @@ class SpecialAllpages extends IncludableSpecialPage { ); $s = $dbr->fetchObject( $res ); - if( $s ) { + if ( $s ) { array_push( $lines, $s->page_title ); } else { // Final chunk, but ended prematurely. Go back and find the end. @@ -233,8 +236,9 @@ class SpecialAllpages extends IncludableSpecialPage { array_push( $lines, $endTitle ); $done = true; } + $s = $res->fetchObject(); - if( $s ) { + if ( $s ) { array_push( $lines, $s->page_title ); $lastTitle = $s->page_title; } else { @@ -249,18 +253,19 @@ class SpecialAllpages extends IncludableSpecialPage { // If there are only two or less sections, don't even display them. // Instead, display the first section directly. - if( count( $lines ) <= 2 ) { - if( !empty( $lines ) ) { + if ( count( $lines ) <= 2 ) { + if ( !empty( $lines ) ) { $this->showChunk( $namespace, $from, $to, $hideredirects ); } else { $output->addHTML( $this->namespaceForm( $namespace, $from, $to, $hideredirects ) ); } + return; } # At this point, $lines should contain an even number of elements. $out .= Xml::openElement( 'table', array( 'class' => 'allpageslist' ) ); - while( count ( $lines ) > 0 ) { + while ( count( $lines ) > 0 ) { $inpoint = array_shift( $lines ); $outpoint = array_shift( $lines ); $out .= $this->showline( $inpoint, $outpoint, $namespace, $hideredirects ); @@ -269,19 +274,19 @@ class SpecialAllpages extends IncludableSpecialPage { $nsForm = $this->namespaceForm( $namespace, $from, $to, $hideredirects ); # Is there more? - if( $this->including() ) { + if ( $this->including() ) { $out2 = ''; } else { - if( isset( $from ) || isset( $to ) ) { - $out2 = Xml::openElement( 'table', array( 'class' => 'mw-allpages-table-form' ) ). - ' + if ( isset( $from ) || isset( $to ) ) { + $out2 = Xml::openElement( 'table', array( 'class' => 'mw-allpages-table-form' ) ) . + ' ' . - $nsForm . - ' + $nsForm . + ' ' . - Linker::link( $this->getTitle(), $this->msg( 'allpages' )->escaped(), - array(), array(), 'known' ) . - " + Linker::link( $this->getTitle(), $this->msg( 'allpages' )->escaped(), + array(), array(), 'known' ) . + " " . Xml::closeElement( 'table' ); } else { @@ -297,47 +302,56 @@ class SpecialAllpages extends IncludableSpecialPage { * @param string $inpoint lower limit of pagenames * @param string $outpoint upper limit of pagenames * @param $namespace Integer (Default NS_MAIN) - * @param bool $hideredirects dont show redirects (default FALSE) + * @param bool $hideRedirects don't show redirects. Default: false * @return string */ - function showline( $inpoint, $outpoint, $namespace = NS_MAIN, $hideredirects ) { + function showline( $inpoint, $outpoint, $namespace = NS_MAIN, $hideRedirects = false ) { + // Use content language since page titles are considered to use content language global $wgContLang; - $inpointf = htmlspecialchars( str_replace( '_', ' ', $inpoint ) ); - $outpointf = htmlspecialchars( str_replace( '_', ' ', $outpoint ) ); + + $inpointf = str_replace( '_', ' ', $inpoint ); + $outpointf = str_replace( '_', ' ', $outpoint ); + // Don't let the length runaway $inpointf = $wgContLang->truncate( $inpointf, $this->maxPageLength ); $outpointf = $wgContLang->truncate( $outpointf, $this->maxPageLength ); - $queryparams = $namespace ? "namespace=$namespace&" : ''; + $queryParams = array( + 'from' => $inpoint, + 'to' => $outpoint, + ); - $queryhideredirects = array(); - if ( $hideredirects ) { - $queryhideredirects['hideredirects'] = 1; + if ( $namespace ) { + $queryParams['namespace'] = $namespace; + } + if ( $hideRedirects ) { + $queryParams['hideredirects'] = 1; } - $special = $this->getTitle(); - $link = htmlspecialchars( $special->getLocalUrl( $queryparams . 'from=' . urlencode( $inpoint ) . '&to=' . urlencode( $outpoint ), $queryhideredirects ) ); + $url = $this->getTitle()->getLocalURL( $queryParams ); + $inlink = Html::element( 'a', array( 'href' => $url ), $inpointf ); + $outlink = Html::element( 'a', array( 'href' => $url ), $outpointf ); $out = $this->msg( 'alphaindexline' )->rawParams( - "$inpointf", - "$outpointf" + "$inlink", + "$outlink" )->escaped(); + return '' . $out . ''; } /** - * @param $namespace Integer (Default NS_MAIN) + * @param int $namespace Namespace (Default NS_MAIN) * @param string $from list all pages from this name (default FALSE) * @param string $to list all pages to this name (default FALSE) * @param bool $hideredirects dont show redirects (default FALSE) */ function showChunk( $namespace = NS_MAIN, $from = false, $to = false, $hideredirects = false ) { - global $wgContLang; $output = $this->getOutput(); $fromList = $this->getNamespaceKeyAndText( $namespace, $from ); $toList = $this->getNamespaceKeyAndText( $namespace, $to ); - $namespaces = $wgContLang->getNamespaces(); + $namespaces = $this->getContext()->getLanguage()->getNamespaces(); $n = 0; if ( !$fromList || !$toList ) { @@ -360,7 +374,7 @@ class SpecialAllpages extends IncludableSpecialPage { $conds['page_is_redirect'] = 0; } - if( $toKey !== "" ) { + if ( $toKey !== "" ) { $conds[] = 'page_title <= ' . $dbr->addQuotes( $toKey ); } @@ -369,33 +383,36 @@ class SpecialAllpages extends IncludableSpecialPage { $conds, __METHOD__, array( - 'ORDER BY' => 'page_title', - 'LIMIT' => $this->maxPerPage + 1, + 'ORDER BY' => 'page_title', + 'LIMIT' => $this->maxPerPage + 1, 'USE INDEX' => 'name_title', ) ); - if( $res->numRows() > 0 ) { + if ( $res->numRows() > 0 ) { $out = Xml::openElement( 'table', array( 'class' => 'mw-allpages-table-chunk' ) ); - while( ( $n < $this->maxPerPage ) && ( $s = $res->fetchObject() ) ) { + while ( ( $n < $this->maxPerPage ) && ( $s = $res->fetchObject() ) ) { $t = Title::newFromRow( $s ); - if( $t ) { + if ( $t ) { $link = ( $s->page_is_redirect ? '
' : '' ) . Linker::link( $t ) . - ($s->page_is_redirect ? '
' : '' ); + ( $s->page_is_redirect ? '' : '' ); } else { $link = '[[' . htmlspecialchars( $s->page_title ) . ']]'; } - if( $n % 3 == 0 ) { + + if ( $n % 3 == 0 ) { $out .= ''; } + $out .= "$link"; $n++; - if( $n % 3 == 0 ) { + if ( $n % 3 == 0 ) { $out .= "\n"; } } - if( ($n % 3) != 0 ) { + + if ( ( $n % 3 ) != 0 ) { $out .= "\n"; } $out .= Xml::closeElement( 'table' ); @@ -407,7 +424,7 @@ class SpecialAllpages extends IncludableSpecialPage { if ( $this->including() ) { $out2 = ''; } else { - if( $from == '' ) { + if ( $from == '' ) { // First chunk; no previous link. $prevTitle = null; } else { @@ -424,20 +441,20 @@ class SpecialAllpages extends IncludableSpecialPage { ); # Get first title of previous complete chunk - if( $dbr->numrows( $res_prev ) >= $this->maxPerPage ) { + if ( $dbr->numrows( $res_prev ) >= $this->maxPerPage ) { $pt = $dbr->fetchObject( $res_prev ); $prevTitle = Title::makeTitle( $namespace, $pt->page_title ); } else { # The previous chunk is not complete, need to link to the very first title # available in the database $options = array( 'LIMIT' => 1 ); - if ( ! $dbr->implicitOrderby() ) { + if ( !$dbr->implicitOrderby() ) { $options['ORDER BY'] = 'page_title'; } $reallyFirstPage_title = $dbr->selectField( 'page', 'page_title', array( 'page_namespace' => $namespace ), __METHOD__, $options ); # Show the previous link if it s not the current requested chunk - if( $from != $reallyFirstPage_title ) { + if ( $from != $reallyFirstPage_title ) { $prevTitle = Title::makeTitle( $namespace, $reallyFirstPage_title ); } else { $prevTitle = null; @@ -448,23 +465,25 @@ class SpecialAllpages extends IncludableSpecialPage { $self = $this->getTitle(); $nsForm = $this->namespaceForm( $namespace, $from, $to, $hideredirects ); - $out2 = Xml::openElement( 'table', array( 'class' => 'mw-allpages-table-form' ) ). - ' + $out2 = Xml::openElement( 'table', array( 'class' => 'mw-allpages-table-form' ) ) . + ' ' . - $nsForm . - ' + $nsForm . + ' ' . - Linker::link( $self, $this->msg( 'allpages' )->escaped() ); + Linker::link( $self, $this->msg( 'allpages' )->escaped() ); # Do we put a previous link ? - if( isset( $prevTitle ) && $pt = $prevTitle->getText() ) { + if ( isset( $prevTitle ) && $pt = $prevTitle->getText() ) { $query = array( 'from' => $prevTitle->getText() ); - if( $namespace ) + if ( $namespace ) { $query['namespace'] = $namespace; + } - if( $hideredirects ) + if ( $hideredirects ) { $query['hideredirects'] = $hideredirects; + } $prevLink = Linker::linkKnown( $self, @@ -475,16 +494,18 @@ class SpecialAllpages extends IncludableSpecialPage { $out2 = $this->getLanguage()->pipeList( array( $out2, $prevLink ) ); } - if( $n == $this->maxPerPage && $s = $res->fetchObject() ) { + if ( $n == $this->maxPerPage && $s = $res->fetchObject() ) { # $s is the first link of the next chunk $t = Title::makeTitle( $namespace, $s->page_title ); $query = array( 'from' => $t->getText() ); - if( $namespace ) + if ( $namespace ) { $query['namespace'] = $namespace; + } - if( $hideredirects ) + if ( $hideredirects ) { $query['hideredirects'] = $hideredirects; + } $nextLink = Linker::linkKnown( $self, @@ -500,17 +521,22 @@ class SpecialAllpages extends IncludableSpecialPage { $output->addHTML( $out2 . $out ); $links = array(); - if ( isset( $prevLink ) ) $links[] = $prevLink; - if ( isset( $nextLink ) ) $links[] = $nextLink; + 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' ), - $this->getLanguage()->pipeList( $links ) - ) ); + Html::rawElement( 'div', array( 'class' => 'mw-allpages-nav' ), + $this->getLanguage()->pipeList( $links ) + ) + ); } - } /** @@ -519,8 +545,10 @@ class SpecialAllpages extends IncludableSpecialPage { * @return array( int namespace, string dbkey, string pagename ) or NULL on error */ protected function getNamespaceKeyAndText( $ns, $text ) { - if ( $text == '' ) - return array( $ns, '', '' ); # shortcut for common case + if ( $text == '' ) { + # shortcut for common case + return array( $ns, '', '' ); + } $t = Title::makeTitleSafe( $ns, $text ); if ( $t && $t->isLocal() ) { diff --git a/includes/specials/SpecialAncientpages.php b/includes/specials/SpecialAncientpages.php index b0f333c4..b0830327 100644 --- a/includes/specials/SpecialAncientpages.php +++ b/includes/specials/SpecialAncientpages.php @@ -43,12 +43,16 @@ class AncientPagesPage extends QueryPage { function getQueryInfo() { return array( 'tables' => array( 'page', 'revision' ), - 'fields' => array( 'namespace' => 'page_namespace', - 'title' => 'page_title', - 'value' => 'rev_timestamp' ), - 'conds' => array( 'page_namespace' => MWNamespace::getContentNamespaces(), - 'page_is_redirect' => 0, - 'page_latest=rev_id' ) + 'fields' => array( + 'namespace' => 'page_namespace', + 'title' => 'page_title', + 'value' => 'rev_timestamp' + ), + 'conds' => array( + 'page_namespace' => MWNamespace::getContentNamespaces(), + 'page_is_redirect' => 0, + 'page_latest=rev_id' + ) ); } @@ -60,6 +64,11 @@ class AncientPagesPage extends QueryPage { return false; } + /** + * @param Skin $skin + * @param object $result Result row + * @return string + */ function formatResult( $skin, $result ) { global $wgContLang; @@ -69,6 +78,7 @@ class AncientPagesPage extends QueryPage { $title, htmlspecialchars( $wgContLang->convert( $title->getPrefixedText() ) ) ); + return $this->getLanguage()->specialList( $link, htmlspecialchars( $d ) ); } diff --git a/includes/specials/SpecialBlankpage.php b/includes/specials/SpecialBlankpage.php index bfa2f951..e61f12b9 100644 --- a/includes/specials/SpecialBlankpage.php +++ b/includes/specials/SpecialBlankpage.php @@ -31,6 +31,7 @@ class SpecialBlankpage extends UnlistedSpecialPage { public function __construct() { parent::__construct( 'Blankpage' ); } + public function execute( $par ) { $this->setHeaders(); $this->getOutput()->addWikiMsg( 'intentionallyblankpage' ); diff --git a/includes/specials/SpecialBlock.php b/includes/specials/SpecialBlock.php index 50fdbc26..3b73a374 100644 --- a/includes/specials/SpecialBlock.php +++ b/includes/specials/SpecialBlock.php @@ -110,10 +110,10 @@ class SpecialBlock extends FormSpecialPage { $s = HTMLForm::formatErrors( $this->preErrors ); if ( $s ) { $form->addHeaderText( Html::rawElement( - 'div', - array( 'class' => 'error' ), - $s - ) ); + 'div', + array( 'class' => 'error' ), + $s + ) ); } } } @@ -127,6 +127,8 @@ class SpecialBlock extends FormSpecialPage { $user = $this->getUser(); + $suggestedDurations = self::getSuggestedDurations(); + $a = array( 'Target' => array( 'type' => 'text', @@ -139,11 +141,11 @@ class SpecialBlock extends FormSpecialPage { 'validation-callback' => array( __CLASS__, 'validateTargetField' ), ), 'Expiry' => array( - 'type' => !count( self::getSuggestedDurations() ) ? 'text' : 'selectorother', + 'type' => !count( $suggestedDurations ) ? 'text' : 'selectorother', 'label-message' => 'ipbexpiry', 'required' => true, 'tabindex' => '2', - 'options' => self::getSuggestedDurations(), + 'options' => $suggestedDurations, 'other' => $this->msg( 'ipbother' )->text(), 'default' => $this->msg( 'ipb-default-expiry' )->inContentLanguage()->text(), ), @@ -241,8 +243,7 @@ class SpecialBlock extends FormSpecialPage { 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(); @@ -445,6 +446,7 @@ class SpecialBlock extends FormSpecialPage { } elseif ( IP::isIPAddress( $target ) ) { return Title::makeTitleSafe( NS_USER, $target ); } + return null; } @@ -460,8 +462,8 @@ class SpecialBlock extends FormSpecialPage { $i = 0; $target = null; - while( true ) { - switch( $i++ ) { + 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 @@ -511,6 +513,7 @@ class SpecialBlock extends FormSpecialPage { $status = self::validateTarget( $value, $form->getUser() ); if ( !$status->isOK() ) { $errors = $status->getErrorsArray(); + return call_user_func_array( array( $form, 'msg' ), $errors[0] ); } else { return true; @@ -528,6 +531,7 @@ class SpecialBlock extends FormSpecialPage { public static function validateTarget( $value, User $user ) { global $wgBlockCIDRLimit; + /** @var User $target */ list( $target, $type ) = self::getTargetAndType( $value ); $status = Status::newGood( $target ); @@ -606,6 +610,7 @@ class SpecialBlock extends FormSpecialPage { # can come from it $data['Confirm'] = !in_array( $data['Confirm'], array( '', '0', null, false ), true ); + /** @var User $target */ list( $target, $type ) = self::getTargetAndType( $data['Target'] ); if ( $type == Block::TYPE_USER ) { $user = $target; @@ -620,8 +625,8 @@ class SpecialBlock extends FormSpecialPage { # but $data['target'] gets overriden by (non-normalized) request variable # from previous request. if ( $target === $performer->getName() && - ( $data['PreviousTarget'] !== $target || !$data['Confirm'] ) ) - { + ( $data['PreviousTarget'] !== $target || !$data['Confirm'] ) + ) { return array( 'ipb-blockingself' ); } } elseif ( $type == Block::TYPE_RANGE ) { @@ -634,9 +639,9 @@ class SpecialBlock extends FormSpecialPage { return array( 'badipaddress' ); } - if ( ( strlen( $data['Expiry'] ) == 0) || ( strlen( $data['Expiry'] ) > 50 ) - || !self::parseExpiryInput( $data['Expiry'] ) ) - { + if ( ( strlen( $data['Expiry'] ) == 0 ) || ( strlen( $data['Expiry'] ) > 50 ) + || !self::parseExpiryInput( $data['Expiry'] ) + ) { return array( 'ipb_expiry_invalid' ); } @@ -703,9 +708,9 @@ class SpecialBlock extends FormSpecialPage { $reblockNotAllowed = ( array_key_exists( 'Reblock', $data ) && !$data['Reblock'] ); # Show form unless the user is already aware of this... - if( $blockNotConfirmed || $reblockNotAllowed ) { + if ( $blockNotConfirmed || $reblockNotAllowed ) { return array( array( 'ipb_already_blocked', $block->getTarget() ) ); - # Otherwise, try to update the block... + # 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 @@ -748,7 +753,7 @@ class SpecialBlock extends FormSpecialPage { # Can't watch a rangeblock if ( $type != Block::TYPE_RANGE && $data['Watch'] ) { - $performer->addWatch( Title::makeTitle( NS_USER, $target ) ); + WatchAction::doWatch( Title::makeTitle( NS_USER, $target ), $performer, WatchedItem::IGNORE_USER_RIGHTS ); } # Block constructor sanitizes certain block options on insert @@ -767,7 +772,8 @@ class SpecialBlock extends FormSpecialPage { $logaction, Title::makeTitle( NS_USER, $target ), $data['Reason'][0], - $logParams + $logParams, + $performer ); # Relate log ID to block IDs (bug 25763) $blockIds = array_merge( array( $status['id'] ), $status['autoIds'] ); @@ -865,7 +871,7 @@ class SpecialBlock extends FormSpecialPage { # User is trying to unblock themselves if ( $performer->isAllowed( 'unblockself' ) ) { return true; - # User blocked themselves and is now trying to reverse it + # User blocked themselves and is now trying to reverse it } elseif ( $performer->blockedBy() === $performer->getName() ) { return true; } else { @@ -953,4 +959,5 @@ class SpecialBlock extends FormSpecialPage { } # BC @since 1.18 -class IPBlockForm extends SpecialBlock {} +class IPBlockForm extends SpecialBlock { +} diff --git a/includes/specials/SpecialBlockList.php b/includes/specials/SpecialBlockList.php index e10df4fe..f1992c0f 100644 --- a/includes/specials/SpecialBlockList.php +++ b/includes/specials/SpecialBlockList.php @@ -55,10 +55,11 @@ class SpecialBlockList extends SpecialPage { $action = $request->getText( 'action' ); - if( $action == 'unblock' || $action == 'submit' && $request->wasPosted() ) { + if ( $action == 'unblock' || $action == 'submit' && $request->wasPosted() ) { # B/C @since 1.18: Unblock interface is now at Special:Unblock $title = SpecialPage::getTitleFor( 'Unblock', $this->target ); - $out->redirect( $title->getFullUrl() ); + $out->redirect( $title->getFullURL() ); + return; } @@ -95,7 +96,9 @@ class SpecialBlockList extends SpecialPage { 'default' => 50, ), ); - $form = new HTMLForm( $fields, $this->getContext() ); + $context = new DerivativeContext( $this->getContext() ); + $context->setTitle( $this->getTitle() ); // Remove subpage + $form = new HTMLForm( $fields, $context ); $form->setMethod( 'get' ); $form->setWrapperLegendMsg( 'ipblocklist-legend' ); $form->setSubmitTextMsg( 'ipblocklist-submit' ); @@ -120,7 +123,7 @@ class SpecialBlockList extends SpecialPage { if ( $this->target !== '' ) { list( $target, $type ) = Block::parseTarget( $this->target ); - switch( $type ) { + switch ( $type ) { case Block::TYPE_ID: case Block::TYPE_AUTO: $conds['ipb_id'] = $target; @@ -141,23 +144,23 @@ class SpecialBlockList extends SpecialPage { break; case Block::TYPE_USER: - $conds['ipb_address'] = (string)$this->target; + $conds['ipb_address'] = $target->getName(); $conds['ipb_auto'] = 0; break; } } # Apply filters - if( in_array( 'userblocks', $this->options ) ) { + if ( in_array( 'userblocks', $this->options ) ) { $conds['ipb_user'] = 0; } - if( in_array( 'tempblocks', $this->options ) ) { + if ( in_array( 'tempblocks', $this->options ) ) { $conds['ipb_expiry'] = 'infinity'; } - if( in_array( 'addressblocks', $this->options ) ) { + if ( in_array( 'addressblocks', $this->options ) ) { $conds[] = "ipb_user != 0 OR ipb_range_end > ipb_range_start"; } - if( in_array( 'rangeblocks', $this->options ) ) { + if ( in_array( 'rangeblocks', $this->options ) ) { $conds[] = "ipb_range_end = ipb_range_start"; } @@ -169,7 +172,7 @@ class SpecialBlockList extends SpecialPage { # 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 ) ) { + if ( count( $otherBlockLink ) ) { $out->addHTML( Html::element( 'h2', array(), $this->msg( 'ipblocklist-localblock' )->text() ) . "\n" ); @@ -179,18 +182,16 @@ class SpecialBlockList extends SpecialPage { if ( $pager->getNumRows() ) { $out->addHTML( $pager->getNavigationBar() . - $pager->getBody(). - $pager->getNavigationBar() + $pager->getBody() . + $pager->getNavigationBar() ); - } elseif ( $this->target ) { $out->addWikiMsg( 'ipblocklist-no-results' ); - } else { $out->addWikiMsg( 'ipblocklist-empty' ); } - if( count( $otherBlockLink ) ) { + if ( count( $otherBlockLink ) ) { $out->addHTML( Html::rawElement( 'h2', @@ -199,7 +200,7 @@ class SpecialBlockList extends SpecialPage { ) . "\n" ); $list = ''; - foreach( $otherBlockLink as $link ) { + foreach ( $otherBlockLink as $link ) { $list .= Html::rawElement( 'li', array(), $link ) . "\n"; } $out->addHTML( Html::rawElement( 'ul', array( 'class' => 'mw-ipblocklist-otherblocks' ), $list ) . "\n" ); @@ -238,7 +239,7 @@ class BlockListPager extends TablePager { 'ipb_params' => 'blocklist-params', 'ipb_reason' => 'blocklist-reason', ); - foreach( $headers as $key => $val ) { + foreach ( $headers as $key => $val ) { $headers[$key] = $this->msg( $val )->text(); } } @@ -267,17 +268,17 @@ class BlockListPager extends TablePager { $formatted = ''; - switch( $name ) { + switch ( $name ) { case 'ipb_timestamp': $formatted = $this->getLanguage()->userTimeAndDate( $value, $this->getUser() ); break; case 'ipb_target': - if( $row->ipb_auto ) { + if ( $row->ipb_auto ) { $formatted = $this->msg( 'autoblockid', $row->ipb_id )->parse(); } else { list( $target, $type ) = Block::parseTarget( $row->ipb_address ); - switch( $type ) { + switch ( $type ) { case Block::TYPE_USER: case Block::TYPE_IP: $formatted = Linker::userLink( $target->getId(), $target ); @@ -295,9 +296,9 @@ class BlockListPager extends TablePager { break; case 'ipb_expiry': - $formatted = $this->getLanguage()->formatExpiry( $value, /* User preference timezone */ true ); - if( $this->getUser()->isAllowed( 'block' ) ) { - if( $row->ipb_auto ) { + $formatted = $this->getLanguage()->formatExpiry( $value, /* User preference timezone */true ); + if ( $this->getUser()->isAllowed( 'block' ) ) { + if ( $row->ipb_auto ) { $links[] = Linker::linkKnown( SpecialPage::getTitleFor( 'Unblock' ), $msg['unblocklink'], @@ -420,7 +421,7 @@ class BlockListPager extends TablePager { /** * Do a LinkBatch query to minimise database load when generating all these links - * @param $result + * @param ResultWrapper $result */ function preprocessResults( $result ) { wfProfileIn( __METHOD__ ); @@ -441,7 +442,7 @@ class BlockListPager extends TablePager { } $ua = UserArray::newFromIDs( $userids ); - foreach( $ua as $user ) { + foreach ( $ua as $user ) { $name = str_replace( ' ', '_', $user->getName() ); $lb->add( NS_USER, $name ); $lb->add( NS_USER_TALK, $name ); @@ -482,5 +483,4 @@ class HTMLBlockedUsersItemSelect extends HTMLSelectField { return true; } - } diff --git a/includes/specials/SpecialBlockme.php b/includes/specials/SpecialBlockme.php deleted file mode 100644 index 85a3019e..00000000 --- a/includes/specials/SpecialBlockme.php +++ /dev/null @@ -1,66 +0,0 @@ -setHeaders(); - $this->outputHeader(); - - $ip = $this->getRequest()->getIP(); - if( !$wgBlockOpenProxies || $this->getRequest()->getText( 'ip' ) != md5( $ip . $wgProxyKey ) ) { - $this->getOutput()->addWikiMsg( 'proxyblocker-disabled' ); - return; - } - - $user = User::newFromName( $this->msg( 'proxyblocker' )->inContentLanguage()->text() ); - # FIXME: newFromName could return false on a badly configured wiki. - if ( !$user->isLoggedIn() ) { - $user->addToDatabase(); - } - - $block = new Block(); - $block->setTarget( $ip ); - $block->setBlocker( $user ); - $block->mReason = $this->msg( 'proxyblockreason' )->inContentLanguage()->text(); - - $block->insert(); - - $this->getOutput()->addWikiMsg( 'proxyblocksuccess' ); - } - - protected function getGroupName() { - return 'other'; - } -} diff --git a/includes/specials/SpecialBooksources.php b/includes/specials/SpecialBooksources.php index bdbd77b8..5ad961c3 100644 --- a/includes/specials/SpecialBooksources.php +++ b/includes/specials/SpecialBooksources.php @@ -53,8 +53,8 @@ class SpecialBookSources extends SpecialPage { $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 ) ) { + if ( strlen( $this->isbn ) > 0 ) { + if ( !self::isValidISBN( $this->isbn ) ) { $this->getOutput()->wrapWikiMsg( "
\n$1\n
", 'booksources-invalid-isbn' ); } $this->showList(); @@ -69,32 +69,33 @@ class SpecialBookSources extends SpecialPage { public static function isValidISBN( $isbn ) { $isbn = self::cleanIsbn( $isbn ); $sum = 0; - if( strlen( $isbn ) == 13 ) { - for( $i = 0; $i < 12; $i++ ) { - if( $i % 2 == 0 ) { + if ( strlen( $isbn ) == 13 ) { + for ( $i = 0; $i < 12; $i++ ) { + if ( $i % 2 == 0 ) { $sum += $isbn[$i]; } else { $sum += 3 * $isbn[$i]; } } - $check = (10 - ($sum % 10)) % 10; + $check = ( 10 - ( $sum % 10 ) ) % 10; if ( $check == $isbn[12] ) { return true; } - } elseif( strlen( $isbn ) == 10 ) { - for( $i = 0; $i < 9; $i++ ) { - $sum += $isbn[$i] * ($i + 1); + } elseif ( strlen( $isbn ) == 10 ) { + for ( $i = 0; $i < 9; $i++ ) { + $sum += $isbn[$i] * ( $i + 1 ); } $check = $sum % 11; - if( $check == 10 ) { + if ( $check == 10 ) { $check = "X"; } - if( $check == $isbn[9] ) { + if ( $check == $isbn[9] ) { return true; } } + return false; } @@ -116,13 +117,14 @@ class SpecialBookSources extends SpecialPage { private function makeForm() { global $wgScript; - $form = '
' . $this->msg( 'booksources-search-legend' )->escaped() . ''; - $form .= Xml::openElement( 'form', array( 'method' => 'get', 'action' => $wgScript ) ); - $form .= Html::hidden( 'title', $this->getTitle()->getPrefixedText() ); - $form .= '

' . Xml::inputLabel( $this->msg( 'booksources-isbn' )->text(), 'isbn', 'isbn', 20, $this->isbn ); - $form .= ' ' . Xml::submitButton( $this->msg( 'booksources-go' )->text() ) . '

'; - $form .= Xml::closeElement( 'form' ); - $form .= '
'; + $form = Html::openElement( 'fieldset' ) . "\n"; + $form .= Html::element( 'legend', array(), $this->msg( 'booksources-search-legend' )->text() ) . "\n"; + $form .= Html::openElement( 'form', array( 'method' => 'get', 'action' => $wgScript ) ) . "\n"; + $form .= Html::hidden( 'title', $this->getTitle()->getPrefixedText() ) . "\n"; + $form .= '

' . Xml::inputLabel( $this->msg( 'booksources-isbn' )->text(), 'isbn', 'isbn', 20, $this->isbn, array( 'autofocus' => true ) ); + $form .= ' ' . Xml::submitButton( $this->msg( 'booksources-go' )->text() ) . "

\n"; + $form .= Html::closeElement( 'form' ) . "\n"; + $form .= Html::closeElement( 'fieldset' ) . "\n"; return $form; } @@ -143,7 +145,7 @@ class SpecialBookSources extends SpecialPage { # Check for a local page such as Project:Book_sources and use that if available $page = $this->msg( 'booksources' )->inContentLanguage()->text(); $title = Title::makeTitleSafe( NS_PROJECT, $page ); # Show list in content language - if( is_object( $title ) && $title->exists() ) { + if ( is_object( $title ) && $title->exists() ) { $rev = Revision::newFromTitle( $title, false, Revision::READ_NORMAL ); $content = $rev->getContent(); @@ -152,6 +154,7 @@ class SpecialBookSources extends SpecialPage { $text = $content->getNativeData(); $this->getOutput()->addWikiText( str_replace( 'MAGICNUMBER', $this->isbn, $text ) ); + return true; } else { throw new MWException( "Unexpected content type for book sources: " . $content->getModel() ); @@ -162,9 +165,11 @@ class SpecialBookSources extends SpecialPage { $this->getOutput()->addWikiMsg( 'booksources-text' ); $this->getOutput()->addHTML( '' ); + return true; } @@ -177,7 +182,9 @@ class SpecialBookSources extends SpecialPage { */ private function makeListItem( $label, $url ) { $url = str_replace( '$1', $this->isbn, $url ); - return '
  • ' . htmlspecialchars( $label ) . '
  • '; + + return Html::rawElement( 'li', array(), + Html::element( 'a', array( 'href' => $url, 'class' => 'external' ), $label ) ); } protected function getGroupName() { diff --git a/includes/specials/SpecialBrokenRedirects.php b/includes/specials/SpecialBrokenRedirects.php index fac41236..b2ddc220 100644 --- a/includes/specials/SpecialBrokenRedirects.php +++ b/includes/specials/SpecialBrokenRedirects.php @@ -51,6 +51,7 @@ class BrokenRedirectsPage extends QueryPage { function getQueryInfo() { $dbr = wfGetDB( DB_SLAVE ); + return array( 'tables' => array( 'redirect', @@ -88,13 +89,13 @@ class BrokenRedirectsPage extends QueryPage { * @return array */ function getOrderFields() { - return array ( 'rd_namespace', 'rd_title', 'rd_from' ); + return array( 'rd_namespace', 'rd_title', 'rd_from' ); } /** - * @param $skin Skin - * @param $result - * @return String + * @param Skin $skin + * @param object $result Result row + * @return string */ function formatResult( $skin, $result ) { $fromObj = Title::makeTitle( $result->namespace, $result->title ); @@ -138,7 +139,7 @@ class BrokenRedirectsPage extends QueryPage { $out = $from . $this->msg( 'word-separator' )->escaped(); - if( $this->getUser()->isAllowed( 'delete' ) ) { + if ( $this->getUser()->isAllowed( 'delete' ) ) { $links[] = Linker::linkKnown( $fromObj, $this->msg( 'brokenredirects-delete' )->escaped(), @@ -149,6 +150,7 @@ class BrokenRedirectsPage extends QueryPage { $out .= $this->msg( 'parentheses' )->rawParams( $this->getLanguage()->pipeList( $links ) )->escaped(); $out .= " {$arr} {$to}"; + return $out; } diff --git a/includes/specials/SpecialCachedPage.php b/includes/specials/SpecialCachedPage.php index ddd11ad0..39305f01 100644 --- a/includes/specials/SpecialCachedPage.php +++ b/includes/specials/SpecialCachedPage.php @@ -194,5 +194,4 @@ abstract class SpecialCachedPage extends SpecialPage implements ICacheHelper { $this->getOutput()->setSubtitle( $this->cacheHelper->getCachedNotice( $this->getContext() ) ); } } - } diff --git a/includes/specials/SpecialCategories.php b/includes/specials/SpecialCategories.php index 9040c640..d01bfd7d 100644 --- a/includes/specials/SpecialCategories.php +++ b/includes/specials/SpecialCategories.php @@ -42,12 +42,12 @@ class SpecialCategories extends SpecialPage { $this->getOutput()->addHTML( Html::openElement( 'div', array( 'class' => 'mw-spcontent' ) ) . - $this->msg( 'categoriespagetext', $cap->getNumRows() )->parseAsBlock() . - $cap->getStartForm( $from ) . - $cap->getNavigationBar() . - '' . - $cap->getNavigationBar() . - Html::closeElement( 'div' ) + $this->msg( 'categoriespagetext', $cap->getNumRows() )->parseAsBlock() . + $cap->getStartForm( $from ) . + $cap->getNavigationBar() . + '' . + $cap->getNavigationBar() . + Html::closeElement( 'div' ) ); } @@ -66,7 +66,7 @@ class CategoryPager extends AlphabeticPager { function __construct( IContextSource $context, $from ) { parent::__construct( $context ); $from = str_replace( ' ', '_', $from ); - if( $from !== '' ) { + if ( $from !== '' ) { $from = Title::capitalize( $from, NS_CATEGORY ); $this->setOffset( $from ); $this->setIncludeOffset( true ); @@ -90,8 +90,10 @@ class CategoryPager extends AlphabeticPager { function getDefaultQuery() { parent::getDefaultQuery(); unset( $this->mDefaultQuery['from'] ); + return $this->mDefaultQuery; } + # protected function getOrderTypeMessages() { # return array( 'abc' => 'special-categories-sort-abc', # 'count' => 'special-categories-sort-count' ); @@ -113,6 +115,7 @@ class CategoryPager extends AlphabeticPager { } $batch->execute(); $this->mResult->rewind(); + return parent::getBody(); } @@ -120,19 +123,26 @@ class CategoryPager extends AlphabeticPager { $title = Title::makeTitle( NS_CATEGORY, $result->cat_title ); $titleText = Linker::link( $title, htmlspecialchars( $title->getText() ) ); $count = $this->msg( 'nmembers' )->numParams( $result->cat_pages )->escaped(); + return Xml::tags( 'li', null, $this->getLanguage()->specialList( $titleText, $count ) ) . "\n"; } public function getStartForm( $from ) { global $wgScript; - return - Xml::tags( 'form', array( 'method' => 'get', 'action' => $wgScript ), - Html::hidden( 'title', $this->getTitle()->getPrefixedText() ) . - Xml::fieldset( $this->msg( 'categories' )->text(), - Xml::inputLabel( $this->msg( 'categoriesfrom' )->text(), + return Xml::tags( + 'form', + array( 'method' => 'get', 'action' => $wgScript ), + Html::hidden( 'title', $this->getTitle()->getPrefixedText() ) . + Xml::fieldset( + $this->msg( 'categories' )->text(), + Xml::inputLabel( + $this->msg( 'categoriesfrom' )->text(), 'from', 'from', 20, $from ) . - ' ' . - Xml::submitButton( $this->msg( 'allpagessubmit' )->text() ) ) ); + ' ' . + Xml::submitButton( $this->msg( 'allpagessubmit' )->text() + ) + ) + ); } } diff --git a/includes/specials/SpecialChangeEmail.php b/includes/specials/SpecialChangeEmail.php index 59a02578..aab839fd 100644 --- a/includes/specials/SpecialChangeEmail.php +++ b/includes/specials/SpecialChangeEmail.php @@ -41,7 +41,7 @@ class SpecialChangeEmail extends UnlistedSpecialPage { protected $mNewEmail; public function __construct() { - parent::__construct( 'ChangeEmail' ); + parent::__construct( 'ChangeEmail', 'editmyprivateinfo' ); } /** @@ -49,6 +49,7 @@ class SpecialChangeEmail extends UnlistedSpecialPage { */ function isListed() { global $wgAuth; + return $wgAuth->allowPropChange( 'emailaddress' ); } @@ -67,6 +68,7 @@ class SpecialChangeEmail extends UnlistedSpecialPage { if ( !$wgAuth->allowPropChange( 'emailaddress' ) ) { $this->error( 'cannotchangeemail' ); + return; } @@ -75,22 +77,31 @@ class SpecialChangeEmail extends UnlistedSpecialPage { if ( !$request->wasPosted() && !$user->isLoggedIn() ) { $this->error( 'changeemail-no-info' ); + return; } if ( $request->wasPosted() && $request->getBool( 'wpCancel' ) ) { $this->doReturnTo(); + return; } $this->checkReadOnly(); + $this->checkPermissions(); + + // This could also let someone check the current email address, so + // require both permissions. + if ( !$this->getUser()->isAllowed( 'viewmyprivateinfo' ) ) { + throw new PermissionsError( 'viewmyprivateinfo' ); + } $this->mPassword = $request->getVal( 'wpPassword' ); $this->mNewEmail = $request->getVal( 'wpNewEmail' ); if ( $request->wasPosted() - && $user->matchEditToken( $request->getVal( 'token' ) ) ) - { + && $user->matchEditToken( $request->getVal( 'token' ) ) + ) { $info = $this->attemptChange( $user, $this->mPassword, $this->mNewEmail ); if ( $info === true ) { $this->doReturnTo(); @@ -138,15 +149,15 @@ class SpecialChangeEmail extends UnlistedSpecialPage { $this->getOutput()->addHTML( Xml::fieldset( $this->msg( 'changeemail-header' )->text() ) . - Xml::openElement( 'form', - array( - 'method' => 'post', - 'action' => $this->getTitle()->getLocalUrl(), - 'id' => 'mw-changeemail-form' ) ) . "\n" . - Html::hidden( 'token', $user->getEditToken() ) . "\n" . - Html::hidden( 'returnto', $this->getRequest()->getVal( 'returnto' ) ) . "\n" . - $this->msg( 'changeemail-text' )->parseAsBlock() . "\n" . - Xml::openElement( 'table', array( 'id' => 'mw-changeemail-table' ) ) . "\n" + Xml::openElement( 'form', + array( + 'method' => 'post', + 'action' => $this->getTitle()->getLocalURL(), + 'id' => 'mw-changeemail-form' ) ) . "\n" . + Html::hidden( 'token', $user->getEditToken() ) . "\n" . + Html::hidden( 'returnto', $this->getRequest()->getVal( 'returnto' ) ) . "\n" . + $this->msg( 'changeemail-text' )->parseAsBlock() . "\n" . + Xml::openElement( 'table', array( 'id' => 'mw-changeemail-table' ) ) . "\n" ); $items = array( array( 'wpName', 'username', 'text', $user->getName() ), @@ -159,17 +170,17 @@ class SpecialChangeEmail extends UnlistedSpecialPage { $this->getOutput()->addHTML( $this->pretty( $items ) . - "\n" . - "\n" . + "\n" . + "\n" . "\n" . '' . - Xml::submitButton( $this->msg( 'changeemail-submit' )->text() ) . - Xml::submitButton( $this->msg( 'changeemail-cancel' )->text(), array( 'name' => 'wpCancel' ) ) . + Xml::submitButton( $this->msg( 'changeemail-submit' )->text() ) . + Xml::submitButton( $this->msg( 'changeemail-cancel' )->text(), array( 'name' => 'wpCancel' ) ) . "\n" . - "\n" . - Xml::closeElement( 'table' ) . - Xml::closeElement( 'form' ) . - Xml::closeElement( 'fieldset' ) . "\n" + "\n" . + Xml::closeElement( 'table' ) . + Xml::closeElement( 'form' ) . + Xml::closeElement( 'fieldset' ) . "\n" ); } @@ -181,7 +192,7 @@ class SpecialChangeEmail extends UnlistedSpecialPage { $out = ''; foreach ( $fields as $list ) { list( $name, $label, $type, $value ) = $list; - if( $type == 'text' ) { + if ( $type == 'text' ) { $field = htmlspecialchars( $value ); } else { $attribs = array( 'id' => $name ); @@ -203,6 +214,7 @@ class SpecialChangeEmail extends UnlistedSpecialPage { $out .= "\n"; $out .= ""; } + return $out; } @@ -213,22 +225,26 @@ class SpecialChangeEmail extends UnlistedSpecialPage { * @return bool|string true or string on success, false on failure */ protected function attemptChange( User $user, $pass, $newaddr ) { - global $wgAuth; + global $wgAuth, $wgPasswordAttemptThrottle; if ( $newaddr != '' && !Sanitizer::validateEmail( $newaddr ) ) { $this->error( 'invalidemailaddress' ); + return false; } $throttleCount = LoginForm::incLoginThrottle( $user->getName() ); if ( $throttleCount === true ) { - $this->error( 'login-throttled' ); + $lang = $this->getLanguage(); + $this->error( array( 'login-throttled', $lang->formatDuration( $wgPasswordAttemptThrottle['seconds'] ) ) ); + return false; } global $wgRequirePasswordforEmailChange; if ( $wgRequirePasswordforEmailChange && !$user->checkTemporaryPassword( $pass ) && !$user->checkPassword( $pass ) ) { $this->error( 'wrongpassword' ); + return false; } @@ -241,8 +257,9 @@ class SpecialChangeEmail extends UnlistedSpecialPage { if ( !$status->isGood() ) { $this->getOutput()->addHTML( '

    ' . - $this->getOutput()->parseInline( $status->getWikiText( 'mailerror' ) ) . - '

    ' ); + $this->getOutput()->parseInline( $status->getWikiText( 'mailerror' ) ) . + '

    ' ); + return false; } diff --git a/includes/specials/SpecialChangePassword.php b/includes/specials/SpecialChangePassword.php index e538caca..c54b5575 100644 --- a/includes/specials/SpecialChangePassword.php +++ b/includes/specials/SpecialChangePassword.php @@ -31,7 +31,7 @@ class SpecialChangePassword extends UnlistedSpecialPage { protected $mUserName, $mOldpass, $mNewpass, $mRetype, $mDomain; public function __construct() { - parent::__construct( 'ChangePassword' ); + parent::__construct( 'ChangePassword', 'editmyprivateinfo' ); } /** @@ -52,62 +52,66 @@ class SpecialChangePassword extends UnlistedSpecialPage { $this->mDomain = $request->getVal( 'wpDomain' ); $user = $this->getUser(); - if( !$request->wasPosted() && !$user->isLoggedIn() ) { + if ( !$request->wasPosted() && !$user->isLoggedIn() ) { $this->error( $this->msg( 'resetpass-no-info' )->text() ); + return; } - if( $request->wasPosted() && $request->getBool( 'wpCancel' ) ) { - $this->doReturnTo(); + if ( $request->wasPosted() && $request->getBool( 'wpCancel' ) ) { + $titleObj = Title::newFromText( $request->getVal( 'returnto' ) ); + if ( !$titleObj instanceof Title ) { + $titleObj = Title::newMainPage(); + } + $query = $request->getVal( 'returntoquery' ); + $this->getOutput()->redirect( $titleObj->getFullURL( $query ) ); + return; } $this->checkReadOnly(); + $this->checkPermissions(); - if( $request->wasPosted() && $user->matchEditToken( $request->getVal( 'token' ) ) ) { + if ( $request->wasPosted() && $user->matchEditToken( $request->getVal( 'token' ) ) ) { try { $this->mDomain = $wgAuth->getDomain(); - if( !$wgAuth->allowPasswordChange() ) { + if ( !$wgAuth->allowPasswordChange() ) { $this->error( $this->msg( 'resetpass_forbidden' )->text() ); + return; } $this->attemptReset( $this->mNewpass, $this->mRetype ); - if( $user->isLoggedIn() ) { - $this->doReturnTo(); + if ( $user->isLoggedIn() ) { + $this->getOutput()->wrapWikiMsg( + "
    \n$1\n
    ", + 'changepassword-success' + ); + $this->getOutput()->returnToMain(); } else { LoginForm::setLoginToken(); $token = LoginForm::getLoginToken(); $data = array( - 'action' => 'submitlogin', - 'wpName' => $this->mUserName, - 'wpDomain' => $this->mDomain, + 'action' => 'submitlogin', + 'wpName' => $this->mUserName, + 'wpDomain' => $this->mDomain, 'wpLoginToken' => $token, - 'wpPassword' => $request->getVal( 'wpNewPassword' ), + 'wpPassword' => $request->getVal( 'wpNewPassword' ), ) + $request->getValues( 'wpRemember', 'returnto', 'returntoquery' ); - $login = new LoginForm( new FauxRequest( $data, true ) ); + $login = new LoginForm( new DerivativeRequest( $request, $data, true ) ); $login->setContext( $this->getContext() ); $login->execute( null ); } + return; - } catch( PasswordError $e ) { + } catch ( PasswordError $e ) { $this->error( $e->getMessage() ); } } $this->showForm(); } - function doReturnTo() { - $request = $this->getRequest(); - $titleObj = Title::newFromText( $request->getVal( 'returnto' ) ); - if ( !$titleObj instanceof Title ) { - $titleObj = Title::newMainPage(); - } - $query = $request->getVal( 'returntoquery' ); - $this->getOutput()->redirect( $titleObj->getFullURL( $query ) ); - } - /** * @param $msg string */ @@ -127,12 +131,12 @@ class SpecialChangePassword extends UnlistedSpecialPage { $rememberMe = '' . '' . '' . - Xml::checkLabel( - $this->msg( 'remembermypassword' )->numParams( ceil( $wgCookieExpiration / ( 3600 * 24 ) ) )->text(), - 'wpRemember', 'wpRemember', - $this->getRequest()->getCheck( 'wpRemember' ) ) . + Xml::checkLabel( + $this->msg( 'remembermypassword' )->numParams( ceil( $wgCookieExpiration / ( 3600 * 24 ) ) )->text(), + 'wpRemember', 'wpRemember', + $this->getRequest()->getCheck( 'wpRemember' ) ) . '' . - ''; + ''; $submitMsg = 'resetpass_submit'; $oldpassMsg = 'resetpass-temp-password'; } else { @@ -142,11 +146,11 @@ class SpecialChangePassword extends UnlistedSpecialPage { $extraFields = array(); wfRunHooks( 'ChangePasswordForm', array( &$extraFields ) ); $prettyFields = array( - array( 'wpName', 'username', 'text', $this->mUserName ), - array( 'wpPassword', $oldpassMsg, 'password', $this->mOldpass ), - array( 'wpNewPassword', 'newpassword', 'password', null ), - array( 'wpRetype', 'retypenew', 'password', null ), - ); + array( 'wpName', 'username', 'text', $this->mUserName ), + array( 'wpPassword', $oldpassMsg, 'password', $this->mOldpass ), + array( 'wpNewPassword', 'newpassword', 'password', null ), + array( 'wpRetype', 'retypenew', 'password', null ), + ); $prettyFields = array_merge( $prettyFields, $extraFields ); $hiddenFields = array( 'token' => $user->getEditToken(), @@ -154,31 +158,31 @@ class SpecialChangePassword extends UnlistedSpecialPage { 'wpDomain' => $this->mDomain, ) + $this->getRequest()->getValues( 'returnto', 'returntoquery' ); $hiddenFieldsStr = ''; - foreach( $hiddenFields as $fieldname => $fieldvalue ) { + foreach ( $hiddenFields as $fieldname => $fieldvalue ) { $hiddenFieldsStr .= Html::hidden( $fieldname, $fieldvalue ) . "\n"; } $this->getOutput()->addHTML( Xml::fieldset( $this->msg( 'resetpass_header' )->text() ) . - Xml::openElement( 'form', - array( - 'method' => 'post', - 'action' => $this->getTitle()->getLocalUrl(), - 'id' => 'mw-resetpass-form' ) ) . "\n" . - $hiddenFieldsStr . - $this->msg( 'resetpass_text' )->parseAsBlock() . "\n" . - Xml::openElement( 'table', array( 'id' => 'mw-resetpass-table' ) ) . "\n" . - $this->pretty( $prettyFields ) . "\n" . - $rememberMe . - "\n" . + Xml::openElement( 'form', + array( + 'method' => 'post', + 'action' => $this->getTitle()->getLocalURL(), + 'id' => 'mw-resetpass-form' ) ) . "\n" . + $hiddenFieldsStr . + $this->msg( 'resetpass_text' )->parseAsBlock() . "\n" . + Xml::openElement( 'table', array( 'id' => 'mw-resetpass-table' ) ) . "\n" . + $this->pretty( $prettyFields ) . "\n" . + $rememberMe . + "\n" . "\n" . '' . - Xml::submitButton( $this->msg( $submitMsg )->text() ) . - Xml::submitButton( $this->msg( 'resetpass-submit-cancel' )->text(), array( 'name' => 'wpCancel' ) ) . + Xml::submitButton( $this->msg( $submitMsg )->text() ) . + Xml::submitButton( $this->msg( 'resetpass-submit-cancel' )->text(), array( 'name' => 'wpCancel' ) ) . "\n" . - "\n" . - Xml::closeElement( 'table' ) . - Xml::closeElement( 'form' ) . - Xml::closeElement( 'fieldset' ) . "\n" + "\n" . + Xml::closeElement( 'table' ) . + Xml::closeElement( 'form' ) . + Xml::closeElement( 'fieldset' ) . "\n" ); } @@ -190,7 +194,7 @@ class SpecialChangePassword extends UnlistedSpecialPage { $out = ''; foreach ( $fields as $list ) { list( $name, $label, $type, $value ) = $list; - if( $type == 'text' ) { + if ( $type == 'text' ) { $field = htmlspecialchars( $value ); } else { $attribs = array( 'id' => $name ); @@ -205,16 +209,20 @@ class SpecialChangePassword extends UnlistedSpecialPage { } $out .= "\n"; $out .= "\t"; - if ( $type != 'text' ) + + if ( $type != 'text' ) { $out .= Xml::label( $this->msg( $label )->text(), $name ); - else + } else { $out .= $this->msg( $label )->escaped(); + } + $out .= "\n"; $out .= "\t"; $out .= $field; $out .= "\n"; $out .= ""; } + return $out; } @@ -222,6 +230,8 @@ class SpecialChangePassword extends UnlistedSpecialPage { * @throws PasswordError when cannot set the new password because requirements not met. */ protected function attemptReset( $newpass, $retype ) { + global $wgPasswordAttemptThrottle; + $isSelf = ( $this->mUserName === $this->getUser()->getName() ); if ( $isSelf ) { $user = $this->getUser(); @@ -229,18 +239,22 @@ class SpecialChangePassword extends UnlistedSpecialPage { $user = User::newFromName( $this->mUserName ); } - if( !$user || $user->isAnon() ) { + if ( !$user || $user->isAnon() ) { throw new PasswordError( $this->msg( 'nosuchusershort', $this->mUserName )->text() ); } - if( $newpass !== $retype ) { + if ( $newpass !== $retype ) { wfRunHooks( 'PrefsPasswordAudit', array( $user, $newpass, 'badretype' ) ); throw new PasswordError( $this->msg( 'badretype' )->text() ); } $throttleCount = LoginForm::incLoginThrottle( $this->mUserName ); if ( $throttleCount === true ) { - throw new PasswordError( $this->msg( 'login-throttled' )->text() ); + $lang = $this->getLanguage(); + throw new PasswordError( $this->msg( 'login-throttled' ) + ->params( $lang->formatDuration( $wgPasswordAttemptThrottle['seconds'] ) ) + ->text() + ); } $abortMsg = 'resetpass-abort-generic'; @@ -249,7 +263,7 @@ class SpecialChangePassword extends UnlistedSpecialPage { throw new PasswordError( $this->msg( $abortMsg )->text() ); } - if( !$user->checkTemporaryPassword( $this->mOldpass ) && !$user->checkPassword( $this->mOldpass ) ) { + if ( !$user->checkTemporaryPassword( $this->mOldpass ) && !$user->checkPassword( $this->mOldpass ) ) { wfRunHooks( 'PrefsPasswordAudit', array( $user, $newpass, 'wrongpassword' ) ); throw new PasswordError( $this->msg( 'resetpass-wrong-oldpass' )->text() ); } @@ -263,7 +277,7 @@ class SpecialChangePassword extends UnlistedSpecialPage { $user->setPassword( $this->mNewpass ); wfRunHooks( 'PrefsPasswordAudit', array( $user, $newpass, 'success' ) ); $this->mNewpass = $this->mOldpass = $this->mRetype = ''; - } catch( PasswordError $e ) { + } catch ( PasswordError $e ) { wfRunHooks( 'PrefsPasswordAudit', array( $user, $newpass, 'error' ) ); throw new PasswordError( $e->getMessage() ); } diff --git a/includes/specials/SpecialComparePages.php b/includes/specials/SpecialComparePages.php index c3bd3fec..fc6b0c58 100644 --- a/includes/specials/SpecialComparePages.php +++ b/includes/specials/SpecialComparePages.php @@ -110,7 +110,7 @@ class SpecialComparePages extends SpecialPage { $rev1 = self::revOrTitle( $data['Revision1'], $data['Page1'] ); $rev2 = self::revOrTitle( $data['Revision2'], $data['Page2'] ); - if( $rev1 && $rev2 ) { + if ( $rev1 && $rev2 ) { $revision = Revision::newFromId( $rev1 ); if ( $revision ) { // NOTE: $rev1 was already checked, should exist. @@ -128,14 +128,15 @@ class SpecialComparePages extends SpecialPage { } public static function revOrTitle( $revision, $title ) { - if( $revision ) { + if ( $revision ) { return $revision; - } elseif( $title ) { + } elseif ( $title ) { $title = Title::newFromText( $title ); - if( $title instanceof Title ) { + if ( $title instanceof Title ) { return $title->getLatestRevID(); } } + return null; } @@ -150,6 +151,7 @@ class SpecialComparePages extends SpecialPage { if ( !$title->exists() ) { return $this->msg( 'compare-title-not-exists' )->parseAsBlock(); } + return true; } @@ -161,6 +163,7 @@ class SpecialComparePages extends SpecialPage { if ( $revision === null ) { return $this->msg( 'compare-revision-not-exists' )->parseAsBlock(); } + return true; } diff --git a/includes/specials/SpecialConfirmemail.php b/includes/specials/SpecialConfirmemail.php index 078c3865..3828b1c6 100644 --- a/includes/specials/SpecialConfirmemail.php +++ b/includes/specials/SpecialConfirmemail.php @@ -30,27 +30,30 @@ * @author Rob Church */ class EmailConfirmation extends UnlistedSpecialPage { - - /** - * Constructor - */ public function __construct() { - parent::__construct( 'Confirmemail' ); + parent::__construct( 'Confirmemail', 'editmyprivateinfo' ); } /** * Main execution point * - * @param $code Confirmation code passed to the page + * @param null|string $code Confirmation code passed to the page */ function execute( $code ) { $this->setHeaders(); $this->checkReadOnly(); + $this->checkPermissions(); - if( $code === null || $code === '' ) { - if( $this->getUser()->isLoggedIn() ) { - if( Sanitizer::validateEmail( $this->getUser()->getEmail() ) ) { + // This could also let someone check the current email address, so + // require both permissions. + if ( !$this->getUser()->isAllowed( 'viewmyprivateinfo' ) ) { + throw new PermissionsError( 'viewmyprivateinfo' ); + } + + if ( $code === null || $code === '' ) { + if ( $this->getUser()->isLoggedIn() ) { + if ( Sanitizer::validateEmail( $this->getUser()->getEmail() ) ) { $this->showRequestForm(); } else { $this->getOutput()->addWikiMsg( 'confirmemail_noemail' ); @@ -62,7 +65,9 @@ class EmailConfirmation extends UnlistedSpecialPage { array(), array( 'returnto' => $this->getTitle()->getPrefixedText() ) ); - $this->getOutput()->addHTML( $this->msg( 'confirmemail_needlogin' )->rawParams( $llink )->parse() ); + $this->getOutput()->addHTML( + $this->msg( 'confirmemail_needlogin' )->rawParams( $llink )->parse() + ); } } else { $this->attemptConfirm( $code ); @@ -75,7 +80,10 @@ class EmailConfirmation extends UnlistedSpecialPage { function showRequestForm() { $user = $this->getUser(); $out = $this->getOutput(); - if( $this->getRequest()->wasPosted() && $user->matchEditToken( $this->getRequest()->getText( 'token' ) ) ) { + + if ( $this->getRequest()->wasPosted() && + $user->matchEditToken( $this->getRequest()->getText( 'token' ) ) + ) { $status = $user->sendConfirmationMail(); if ( $status->isGood() ) { $out->addWikiMsg( 'confirmemail_sent' ); @@ -83,7 +91,7 @@ class EmailConfirmation extends UnlistedSpecialPage { $out->addWikiText( $status->getWikiText( 'confirmemail_sendfailed' ) ); } } else { - if( $user->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 @@ -94,14 +102,22 @@ class EmailConfirmation extends UnlistedSpecialPage { $t = $lang->userTime( $emailAuthenticated, $user ); $out->addWikiMsg( 'emailauthenticated', $time, $d, $t ); } - if( $user->isEmailConfirmationPending() ) { - $out->wrapWikiMsg( "
    \n$1\n
    ", 'confirmemail_pending' ); + + if ( $user->isEmailConfirmationPending() ) { + $out->wrapWikiMsg( + "
    \n$1\n
    ", + 'confirmemail_pending' + ); } + $out->addWikiMsg( 'confirmemail_text' ); - $form = Xml::openElement( 'form', array( 'method' => 'post', 'action' => $this->getTitle()->getLocalUrl() ) ); - $form .= Html::hidden( 'token', $user->getEditToken() ); - $form .= Xml::submitButton( $this->msg( 'confirmemail_send' )->text() ); - $form .= Xml::closeElement( 'form' ); + $form = Html::openElement( + 'form', + array( 'method' => 'post', 'action' => $this->getTitle()->getLocalURL() ) + ) . "\n"; + $form .= Html::hidden( 'token', $user->getEditToken() ) . "\n"; + $form .= Xml::submitButton( $this->msg( 'confirmemail_send' )->text() ) . "\n"; + $form .= Html::closeElement( 'form' ) . "\n"; $out->addHTML( $form ); } } @@ -114,20 +130,22 @@ class EmailConfirmation extends UnlistedSpecialPage { */ function attemptConfirm( $code ) { $user = User::newFromConfirmationCode( $code ); - if( is_object( $user ) ) { - $user->confirmEmail(); - $user->saveSettings(); - $message = $this->getUser()->isLoggedIn() ? 'confirmemail_loggedin' : 'confirmemail_success'; - $this->getOutput()->addWikiMsg( $message ); - if( !$this->getUser()->isLoggedIn() ) { - $title = SpecialPage::getTitleFor( 'Userlogin' ); - $this->getOutput()->returnToMain( true, $title ); - } - } else { + if ( !is_object( $user ) ) { $this->getOutput()->addWikiMsg( 'confirmemail_invalid' ); + + return; } - } + $user->confirmEmail(); + $user->saveSettings(); + $message = $this->getUser()->isLoggedIn() ? 'confirmemail_loggedin' : 'confirmemail_success'; + $this->getOutput()->addWikiMsg( $message ); + + if ( !$this->getUser()->isLoggedIn() ) { + $title = SpecialPage::getTitleFor( 'Userlogin' ); + $this->getOutput()->returnToMain( true, $title ); + } + } } /** @@ -137,16 +155,14 @@ class EmailConfirmation extends UnlistedSpecialPage { * @ingroup SpecialPage */ class EmailInvalidation extends UnlistedSpecialPage { - public function __construct() { - parent::__construct( 'Invalidateemail' ); + parent::__construct( 'Invalidateemail', 'editmyprivateinfo' ); } function execute( $code ) { $this->setHeaders(); - $this->checkReadOnly(); - + $this->checkPermissions(); $this->attemptInvalidate( $code ); } @@ -158,15 +174,18 @@ class EmailInvalidation extends UnlistedSpecialPage { */ function attemptInvalidate( $code ) { $user = User::newFromConfirmationCode( $code ); - if( is_object( $user ) ) { - $user->invalidateEmail(); - $user->saveSettings(); - $this->getOutput()->addWikiMsg( 'confirmemail_invalidated' ); - if( !$this->getUser()->isLoggedIn() ) { - $this->getOutput()->returnToMain(); - } - } else { + if ( !is_object( $user ) ) { $this->getOutput()->addWikiMsg( 'confirmemail_invalid' ); + + return; + } + + $user->invalidateEmail(); + $user->saveSettings(); + $this->getOutput()->addWikiMsg( 'confirmemail_invalidated' ); + + if ( !$this->getUser()->isLoggedIn() ) { + $this->getOutput()->returnToMain(); } } } diff --git a/includes/specials/SpecialContributions.php b/includes/specials/SpecialContributions.php index b118059c..1fe98190 100644 --- a/includes/specials/SpecialContributions.php +++ b/includes/specials/SpecialContributions.php @@ -28,7 +28,6 @@ */ class SpecialContributions extends SpecialPage { - protected $opts; public function __construct() { @@ -65,6 +64,7 @@ class SpecialContributions extends SpecialPage { if ( !strlen( $target ) ) { $out->addHTML( $this->getForm() ); + return; } @@ -77,11 +77,13 @@ class SpecialContributions extends SpecialPage { $nt = Title::makeTitleSafe( NS_USER, $target ); if ( !$nt ) { $out->addHTML( $this->getForm() ); + return; } $userObj = User::newFromName( $nt->getText(), false ); if ( !$userObj ) { $out->addHTML( $this->getForm() ); + return; } $id = $userObj->getID(); @@ -89,11 +91,17 @@ class SpecialContributions extends SpecialPage { if ( $this->opts['contribs'] != 'newbie' ) { $target = $nt->getText(); $out->addSubtitle( $this->contributionsSub( $userObj ) ); - $out->setHTMLTitle( $this->msg( 'pagetitle', $this->msg( 'contributions-title', $target )->plain() ) ); + $out->setHTMLTitle( $this->msg( + 'pagetitle', + $this->msg( 'contributions-title', $target )->plain() + ) ); $this->getSkin()->setRelevantUser( $userObj ); } else { $out->addSubtitle( $this->msg( 'sp-contributions-newbies-sub' ) ); - $out->setHTMLTitle( $this->msg( 'pagetitle', $this->msg( 'sp-contributions-newbies-title' )->plain() ) ); + $out->setHTMLTitle( $this->msg( + 'pagetitle', + $this->msg( 'sp-contributions-newbies-title' )->plain() + ) ); } if ( ( $ns = $request->getVal( 'namespace', null ) ) !== null && $ns !== '' ) { @@ -103,10 +111,8 @@ class SpecialContributions extends SpecialPage { } $this->opts['associated'] = $request->getBool( 'associated' ); - - $this->opts['nsInvert'] = (bool) $request->getVal( 'nsInvert' ); - - $this->opts['tagfilter'] = (string) $request->getVal( 'tagfilter' ); + $this->opts['nsInvert'] = (bool)$request->getVal( 'nsInvert' ); + $this->opts['tagfilter'] = (string)$request->getVal( 'tagfilter' ); // Allows reverts to have the bot flag in recent changes. It is just here to // be passed in the form at the top of the page @@ -152,9 +158,10 @@ class SpecialContributions extends SpecialPage { $apiParams['month'] = $this->opts['month']; } - $url = wfScript( 'api' ) . '?' . wfArrayToCgi( $apiParams ); + $url = wfAppendQuery( wfScript( 'api' ), $apiParams ); $out->redirect( $url, '301' ); + return; } @@ -162,13 +169,13 @@ class SpecialContributions extends SpecialPage { $this->addFeedLinks( array( 'action' => 'feedcontributions', 'user' => $target ) ); if ( wfRunHooks( 'SpecialContributionsBeforeMainOutput', array( $id ) ) ) { - $out->addHTML( $this->getForm() ); $pager = new ContribsPager( $this->getContext(), array( 'target' => $target, 'contribs' => $this->opts['contribs'], 'namespace' => $this->opts['namespace'], + 'tagfilter' => $this->opts['tagfilter'], 'year' => $this->opts['year'], 'month' => $this->opts['month'], 'deletedOnly' => $this->opts['deletedOnly'], @@ -176,18 +183,20 @@ class SpecialContributions extends SpecialPage { 'nsInvert' => $this->opts['nsInvert'], 'associated' => $this->opts['associated'], ) ); + if ( !$pager->getNumRows() ) { $out->addWikiMsg( 'nocontribs', $target ); } else { # Show a message about slave lag, if applicable $lag = wfGetLB()->safeGetLag( $pager->getDatabase() ); - if ( $lag > 0 ) + if ( $lag > 0 ) { $out->showLagWarning( $lag ); + } $out->addHTML( '

    ' . $pager->getNavigationBar() . '

    ' . - $pager->getBody() . - '

    ' . $pager->getNavigationBar() . '

    ' + $pager->getBody() . + '

    ' . $pager->getNavigationBar() . '

    ' ); } $out->preventClickjacking( $pager->getPreventClickjacking() ); @@ -195,16 +204,16 @@ class SpecialContributions extends SpecialPage { # Show the appropriate "footer" message - WHOIS tools, etc. if ( $this->opts['contribs'] == 'newbie' ) { $message = 'sp-contributions-footer-newbies'; - } elseif( IP::isIPAddress( $target ) ) { + } elseif ( IP::isIPAddress( $target ) ) { $message = 'sp-contributions-footer-anon'; - } elseif( $userObj->isAnon() ) { + } elseif ( $userObj->isAnon() ) { // No message for non-existing users $message = ''; } else { $message = 'sp-contributions-footer'; } - if( $message ) { + if ( $message ) { if ( !$this->msg( $message, $target )->isDisabled() ) { $out->wrapWikiMsg( "", @@ -218,7 +227,8 @@ class SpecialContributions extends SpecialPage { * Generates the subheading with links * @param $userObj User object 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( $userObj ) { if ( $userObj->isAnon() ) { @@ -258,18 +268,7 @@ class SpecialContributions extends SpecialPage { } } - // Old message 'contribsub' had one parameter, but that doesn't work for - // 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'. - // @todo Should this be removed at some point? - $oldMsg = $this->msg( 'contribsub' ); - if ( $oldMsg->exists() ) { - $linksWithParentheses = $this->msg( 'parentheses' )->rawParams( $links )->escaped(); - return $oldMsg->rawParams( "$user $linksWithParentheses" ); - } else { - return $this->msg( 'contribsub2' )->rawParams( $user, $links ); - } + return $this->msg( 'contribsub2' )->rawParams( $user, $links )->params( $userObj->getName() ); } /** @@ -288,7 +287,7 @@ class SpecialContributions extends SpecialPage { if ( ( $id !== null ) || ( $id === null && IP::isIPAddress( $username ) ) ) { if ( $this->getUser()->isAllowed( 'block' ) ) { # Block / Change block / Unblock links - if ( $target->isBlocked() ) { + if ( $target->isBlocked() && $target->getBlock()->getType() != Block::TYPE_AUTO ) { $tools[] = Linker::linkKnown( # Change block link SpecialPage::getTitleFor( 'Block', $username ), $this->msg( 'change-blocklink' )->escaped() @@ -304,14 +303,13 @@ class SpecialContributions extends SpecialPage { ); } } + # Block log link $tools[] = Linker::linkKnown( SpecialPage::getTitleFor( 'Log', 'block' ), $this->msg( 'sp-contributions-blocklog' )->escaped(), array(), - array( - 'page' => $userpage->getPrefixedText() - ) + array( 'page' => $userpage->getPrefixedText() ) ); } # Uploads @@ -345,6 +343,7 @@ class SpecialContributions extends SpecialPage { } wfRunHooks( 'ContributionsToolLinks', array( $id, $userpage, &$tools ) ); + return $tools; } @@ -398,10 +397,28 @@ class SpecialContributions extends SpecialPage { $this->opts['topOnly'] = false; } - $form = Html::openElement( 'form', array( 'method' => 'get', 'action' => $wgScript, 'class' => 'mw-contributions-form' ) ); + $form = Html::openElement( + 'form', + array( + 'method' => 'get', + 'action' => $wgScript, + 'class' => 'mw-contributions-form' + ) + ); # Add hidden params for tracking except for parameters in $skipParameters - $skipParameters = array( 'namespace', 'nsInvert', 'deletedOnly', 'target', 'contribs', 'year', 'month', 'topOnly', 'associated' ); + $skipParameters = array( + 'namespace', + 'nsInvert', + 'deletedOnly', + 'target', + 'contribs', + 'year', + 'month', + 'topOnly', + 'associated' + ); + foreach ( $this->opts as $name => $value ) { if ( in_array( $name, $skipParameters ) ) { continue; @@ -412,65 +429,82 @@ class SpecialContributions extends SpecialPage { $tagFilter = ChangeTags::buildTagFilterSelector( $this->opts['tagfilter'] ); if ( $tagFilter ) { - $filterSelection = - Html::rawElement( 'td', array( 'class' => 'mw-label' ), array_shift( $tagFilter ) ) . - Html::rawElement( 'td', array( 'class' => 'mw-input' ), implode( ' ', $tagFilter ) ); + $filterSelection = Html::rawElement( + 'td', + array( 'class' => 'mw-label' ), + array_shift( $tagFilter ) + ); + $filterSelection .= Html::rawElement( + 'td', + array( 'class' => 'mw-input' ), + implode( ' ', $tagFilter ) + ); } else { $filterSelection = Html::rawElement( 'td', array( 'colspan' => 2 ), '' ); } - $targetSelection = Html::rawElement( 'td', array( 'colspan' => 2 ), - Xml::radioLabel( - $this->msg( 'sp-contributions-newbies' )->text(), - 'contribs', - 'newbie', - 'newbie', - $this->opts['contribs'] == 'newbie', - array( 'class' => 'mw-input' ) - ) . '
    ' . - Xml::radioLabel( - $this->msg( 'sp-contributions-username' )->text(), - 'contribs', - 'user', - 'user', - $this->opts['contribs'] == 'user', - array( 'class' => 'mw-input' ) - ) . ' ' . - Html::input( - 'target', - $this->opts['target'], - 'text', - array( 'size' => '40', 'required' => '', 'class' => 'mw-input' ) + - ( $this->opts['target'] ? array() : array( 'autofocus' ) + $labelNewbies = Xml::radioLabel( + $this->msg( 'sp-contributions-newbies' )->text(), + 'contribs', + 'newbie', + 'newbie', + $this->opts['contribs'] == 'newbie', + array( 'class' => 'mw-input' ) + ); + $labelUsername = Xml::radioLabel( + $this->msg( 'sp-contributions-username' )->text(), + 'contribs', + 'user', + 'user', + $this->opts['contribs'] == 'user', + array( 'class' => 'mw-input' ) + ); + $input = Html::input( + 'target', + $this->opts['target'], + 'text', + array( 'size' => '40', 'required' => '', 'class' => 'mw-input' ) + + ( $this->opts['target'] ? array() : array( 'autofocus' ) ) - ) . ' ' + ); + $targetSelection = Html::rawElement( + 'td', + array( 'colspan' => 2 ), + $labelNewbies . '
    ' . $labelUsername . ' ' . $input . ' ' ); - $namespaceSelection = - Xml::tags( 'td', array( 'class' => 'mw-label' ), - Xml::label( - $this->msg( 'namespace' )->text(), - 'namespace', - '' - ) - ) . - Html::rawElement( 'td', null, - Html::namespaceSelector( array( - 'selected' => $this->opts['namespace'], - 'all' => '', - ), array( - 'name' => 'namespace', - 'id' => 'namespace', + $namespaceSelection = Xml::tags( + 'td', + array( 'class' => 'mw-label' ), + Xml::label( + $this->msg( 'namespace' )->text(), + 'namespace', + '' + ) + ); + $namespaceSelection .= Html::rawElement( + 'td', + null, + Html::namespaceSelector( + array( 'selected' => $this->opts['namespace'], 'all' => '' ), + array( + 'name' => 'namespace', + 'id' => 'namespace', 'class' => 'namespaceselector', - ) ) . - ' ' . - Html::rawElement( 'span', array( 'style' => 'white-space: nowrap' ), + ) + ) . ' ' . + Html::rawElement( + 'span', + array( 'style' => 'white-space: nowrap' ), Xml::checkLabel( $this->msg( 'invert' )->text(), 'nsInvert', 'nsInvert', $this->opts['nsInvert'], - array( 'title' => $this->msg( 'tooltip-invert' )->text(), 'class' => 'mw-input' ) + array( + 'title' => $this->msg( 'tooltip-invert' )->text(), + 'class' => 'mw-input' + ) ) . ' ' ) . Html::rawElement( 'span', array( 'style' => 'white-space: nowrap' ), @@ -479,13 +513,18 @@ class SpecialContributions extends SpecialPage { 'associated', 'associated', $this->opts['associated'], - array( 'title' => $this->msg( 'tooltip-namespace_association' )->text(), 'class' => 'mw-input' ) + array( + 'title' => $this->msg( 'tooltip-namespace_association' )->text(), + 'class' => 'mw-input' + ) ) . ' ' ) - ); + ); if ( $this->getUser()->isAllowed( 'deletedhistory' ) ) { - $deletedOnlyCheck = Html::rawElement( 'span', array( 'style' => 'white-space: nowrap' ), + $deletedOnlyCheck = Html::rawElement( + 'span', + array( 'style' => 'white-space: nowrap' ), Xml::checkLabel( $this->msg( 'history-show-deleted' )->text(), 'deletedOnly', @@ -498,46 +537,50 @@ class SpecialContributions extends SpecialPage { $deletedOnlyCheck = ''; } - $extraOptions = Html::rawElement( 'td', array( 'colspan' => 2 ), - $deletedOnlyCheck . - Html::rawElement( 'span', array( 'style' => 'white-space: nowrap' ), - Xml::checkLabel( - $this->msg( 'sp-contributions-toponly' )->text(), - 'topOnly', - 'mw-show-top-only', - $this->opts['topOnly'], - array( 'class' => 'mw-input' ) - ) + $checkLabelTopOnly = Html::rawElement( + 'span', + array( 'style' => 'white-space: nowrap' ), + Xml::checkLabel( + $this->msg( 'sp-contributions-toponly' )->text(), + 'topOnly', + 'mw-show-top-only', + $this->opts['topOnly'], + array( 'class' => 'mw-input' ) ) ); + $extraOptions = Html::rawElement( + 'td', + array( 'colspan' => 2 ), + $deletedOnlyCheck . $checkLabelTopOnly + ); $dateSelectionAndSubmit = Xml::tags( 'td', array( 'colspan' => 2 ), Xml::dateMenu( - $this->opts['year'], + $this->opts['year'] === '' ? MWTimestamp::getInstance()->format( 'Y' ) : $this->opts['year'], $this->opts['month'] ) . ' ' . - Xml::submitButton( - $this->msg( 'sp-contributions-submit' )->text(), - array( 'class' => 'mw-submit' ) - ) + Xml::submitButton( + $this->msg( 'sp-contributions-submit' )->text(), + array( 'class' => 'mw-submit' ) + ) ); - $form .= - Xml::fieldset( $this->msg( 'sp-contributions-search' )->text() ) . - Html::rawElement( 'table', array( 'class' => 'mw-contributions-table' ), "\n" . - Html::rawElement( 'tr', array(), $targetSelection ) . "\n" . - Html::rawElement( 'tr', array(), $namespaceSelection ) . "\n" . - Html::rawElement( 'tr', array(), $filterSelection ) . "\n" . - Html::rawElement( 'tr', array(), $extraOptions ) . "\n" . - Html::rawElement( 'tr', array(), $dateSelectionAndSubmit ) . "\n" - ); + $form .= Xml::fieldset( $this->msg( 'sp-contributions-search' )->text() ); + $form .= Html::rawElement( 'table', array( 'class' => 'mw-contributions-table' ), "\n" . + Html::rawElement( 'tr', array(), $targetSelection ) . "\n" . + Html::rawElement( 'tr', array(), $namespaceSelection ) . "\n" . + Html::rawElement( 'tr', array(), $filterSelection ) . "\n" . + Html::rawElement( 'tr', array(), $extraOptions ) . "\n" . + Html::rawElement( 'tr', array(), $dateSelectionAndSubmit ) . "\n" + ); $explain = $this->msg( 'sp-contributions-explain' ); if ( !$explain->isBlank() ) { $form .= "

    {$explain->parse()}

    "; } - $form .= Xml::closeElement( 'fieldset' ) . - Xml::closeElement( 'form' ); + + $form .= Xml::closeElement( 'fieldset' ) . Xml::closeElement( 'form' ); + return $form; } @@ -552,9 +595,11 @@ class SpecialContributions extends SpecialPage { */ class ContribsPager extends ReverseChronologicalPager { public $mDefaultDirection = true; - var $messages, $target; - var $namespace = '', $mDb; - var $preventClickjacking = false; + public $messages; + public $target; + public $namespace = ''; + public $mDb; + public $preventClickjacking = false; /** * @var array @@ -564,7 +609,15 @@ class ContribsPager extends ReverseChronologicalPager { function __construct( IContextSource $context, array $options ) { parent::__construct( $context ); - $msgs = array( 'uctop', 'diff', 'newarticle', 'rollbacklink', 'diff', 'hist', 'rev-delundel', 'pipe-separator' ); + $msgs = array( + 'diff', + 'hist', + 'newarticle', + 'pipe-separator', + 'rev-delundel', + 'rollbacklink', + 'uctop' + ); foreach ( $msgs as $msg ) { $this->messages[$msg] = $this->msg( $msg )->escaped(); @@ -590,6 +643,7 @@ class ContribsPager extends ReverseChronologicalPager { function getDefaultQuery() { $query = parent::getDefaultQuery(); $query['target'] = $this->target; + return $query; } @@ -603,7 +657,11 @@ class ContribsPager extends ReverseChronologicalPager { * @return ResultWrapper */ function reallyDoQuery( $offset, $limit, $descending ) { - list( $tables, $fields, $conds, $fname, $options, $join_conds ) = $this->buildQueryInfo( $offset, $limit, $descending ); + list( $tables, $fields, $conds, $fname, $options, $join_conds ) = $this->buildQueryInfo( + $offset, + $limit, + $descending + ); $pager = $this; /* @@ -624,8 +682,13 @@ class ContribsPager extends ReverseChronologicalPager { * $limit: see phpdoc above * $descending: see phpdoc above */ - $data = array( $this->mDb->select( $tables, $fields, $conds, $fname, $options, $join_conds ) ); - wfRunHooks( 'ContribsPager::reallyDoQuery', array( &$data, $pager, $offset, $limit, $descending ) ); + $data = array( $this->mDb->select( + $tables, $fields, $conds, $fname, $options, $join_conds + ) ); + wfRunHooks( + 'ContribsPager::reallyDoQuery', + array( &$data, $pager, $offset, $limit, $descending ) + ); $result = array(); @@ -673,15 +736,15 @@ class ContribsPager extends ReverseChronologicalPager { $join_cond['user'] = Revision::userJoinCond(); $queryInfo = array( - 'tables' => $tables, - 'fields' => array_merge( + 'tables' => $tables, + 'fields' => array_merge( Revision::selectFields(), Revision::selectUserFields(), array( 'page_namespace', 'page_title', 'page_is_new', 'page_latest', 'page_is_redirect', 'page_len' ) ), - 'conds' => $conds, - 'options' => array( 'USE INDEX' => array( 'revision' => $index ) ), + 'conds' => $conds, + 'options' => array( 'USE INDEX' => array( 'revision' => $index ) ), 'join_conds' => $join_cond ); @@ -695,6 +758,7 @@ class ContribsPager extends ReverseChronologicalPager { ); wfRunHooks( 'ContribsPager::getQueryInfo', array( &$this, &$queryInfo ) ); + return $queryInfo; } @@ -709,7 +773,7 @@ class ContribsPager extends ReverseChronologicalPager { # ignore local groups with the bot right # @todo FIXME: Global groups may have 'bot' rights $groupsWithBotPermission = User::getGroupsWithPermission( 'bot' ); - if( count( $groupsWithBotPermission ) ) { + if ( count( $groupsWithBotPermission ) ) { $tables[] = 'user_groups'; $condition[] = 'ug_group IS NULL'; $join_conds['user_groups'] = array( @@ -729,12 +793,15 @@ class ContribsPager extends ReverseChronologicalPager { $index = 'usertext_timestamp'; } } + if ( $this->deletedOnly ) { $condition[] = 'rev_deleted != 0'; } + if ( $this->topOnly ) { $condition[] = 'rev_id = page_latest'; } + return array( $tables, $index, $condition, $join_conds ); } @@ -746,20 +813,20 @@ class ContribsPager extends ReverseChronologicalPager { if ( !$this->associated ) { return array( "page_namespace $eq_op $selectedNS" ); - } else { - $associatedNS = $this->mDb->addQuotes ( - MWNamespace::getAssociated( $this->namespace ) - ); - return array( - "page_namespace $eq_op $selectedNS " . - $bool_op . - " page_namespace $eq_op $associatedNS" - ); } - } else { - return array(); + $associatedNS = $this->mDb->addQuotes( + MWNamespace::getAssociated( $this->namespace ) + ); + + return array( + "page_namespace $eq_op $selectedNS " . + $bool_op . + " page_namespace $eq_op $associatedNS" + ); } + + return array(); } function getIndexField() { @@ -773,7 +840,7 @@ class ContribsPager extends ReverseChronologicalPager { $batch = new LinkBatch(); # Give some pointers to make (last) links foreach ( $this->mResult as $row ) { - if( isset( $row->rev_parent_id ) && $row->rev_parent_id ) { + if ( isset( $row->rev_parent_id ) && $row->rev_parent_id ) { $revIds[] = $row->rev_parent_id; } if ( isset( $row->rev_id ) ) { @@ -830,7 +897,7 @@ class ContribsPager extends ReverseChronologicalPager { */ wfSuppressWarnings(); $rev = new Revision( $row ); - $validRevision = (bool) $rev->getId(); + $validRevision = (bool)$rev->getId(); wfRestoreWarnings(); if ( $validRevision ) { @@ -850,8 +917,8 @@ class ContribsPager extends ReverseChronologicalPager { $topmarktext .= '' . $this->messages['uctop'] . ''; # Add rollback link if ( !$row->page_is_new && $page->quickUserCan( 'rollback', $user ) - && $page->quickUserCan( 'edit', $user ) ) - { + && $page->quickUserCan( 'edit', $user ) + ) { $this->preventClickjacking(); $topmarktext .= ' ' . Linker::generateRollback( $rev, $this->getContext() ); } @@ -881,11 +948,22 @@ class ContribsPager extends ReverseChronologicalPager { // For some reason rev_parent_id isn't populated for this row. // Its rumoured this is true on wikipedia for some revisions (bug 34922). // Next best thing is to have the total number of bytes. - $chardiff = ' . . ' . Linker::formatRevisionSize( $row->rev_len ) . ' . . '; + $chardiff = ' . . '; + $chardiff .= Linker::formatRevisionSize( $row->rev_len ); + $chardiff .= ' . . '; } else { - $parentLen = isset( $this->mParentLens[$row->rev_parent_id] ) ? $this->mParentLens[$row->rev_parent_id] : 0; - $chardiff = ' . . ' . ChangesList::showCharacterDifference( - $parentLen, $row->rev_len, $this->getContext() ) . ' . . '; + $parentLen = 0; + if ( isset( $this->mParentLens[$row->rev_parent_id] ) ) { + $parentLen = $this->mParentLens[$row->rev_parent_id]; + } + + $chardiff = ' . . '; + $chardiff .= ChangesList::showCharacterDifference( + $parentLen, + $row->rev_len, + $this->getContext() + ); + $chardiff .= ' . . '; } $lang = $this->getLanguage(); @@ -908,7 +986,7 @@ class ContribsPager extends ReverseChronologicalPager { # Show user names for /newbies as there may be different users. # Note that we already excluded rows with hidden user names. if ( $this->contribs == 'newbie' ) { - $userlink = ' . . ' . Linker::userLink( $rev->getUser(), $rev->getUserText() ); + $userlink = ' . . ' . $lang->getDirMark() . Linker::userLink( $rev->getUser(), $rev->getUserText() ); $userlink .= ' ' . $this->msg( 'parentheses' )->rawParams( Linker::userTalkLink( $rev->getUser(), $rev->getUserText() ) )->escaped() . ' '; } else { @@ -932,16 +1010,24 @@ class ContribsPager extends ReverseChronologicalPager { $del .= ' '; } - $diffHistLinks = $this->msg( 'parentheses' )->rawParams( $difftext . $this->messages['pipe-separator'] . $histlink )->escaped(); - $ret = "{$del}{$d} {$diffHistLinks}{$chardiff}{$nflag}{$mflag} {$link}{$userlink} {$comment} {$topmarktext}"; + $diffHistLinks = $this->msg( 'parentheses' ) + ->rawParams( $difftext . $this->messages['pipe-separator'] . $histlink ) + ->escaped(); + $ret = "{$del}{$d} {$diffHistLinks}{$chardiff}{$nflag}{$mflag} "; + $ret .= "{$link}{$userlink} {$comment} {$topmarktext}"; # Denote if username is redacted for this edit if ( $rev->isDeleted( Revision::DELETED_USER ) ) { - $ret .= " " . $this->msg( 'rev-deleted-user-contribs' )->escaped() . ""; + $ret .= " " . + $this->msg( 'rev-deleted-user-contribs' )->escaped() . + ""; } # Tags, if any. - list( $tagSummary, $newClasses ) = ChangeTags::formatSummaryRow( $row->ts_tags, 'contributions' ); + list( $tagSummary, $newClasses ) = ChangeTags::formatSummaryRow( + $row->ts_tags, + 'contributions' + ); $classes = array_merge( $classes, $newClasses ); $ret .= " $tagSummary"; } @@ -957,6 +1043,7 @@ class ContribsPager extends ReverseChronologicalPager { } wfProfileOut( __METHOD__ ); + return $ret; } @@ -966,7 +1053,8 @@ class ContribsPager extends ReverseChronologicalPager { */ function getSqlComment() { if ( $this->namespace || $this->deletedOnly ) { - return 'contributions page filtered for namespace or RevisionDeleted edits'; // potentially slow, see CR r58153 + // potentially slow, see CR r58153 + return 'contributions page filtered for namespace or RevisionDeleted edits'; } else { return 'contributions page unfiltered'; } diff --git a/includes/specials/SpecialDeadendpages.php b/includes/specials/SpecialDeadendpages.php index 6978d6bb..44137c1e 100644 --- a/includes/specials/SpecialDeadendpages.php +++ b/includes/specials/SpecialDeadendpages.php @@ -59,24 +59,29 @@ class DeadendPagesPage extends PageQueryPage { function getQueryInfo() { return array( 'tables' => array( 'page', 'pagelinks' ), - 'fields' => array( 'namespace' => 'page_namespace', - 'title' => 'page_title', - 'value' => 'page_title' + 'fields' => array( + 'namespace' => 'page_namespace', + 'title' => 'page_title', + 'value' => 'page_title' ), - 'conds' => array( 'pl_from IS NULL', - 'page_namespace' => MWNamespace::getContentNamespaces(), - 'page_is_redirect' => 0 + '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' - ) ) ) + 'join_conds' => array( + 'pagelinks' => array( + 'LEFT JOIN', + array( 'page_id=pl_from' ) + ) + ) ); } function getOrderFields() { // For some crazy reason ordering by a constant // causes a filesort - if( count( MWNamespace::getContentNamespaces() ) > 1 ) { + 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 e374979e..9b9888ad 100644 --- a/includes/specials/SpecialDeletedContributions.php +++ b/includes/specials/SpecialDeletedContributions.php @@ -27,13 +27,20 @@ */ class DeletedContribsPager extends IndexPager { public $mDefaultDirection = true; - var $messages, $target; - var $namespace = '', $mDb; + public $messages; + public $target; + public $namespace = ''; + public $mDb; + + /** + * @var string Navigation bar with paging links. + */ + protected $mNavigationBar; function __construct( IContextSource $context, $target, $namespace = false ) { parent::__construct( $context ); $msgs = array( 'deletionlog', 'undeleteviewlink', 'diff' ); - foreach( $msgs as $msg ) { + foreach ( $msgs as $msg ) { $this->messages[$msg] = $this->msg( $msg )->escaped(); } $this->target = $target; @@ -44,6 +51,7 @@ class DeletedContribsPager extends IndexPager { function getDefaultQuery() { $query = parent::getDefaultQuery(); $query['target'] = $this->target; + return $query; } @@ -52,17 +60,18 @@ class DeletedContribsPager extends IndexPager { $conds = array_merge( $userCond, $this->getNamespaceCond() ); $user = $this->getUser(); // Paranoia: avoid brute force searches (bug 17792) - if( !$user->isAllowed( 'deletedhistory' ) ) { + if ( !$user->isAllowed( 'deletedhistory' ) ) { $conds[] = $this->mDb->bitAnd( 'ar_deleted', Revision::DELETED_USER ) . ' = 0'; - } elseif( !$user->isAllowed( 'suppressrevision' ) ) { + } elseif ( !$user->isAllowed( 'suppressrevision' ) ) { $conds[] = $this->mDb->bitAnd( 'ar_deleted', Revision::SUPPRESSED_USER ) . ' != ' . Revision::SUPPRESSED_USER; } + return array( 'tables' => array( 'archive' ), 'fields' => array( - 'ar_rev_id', 'ar_namespace', 'ar_title', 'ar_timestamp', 'ar_comment', 'ar_minor_edit', - 'ar_user', 'ar_user_text', 'ar_deleted' + 'ar_rev_id', 'ar_namespace', 'ar_title', 'ar_timestamp', 'ar_comment', + 'ar_minor_edit', 'ar_user', 'ar_user_text', 'ar_deleted' ), 'conds' => $conds, 'options' => array( 'USE INDEX' => $index ) @@ -107,8 +116,17 @@ class DeletedContribsPager extends IndexPager { $lang = $this->getLanguage(); $limits = $lang->pipeList( $limitLinks ); - $this->mNavigationBar = "(" . $lang->pipeList( array( $pagingLinks['first'], $pagingLinks['last'] ) ) . ") " . - $this->msg( 'viewprevnext' )->rawParams( $pagingLinks['prev'], $pagingLinks['next'], $limits )->escaped(); + $firstLast = $lang->pipeList( array( $pagingLinks['first'], $pagingLinks['last'] ) ); + $firstLast = $this->msg( 'parentheses' )->rawParams( $firstLast )->escaped(); + $prevNext = $this->msg( 'viewprevnext' ) + ->rawParams( + $pagingLinks['prev'], + $pagingLinks['next'], + $limits + )->escaped(); + $separator = $this->msg( 'word-separator' )->escaped(); + $this->mNavigationBar = $firstLast . $separator . $prevNext; + return $this->mNavigationBar; } @@ -138,15 +156,15 @@ class DeletedContribsPager extends IndexPager { $page = Title::makeTitle( $row->ar_namespace, $row->ar_title ); $rev = new Revision( array( - 'title' => $page, - 'id' => $row->ar_rev_id, - 'comment' => $row->ar_comment, - 'user' => $row->ar_user, - 'user_text' => $row->ar_user_text, - 'timestamp' => $row->ar_timestamp, - 'minor_edit' => $row->ar_minor_edit, - 'deleted' => $row->ar_deleted, - ) ); + 'title' => $page, + 'id' => $row->ar_rev_id, + 'comment' => $row->ar_comment, + 'user' => $row->ar_user, + 'user_text' => $row->ar_user_text, + 'timestamp' => $row->ar_timestamp, + 'minor_edit' => $row->ar_minor_edit, + 'deleted' => $row->ar_deleted, + ) ); $undelete = SpecialPage::getTitleFor( 'Undelete' ); @@ -168,7 +186,7 @@ class DeletedContribsPager extends IndexPager { $user = $this->getUser(); - if( $user->isAllowed( 'deletedtext' ) ) { + if ( $user->isAllowed( 'deletedtext' ) ) { $last = Linker::linkKnown( $undelete, $this->messages['diff'], @@ -184,9 +202,10 @@ class DeletedContribsPager extends IndexPager { } $comment = Linker::revComment( $rev ); - $date = htmlspecialchars( $this->getLanguage()->userTimeAndDate( $rev->getTimestamp(), $user ) ); + $date = $this->getLanguage()->userTimeAndDate( $rev->getTimestamp(), $user ); + $date = htmlspecialchars( $date ); - if( !$user->isAllowed( 'undelete' ) || !$rev->userCan( Revision::DELETED_TEXT, $user ) ) { + if ( !$user->isAllowed( 'undelete' ) || !$rev->userCan( Revision::DELETED_TEXT, $user ) ) { $link = $date; // unusable link } else { $link = Linker::linkKnown( @@ -200,7 +219,7 @@ class DeletedContribsPager extends IndexPager { ); } // Style deleted items - if( $rev->isDeleted( Revision::DELETED_TEXT ) ) { + if ( $rev->isDeleted( Revision::DELETED_TEXT ) ) { $link = '' . $link . ''; } @@ -210,7 +229,7 @@ class DeletedContribsPager extends IndexPager { array( 'class' => 'mw-changeslist-title' ) ); - if( $rev->isMinor() ) { + if ( $rev->isMinor() ) { $mflag = ChangesList::flag( 'minor' ); } else { $mflag = ''; @@ -218,7 +237,9 @@ class DeletedContribsPager extends IndexPager { // Revision delete link $del = Linker::getRevDeleteLink( $user, $rev, $page ); - if ( $del ) $del .= ' '; + if ( $del ) { + $del .= ' '; + } $tools = Html::rawElement( 'span', @@ -231,13 +252,14 @@ class DeletedContribsPager extends IndexPager { $ret = "{$del}{$link} {$tools} {$separator} {$mflag} {$pagelink} {$comment}"; # Denote if username is redacted for this edit - if( $rev->isDeleted( Revision::DELETED_USER ) ) { + if ( $rev->isDeleted( Revision::DELETED_USER ) ) { $ret .= " " . $this->msg( 'rev-deleted-user-contribs' )->escaped() . ""; } $ret = Html::rawElement( 'li', array(), $ret ) . "\n"; wfProfileOut( __METHOD__ ); + return $ret; } @@ -254,7 +276,7 @@ class DeletedContribsPager extends IndexPager { class DeletedContributionsPage extends SpecialPage { function __construct() { parent::__construct( 'DeletedContributions', 'deletedhistory', - /*listed*/ true, /*function*/ false, /*file*/ false ); + /*listed*/true, /*function*/false, /*file*/false ); } /** @@ -265,6 +287,7 @@ class DeletedContributionsPage extends SpecialPage { */ function execute( $par ) { global $wgQueryPageDefaultLimit; + $this->setHeaders(); $this->outputHeader(); @@ -272,6 +295,7 @@ class DeletedContributionsPage extends SpecialPage { if ( !$this->userCanExecute( $user ) ) { $this->displayRestrictionError(); + return; } @@ -289,6 +313,7 @@ class DeletedContributionsPage extends SpecialPage { if ( !strlen( $target ) ) { $out->addHTML( $this->getForm( '' ) ); + return; } @@ -298,6 +323,7 @@ class DeletedContributionsPage extends SpecialPage { $userObj = User::newFromName( $target, false ); if ( !$userObj ) { $out->addHTML( $this->getForm( '' ) ); + return; } $this->getSkin()->setRelevantUser( $userObj ); @@ -316,28 +342,33 @@ class DeletedContributionsPage extends SpecialPage { $pager = new DeletedContribsPager( $this->getContext(), $target, $options['namespace'] ); if ( !$pager->getNumRows() ) { $out->addWikiMsg( 'nocontribs' ); + return; } # Show a message about slave lag, if applicable $lag = wfGetLB()->safeGetLag( $pager->getDatabase() ); - if( $lag > 0 ) + if ( $lag > 0 ) { $out->showLagWarning( $lag ); + } $out->addHTML( '

    ' . $pager->getNavigationBar() . '

    ' . - $pager->getBody() . - '

    ' . $pager->getNavigationBar() . '

    ' ); + $pager->getBody() . + '

    ' . $pager->getNavigationBar() . '

    ' ); # If there were contributions, and it was a valid user or IP, show # the appropriate "footer" message - WHOIS tools, etc. - if( $target != 'newbies' ) { - $message = IP::isIPAddress( $target ) - ? 'sp-contributions-footer-anon' - : 'sp-contributions-footer'; - - if( !$this->msg( $message )->isDisabled() ) { - $out->wrapWikiMsg( "", array( $message, $target ) ); + if ( $target != 'newbies' ) { + $message = IP::isIPAddress( $target ) ? + 'sp-contributions-footer-anon' : + 'sp-contributions-footer'; + + if ( !$this->msg( $message )->isDisabled() ) { + $out->wrapWikiMsg( + "", + array( $message, $target ) + ); } } } @@ -358,11 +389,12 @@ class DeletedContributionsPage extends SpecialPage { $nt = $userObj->getUserPage(); $id = $userObj->getID(); $talk = $nt->getTalkPage(); - if( $talk ) { + if ( $talk ) { # Talk page link $tools[] = Linker::link( $talk, $this->msg( 'sp-contributions-talk' )->escaped() ); - if( ( $id !== null ) || ( $id === null && IP::isIPAddress( $nt->getText() ) ) ) { - if( $this->getUser()->isAllowed( 'block' ) ) { # Block / Change block / Unblock links + if ( ( $id !== null ) || ( $id === null && IP::isIPAddress( $nt->getText() ) ) ) { + # Block / Change block / Unblock links + if ( $this->getUser()->isAllowed( 'block' ) ) { if ( $userObj->isBlocked() ) { $tools[] = Linker::linkKnown( # Change block link SpecialPage::getTitleFor( 'Block', $nt->getDBkey() ), @@ -377,8 +409,8 @@ class DeletedContributionsPage extends SpecialPage { 'ip' => $nt->getDBkey() ) ); - } - else { # User is not blocked + } else { + # User is not blocked $tools[] = Linker::linkKnown( # Block link SpecialPage::getTitleFor( 'Block', $nt->getDBkey() ), $this->msg( 'blocklink' )->escaped() @@ -419,7 +451,7 @@ class DeletedContributionsPage extends SpecialPage { # Add a link to change user rights for privileged users $userrightsPage = new UserrightsPage(); $userrightsPage->setContext( $this->getContext() ); - if( $userrightsPage->userCanChangeRights( $userObj ) ) { + if ( $userrightsPage->userCanChangeRights( $userObj ) ) { $tools[] = Linker::linkKnown( SpecialPage::getTitleFor( 'Userrights', $nt->getDBkey() ), $this->msg( 'sp-contributions-userrights' )->escaped() @@ -432,7 +464,8 @@ class DeletedContributionsPage extends SpecialPage { // Show a note if the user is blocked and display the last block log entry. if ( $userObj->isBlocked() ) { - $out = $this->getOutput(); // LogEventsList::showLogExtract() wants the first parameter by ref + // LogEventsList::showLogExtract() wants the first parameter by ref + $out = $this->getOutput(); LogEventsList::showLogExtract( $out, 'block', @@ -451,16 +484,7 @@ class DeletedContributionsPage extends SpecialPage { } } - // Old message 'contribsub' had one parameter, but that doesn't work for - // 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'. - $oldMsg = $this->msg( 'contribsub' ); - if ( $oldMsg->exists() ) { - return $oldMsg->rawParams( "$user ($links)" ); - } else { - return $this->msg( 'contribsub2' )->rawParams( $user, $links ); - } + return $this->msg( 'contribsub2' )->rawParams( $user, $links )->params( $userObj->getName() ); } /** @@ -499,27 +523,38 @@ class DeletedContributionsPage extends SpecialPage { $f .= "\t" . Html::hidden( $name, $value ) . "\n"; } - $f .= Xml::openElement( 'fieldset' ) . - Xml::element( 'legend', array(), $this->msg( 'sp-contributions-search' )->text() ) . - Xml::tags( 'label', array( 'for' => 'target' ), $this->msg( 'sp-contributions-username' )->parse() ) . ' ' . - Html::input( 'target', $options['target'], 'text', array( + $f .= Xml::openElement( 'fieldset' ); + $f .= Xml::element( 'legend', array(), $this->msg( 'sp-contributions-search' )->text() ); + $f .= Xml::tags( + 'label', + array( 'for' => 'target' ), + $this->msg( 'sp-contributions-username' )->parse() + ) . ' '; + $f .= Html::input( + 'target', + $options['target'], + 'text', + array( 'size' => '20', 'required' => '' - ) + ( $options['target'] ? array() : array( 'autofocus' ) ) ) . ' '. - Html::namespaceSelector( - array( - 'selected' => $options['namespace'], - 'all' => '', - 'label' => $this->msg( 'namespace' )->text() - ), array( - 'name' => 'namespace', - 'id' => 'namespace', - 'class' => 'namespaceselector', - ) - ) . ' ' . - Xml::submitButton( $this->msg( 'sp-contributions-submit' )->text() ) . - Xml::closeElement( 'fieldset' ) . - Xml::closeElement( 'form' ); + ) + ( $options['target'] ? array() : array( 'autofocus' ) ) + ) . ' '; + $f .= Html::namespaceSelector( + array( + 'selected' => $options['namespace'], + 'all' => '', + 'label' => $this->msg( 'namespace' )->text() + ), + array( + 'name' => 'namespace', + 'id' => 'namespace', + 'class' => 'namespaceselector', + ) + ) . ' '; + $f .= Xml::submitButton( $this->msg( 'sp-contributions-submit' )->text() ); + $f .= Xml::closeElement( 'fieldset' ); + $f .= Xml::closeElement( 'form' ); + return $f; } diff --git a/includes/specials/SpecialDisambiguations.php b/includes/specials/SpecialDisambiguations.php deleted file mode 100644 index 2126ca52..00000000 --- a/includes/specials/SpecialDisambiguations.php +++ /dev/null @@ -1,165 +0,0 @@ -msg( 'disambiguations-text' )->parseAsBlock(); - } - - /** - * @return string|bool False on failure - */ - function getQueryFromLinkBatch() { - $dbr = wfGetDB( DB_SLAVE ); - $dMsgText = $this->msg( 'disambiguationspage' )->inContentLanguage()->text(); - $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 ) { - # @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" ); - } - $linkBatch->addObj( $dp ); - } else { - # Get all the templates linked from the Mediawiki:Disambiguationspage - $disPageObj = Title::makeTitleSafe( NS_MEDIAWIKI, 'disambiguationspage' ); - $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() - ), __METHOD__ ); - - foreach ( $res as $row ) { - $linkBatch->addObj( Title::makeTitle( NS_TEMPLATE, $row->pl_title )); - } - } - $set = $linkBatch->constructSet( 'tl', $dbr ); - - if( $set === false ) { - # 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" ); - } - return $set; - } - - function getQueryInfo() { - // @todo FIXME: What are pagelinks and p2 doing here? - return array ( - 'tables' => array( - 'templatelinks', - 'p1' => 'page', - 'pagelinks', - 'p2' => 'page' - ), - 'fields' => array( - 'namespace' => 'p1.page_namespace', - 'title' => 'p1.page_title', - 'value' => 'pl_from' - ), - 'conds' => array( - $this->getQueryFromLinkBatch(), - '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() - ) - ); - } - - function getOrderFields() { - return array( 'tl_namespace', 'tl_title', 'value' ); - } - - function sortDescending() { - return false; - } - - /** - * Fetch links and cache their existence - * - * @param $db DatabaseBase - * @param $res - */ - function preprocessResults( $db, $res ) { - if ( !$res->numRows() ) { - return; - } - - $batch = new LinkBatch; - foreach ( $res as $row ) { - $batch->add( $row->namespace, $row->title ); - } - $batch->execute(); - - $res->seek( 0 ); - } - - function formatResult( $skin, $result ) { - $title = Title::newFromID( $result->value ); - $dp = Title::makeTitle( $result->namespace, $result->title ); - - $from = Linker::link( $title ); - $edit = Linker::link( - $title, - $this->msg( 'parentheses', $this->msg( 'editlink' )->text() )->escaped(), - array(), - array( 'redirect' => 'no', 'action' => 'edit' ) - ); - $arr = $this->getLanguage()->getArrow(); - $to = Linker::link( $dp ); - - return "$from $edit $arr $to"; - } - - protected function getGroupName() { - return 'pages'; - } -} diff --git a/includes/specials/SpecialDoubleRedirects.php b/includes/specials/SpecialDoubleRedirects.php index 5a5d749c..c364f70f 100644 --- a/includes/specials/SpecialDoubleRedirects.php +++ b/includes/specials/SpecialDoubleRedirects.php @@ -28,7 +28,6 @@ * @ingroup SpecialPage */ class DoubleRedirectsPage extends QueryPage { - function __construct( $name = 'DoubleRedirects' ) { parent::__construct( $name ); } @@ -52,8 +51,8 @@ class DoubleRedirectsPage extends QueryPage { function reallyGetQueryInfo( $namespace = null, $title = null ) { $limitToTitle = !( $namespace === null && $title === null ); $dbr = wfGetDB( DB_SLAVE ); - $retval = array ( - 'tables' => array ( + $retval = array( + 'tables' => array( 'ra' => 'redirect', 'rb' => 'redirect', 'pa' => 'page', @@ -91,10 +90,12 @@ class DoubleRedirectsPage extends QueryPage { 'rb.rd_from = pb.page_id', ) ); + if ( $limitToTitle ) { $retval['conds']['pa.page_namespace'] = $namespace; $retval['conds']['pa.page_title'] = $title; } + return $retval; } @@ -103,9 +104,14 @@ class DoubleRedirectsPage extends QueryPage { } function getOrderFields() { - return array ( 'ra.rd_namespace', 'ra.rd_title' ); + return array( 'ra.rd_namespace', 'ra.rd_title' ); } + /** + * @param Skin $skin + * @param object $result Result row + * @return string + */ function formatResult( $skin, $result ) { $titleA = Title::makeTitle( $result->namespace, $result->title ); @@ -116,10 +122,17 @@ class DoubleRedirectsPage extends QueryPage { // using the filter of reallyGetQueryInfo. if ( $result && !isset( $result->nsb ) ) { $dbr = wfGetDB( DB_SLAVE ); - $qi = $this->reallyGetQueryInfo( $result->namespace, - $result->title ); - $res = $dbr->select( $qi['tables'], $qi['fields'], - $qi['conds'], __METHOD__ ); + $qi = $this->reallyGetQueryInfo( + $result->namespace, + $result->title + ); + $res = $dbr->select( + $qi['tables'], + $qi['fields'], + $qi['conds'], + __METHOD__ + ); + if ( $res ) { $result = $dbr->fetchObject( $res ); } @@ -160,7 +173,7 @@ class DoubleRedirectsPage extends QueryPage { $lang = $this->getLanguage(); $arr = $lang->getArrow() . $lang->getDirMark(); - return( "{$linkA} {$edit} {$arr} {$linkB} {$arr} {$linkC}" ); + return ( "{$linkA} {$edit} {$arr} {$linkB} {$arr} {$linkC}" ); } protected function getGroupName() { diff --git a/includes/specials/SpecialEditWatchlist.php b/includes/specials/SpecialEditWatchlist.php index d2838e01..501552e9 100644 --- a/includes/specials/SpecialEditWatchlist.php +++ b/includes/specials/SpecialEditWatchlist.php @@ -35,7 +35,6 @@ * @author Rob Church */ class SpecialEditWatchlist extends UnlistedSpecialPage { - /** * Editing modes */ @@ -50,7 +49,7 @@ class SpecialEditWatchlist extends UnlistedSpecialPage { private $badItems = array(); public function __construct() { - parent::__construct( 'EditWatchlist' ); + parent::__construct( 'EditWatchlist', 'editmywatchlist' ); } /** @@ -64,7 +63,7 @@ class SpecialEditWatchlist extends UnlistedSpecialPage { $out = $this->getOutput(); # Anons don't get a watchlist - if( $this->getUser()->isAnon() ) { + if ( $this->getUser()->isAnon() ) { $out->setPageTitle( $this->msg( 'watchnologin' ) ); $llink = Linker::linkKnown( SpecialPage::getTitleFor( 'Userlogin' ), @@ -73,6 +72,7 @@ class SpecialEditWatchlist extends UnlistedSpecialPage { array( 'returnto' => $this->getTitle()->getPrefixedText() ) ); $out->addHTML( $this->msg( 'watchlistanontext' )->rawParams( $llink )->parse() ); + return; } @@ -81,20 +81,20 @@ class SpecialEditWatchlist extends UnlistedSpecialPage { $this->outputHeader(); - $out->addSubtitle( $this->msg( 'watchlistfor2', $this->getUser()->getName() - )->rawParams( SpecialEditWatchlist::buildTools( null ) ) ); + $out->addSubtitle( $this->msg( 'watchlistfor2', $this->getUser()->getName() ) + ->rawParams( SpecialEditWatchlist::buildTools( null ) ) ); # B/C: $mode used to be waaay down the parameter list, and the first parameter # was $wgUser - if( $mode instanceof User ) { + if ( $mode instanceof User ) { $args = func_get_args(); - if( count( $args >= 4 ) ) { + if ( count( $args ) >= 4 ) { $mode = $args[3]; } } $mode = self::getMode( $this->getRequest(), $mode ); - switch( $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. @@ -102,7 +102,7 @@ class SpecialEditWatchlist extends UnlistedSpecialPage { case self::EDIT_RAW: $out->setPageTitle( $this->msg( 'watchlistedit-raw-title' ) ); $form = $this->getRawForm(); - if( $form->show() ) { + if ( $form->show() ) { $out->addHTML( $this->successMessage ); $out->addReturnTo( SpecialPage::getTitleFor( 'Watchlist' ) ); } @@ -112,7 +112,7 @@ class SpecialEditWatchlist extends UnlistedSpecialPage { default: $out->setPageTitle( $this->msg( 'watchlistedit-normal-title' ) ); $form = $this->getNormalForm(); - if( $form->show() ) { + if ( $form->show() ) { $out->addHTML( $this->successMessage ); $out->addReturnTo( SpecialPage::getTitleFor( 'Watchlist' ) ); } elseif ( $this->toc !== false ) { @@ -131,15 +131,17 @@ class SpecialEditWatchlist extends UnlistedSpecialPage { */ private function extractTitles( $list ) { $list = explode( "\n", trim( $list ) ); - if( !is_array( $list ) ) { + if ( !is_array( $list ) ) { return array(); } + $titles = array(); - foreach( $list as $text ) { + + foreach ( $list as $text ) { $text = trim( $text ); - if( strlen( $text ) > 0 ) { + if ( strlen( $text ) > 0 ) { $title = Title::newFromText( $text ); - if( $title instanceof Title && $title->isWatchable() ) { + if ( $title instanceof Title && $title->isWatchable() ) { $titles[] = $title; } } @@ -148,9 +150,11 @@ class SpecialEditWatchlist extends UnlistedSpecialPage { GenderCache::singleton()->doTitlesArray( $titles ); $list = array(); - foreach( $titles as $title ) { + /** @var Title $title */ + foreach ( $titles as $title ) { $list[] = $title->getPrefixedText(); } + return array_unique( $list ); } @@ -158,44 +162,45 @@ class SpecialEditWatchlist extends UnlistedSpecialPage { $wanted = $this->extractTitles( $data['Titles'] ); $current = $this->getWatchlist(); - if( count( $wanted ) > 0 ) { + 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 ) { + if ( count( $toWatch ) > 0 || count( $toUnwatch ) > 0 ) { $this->successMessage = $this->msg( 'watchlistedit-raw-done' )->parse(); } else { return false; } - if( count( $toWatch ) > 0 ) { + if ( count( $toWatch ) > 0 ) { $this->successMessage .= ' ' . $this->msg( 'watchlistedit-raw-added' - )->numParams( count( $toWatch ) )->parse(); + )->numParams( count( $toWatch ) )->parse(); $this->showTitles( $toWatch, $this->successMessage ); } - if( count( $toUnwatch ) > 0 ) { + if ( count( $toUnwatch ) > 0 ) { $this->successMessage .= ' ' . $this->msg( 'watchlistedit-raw-removed' - )->numParams( count( $toUnwatch ) )->parse(); + )->numParams( count( $toUnwatch ) )->parse(); $this->showTitles( $toUnwatch, $this->successMessage ); } } else { $this->clearWatchlist(); $this->getUser()->invalidateCache(); - if( count( $current ) > 0 ) { + if ( count( $current ) > 0 ) { $this->successMessage = $this->msg( 'watchlistedit-raw-done' )->parse(); } else { return false; } - $this->successMessage .= ' ' . $this->msg( 'watchlistedit-raw-removed' - )->numParams( count( $current ) )->parse(); + $this->successMessage .= ' ' . $this->msg( 'watchlistedit-raw-removed' ) + ->numParams( count( $current ) )->parse(); $this->showTitles( $current, $this->successMessage ); } + return true; } @@ -212,29 +217,35 @@ class SpecialEditWatchlist extends UnlistedSpecialPage { $talk = $this->msg( 'talkpagelinktext' )->escaped(); // Do a batch existence check $batch = new LinkBatch(); - foreach( $titles as $title ) { - if( !$title instanceof Title ) { + foreach ( $titles as $title ) { + if ( !$title instanceof Title ) { $title = Title::newFromText( $title ); } - if( $title instanceof Title ) { + + if ( $title instanceof Title ) { $batch->addObj( $title ); $batch->addObj( $title->getTalkPage() ); } } + $batch->execute(); + // Print out the list $output .= "
      \n"; - foreach( $titles as $title ) { - if( !$title instanceof Title ) { + + foreach ( $titles as $title ) { + if ( !$title instanceof Title ) { $title = Title::newFromText( $title ); } - if( $title instanceof Title ) { + + if ( $title instanceof Title ) { $output .= "
    • " . Linker::link( $title ) . ' (' . Linker::link( $title->getTalkPage(), $talk ) . ")
    • \n"; } } + $output .= "
    \n"; } @@ -247,6 +258,7 @@ class SpecialEditWatchlist extends UnlistedSpecialPage { private function getWatchlist() { $list = array(); $dbr = wfGetDB( DB_MASTER ); + $res = $dbr->select( 'watchlist', array( @@ -256,10 +268,12 @@ class SpecialEditWatchlist extends UnlistedSpecialPage { ), __METHOD__ ); - if( $res->numRows() > 0 ) { + + if ( $res->numRows() > 0 ) { $titles = array(); foreach ( $res as $row ) { $title = Title::makeTitleSafe( $row->wl_namespace, $row->wl_title ); + if ( $this->checkTitle( $title, $row->wl_namespace, $row->wl_title ) && !$title->isTalkPage() ) { @@ -270,11 +284,13 @@ class SpecialEditWatchlist extends UnlistedSpecialPage { GenderCache::singleton()->doTitlesArray( $titles ); - foreach( $titles as $title ) { + foreach ( $titles as $title ) { $list[] = $title->getPrefixedText(); } } + $this->cleanupWatchlist(); + return $list; } @@ -297,6 +313,7 @@ class SpecialEditWatchlist extends UnlistedSpecialPage { ); $lb = new LinkBatch(); + foreach ( $res as $row ) { $lb->add( $row->wl_namespace, $row->wl_title ); if ( !MWNamespace::isTalk( $row->wl_namespace ) ) { @@ -305,6 +322,7 @@ class SpecialEditWatchlist extends UnlistedSpecialPage { } $lb->execute(); + return $titles; } @@ -324,12 +342,14 @@ class SpecialEditWatchlist extends UnlistedSpecialPage { ) { $title = false; // unrecoverable } + if ( !$title || $title->getNamespace() != $namespace || $title->getDBkey() != $dbKey ) { $this->badItems[] = array( $title, $namespace, $dbKey ); } + return (bool)$title; } @@ -337,16 +357,17 @@ class SpecialEditWatchlist extends UnlistedSpecialPage { * Attempts to clean up broken items */ private function cleanupWatchlist() { - if( !count( $this->badItems ) ) { + if ( !count( $this->badItems ) ) { return; //nothing to do } + $dbw = wfGetDB( DB_MASTER ); $user = $this->getUser(); + foreach ( $this->badItems as $row ) { list( $title, $namespace, $dbKey ) = $row; - wfDebug( "User {$user->getName()} has broken watchlist item ns($namespace):$dbKey, " - . ( $title ? 'cleaning up' : 'deleting' ) . ".\n" - ); + $action = $title ? 'cleaning up' : 'deleting'; + wfDebug( "User {$user->getName()} has broken watchlist item ns($namespace):$dbKey, $action.\n" ); $dbw->delete( 'watchlist', array( @@ -387,11 +408,13 @@ class SpecialEditWatchlist extends UnlistedSpecialPage { private function watchTitles( $titles ) { $dbw = wfGetDB( DB_MASTER ); $rows = array(); - foreach( $titles as $title ) { - if( !$title instanceof Title ) { + + foreach ( $titles as $title ) { + if ( !$title instanceof Title ) { $title = Title::newFromText( $title ); } - if( $title instanceof Title ) { + + if ( $title instanceof Title ) { $rows[] = array( 'wl_user' => $this->getUser()->getId(), 'wl_namespace' => MWNamespace::getSubject( $title->getNamespace() ), @@ -406,6 +429,7 @@ class SpecialEditWatchlist extends UnlistedSpecialPage { ); } } + $dbw->insert( 'watchlist', $rows, __METHOD__, 'IGNORE' ); } @@ -419,11 +443,13 @@ class SpecialEditWatchlist extends UnlistedSpecialPage { */ private function unwatchTitles( $titles ) { $dbw = wfGetDB( DB_MASTER ); - foreach( $titles as $title ) { - if( !$title instanceof Title ) { + + foreach ( $titles as $title ) { + if ( !$title instanceof Title ) { $title = Title::newFromText( $title ); } - if( $title instanceof Title ) { + + if ( $title instanceof Title ) { $dbw->delete( 'watchlist', array( @@ -433,6 +459,7 @@ class SpecialEditWatchlist extends UnlistedSpecialPage { ), __METHOD__ ); + $dbw->delete( 'watchlist', array( @@ -442,6 +469,7 @@ class SpecialEditWatchlist extends UnlistedSpecialPage { ), __METHOD__ ); + $page = WikiPage::factory( $title ); wfRunHooks( 'UnwatchArticleComplete', array( $this->getUser(), &$page ) ); } @@ -451,15 +479,16 @@ class SpecialEditWatchlist extends UnlistedSpecialPage { public function submitNormal( $data ) { $removed = array(); - foreach( $data as $titles ) { + foreach ( $data as $titles ) { $this->unwatchTitles( $titles ); $removed = array_merge( $removed, $titles ); } - if( count( $removed ) > 0 ) { + if ( count( $removed ) > 0 ) { $this->successMessage = $this->msg( 'watchlistedit-normal-done' - )->numParams( count( $removed ) )->parse(); + )->numParams( count( $removed ) )->parse(); $this->showTitles( $removed, $this->successMessage ); + return true; } else { return false; @@ -477,7 +506,7 @@ class SpecialEditWatchlist extends UnlistedSpecialPage { $fields = array(); $count = 0; - foreach( $this->getWatchlistInfo() as $namespace => $pages ) { + foreach ( $this->getWatchlistInfo() as $namespace => $pages ) { if ( $namespace >= 0 ) { $fields['TitlesNs' . $namespace] = array( 'class' => 'EditWatchlistCheckboxSeriesField', @@ -486,8 +515,9 @@ class SpecialEditWatchlist extends UnlistedSpecialPage { ); } - foreach( array_keys( $pages ) as $dbkey ) { + foreach ( array_keys( $pages ) as $dbkey ) { $title = Title::makeTitleSafe( $namespace, $dbkey ); + if ( $this->checkTitle( $title, $namespace, $dbkey ) ) { $text = $this->buildRemoveLine( $title ); $fields['TitlesNs' . $namespace]['options'][$text] = $title->getPrefixedText(); @@ -500,30 +530,33 @@ class SpecialEditWatchlist extends UnlistedSpecialPage { if ( count( $fields ) > 1 && $count > 30 ) { $this->toc = Linker::tocIndent(); $tocLength = 0; - foreach( $fields as $data ) { + foreach ( $fields as $data ) { # strip out the 'ns' prefix from the section name: $ns = substr( $data['section'], 2 ); - $nsText = ($ns == NS_MAIN) + $nsText = ( $ns == NS_MAIN ) ? $this->msg( 'blanknamespace' )->escaped() : htmlspecialchars( $wgContLang->getFormattedNsText( $ns ) ); $this->toc .= Linker::tocLine( "editwatchlist-{$data['section']}", $nsText, $this->getLanguage()->formatNum( ++$tocLength ), 1 ) . Linker::tocLineEnd(); } + $this->toc = Linker::tocList( $this->toc ); } else { $this->toc = false; } - $form = new EditWatchlistNormalHTMLForm( $fields, $this->getContext() ); - $form->setTitle( $this->getTitle() ); + $context = new DerivativeContext( $this->getContext() ); + $context->setTitle( $this->getTitle() ); // Remove subpage + $form = new EditWatchlistNormalHTMLForm( $fields, $context ); $form->setSubmitTextMsg( 'watchlistedit-normal-submit' ); # Used message keys: 'accesskey-watchlistedit-normal-submit', 'tooltip-watchlistedit-normal-submit' $form->setSubmitTooltip( 'watchlistedit-normal-submit' ); $form->setWrapperLegendMsg( 'watchlistedit-normal-legend' ); $form->addHeaderText( $this->msg( 'watchlistedit-normal-explain' )->parse() ); $form->setSubmitCallback( array( $this, 'submitNormal' ) ); + return $form; } @@ -535,12 +568,15 @@ class SpecialEditWatchlist extends UnlistedSpecialPage { */ private function buildRemoveLine( $title ) { $link = Linker::link( $title ); - if( $title->isRedirect() ) { + + if ( $title->isRedirect() ) { // Linker already makes class mw-redirect, so this is redundant $link = '' . $link . ''; } + $tools[] = Linker::link( $title->getTalkPage(), $this->msg( 'talkpagelinktext' )->escaped() ); - if( $title->exists() ) { + + if ( $title->exists() ) { $tools[] = Linker::linkKnown( $title, $this->msg( 'history_short' )->escaped(), @@ -548,7 +584,8 @@ class SpecialEditWatchlist extends UnlistedSpecialPage { array( 'action' => 'history' ) ); } - if( $title->getNamespace() == NS_USER && !$title->isSubpage() ) { + + if ( $title->getNamespace() == NS_USER && !$title->isSubpage() ) { $tools[] = Linker::linkKnown( SpecialPage::getTitleFor( 'Contributions', $title->getText() ), $this->msg( 'contributions' )->escaped() @@ -574,14 +611,16 @@ class SpecialEditWatchlist extends UnlistedSpecialPage { 'default' => $titles, ), ); - $form = new HTMLForm( $fields, $this->getContext() ); - $form->setTitle( $this->getTitle( 'raw' ) ); + $context = new DerivativeContext( $this->getContext() ); + $context->setTitle( $this->getTitle( 'raw' ) ); // Reset subpage + $form = new HTMLForm( $fields, $context ); $form->setSubmitTextMsg( 'watchlistedit-raw-submit' ); # Used message keys: 'accesskey-watchlistedit-raw-submit', 'tooltip-watchlistedit-raw-submit' $form->setSubmitTooltip( 'watchlistedit-raw-submit' ); $form->setWrapperLegendMsg( 'watchlistedit-raw-legend' ); $form->addHeaderText( $this->msg( 'watchlistedit-raw-explain' )->parse() ); $form->setSubmitCallback( array( $this, 'submitRaw' ) ); + return $form; } @@ -595,19 +634,17 @@ class SpecialEditWatchlist extends UnlistedSpecialPage { */ public static function getMode( $request, $par ) { $mode = strtolower( $request->getVal( 'action', $par ) ); - switch( $mode ) { + + 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; } @@ -629,21 +666,26 @@ class SpecialEditWatchlist extends UnlistedSpecialPage { 'edit' => array( 'EditWatchlist', false ), 'raw' => array( 'EditWatchlist', 'raw' ), ); - foreach( $modes as $mode => $arr ) { + + foreach ( $modes as $mode => $arr ) { // can use messages 'watchlisttools-view', 'watchlisttools-edit', 'watchlisttools-raw' $tools[] = Linker::linkKnown( SpecialPage::getTitleFor( $arr[0], $arr[1] ), wfMessage( "watchlisttools-{$mode}" )->escaped() ); } - return Html::rawElement( 'span', - array( 'class' => 'mw-watchlist-toollinks' ), - wfMessage( 'parentheses', $wgLang->pipeList( $tools ) )->text() ); + + return Html::rawElement( + 'span', + array( 'class' => 'mw-watchlist-toollinks' ), + wfMessage( 'parentheses', $wgLang->pipeList( $tools ) )->text() + ); } } # B/C since 1.18 -class WatchlistEditor extends SpecialEditWatchlist {} +class WatchlistEditor extends SpecialEditWatchlist { +} /** * Extend HTMLForm purely so we can have a more sane way of getting the section headers @@ -651,10 +693,12 @@ class WatchlistEditor extends SpecialEditWatchlist {} class EditWatchlistNormalHTMLForm extends HTMLForm { public function getLegend( $namespace ) { $namespace = substr( $namespace, 2 ); + return $namespace == NS_MAIN ? $this->msg( 'blanknamespace' )->escaped() : htmlspecialchars( $this->getContext()->getLanguage()->getFormattedNsText( $namespace ) ); } + public function getBody() { return $this->displaySection( $this->mFieldTree, '', 'editwatchlist-' ); } diff --git a/includes/specials/SpecialEmailuser.php b/includes/specials/SpecialEmailuser.php index b5ad589e..2e90d996 100644 --- a/includes/specials/SpecialEmailuser.php +++ b/includes/specials/SpecialEmailuser.php @@ -29,13 +29,18 @@ class SpecialEmailUser extends UnlistedSpecialPage { protected $mTarget; + /** + * @var User|string $mTargetObj + */ + protected $mTargetObj; + public function __construct() { parent::__construct( 'Emailuser' ); } public function getDescription() { $target = self::getTarget( $this->mTarget ); - if( !$target instanceof User ) { + if ( !$target instanceof User ) { return $this->msg( 'emailuser-title-notarget' )->text(); } @@ -106,7 +111,11 @@ class SpecialEmailUser extends UnlistedSpecialPage { $this->outputHeader(); // error out if sending user cannot do this - $error = self::getPermissionsError( $this->getUser(), $this->getRequest()->getVal( 'wpEditToken' ) ); + $error = self::getPermissionsError( + $this->getUser(), + $this->getRequest()->getVal( 'wpEditToken' ) + ); + switch ( $error ) { case null: # Wahey! @@ -119,43 +128,45 @@ class SpecialEmailUser extends UnlistedSpecialPage { throw new ThrottledError; case 'mailnologin': case 'usermaildisabled': - throw new ErrorPageError( $error, "{$error}text" ); + throw new ErrorPageError( $error, "{$error}text" ); default: # It's a hook error list( $title, $msg, $params ) = $error; - throw new ErrorPageError( $title, $msg, $params ); + throw new ErrorPageError( $title, $msg, $params ); } // Got a valid target user name? Else ask for one. $ret = self::getTarget( $this->mTarget ); - if( !$ret instanceof User ) { - if( $this->mTarget != '' ) { + if ( !$ret instanceof User ) { + if ( $this->mTarget != '' ) { $ret = ( $ret == 'notarget' ) ? 'emailnotarget' : ( $ret . 'text' ); $out->wrapWikiMsg( "

    $1

    ", $ret ); } $out->addHTML( $this->userForm( $this->mTarget ) ); + return false; } $this->mTargetObj = $ret; - $form = new HTMLForm( $this->getFormFields(), $this->getContext() ); + $context = new DerivativeContext( $this->getContext() ); + $context->setTitle( $this->getTitle() ); // Remove subpage + $form = new HTMLForm( $this->getFormFields(), $context ); // By now we are supposed to be sure that $this->mTarget is a user name $form->addPreText( $this->msg( 'emailpagetext', $this->mTarget )->parse() ); $form->setSubmitTextMsg( 'emailsend' ); - $form->setTitle( $this->getTitle() ); $form->setSubmitCallback( array( __CLASS__, 'uiSubmit' ) ); $form->setWrapperLegendMsg( 'email-legend' ); $form->loadData(); - if( !wfRunHooks( 'EmailUserForm', array( &$form ) ) ) { + if ( !wfRunHooks( 'EmailUserForm', array( &$form ) ) ) { return false; } $result = $form->show(); - if( $result === true || ( $result instanceof Status && $result->isGood() ) ) { + if ( $result === true || ( $result instanceof Status && $result->isGood() ) ) { $out->setPageTitle( $this->msg( 'emailsent' ) ); - $out->addWikiMsg( 'emailsenttext' ); + $out->addWikiMsg( 'emailsenttext', $this->mTarget ); $out->returnToMain( false, $this->mTargetObj->getUserPage() ); } } @@ -169,18 +180,22 @@ class SpecialEmailUser extends UnlistedSpecialPage { public static function getTarget( $target ) { if ( $target == '' ) { wfDebug( "Target is empty.\n" ); + return 'notarget'; } $nu = User::newFromName( $target ); - if( !$nu instanceof User || !$nu->getId() ) { + if ( !$nu instanceof User || !$nu->getId() ) { wfDebug( "Target is invalid user.\n" ); + return 'notarget'; } elseif ( !$nu->isEmailConfirmed() ) { wfDebug( "User has no valid email.\n" ); + return 'noemail'; } elseif ( !$nu->canReceiveEmail() ) { wfDebug( "User does not allow user emails.\n" ); + return 'nowikiemail'; } @@ -196,31 +211,36 @@ 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' ) ) { + if ( !$user->isAllowed( 'sendemail' ) ) { return 'badaccess'; } - if( !$user->isEmailConfirmed() ) { + if ( !$user->isEmailConfirmed() ) { return 'mailnologin'; } - if( $user->isBlockedFromEmailuser() ) { + if ( $user->isBlockedFromEmailuser() ) { wfDebug( "User is blocked from sending e-mail.\n" ); + return "blockedemailuser"; } - if( $user->pingLimiter( 'emailuser' ) ) { + if ( $user->pingLimiter( 'emailuser' ) ) { wfDebug( "Ping limiter triggered.\n" ); + return 'actionthrottledtext'; } $hookErr = false; + wfRunHooks( 'UserCanSendEmail', array( &$user, &$hookErr ) ); wfRunHooks( 'EmailUserPermissionsErrors', array( $user, $editToken, &$hookErr ) ); + if ( $hookErr ) { return $hookErr; } @@ -236,14 +256,25 @@ class SpecialEmailUser extends UnlistedSpecialPage { */ protected function userForm( $name ) { global $wgScript; - $string = Xml::openElement( 'form', array( 'method' => 'get', 'action' => $wgScript, 'id' => 'askusername' ) ) . + $string = Xml::openElement( + 'form', + array( 'method' => 'get', 'action' => $wgScript, 'id' => 'askusername' ) + ) . Html::hidden( 'title', $this->getTitle()->getPrefixedText() ) . Xml::openElement( 'fieldset' ) . Html::rawElement( 'legend', null, $this->msg( 'emailtarget' )->parse() ) . - Xml::inputLabel( $this->msg( 'emailusername' )->text(), 'target', 'emailusertarget', 30, $name ) . ' ' . + Xml::inputLabel( + $this->msg( 'emailusername' )->text(), + 'target', + 'emailusertarget', + 30, + $name + ) . + ' ' . Xml::submitButton( $this->msg( 'emailusernamesubmit' )->text() ) . Xml::closeElement( 'fieldset' ) . Xml::closeElement( 'form' ) . "\n"; + return $string; } @@ -264,6 +295,8 @@ class SpecialEmailUser extends UnlistedSpecialPage { * getPermissionsError(). It is probably also a good * idea to check the edit token and ping limiter in advance. * + * @param array $data + * @param IContextSource $context * @return Mixed: Status object, or potentially a String on error * or maybe even true on success if anything uses the EmailUser hook. */ @@ -271,9 +304,10 @@ class SpecialEmailUser extends UnlistedSpecialPage { global $wgUserEmailUseReplyTo; $target = self::getTarget( $data['Target'] ); - if( !$target instanceof User ) { + if ( !$target instanceof User ) { return $context->msg( $target . 'text' )->parseAsBlock(); } + $to = new MailAddress( $target ); $from = new MailAddress( $context->getUser() ); $subject = $data['Subject']; @@ -285,11 +319,11 @@ class SpecialEmailUser extends UnlistedSpecialPage { $from->name, $to->name )->inContentLanguage()->text(); $error = ''; - if( !wfRunHooks( 'EmailUser', array( &$to, &$from, &$subject, &$text, &$error ) ) ) { + if ( !wfRunHooks( 'EmailUser', array( &$to, &$from, &$subject, &$text, &$error ) ) ) { return $error; } - if( $wgUserEmailUseReplyTo ) { + if ( $wgUserEmailUseReplyTo ) { // Put the generic wiki autogenerated address in the From: // header and reserve the user for Reply-To. // @@ -297,6 +331,7 @@ class SpecialEmailUser extends UnlistedSpecialPage { // wiki-borne mails from direct mails and protects against // SPF and bounce problems with some mailers (see below). global $wgPasswordSender, $wgPasswordSenderName; + $mailFrom = new MailAddress( $wgPasswordSender, $wgPasswordSenderName ); $replyTo = $from; } else { @@ -319,7 +354,7 @@ class SpecialEmailUser extends UnlistedSpecialPage { $status = UserMailer::send( $to, $mailFrom, $subject, $text, $replyTo ); - if( !$status->isGood() ) { + if ( !$status->isGood() ) { return $status; } else { // if the user requested a copy of this mail, do this now, @@ -334,6 +369,7 @@ class SpecialEmailUser extends UnlistedSpecialPage { } wfRunHooks( 'EmailUserComplete', array( $to, $from, $subject, $text ) ); + return $status; } } diff --git a/includes/specials/SpecialExport.php b/includes/specials/SpecialExport.php index 7abfefe2..61ed34d4 100644 --- a/includes/specials/SpecialExport.php +++ b/includes/specials/SpecialExport.php @@ -29,7 +29,6 @@ * @ingroup SpecialPage */ class SpecialExport extends SpecialPage { - private $curonly, $doExport, $pageLinkDepth, $templates; private $images; @@ -75,8 +74,7 @@ class SpecialExport extends SpecialPage { } } } - } - elseif( $request->getCheck( 'addns' ) && $wgExportFromNamespaces ) { + } elseif ( $request->getCheck( 'addns' ) && $wgExportFromNamespaces ) { $page = $request->getText( 'pages' ); $nsindex = $request->getText( 'nsindex', '' ); @@ -89,8 +87,7 @@ class SpecialExport extends SpecialPage { $page .= "\n" . implode( "\n", $nspages ); } } - } - elseif( $request->getCheck( 'exportall' ) && $wgExportAllowAll ) { + } elseif ( $request->getCheck( 'exportall' ) && $wgExportAllowAll ) { $this->doExport = true; $exportall = true; @@ -100,13 +97,12 @@ class SpecialExport extends SpecialPage { doExport(...) further down) */ $page = ''; $history = ''; - } - elseif( $request->wasPosted() && $par == '' ) { + } elseif ( $request->wasPosted() && $par == '' ) { $page = $request->getText( 'pages' ); $this->curonly = $request->getCheck( 'curonly' ); $rawOffset = $request->getVal( 'offset' ); - if( $rawOffset ) { + if ( $rawOffset ) { $offset = wfTimestamp( TS_MW, $rawOffset ); } else { $offset = null; @@ -127,15 +123,17 @@ class SpecialExport extends SpecialPage { if ( $limit > 0 && ( $wgExportMaxHistory == 0 || $limit < $wgExportMaxHistory ) ) { $history['limit'] = $limit; } + if ( !is_null( $offset ) ) { $history['offset'] = $offset; } + if ( strtolower( $dir ) == 'desc' ) { $history['dir'] = 'desc'; } } - if( $page != '' ) { + if ( $page != '' ) { $this->doExport = true; } } else { @@ -143,18 +141,18 @@ class SpecialExport extends SpecialPage { $page = $request->getText( 'pages', $par ); $historyCheck = $request->getCheck( 'history' ); - if( $historyCheck ) { + if ( $historyCheck ) { $history = WikiExporter::FULL; } else { $history = WikiExporter::CURRENT; } - if( $page != '' ) { + if ( $page != '' ) { $this->doExport = true; } } - if( !$wgExportAllowHistory ) { + if ( !$wgExportAllowHistory ) { // Override $history = WikiExporter::CURRENT; } @@ -172,7 +170,7 @@ class SpecialExport extends SpecialPage { wfResetOutputBuffers(); $request->response()->header( "Content-type: application/xml; charset=utf-8" ); - if( $request->getCheck( 'wpDownload' ) ) { + if ( $request->getCheck( 'wpDownload' ) ) { // Provide a sane filename suggestion $filename = urlencode( $wgSitename . '-' . wfTimestampNow() . '.xml' ); $request->response()->header( "Content-disposition: attachment;filename={$filename}" ); @@ -187,9 +185,17 @@ class SpecialExport extends SpecialPage { $out->addWikiMsg( 'exporttext' ); $form = Xml::openElement( 'form', array( 'method' => 'post', - 'action' => $this->getTitle()->getLocalUrl( 'action=submit' ) ) ); - $form .= Xml::inputLabel( $this->msg( 'export-addcattext' )->text(), 'catname', 'catname', 40 ) . ' '; - $form .= Xml::submitButton( $this->msg( 'export-addcat' )->text(), array( 'name' => 'addcat' ) ) . '
    '; + 'action' => $this->getTitle()->getLocalURL( 'action=submit' ) ) ); + $form .= Xml::inputLabel( + $this->msg( 'export-addcattext' )->text(), + 'catname', + 'catname', + 40 + ) . ' '; + $form .= Xml::submitButton( + $this->msg( 'export-addcat' )->text(), + array( 'name' => 'addcat' ) + ) . '
    '; if ( $wgExportFromNamespaces ) { $form .= Html::namespaceSelector( @@ -197,12 +203,15 @@ class SpecialExport extends SpecialPage { 'selected' => $nsindex, 'label' => $this->msg( 'export-addnstext' )->text() ), array( - 'name' => 'nsindex', - 'id' => 'namespace', + 'name' => 'nsindex', + 'id' => 'namespace', 'class' => 'namespaceselector', ) ) . ' '; - $form .= Xml::submitButton( $this->msg( 'export-addns' )->text(), array( 'name' => 'addns' ) ) . '
    '; + $form .= Xml::submitButton( + $this->msg( 'export-addns' )->text(), + array( 'name' => 'addns' ) + ) . '
    '; } if ( $wgExportAllowAll ) { @@ -214,10 +223,15 @@ class SpecialExport extends SpecialPage { ) . '
    '; } - $form .= Xml::element( 'textarea', array( 'name' => 'pages', 'cols' => 40, 'rows' => 10 ), $page, false ); + $form .= Xml::element( + 'textarea', + array( 'name' => 'pages', 'cols' => 40, 'rows' => 10 ), + $page, + false + ); $form .= '
    '; - if( $wgExportAllowHistory ) { + if ( $wgExportAllowHistory ) { $form .= Xml::checkLabel( $this->msg( 'exportcuronly' )->text(), 'curonly', @@ -235,9 +249,16 @@ class SpecialExport extends SpecialPage { $request->wasPosted() ? $request->getCheck( 'templates' ) : false ) . '
    '; - if( $wgExportMaxLinkDepth || $this->userCanOverrideExportDepth() ) { - $form .= Xml::inputLabel( $this->msg( 'export-pagelinks' )->text(), 'pagelink-depth', 'pagelink-depth', 20, 0 ) . '
    '; + if ( $wgExportMaxLinkDepth || $this->userCanOverrideExportDepth() ) { + $form .= Xml::inputLabel( + $this->msg( 'export-pagelinks' )->text(), + 'pagelink-depth', + 'pagelink-depth', + 20, + 0 + ) . '
    '; } + // Enable this when we can do something useful exporting/importing image information. :) //$form .= Xml::checkLabel( $this->msg( 'export-images' )->text(), 'images', 'wpExportImages', false ) . '
    '; $form .= Xml::checkLabel( @@ -256,7 +277,10 @@ class SpecialExport extends SpecialPage { ) . '
    '; } - $form .= Xml::submitButton( $this->msg( 'export-submit' )->text(), Linker::tooltipAndAccesskeyAttribs( 'export' ) ); + $form .= Xml::submitButton( + $this->msg( 'export-submit' )->text(), + Linker::tooltipAndAccesskeyAttribs( 'export' ) + ); $form .= Xml::closeElement( 'form' ); $out->addHTML( $form ); @@ -288,10 +312,10 @@ class SpecialExport extends SpecialPage { $pageSet = array(); // Inverted index of all pages to look up // Split up and normalize input - foreach( explode( "\n", $page ) as $pageName ) { + foreach ( explode( "\n", $page ) as $pageName ) { $pageName = trim( $pageName ); $title = Title::newFromText( $pageName ); - if( $title && $title->getInterwiki() == '' && $title->getText() !== '' ) { + if ( $title && $title->getInterwiki() == '' && $title->getText() !== '' ) { // Only record each page once! $pageSet[$title->getPrefixedText()] = true; } @@ -301,25 +325,23 @@ class SpecialExport extends SpecialPage { $inputPages = array_keys( $pageSet ); // Look up any linked pages if asked... - if( $this->templates ) { + if ( $this->templates ) { $pageSet = $this->getTemplates( $inputPages, $pageSet ); } $linkDepth = $this->pageLinkDepth; - if( $linkDepth ) { + if ( $linkDepth ) { $pageSet = $this->getPageLinks( $inputPages, $pageSet, $linkDepth ); } - /* - // Enable this when we can do something useful exporting/importing image information. :) - if( $this->images ) ) { - $pageSet = $this->getImages( $inputPages, $pageSet ); - } - */ + // Enable this when we can do something useful exporting/importing image information. + // if( $this->images ) ) { + // $pageSet = $this->getImages( $inputPages, $pageSet ); + // } $pages = array_keys( $pageSet ); // Normalize titles to the same format and remove dupes, see bug 17374 - foreach( $pages as $k => $v ) { + foreach ( $pages as $k => $v ) { $pages[$k] = str_replace( " ", "_", $v ); } @@ -327,7 +349,7 @@ class SpecialExport extends SpecialPage { } /* Ok, let's get to it... */ - if( $history == WikiExporter::CURRENT ) { + if ( $history == WikiExporter::CURRENT ) { $lb = false; $db = wfGetDB( DB_SLAVE ); $buffer = WikiExporter::BUFFER; @@ -350,26 +372,17 @@ class SpecialExport extends SpecialPage { if ( $exportall ) { $exporter->allPages(); } else { - foreach( $pages as $page ) { - /* - if( $wgExportMaxHistory && !$this->curonly ) { - $title = Title::newFromText( $page ); - if( $title ) { - $count = Revision::countByTitle( $db, $title ); - if( $count > $wgExportMaxHistory ) { - wfDebug( __FUNCTION__ . - ": Skipped $page, $count revisions too big\n" ); - continue; - } - } - }*/ - #Bug 8824: Only export pages the user can read + foreach ( $pages as $page ) { + #Bug 8824: Only export pages the user can read $title = Title::newFromText( $page ); - if( is_null( $title ) ) { - continue; #TODO: perhaps output an tag or something. + if ( is_null( $title ) ) { + // @todo Perhaps output an tag or something. + continue; } - if( !$title->userCan( 'read', $this->getUser() ) ) { - continue; #TODO: perhaps output an tag or something. + + if ( !$title->userCan( 'read', $this->getUser() ) ) { + // @todo Perhaps output an tag or something. + continue; } $exporter->pageByTitle( $title ); @@ -378,7 +391,7 @@ class SpecialExport extends SpecialPage { $exporter->closeStream(); - if( $lb ) { + if ( $lb ) { $lb->closeAll(); } } @@ -412,6 +425,7 @@ class SpecialExport extends SpecialPage { $pages[] = $n; } + return $pages; } @@ -443,6 +457,7 @@ class SpecialExport extends SpecialPage { $pages[] = $n; } + return $pages; } @@ -468,12 +483,12 @@ class SpecialExport extends SpecialPage { private function validateLinkDepth( $depth ) { global $wgExportMaxLinkDepth; - if( $depth < 0 ) { + if ( $depth < 0 ) { return 0; } if ( !$this->userCanOverrideExportDepth() ) { - if( $depth > $wgExportMaxLinkDepth ) { + if ( $depth > $wgExportMaxLinkDepth ) { return $wgExportMaxLinkDepth; } } @@ -483,6 +498,7 @@ class SpecialExport extends SpecialPage { * crazy-big export from being done by someone setting the depth * number too high. In other words, last resort safety net. */ + return intval( min( $depth, 5 ) ); } @@ -494,7 +510,7 @@ class SpecialExport extends SpecialPage { * @return array */ private function getPageLinks( $inputPages, $pageSet, $depth ) { - for( ; $depth > 0; --$depth ) { + for ( ; $depth > 0; --$depth ) { $pageSet = $this->getLinks( $inputPages, $pageSet, 'pagelinks', array( 'namespace' => 'pl_namespace', 'title' => 'pl_title' ), @@ -526,15 +542,20 @@ class SpecialExport extends SpecialPage { /** * Expand a list of pages to include items used in those pages. + * @param array $inputPages Array of page titles + * @param array $pageSet + * @param string $table + * @param array $fields Array of field names + * @param array $join * @return array */ private function getLinks( $inputPages, $pageSet, $table, $fields, $join ) { $dbr = wfGetDB( DB_SLAVE ); - foreach( $inputPages as $page ) { + foreach ( $inputPages as $page ) { $title = Title::newFromText( $page ); - if( $title ) { + if ( $title ) { $pageSet[$title->getPrefixedText()] = true; /// @todo FIXME: May or may not be more efficient to batch these /// by namespace when given multiple input pages. @@ -551,7 +572,7 @@ class SpecialExport extends SpecialPage { __METHOD__ ); - foreach( $result as $row ) { + foreach ( $result as $row ) { $template = Title::makeTitle( $row->namespace, $row->title ); $pageSet[$template->getPrefixedText()] = true; } diff --git a/includes/specials/SpecialFewestrevisions.php b/includes/specials/SpecialFewestrevisions.php index 5b7f353d..47a4d75f 100644 --- a/includes/specials/SpecialFewestrevisions.php +++ b/includes/specials/SpecialFewestrevisions.php @@ -28,7 +28,6 @@ * @author Martin Drashkov */ class FewestrevisionsPage extends QueryPage { - function __construct( $name = 'Fewestrevisions' ) { parent::__construct( $name ); } @@ -42,21 +41,26 @@ class FewestrevisionsPage extends QueryPage { } function getQueryInfo() { - return array ( - 'tables' => array ( 'revision', 'page' ), - 'fields' => array ( 'namespace' => 'page_namespace', - 'title' => 'page_title', - 'value' => 'COUNT(*)', - 'redirect' => 'page_is_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' => array( 'page_namespace', 'page_title', 'page_is_redirect' ) ) + return array( + 'tables' => array( 'revision', 'page' ), + 'fields' => array( + 'namespace' => 'page_namespace', + 'title' => 'page_title', + 'value' => 'COUNT(*)', + 'redirect' => 'page_is_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' => array( 'page_namespace', 'page_title', 'page_is_redirect' ) + ) ); } @@ -65,17 +69,24 @@ class FewestrevisionsPage extends QueryPage { } /** - * @param $skin Skin object - * @param $result Object: database row + * @param Skin $skin + * @param object $result Database row * @return String */ function formatResult( $skin, $result ) { global $wgContLang; $nt = Title::makeTitleSafe( $result->namespace, $result->title ); - if( !$nt ) { - return Html::element( 'span', array( 'class' => 'mw-invalidtitle' ), - Linker::getInvalidTitleDescription( $this->getContext(), $result->namespace, $result->title ) ); + if ( !$nt ) { + return Html::element( + 'span', + array( 'class' => 'mw-invalidtitle' ), + Linker::getInvalidTitleDescription( + $this->getContext(), + $result->namespace, + $result->title + ) + ); } $text = htmlspecialchars( $wgContLang->convert( $nt->getPrefixedText() ) ); diff --git a/includes/specials/SpecialFileDuplicateSearch.php b/includes/specials/SpecialFileDuplicateSearch.php index 3fe64e6f..4c6593b2 100644 --- a/includes/specials/SpecialFileDuplicateSearch.php +++ b/includes/specials/SpecialFileDuplicateSearch.php @@ -59,7 +59,7 @@ class FileDuplicateSearchPage extends QueryPage { /** * Fetch dupes from all connected file repositories. * - * @return Array of File objects + * @return array of File objects */ function getDupes() { return RepoGroup::singleton()->findBySha1( $this->hash ); @@ -101,11 +101,11 @@ class FileDuplicateSearchPage extends QueryPage { $this->setHeaders(); $this->outputHeader(); - $this->filename = isset( $par ) ? $par : $this->getRequest()->getText( 'filename' ); + $this->filename = isset( $par ) ? $par : $this->getRequest()->getText( 'filename' ); $this->file = null; $this->hash = ''; $title = Title::newFromText( $this->filename, NS_FILE ); - if( $title && $title->getText() != '' ) { + if ( $title && $title->getText() != '' ) { $this->file = wfFindFile( $title ); } @@ -113,37 +113,46 @@ class FileDuplicateSearchPage extends QueryPage { # Create the input form $out->addHTML( - Xml::openElement( 'form', array( 'id' => 'fileduplicatesearch', 'method' => 'get', 'action' => $wgScript ) ) . - Html::hidden( 'title', $this->getTitle()->getPrefixedDBkey() ) . - Xml::openElement( 'fieldset' ) . - Xml::element( 'legend', null, $this->msg( 'fileduplicatesearch-legend' )->text() ) . - Xml::inputLabel( $this->msg( 'fileduplicatesearch-filename' )->text(), 'filename', 'filename', 50, $this->filename ) . ' ' . - Xml::submitButton( $this->msg( 'fileduplicatesearch-submit' )->text() ) . - Xml::closeElement( 'fieldset' ) . - Xml::closeElement( 'form' ) + Html::openElement( + 'form', + array( 'id' => 'fileduplicatesearch', 'method' => 'get', 'action' => $wgScript ) + ) . "\n" . + Html::hidden( 'title', $this->getTitle()->getPrefixedDBkey() ) . "\n" . + Html::openElement( 'fieldset' ) . "\n" . + Html::element( 'legend', null, $this->msg( 'fileduplicatesearch-legend' )->text() ) . "\n" . + Xml::inputLabel( + $this->msg( 'fileduplicatesearch-filename' )->text(), + 'filename', + 'filename', + 50, + $this->filename + ) . "\n" . + Xml::submitButton( $this->msg( 'fileduplicatesearch-submit' )->text() ) . "\n" . + Html::closeElement( 'fieldset' ) . "\n" . + Html::closeElement( 'form' ) ); - if( $this->file ) { + if ( $this->file ) { $this->hash = $this->file->getSha1(); - } elseif( $this->filename !== '' ) { + } elseif ( $this->filename !== '' ) { $out->wrapWikiMsg( "

    \n$1\n

    ", array( 'fileduplicatesearch-noresults', wfEscapeWikiText( $this->filename ) ) ); } - if( $this->hash != '' ) { + if ( $this->hash != '' ) { # Show a thumbnail of the file $img = $this->file; if ( $img ) { $thumb = $img->transform( array( 'width' => 120, 'height' => 120 ) ); - if( $thumb ) { + if ( $thumb ) { $out->addHTML( '
    ' . $thumb->toHtml( array( 'desc-link' => false ) ) . '
    ' . $this->msg( 'fileduplicatesearch-info' )->numParams( $img->getWidth(), $img->getHeight() )->params( - $this->getLanguage()->formatSize( $img->getSize() ), - $img->getMimeType() )->parseAsBlock() . + $this->getLanguage()->formatSize( $img->getSize() ), + $img->getMimeType() )->parseAsBlock() . '
    ' ); } } @@ -152,7 +161,7 @@ class FileDuplicateSearchPage extends QueryPage { $numRows = count( $dupes ); # Show a short summary - if( $numRows == 1 ) { + if ( $numRows == 1 ) { $out->wrapWikiMsg( "

    \n$1\n

    ", array( 'fileduplicatesearch-result-1', wfEscapeWikiText( $this->filename ) ) @@ -172,14 +181,16 @@ class FileDuplicateSearchPage extends QueryPage { function doBatchLookups( $list ) { $batch = new LinkBatch(); - foreach( $list as $file ) { + /** @var File $file */ + foreach ( $list as $file ) { $batch->addObj( $file->getTitle() ); - if( $file->isLocal() ) { + if ( $file->isLocal() ) { $userName = $file->getUser( 'text' ); $batch->add( NS_USER, $userName ); $batch->add( NS_USER_TALK, $userName ); } } + $batch->execute(); } diff --git a/includes/specials/SpecialFilepath.php b/includes/specials/SpecialFilepath.php index bbcced26..e7ced52a 100644 --- a/includes/specials/SpecialFilepath.php +++ b/includes/specials/SpecialFilepath.php @@ -2,6 +2,7 @@ /** * Implements Special:Filepath * + * @section LICENSE * 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 @@ -26,65 +27,16 @@ * * @ingroup SpecialPage */ -class SpecialFilepath extends SpecialPage { - +class SpecialFilepath extends RedirectSpecialPage { function __construct() { parent::__construct( 'Filepath' ); + $this->mAllowedRedirectParams = array( 'width', 'height' ); } - function execute( $par ) { - $this->setHeaders(); - $this->outputHeader(); - - $request = $this->getRequest(); - $file = !is_null( $par ) ? $par : $request->getText( '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 behavior: Use the direct link to the file. - $url = $file->getURL(); - $width = $request->getInt( 'width', -1 ); - $height = $request->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(); - } - } - $this->getOutput()->redirect( $url ); - } else { - $this->getOutput()->setStatusCode( 404 ); - $this->showForm( $title ); - } - } - } - - /** - * @param $title Title - */ - function showForm( $title ) { - global $wgScript; - - $this->getOutput()->addHTML( - Html::openElement( 'form', array( 'method' => 'get', 'action' => $wgScript, 'id' => 'specialfilepath' ) ) . - Html::openElement( 'fieldset' ) . - Html::element( 'legend', null, $this->msg( 'filepath' )->text() ) . - Html::hidden( 'title', $this->getTitle()->getPrefixedText() ) . - Xml::inputLabel( $this->msg( 'filepath-page' )->text(), 'file', 'file', 25, is_object( $title ) ? $title->getText() : '' ) . ' ' . - Xml::submitButton( $this->msg( 'filepath-submit' )->text() ) . "\n" . - Html::closeElement( 'fieldset' ) . - Html::closeElement( 'form' ) - ); + // implement by redirecting through Special:Redirect/file + function getRedirect( $par ) { + $file = $par ?: $this->getRequest()->getText( 'file' ); + return SpecialPage::getSafeTitleFor( 'Redirect', 'file/' . $file ); } protected function getGroupName() { diff --git a/includes/specials/SpecialImport.php b/includes/specials/SpecialImport.php index aa56041b..d7d860de 100644 --- a/includes/specials/SpecialImport.php +++ b/includes/specials/SpecialImport.php @@ -30,12 +30,11 @@ * @ingroup SpecialPage */ class SpecialImport extends SpecialPage { - private $interwiki = false; private $namespace; private $rootpage = ''; private $frompage = ''; - private $logcomment= false; + private $logcomment = false; private $history = true; private $includeTemplates = false; private $pageLinkDepth; @@ -108,13 +107,13 @@ class SpecialImport extends SpecialPage { $source = Status::newFatal( 'import-token-mismatch' ); } elseif ( $sourceName == 'upload' ) { $isUpload = true; - if( $user->isAllowed( 'importupload' ) ) { + if ( $user->isAllowed( 'importupload' ) ) { $source = ImportStreamSource::newFromUpload( "xmlimport" ); } else { throw new PermissionsError( 'importupload' ); } } elseif ( $sourceName == "interwiki" ) { - if( !$user->isAllowed( 'import' ) ) { + if ( !$user->isAllowed( 'import' ) ) { throw new PermissionsError( 'import' ); } $this->interwiki = $request->getVal( 'interwiki' ); @@ -136,24 +135,40 @@ class SpecialImport extends SpecialPage { } $out = $this->getOutput(); - if( !$source->isGood() ) { - $out->wrapWikiMsg( "

    \n$1\n

    ", array( 'importfailed', $source->getWikiText() ) ); + if ( !$source->isGood() ) { + $out->wrapWikiMsg( + "

    \n$1\n

    ", + array( 'importfailed', $source->getWikiText() ) + ); } else { $importer = new WikiImporter( $source->value ); - if( !is_null( $this->namespace ) ) { + if ( !is_null( $this->namespace ) ) { $importer->setTargetNamespace( $this->namespace ); } - if( !is_null( $this->rootpage ) ) { + if ( !is_null( $this->rootpage ) ) { $statusRootPage = $importer->setTargetRootPage( $this->rootpage ); - if( !$statusRootPage->isGood() ) { - $out->wrapWikiMsg( "

    \n$1\n

    ", array( 'import-options-wrong', $statusRootPage->getWikiText(), count( $statusRootPage->getErrorsArray() ) ) ); + if ( !$statusRootPage->isGood() ) { + $out->wrapWikiMsg( + "

    \n$1\n

    ", + array( + 'import-options-wrong', + $statusRootPage->getWikiText(), + count( $statusRootPage->getErrorsArray() ) + ) + ); + return; } } $out->addWikiMsg( "importstart" ); - $reporter = new ImportReporter( $importer, $isUpload, $this->interwiki, $this->logcomment ); + $reporter = new ImportReporter( + $importer, + $isUpload, + $this->interwiki, + $this->logcomment + ); $reporter->setContext( $this->getContext() ); $exception = false; @@ -167,10 +182,16 @@ class SpecialImport extends SpecialPage { if ( $exception ) { # No source or XML parse error - $out->wrapWikiMsg( "

    \n$1\n

    ", array( 'importfailed', $exception->getMessage() ) ); - } elseif( !$result->isGood() ) { + $out->wrapWikiMsg( + "

    \n$1\n

    ", + array( 'importfailed', $exception->getMessage() ) + ); + } elseif ( !$result->isGood() ) { # Zero revisions - $out->wrapWikiMsg( "

    \n$1\n

    ", array( 'importfailed', $result->getWikiText() ) ); + $out->wrapWikiMsg( + "

    \n$1\n

    ", + array( 'importfailed', $result->getWikiText() ) + ); } else { # Success! $out->addWikiMsg( 'importsuccess' ); @@ -182,162 +203,195 @@ class SpecialImport extends SpecialPage { private function showForm() { global $wgImportSources, $wgExportMaxLinkDepth; - $action = $this->getTitle()->getLocalUrl( array( 'action' => 'submit' ) ); + $action = $this->getTitle()->getLocalURL( array( 'action' => 'submit' ) ); $user = $this->getUser(); $out = $this->getOutput(); - if( $user->isAllowed( 'importupload' ) ) { + if ( $user->isAllowed( 'importupload' ) ) { $out->addHTML( - Xml::fieldset( $this->msg( 'import-upload' )->text() ). - Xml::openElement( 'form', array( 'enctype' => 'multipart/form-data', 'method' => 'post', - 'action' => $action, 'id' => 'mw-import-upload-form' ) ) . - $this->msg( 'importtext' )->parseAsBlock() . - Html::hidden( 'action', 'submit' ) . - Html::hidden( 'source', 'upload' ) . - Xml::openElement( 'table', array( 'id' => 'mw-import-table-upload' ) ) . - - " + Xml::fieldset( $this->msg( 'import-upload' )->text() ) . + Xml::openElement( + 'form', + array( + 'enctype' => 'multipart/form-data', + 'method' => 'post', + 'action' => $action, + 'id' => 'mw-import-upload-form' + ) + ) . + $this->msg( 'importtext' )->parseAsBlock() . + Html::hidden( 'action', 'submit' ) . + Html::hidden( 'source', 'upload' ) . + Xml::openElement( 'table', array( 'id' => 'mw-import-table-upload' ) ) . + " " . - Xml::label( $this->msg( 'import-upload-filename' )->text(), 'xmlimport' ) . + Xml::label( $this->msg( 'import-upload-filename' )->text(), 'xmlimport' ) . " " . - Html::input( 'xmlimport', '', 'file', array( 'id' => 'xmlimport' ) ) . ' ' . + Html::input( 'xmlimport', '', 'file', array( 'id' => 'xmlimport' ) ) . ' ' . " " . - Xml::label( $this->msg( 'import-comment' )->text(), 'mw-import-comment' ) . + Xml::label( $this->msg( 'import-comment' )->text(), 'mw-import-comment' ) . " " . - Xml::input( 'log-comment', 50, '', - array( 'id' => 'mw-import-comment', 'type' => 'text' ) ) . ' ' . + Xml::input( 'log-comment', 50, '', + array( 'id' => 'mw-import-comment', 'type' => 'text' ) ) . ' ' . " " . - Xml::label( $this->msg( 'import-interwiki-rootpage' )->text(), 'mw-interwiki-rootpage-upload' ) . + Xml::label( $this->msg( 'import-interwiki-rootpage' )->text(), 'mw-interwiki-rootpage-upload' ) . " " . - Xml::input( 'rootpage', 50, $this->rootpage, - array( 'id' => 'mw-interwiki-rootpage-upload', 'type' => 'text' ) ) . ' ' . + Xml::input( 'rootpage', 50, $this->rootpage, + array( 'id' => 'mw-interwiki-rootpage-upload', 'type' => 'text' ) ) . ' ' . " " . - Xml::submitButton( $this->msg( 'uploadbtn' )->text() ) . + Xml::submitButton( $this->msg( 'uploadbtn' )->text() ) . " " . - Xml::closeElement( 'table' ). - Html::hidden( 'editToken', $user->getEditToken() ) . - Xml::closeElement( 'form' ) . - Xml::closeElement( 'fieldset' ) + Xml::closeElement( 'table' ) . + Html::hidden( 'editToken', $user->getEditToken() ) . + Xml::closeElement( 'form' ) . + Xml::closeElement( 'fieldset' ) ); } else { - if( empty( $wgImportSources ) ) { + if ( empty( $wgImportSources ) ) { $out->addWikiMsg( 'importnosources' ); } } - if( $user->isAllowed( 'import' ) && !empty( $wgImportSources ) ) { + if ( $user->isAllowed( 'import' ) && !empty( $wgImportSources ) ) { # Show input field for import depth only if $wgExportMaxLinkDepth > 0 $importDepth = ''; - if( $wgExportMaxLinkDepth > 0 ) { + if ( $wgExportMaxLinkDepth > 0 ) { $importDepth = " " . - $this->msg( 'export-pagelinks' )->parse() . - " + $this->msg( 'export-pagelinks' )->parse() . + " " . - Xml::input( 'pagelink-depth', 3, 0 ) . - " - "; + Xml::input( 'pagelink-depth', 3, 0 ) . + " + "; } $out->addHTML( Xml::fieldset( $this->msg( 'importinterwiki' )->text() ) . - Xml::openElement( 'form', array( 'method' => 'post', 'action' => $action, 'id' => 'mw-import-interwiki-form' ) ) . - $this->msg( 'import-interwiki-text' )->parseAsBlock() . - Html::hidden( 'action', 'submit' ) . - Html::hidden( 'source', 'interwiki' ) . - Html::hidden( 'editToken', $user->getEditToken() ) . - Xml::openElement( 'table', array( 'id' => 'mw-import-table-interwiki' ) ) . - " + Xml::openElement( + 'form', + array( + 'method' => 'post', + 'action' => $action, + 'id' => 'mw-import-interwiki-form' + ) + ) . + $this->msg( 'import-interwiki-text' )->parseAsBlock() . + Html::hidden( 'action', 'submit' ) . + Html::hidden( 'source', 'interwiki' ) . + Html::hidden( 'editToken', $user->getEditToken() ) . + Xml::openElement( 'table', array( 'id' => 'mw-import-table-interwiki' ) ) . + " " . - Xml::label( $this->msg( 'import-interwiki-source' )->text(), 'interwiki' ) . + Xml::label( $this->msg( 'import-interwiki-source' )->text(), 'interwiki' ) . " " . - Xml::openElement( 'select', array( 'name' => 'interwiki', 'id' => 'interwiki' ) ) + Xml::openElement( + 'select', + array( 'name' => 'interwiki', 'id' => 'interwiki' ) + ) ); - foreach( $wgImportSources as $prefix ) { + + foreach ( $wgImportSources as $prefix ) { $selected = ( $this->interwiki === $prefix ) ? ' selected="selected"' : ''; $out->addHTML( Xml::option( $prefix, $prefix, $selected ) ); } $out->addHTML( - Xml::closeElement( 'select' ) . - Xml::input( 'frompage', 50, $this->frompage, array( 'id' => 'frompage' ) ) . + Xml::closeElement( 'select' ) . + Xml::input( 'frompage', 50, $this->frompage, array( 'id' => 'frompage' ) ) . " " . - Xml::checkLabel( $this->msg( 'import-interwiki-history' )->text(), 'interwikiHistory', 'interwikiHistory', $this->history ) . + Xml::checkLabel( + $this->msg( 'import-interwiki-history' )->text(), + 'interwikiHistory', + 'interwikiHistory', + $this->history + ) . " " . - Xml::checkLabel( $this->msg( 'import-interwiki-templates' )->text(), 'interwikiTemplates', 'interwikiTemplates', $this->includeTemplates ) . + Xml::checkLabel( + $this->msg( 'import-interwiki-templates' )->text(), + 'interwikiTemplates', + 'interwikiTemplates', + $this->includeTemplates + ) . " $importDepth " . - Xml::label( $this->msg( 'import-interwiki-namespace' )->text(), 'namespace' ) . + Xml::label( $this->msg( 'import-interwiki-namespace' )->text(), 'namespace' ) . " " . - Html::namespaceSelector( - array( - 'selected' => $this->namespace, - 'all' => '', - ), array( - 'name' => 'namespace', - 'id' => 'namespace', - 'class' => 'namespaceselector', - ) - ) . + Html::namespaceSelector( + array( + 'selected' => $this->namespace, + 'all' => '', + ), array( + 'name' => 'namespace', + 'id' => 'namespace', + 'class' => 'namespaceselector', + ) + ) . " " . - Xml::label( $this->msg( 'import-comment' )->text(), 'mw-interwiki-comment' ) . + Xml::label( $this->msg( 'import-comment' )->text(), 'mw-interwiki-comment' ) . " " . - Xml::input( 'log-comment', 50, '', - array( 'id' => 'mw-interwiki-comment', 'type' => 'text' ) ) . ' ' . + Xml::input( 'log-comment', 50, '', + array( 'id' => 'mw-interwiki-comment', 'type' => 'text' ) ) . ' ' . " " . - Xml::label( $this->msg( 'import-interwiki-rootpage' )->text(), 'mw-interwiki-rootpage-interwiki' ) . + Xml::label( + $this->msg( 'import-interwiki-rootpage' )->text(), + 'mw-interwiki-rootpage-interwiki' + ) . " " . - Xml::input( 'rootpage', 50, $this->rootpage, - array( 'id' => 'mw-interwiki-rootpage-interwiki', 'type' => 'text' ) ) . ' ' . + Xml::input( 'rootpage', 50, $this->rootpage, + array( 'id' => 'mw-interwiki-rootpage-interwiki', 'type' => 'text' ) ) . ' ' . " " . - Xml::submitButton( $this->msg( 'import-interwiki-submit' )->text(), Linker::tooltipAndAccesskeyAttribs( 'import' ) ) . + Xml::submitButton( + $this->msg( 'import-interwiki-submit' )->text(), + Linker::tooltipAndAccesskeyAttribs( 'import' ) + ) . " " . - Xml::closeElement( 'table' ). - Xml::closeElement( 'form' ) . - Xml::closeElement( 'fieldset' ) + Xml::closeElement( 'table' ) . + Xml::closeElement( 'form' ) . + Xml::closeElement( 'fieldset' ) ); } } @@ -352,14 +406,21 @@ class SpecialImport extends SpecialPage { * @ingroup SpecialPage */ class ImportReporter extends ContextSource { - private $reason=false; + private $reason = false; private $mOriginalLogCallback = null; private $mOriginalPageOutCallback = null; private $mLogItemCount = 0; + + /** + * @param WikiImporter $importer + * @param $upload + * @param $interwiki + * @param string|bool $reason + */ function __construct( $importer, $upload, $interwiki, $reason = false ) { $this->mOriginalPageOutCallback = - $importer->setPageOutCallback( array( $this, 'reportPage' ) ); + $importer->setPageOutCallback( array( $this, 'reportPage' ) ); $this->mOriginalLogCallback = $importer->setLogItemCallback( array( $this, 'reportLogItem' ) ); $importer->setNoticeCallback( array( $this, 'reportNotice' ) ); @@ -403,20 +464,21 @@ class ImportReporter extends ContextSource { $this->mPageCount++; - if( $successCount > 0 ) { - $this->getOutput()->addHTML( "
  • " . Linker::linkKnown( $title ) . " " . - $this->msg( 'import-revision-count' )->numParams( $successCount )->escaped() . - "
  • \n" + if ( $successCount > 0 ) { + $this->getOutput()->addHTML( + "
  • " . Linker::linkKnown( $title ) . " " . + $this->msg( 'import-revision-count' )->numParams( $successCount )->escaped() . + "
  • \n" ); $log = new LogPage( 'import' ); - if( $this->mIsUpload ) { + if ( $this->mIsUpload ) { $detail = $this->msg( 'import-logentry-upload-detail' )->numParams( $successCount )->inContentLanguage()->text(); if ( $this->reason ) { $detail .= $this->msg( 'colon-separator' )->inContentLanguage()->text() . $this->reason; } - $log->addEntry( 'upload', $title, $detail ); + $log->addEntry( 'upload', $title, $detail, array(), $this->getUser() ); } else { $interwiki = '[[:' . $this->mInterwiki . ':' . $origTitle->getPrefixedText() . ']]'; @@ -425,7 +487,7 @@ class ImportReporter extends ContextSource { if ( $this->reason ) { $detail .= $this->msg( 'colon-separator' )->inContentLanguage()->text() . $this->reason; } - $log->addEntry( 'interwiki', $title, $detail ); + $log->addEntry( 'interwiki', $title, $detail, array(), $this->getUser() ); } $comment = $detail; // quick @@ -450,8 +512,9 @@ class ImportReporter extends ContextSource { if ( $this->mLogItemCount > 0 ) { $msg = $this->msg( 'imported-log-entries' )->numParams( $this->mLogItemCount )->parse(); $out->addHTML( Xml::tags( 'li', null, $msg ) ); - } elseif( $this->mPageCount == 0 && $this->mLogItemCount == 0 ) { + } elseif ( $this->mPageCount == 0 && $this->mLogItemCount == 0 ) { $out->addHTML( "\n" ); + return Status::newFatal( 'importnopages' ); } $out->addHTML( "\n" ); diff --git a/includes/specials/SpecialJavaScriptTest.php b/includes/specials/SpecialJavaScriptTest.php index d204d50c..7069d527 100644 --- a/includes/specials/SpecialJavaScriptTest.php +++ b/includes/specials/SpecialJavaScriptTest.php @@ -55,24 +55,29 @@ class SpecialJavaScriptTest extends SpecialPage { if ( $par == '' ) { $out->setPageTitle( $this->msg( 'javascripttest' ) ); $summary = $this->wrapSummaryHtml( - $this->msg( 'javascripttest-pagetext-noframework' )->escaped() . $this->getFrameworkListHtml(), + $this->msg( 'javascripttest-pagetext-noframework' )->escaped() . + $this->getFrameworkListHtml(), 'noframework' ); $out->addHtml( $summary ); - - // Matched! Display proper title and initialize the framework } elseif ( isset( self::$frameworks[$framework] ) ) { - $out->setPageTitle( $this->msg( 'javascripttest-title', $this->msg( "javascripttest-$framework-name" )->plain() ) ); - $out->setSubtitle( $this->msg( 'javascripttest-backlink' )->rawParams( Linker::linkKnown( $this->getTitle() ) ) ); + // Matched! Display proper title and initialize the framework + $out->setPageTitle( $this->msg( + 'javascripttest-title', + // Messages: javascripttest-qunit-name + $this->msg( "javascripttest-$framework-name" )->plain() + ) ); + $out->setSubtitle( $this->msg( 'javascripttest-backlink' ) + ->rawParams( Linker::linkKnown( $this->getTitle() ) ) ); $this->{self::$frameworks[$framework]}(); - - // Framework not found, display error } else { + // Framework not found, display error $out->setPageTitle( $this->msg( 'javascripttest' ) ); - $summary = $this->wrapSummaryHtml( '

    ' - . $this->msg( 'javascripttest-pagetext-unknownframework', $par )->escaped() - . '

    ' - . $this->getFrameworkListHtml(), + $summary = $this->wrapSummaryHtml( + '

    ' . + $this->msg( 'javascripttest-pagetext-unknownframework', $par )->escaped() . + '

    ' . + $this->getFrameworkListHtml(), 'unknownframework' ); $out->addHtml( $summary ); @@ -80,22 +85,28 @@ class SpecialJavaScriptTest extends SpecialPage { } /** - * Get a list of frameworks (including introduction paragraph and links to the framework run pages) - * @return String: HTML + * Get a list of frameworks (including introduction paragraph and links + * to the framework run pages) + * + * @return string HTML */ private function getFrameworkListHtml() { $list = '
      '; - foreach( self::$frameworks as $framework => $initFn ) { + foreach ( self::$frameworks as $framework => $initFn ) { $list .= Html::rawElement( 'li', array(), - Linker::link( $this->getTitle( $framework ), $this->msg( "javascripttest-$framework-name" )->escaped() ) + Linker::link( + $this->getTitle( $framework ), + // Message: javascripttest-qunit-name + $this->msg( "javascripttest-$framework-name" )->escaped() + ) ); } $list .= '
    '; - $msg = $this->msg( 'javascripttest-pagetext-frameworks' )->rawParams( $list )->parseAsBlock(); - return $msg; + return $this->msg( 'javascripttest-pagetext-frameworks' )->rawParams( $list ) + ->parseAsBlock(); } /** @@ -109,12 +120,14 @@ class SpecialJavaScriptTest extends SpecialPage { */ private function wrapSummaryHtml( $html, $state ) { $validStates = array( 'noframework', 'unknownframework', 'frameworkfound' ); - if( !in_array( $state, $validStates ) ) { + + if ( !in_array( $state, $validStates ) ) { throw new MWException( __METHOD__ . ' given an invalid state. Must be one of "' - . join( '", "', $validStates) . '".' + . join( '", "', $validStates ) . '".' ); } + return "
    $html
    "; } @@ -155,7 +168,10 @@ HTML; // Used in ./tests/qunit/data/testrunner.js, see also documentation of // $wgJavaScriptTestConfig in DefaultSettings.php - $out->addJsConfigVars( 'QUnitTestSwarmInjectJSPath', $wgJavaScriptTestConfig['qunit']['testswarm-injectjs'] ); + $out->addJsConfigVars( + 'QUnitTestSwarmInjectJSPath', + $wgJavaScriptTestConfig['qunit']['testswarm-injectjs'] + ); } protected function getGroupName() { diff --git a/includes/specials/SpecialLinkSearch.php b/includes/specials/SpecialLinkSearch.php index 030416fb..5b0c56e5 100644 --- a/includes/specials/SpecialLinkSearch.php +++ b/includes/specials/SpecialLinkSearch.php @@ -55,7 +55,7 @@ class LinkSearchPage extends QueryPage { $namespace = $request->getIntorNull( 'namespace', null ); $protocols_list = array(); - foreach( $wgUrlProtocols as $prot ) { + foreach ( $wgUrlProtocols as $prot ) { if ( $prot !== '//' ) { $protocols_list[] = $prot; } @@ -72,7 +72,7 @@ class LinkSearchPage extends QueryPage { } elseif ( !$pr_sl && $pr_cl ) { // For protocols without '//' like 'mailto:' $protocol = substr( $target2, 0, $pr_cl + 1 ); - $target2 = substr( $target2, $pr_cl+1 ); + $target2 = substr( $target2, $pr_cl + 1 ); } elseif ( $protocol == '' && $target2 != '' ) { // default $protocol = 'http://'; @@ -88,11 +88,21 @@ class LinkSearchPage extends QueryPage { '' . $this->getLanguage()->commaList( $protocols_list ) . '', count( $protocols_list ) ); - $s = Html::openElement( 'form', array( 'id' => 'mw-linksearch-form', 'method' => 'get', 'action' => $wgScript ) ) . "\n" . + $s = Html::openElement( + 'form', + array( 'id' => 'mw-linksearch-form', 'method' => 'get', 'action' => $wgScript ) + ) . "\n" . Html::hidden( 'title', $this->getTitle()->getPrefixedDBkey() ) . "\n" . Html::openElement( 'fieldset' ) . "\n" . Html::element( 'legend', array(), $this->msg( 'linksearch' )->text() ) . "\n" . - Xml::inputLabel( $this->msg( 'linksearch-pat' )->text(), 'target', 'target', 50, $target ) . "\n"; + Xml::inputLabel( + $this->msg( 'linksearch-pat' )->text(), + 'target', + 'target', + 50, + $target + ) . "\n"; + if ( !$wgMiserMode ) { $s .= Html::namespaceSelector( array( @@ -100,25 +110,27 @@ class LinkSearchPage extends QueryPage { 'all' => '', 'label' => $this->msg( 'linksearch-ns' )->text() ), array( - 'name' => 'namespace', - 'id' => 'namespace', + 'name' => 'namespace', + 'id' => 'namespace', 'class' => 'namespaceselector', ) ); } + $s .= Xml::submitButton( $this->msg( 'linksearch-ok' )->text() ) . "\n" . Html::closeElement( 'fieldset' ) . "\n" . Html::closeElement( 'form' ) . "\n"; $out->addHTML( $s ); - if( $target != '' ) { + if ( $target != '' ) { $this->setParams( array( 'query' => $target2, 'namespace' => $namespace, 'protocol' => $protocol ) ); parent::execute( $par ); - if( $this->mMungedQuery === false ) + if ( $this->mMungedQuery === false ) { $out->addWikiMsg( 'linksearch-error' ); + } } } @@ -133,6 +145,8 @@ class LinkSearchPage extends QueryPage { /** * Return an appropriately formatted LIKE query and the clause * + * @param string $query + * @param string $prot * @return array */ static function mungeQuery( $query, $prot ) { @@ -140,12 +154,14 @@ class LinkSearchPage extends QueryPage { $rv = LinkFilter::makeLikeArray( $query, $prot ); 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 ) ) { + $pattern = '/^(:?[0-9]{1,3}\.)+\*\s*$|^(:?[0-9]{1,3}\.){3}[0-9]{1,3}:[0-9]*\*\s*$/'; + if ( preg_match( $pattern, $query ) ) { $dbr = wfGetDB( DB_SLAVE ); $rv = array( $prot . rtrim( $query, " \t*" ), $dbr->anyString() ); $field = 'el_to'; } } + return array( $rv, $field ); } @@ -153,9 +169,10 @@ class LinkSearchPage extends QueryPage { global $wgMiserMode; $params = array(); $params['target'] = $this->mProt . $this->mQuery; - if( isset( $this->mNs ) && !$wgMiserMode ) { + if ( isset( $this->mNs ) && !$wgMiserMode ) { $params['namespace'] = $this->mNs; } + return $params; } @@ -164,29 +181,41 @@ class LinkSearchPage extends QueryPage { $dbr = wfGetDB( DB_SLAVE ); // 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 ) + 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 ); - $retval = array ( - 'tables' => array ( 'page', 'externallinks' ), - 'fields' => array ( 'namespace' => 'page_namespace', - 'title' => 'page_title', - 'value' => 'el_index', 'url' => 'el_to' ), - 'conds' => array ( 'page_id = el_from', - "$clause $like" ), + $retval = array( + 'tables' => array( 'page', 'externallinks' ), + 'fields' => array( + 'namespace' => 'page_namespace', + 'title' => 'page_title', + 'value' => 'el_index', + 'url' => 'el_to' + ), + '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; } + /** + * @param Skin $skin + * @param object $result Result row + * @return string + */ function formatResult( $skin, $result ) { $title = Title::makeTitle( $result->namespace, $result->title ); $url = $result->url; @@ -201,7 +230,7 @@ class LinkSearchPage extends QueryPage { */ function doQuery( $offset = false, $limit = false ) { list( $this->mMungedQuery, ) = LinkSearchPage::mungeQuery( $this->mQuery, $this->mProt ); - if( $this->mMungedQuery === false ) { + if ( $this->mMungedQuery === false ) { $this->getOutput()->addWikiMsg( 'linksearch-error' ); } else { // For debugging diff --git a/includes/specials/SpecialListfiles.php b/includes/specials/SpecialListfiles.php index c864ae2a..dff1cf70 100644 --- a/includes/specials/SpecialListfiles.php +++ b/includes/specials/SpecialListfiles.php @@ -22,7 +22,6 @@ */ class SpecialListFiles extends IncludableSpecialPage { - public function __construct() { parent::__construct( 'Listfiles' ); } @@ -37,9 +36,16 @@ class SpecialListFiles extends IncludableSpecialPage { } else { $userName = $this->getRequest()->getText( 'user', $par ); $search = $this->getRequest()->getText( 'ilsearch', '' ); + $showAll = $this->getRequest()->getBool( 'ilshowall', false ); } - $pager = new ImageListPager( $this->getContext(), $userName, $search, $this->including() ); + $pager = new ImageListPager( + $this->getContext(), + $userName, + $search, + $this->including(), + $showAll + ); if ( $this->including() ) { $html = $pager->getBody(); @@ -62,27 +68,33 @@ class SpecialListFiles extends IncludableSpecialPage { */ class ImageListPager extends TablePager { var $mFieldNames = null; + // Subclasses should override buildQueryConds instead of using $mQueryConds variable. var $mQueryConds = array(); var $mUserName = null; var $mSearch = ''; var $mIncluding = false; + var $mShowAll = false; + var $mTableName = 'image'; - function __construct( IContextSource $context, $userName = null, $search = '', $including = false ) { + function __construct( IContextSource $context, $userName = null, $search = '', + $including = false, $showAll = false + ) { global $wgMiserMode; $this->mIncluding = $including; + $this->mShowAll = $showAll; if ( $userName ) { $nt = Title::newFromText( $userName, NS_USER ); if ( !is_null( $nt ) ) { $this->mUserName = $nt->getText(); - $this->mQueryConds['img_user_text'] = $this->mUserName; } } - if ( $search != '' && !$wgMiserMode ) { + if ( $search !== '' && !$wgMiserMode ) { $this->mSearch = $search; $nt = Title::newFromURL( $this->mSearch ); + if ( $nt ) { $dbr = wfGetDB( DB_SLAVE ); $this->mQueryConds[] = 'LOWER(img_name)' . @@ -104,6 +116,42 @@ class ImageListPager extends TablePager { parent::__construct( $context ); } + /** + * Build the where clause of the query. + * + * Replaces the older mQueryConds member variable. + * @param $table String Either "image" or "oldimage" + * @return array The query conditions. + */ + protected function buildQueryConds( $table ) { + $prefix = $table === 'image' ? 'img' : 'oi'; + $conds = array(); + + if ( !is_null( $this->mUserName ) ) { + $conds[ $prefix . '_user_text' ] = $this->mUserName; + } + + if ( $this->mSearch !== '' ) { + $nt = Title::newFromURL( $this->mSearch ); + if ( $nt ) { + $dbr = wfGetDB( DB_SLAVE ); + $conds[] = 'LOWER(' . $prefix . '_name)' . + $dbr->buildLike( $dbr->anyString(), + strtolower( $nt->getDBkey() ), $dbr->anyString() ); + } + } + + if ( $table === 'oldimage' ) { + // Don't want to deal with revdel. + // Future fixme: Show partial information as appropriate. + // Would have to be careful about filtering by username when username is deleted. + $conds['oi_deleted'] = 0; + } + + // Add mQueryConds in case anyone was subclassing and using the old variable. + return $conds + $this->mQueryConds; + } + /** * @return Array */ @@ -118,34 +166,94 @@ class ImageListPager extends TablePager { 'img_user_text' => $this->msg( 'listfiles_user' )->text(), 'img_description' => $this->msg( 'listfiles_description' )->text(), ); - if( !$wgMiserMode ) { + if ( !$wgMiserMode && !$this->mShowAll ) { $this->mFieldNames['count'] = $this->msg( 'listfiles_count' )->text(); } + if ( $this->mShowAll ) { + $this->mFieldNames['top'] = $this->msg( 'listfiles-latestversion' )->text(); + } } + return $this->mFieldNames; } function isFieldSortable( $field ) { + global $wgMiserMode; 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 - return !isset( $this->mQueryConds['img_user_text'] ); + $sortable = array( 'img_timestamp', 'img_name', 'img_size' ); + /* For reference, the indicies we can use for sorting are: + * On the image table: img_usertext_timestamp, img_size, img_timestamp + * On oldimage: oi_usertext_timestamp, oi_name_timestamp + * + * In particular that means we cannot sort by timestamp when not filtering + * by user and including old images in the results. Which is sad. + */ + if ( $wgMiserMode && !is_null( $this->mUserName ) ) { + // If we're sorting by user, the index only supports sorting by time. + if ( $field === 'img_timestamp' ) { + return true; + } else { + return false; + } + } elseif ( $wgMiserMode && $this->mShowAll /* && mUserName === null */ ) { + // no oi_timestamp index, so only alphabetical sorting in this case. + if ( $field === 'img_name' ) { + return true; + } else { + return false; + } } + return in_array( $field, $sortable ); } function getQueryInfo() { - $tables = array( 'image' ); + // Hacky Hacky Hacky - I want to get query info + // for two different tables, without reimplementing + // the pager class. + $qi = $this->getQueryInfoReal( $this->mTableName ); + return $qi; + } + + /** + * Actually get the query info. + * + * This is to allow displaying both stuff from image and oldimage table. + * + * This is a bit hacky. + * + * @param $table String Either 'image' or 'oldimage' + * @return array Query info + */ + protected function getQueryInfoReal( $table ) { + $prefix = $table === 'oldimage' ? 'oi' : 'img'; + + $tables = array( $table ); $fields = array_keys( $this->getFieldNames() ); - $fields[] = 'img_user'; - $fields[array_search( 'thumb', $fields )] = 'img_name AS thumb'; + + if ( $table === 'oldimage' ) { + foreach ( $fields as $id => &$field ) { + if ( substr( $field, 0, 4 ) !== 'img_' ) { + continue; + } + $field = $prefix . substr( $field, 3 ) . ' AS ' . $field; + } + $fields[array_search('top', $fields)] = "'no' AS top"; + } else { + if ( $this->mShowAll ) { + $fields[array_search( 'top', $fields )] = "'yes' AS top"; + } + } + $fields[] = $prefix . '_user AS img_user'; + $fields[array_search( 'thumb', $fields )] = $prefix . '_name AS thumb'; + $options = $join_conds = array(); # Depends on $wgMiserMode - if( isset( $this->mFieldNames['count'] ) ) { + # Will also not happen if mShowAll is true. + if ( isset( $this->mFieldNames['count'] ) ) { $tables[] = 'oldimage'; # Need to rewrite this one @@ -157,7 +265,7 @@ class ImageListPager extends TablePager { unset( $field ); $dbr = wfGetDB( DB_SLAVE ); - if( $dbr->implicitGroupby() ) { + if ( $dbr->implicitGroupby() ) { $options = array( 'GROUP BY' => 'img_name' ); } else { $columnlist = preg_grep( '/^img/', array_keys( $this->getFieldNames() ) ); @@ -165,17 +273,107 @@ class ImageListPager extends TablePager { } $join_conds = array( 'oldimage' => array( 'LEFT JOIN', 'oi_name = img_name' ) ); } + return array( - 'tables' => $tables, - 'fields' => $fields, - 'conds' => $this->mQueryConds, - 'options' => $options, + 'tables' => $tables, + 'fields' => $fields, + 'conds' => $this->buildQueryConds( $table ), + 'options' => $options, 'join_conds' => $join_conds ); } + /** + * Override reallyDoQuery to mix together two queries. + * + * @note $asc is named $descending in IndexPager base class. However + * it is true when the order is ascending, and false when the order + * is descending, so I renamed it to $asc here. + */ + function reallyDoQuery( $offset, $limit, $asc ) { + $prevTableName = $this->mTableName; + $this->mTableName = 'image'; + list( $tables, $fields, $conds, $fname, $options, $join_conds ) = $this->buildQueryInfo( $offset, $limit, $asc ); + $imageRes = $this->mDb->select( $tables, $fields, $conds, $fname, $options, $join_conds ); + $this->mTableName = $prevTableName; + + if ( !$this->mShowAll ) { + return $imageRes; + } + + $this->mTableName = 'oldimage'; + + # Hacky... + $oldIndex = $this->mIndexField; + if ( substr( $this->mIndexField, 0, 4 ) !== 'img_' ) { + throw new MWException( "Expected to be sorting on an image table field" ); + } + $this->mIndexField = 'oi_' . substr( $this->mIndexField, 4 ); + + list( $tables, $fields, $conds, $fname, $options, $join_conds ) = $this->buildQueryInfo( $offset, $limit, $asc ); + $oldimageRes = $this->mDb->select( $tables, $fields, $conds, $fname, $options, $join_conds ); + + $this->mTableName = $prevTableName; + $this->mIndexField = $oldIndex; + + return $this->combineResult( $imageRes, $oldimageRes, $limit, $asc ); + } + + /** + * Combine results from 2 tables. + * + * Note: This will throw away some results + * + * @param $res1 ResultWrapper + * @param $res2 ResultWrapper + * @param $limit int + * @param $ascending boolean See note about $asc in $this->reallyDoQuery + * @return FakeResultWrapper $res1 and $res2 combined + */ + protected function combineResult( $res1, $res2, $limit, $ascending ) { + $res1->rewind(); + $res2->rewind(); + $topRes1 = $res1->next(); + $topRes2 = $res2->next(); + $resultArray = array(); + for ( $i = 0; $i < $limit && $topRes1 && $topRes2; $i++ ) { + if ( strcmp( $topRes1->{ $this->mIndexField }, $topRes2->{ $this->mIndexField } ) > 0 ) { + if ( !$ascending ) { + $resultArray[] = $topRes1; + $topRes1 = $res1->next(); + } else { + $resultArray[] = $topRes2; + $topRes2 = $res2->next(); + } + } else { + if ( !$ascending ) { + $resultArray[] = $topRes2; + $topRes2 = $res2->next(); + } else { + $resultArray[] = $topRes1; + $topRes1 = $res1->next(); + } + } + } + for ( ; $i < $limit && $topRes1; $i++ ) { + $resultArray[] = $topRes1; + $topRes1 = $res1->next(); + } + for ( ; $i < $limit && $topRes2; $i++ ) { + $resultArray[] = $topRes2; + $topRes2 = $res2->next(); + } + return new FakeResultWrapper( $resultArray ); + } + function getDefaultSort() { - return 'img_timestamp'; + global $wgMiserMode; + if ( $this->mShowAll && $wgMiserMode && is_null( $this->mUserName ) ) { + // Unfortunately no index on oi_timestamp. + return 'img_name'; + } else { + return 'img_timestamp'; + } } function doBatchLookups() { @@ -191,24 +389,37 @@ class ImageListPager extends TablePager { function formatValue( $field, $value ) { switch ( $field ) { case 'thumb': - $file = wfLocalFile( $value ); - $thumb = $file->transform( array( 'width' => 180, 'height' => 360 ) ); - return $thumb->toHtml( array( 'desc-link' => true ) ); + $opt = array( 'time' => $this->mCurrentRow->img_timestamp ); + $file = RepoGroup::singleton()->getLocalRepo()->findFile( $value, $opt ); + // If statement for paranoia + if ( $file ) { + $thumb = $file->transform( array( 'width' => 180, 'height' => 360 ) ); + return $thumb->toHtml( array( 'desc-link' => true ) ); + } else { + return htmlspecialchars( $value ); + } case 'img_timestamp': + // We may want to make this a link to the "old" version when displaying old files return htmlspecialchars( $this->getLanguage()->userTimeAndDate( $value, $this->getUser() ) ); case 'img_name': static $imgfile = null; - if ( $imgfile === null ) $imgfile = $this->msg( 'imgfile' )->text(); + if ( $imgfile === null ) { + $imgfile = $this->msg( 'imgfile' )->text(); + } // Weird files can maybe exist? Bug 22227 $filePage = Title::makeTitleSafe( NS_FILE, $value ); - if( $filePage ) { - $link = Linker::linkKnown( $filePage, htmlspecialchars( $filePage->getText() ) ); + if ( $filePage ) { + $link = Linker::linkKnown( + $filePage, + htmlspecialchars( $filePage->getText() ) + ); $download = Xml::element( 'a', array( 'href' => wfLocalFile( $filePage )->getURL() ), $imgfile ); $download = $this->msg( 'parentheses' )->rawParams( $download )->escaped(); + return "$link $download"; } else { return htmlspecialchars( $value ); @@ -223,6 +434,7 @@ class ImageListPager extends TablePager { } else { $link = htmlspecialchars( $value ); } + return $link; case 'img_size': return htmlspecialchars( $this->getLanguage()->formatSize( $value ) ); @@ -230,32 +442,47 @@ class ImageListPager extends TablePager { return Linker::formatComment( $value ); case 'count': return intval( $value ) + 1; + case 'top': + // Messages: listfiles-latestversion-yes, listfiles-latestversion-no + return $this->msg( 'listfiles-latestversion-' . $value ); } } function getForm() { global $wgScript, $wgMiserMode; $inputForm = array(); - $inputForm['table_pager_limit_label'] = $this->getLimitSelect(); + $inputForm['table_pager_limit_label'] = $this->getLimitSelect( array( 'tabindex' => 1 ) ); if ( !$wgMiserMode ) { - $inputForm['listfiles_search_for'] = Html::input( 'ilsearch', $this->mSearch, 'text', + $inputForm['listfiles_search_for'] = Html::input( + 'ilsearch', + $this->mSearch, + 'text', array( - 'size' => '40', + 'size' => '40', 'maxlength' => '255', - 'id' => 'mw-ilsearch', - ) ); + 'id' => 'mw-ilsearch', + 'tabindex' => 2, + ) + ); } $inputForm['username'] = Html::input( 'user', $this->mUserName, 'text', array( - 'size' => '40', + 'size' => '40', 'maxlength' => '255', - 'id' => 'mw-listfiles-user', + 'id' => 'mw-listfiles-user', + 'tabindex' => 3, + ) ); + + $inputForm['listfiles-show-all'] = Html::input( 'ilshowall', 1, 'checkbox', array( + 'checked' => $this->mShowAll, + 'tabindex' => 4, ) ); return Html::openElement( 'form', - array( 'method' => 'get', 'action' => $wgScript, 'id' => 'mw-listfiles-form' ) ) . + array( 'method' => 'get', 'action' => $wgScript, 'id' => 'mw-listfiles-form' ) + ) . Xml::fieldset( $this->msg( 'listfiles' )->text() ) . Html::hidden( 'title', $this->getTitle()->getPrefixedText() ) . - Xml::buildForm( $inputForm, 'table_pager_limit_submit' ) . - $this->getHiddenFields( array( 'limit', 'ilsearch', 'user', 'title' ) ) . + Xml::buildForm( $inputForm, 'table_pager_limit_submit', array( 'tabindex' => 5 ) ) . + $this->getHiddenFields( array( 'limit', 'ilsearch', 'user', 'title', 'ilshowall' ) ) . Html::closeElement( 'fieldset' ) . Html::closeElement( 'form' ) . "\n"; } @@ -280,6 +507,7 @@ class ImageListPager extends TablePager { $query['user'] = $this->mUserName; } } + return $queries; } @@ -288,6 +516,7 @@ class ImageListPager extends TablePager { 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 7cccf887..82a4f70f 100644 --- a/includes/specials/SpecialListgrouprights.php +++ b/includes/specials/SpecialListgrouprights.php @@ -29,7 +29,6 @@ * @author Petr Kadlec */ class SpecialListGroupRights extends SpecialPage { - /** * Constructor */ @@ -51,11 +50,13 @@ class SpecialListGroupRights extends SpecialPage { $out = $this->getOutput(); $out->addModuleStyles( 'mediawiki.special' ); + $out->wrapWikiMsg( "
    \n$1\n
    ", 'listgrouprights-key' ); + $out->addHTML( Xml::openElement( 'table', array( 'class' => 'wikitable mw-listgrouprights-table' ) ) . '' . - Xml::element( 'th', null, $this->msg( 'listgrouprights-group' )->text() ) . - Xml::element( 'th', null, $this->msg( 'listgrouprights-rights' )->text() ) . + Xml::element( 'th', null, $this->msg( 'listgrouprights-group' )->text() ) . + Xml::element( 'th', null, $this->msg( 'listgrouprights-rights' )->text() ) . '' ); @@ -85,7 +86,7 @@ class SpecialListGroupRights extends SpecialPage { $msg->text() : MWNamespace::getCanonicalName( NS_PROJECT ) . ':' . $groupname; - if( $group == '*' ) { + if ( $group == '*' ) { // Do not make a link for the generic * group $grouppage = htmlspecialchars( $groupnameLocalized ); } else { @@ -124,16 +125,13 @@ class SpecialListGroupRights extends SpecialPage { " $grouppage$grouplink " . - $this->formatPermissions( $permissions, $revoke, $addgroups, $removegroups, - $addgroupsSelf, $removegroupsSelf ) . + $this->formatPermissions( $permissions, $revoke, $addgroups, $removegroups, + $addgroupsSelf, $removegroupsSelf ) . ' ' ) ); } - $out->addHTML( - Xml::closeElement( 'table' ) . "\n

    \n" - ); - $out->wrapWikiMsg( "
    \n$1\n
    ", 'listgrouprights-key' ); + $out->addHTML( Xml::closeElement( 'table' ) ); } /** @@ -149,9 +147,9 @@ class SpecialListGroupRights extends SpecialPage { */ private function formatPermissions( $permissions, $revoke, $add, $remove, $addSelf, $removeSelf ) { $r = array(); - foreach( $permissions as $permission => $granted ) { + foreach ( $permissions as $permission => $granted ) { //show as granted only if it isn't revoked to prevent duplicate display of permissions - if( $granted && ( !isset( $revoke[$permission] ) || !$revoke[$permission] ) ) { + if ( $granted && ( !isset( $revoke[$permission] ) || !$revoke[$permission] ) ) { $description = $this->msg( 'listgrouprights-right-display', User::getRightDescription( $permission ), '' . $permission . '' @@ -159,8 +157,8 @@ class SpecialListGroupRights extends SpecialPage { $r[] = $description; } } - foreach( $revoke as $permission => $revoked ) { - if( $revoked ) { + foreach ( $revoke as $permission => $revoked ) { + if ( $revoked ) { $description = $this->msg( 'listgrouprights-right-revoked', User::getRightDescription( $permission ), '' . $permission . '' @@ -168,45 +166,52 @@ class SpecialListGroupRights extends SpecialPage { $r[] = $description; } } + sort( $r ); + $lang = $this->getLanguage(); - if( $add === true ) { + + if ( $add === true ) { $r[] = $this->msg( 'listgrouprights-addgroup-all' )->escaped(); - } elseif( is_array( $add ) && count( $add ) ) { + } elseif ( is_array( $add ) && count( $add ) ) { $add = array_values( array_unique( $add ) ); $r[] = $this->msg( 'listgrouprights-addgroup', $lang->listToText( array_map( array( 'User', 'makeGroupLinkWiki' ), $add ) ), count( $add ) )->parse(); } - if( $remove === true ) { + + if ( $remove === true ) { $r[] = $this->msg( 'listgrouprights-removegroup-all' )->escaped(); - } elseif( is_array( $remove ) && count( $remove ) ) { + } elseif ( is_array( $remove ) && count( $remove ) ) { $remove = array_values( array_unique( $remove ) ); $r[] = $this->msg( 'listgrouprights-removegroup', $lang->listToText( array_map( array( 'User', 'makeGroupLinkWiki' ), $remove ) ), count( $remove ) )->parse(); } - if( $addSelf === true ) { + + if ( $addSelf === true ) { $r[] = $this->msg( 'listgrouprights-addgroup-self-all' )->escaped(); - } elseif( is_array( $addSelf ) && count( $addSelf ) ) { + } elseif ( is_array( $addSelf ) && count( $addSelf ) ) { $addSelf = array_values( array_unique( $addSelf ) ); $r[] = $this->msg( 'listgrouprights-addgroup-self', $lang->listToText( array_map( array( 'User', 'makeGroupLinkWiki' ), $addSelf ) ), count( $addSelf ) )->parse(); } - if( $removeSelf === true ) { + + if ( $removeSelf === true ) { $r[] = $this->msg( 'listgrouprights-removegroup-self-all' )->parse(); - } elseif( is_array( $removeSelf ) && count( $removeSelf ) ) { + } elseif ( is_array( $removeSelf ) && count( $removeSelf ) ) { $removeSelf = array_values( array_unique( $removeSelf ) ); $r[] = $this->msg( 'listgrouprights-removegroup-self', $lang->listToText( array_map( array( 'User', 'makeGroupLinkWiki' ), $removeSelf ) ), count( $removeSelf ) )->parse(); } - if( empty( $r ) ) { + + if ( empty( $r ) ) { return ''; } else { return '
    • ' . implode( "
    • \n
    • ", $r ) . '
    '; diff --git a/includes/specials/SpecialListredirects.php b/includes/specials/SpecialListredirects.php index 0283767a..2c8792ff 100644 --- a/includes/specials/SpecialListredirects.php +++ b/includes/specials/SpecialListredirects.php @@ -29,7 +29,6 @@ * @ingroup SpecialPage */ class ListredirectsPage extends QueryPage { - function __construct( $name = 'Listredirects' ) { parent::__construct( $name ); } @@ -50,16 +49,16 @@ class ListredirectsPage extends QueryPage { return array( 'tables' => array( 'p1' => 'page', 'redirect', 'p2' => 'page' ), 'fields' => array( 'namespace' => 'p1.page_namespace', - 'title' => 'p1.page_title', - 'value' => 'p1.page_title', - 'rd_namespace', - 'rd_title', - 'rd_fragment', - 'rd_interwiki', - 'redirid' => 'p2.page_id' ), + 'title' => 'p1.page_title', + 'value' => 'p1.page_title', + 'rd_namespace', + 'rd_title', + 'rd_fragment', + 'rd_interwiki', + 'redirid' => 'p2.page_id' ), 'conds' => array( 'p1.page_is_redirect' => 1 ), 'join_conds' => array( 'redirect' => array( - 'LEFT JOIN', 'rd_from=p1.page_id' ), + 'LEFT JOIN', 'rd_from=p1.page_id' ), 'p2' => array( 'LEFT JOIN', array( 'p2.page_namespace=rd_namespace', 'p2.page_title=rd_title' ) ) ) @@ -67,21 +66,23 @@ class ListredirectsPage extends QueryPage { } function getOrderFields() { - return array ( 'p1.page_namespace', 'p1.page_title' ); + return array( 'p1.page_namespace', 'p1.page_title' ); } /** * Cache page existence for performance * - * @param $db DatabaseBase - * @param $res ResultWrapper + * @param DatabaseBase $db + * @param ResultWrapper $res */ 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 @@ -100,10 +101,16 @@ class ListredirectsPage extends QueryPage { } else { $title = Title::makeTitle( $row->namespace, $row->title ); $article = WikiPage::factory( $title ); + return $article->getRedirectTarget(); } } + /** + * @param Skin $skin + * @param object $result Result row + * @return string + */ function formatResult( $skin, $result ) { # Make a link to the redirect itself $rd_title = Title::makeTitle( $result->namespace, $result->title ); @@ -116,11 +123,12 @@ class ListredirectsPage extends QueryPage { # Find out where the redirect leads $target = $this->getRedirectTarget( $result ); - if( $target ) { + if ( $target ) { # Make a link to the destination page $lang = $this->getLanguage(); $arr = $lang->getArrow() . $lang->getDirMark(); $targetLink = Linker::link( $target ); + return "$rd_link $arr $targetLink"; } else { return "$rd_link"; diff --git a/includes/specials/SpecialListusers.php b/includes/specials/SpecialListusers.php index d253a4d3..8cd9173c 100644 --- a/includes/specials/SpecialListusers.php +++ b/includes/specials/SpecialListusers.php @@ -49,7 +49,10 @@ class UsersPager extends AlphabeticPager { $par = ( $par !== null ) ? $par : ''; $parms = explode( '/', $par ); $symsForAll = array( '*', 'user' ); - if ( $parms[0] != '' && ( in_array( $par, User::getAllGroups() ) || in_array( $par, $symsForAll ) ) ) { + + if ( $parms[0] != '' && + ( in_array( $par, User::getAllGroups() ) || in_array( $par, $symsForAll ) ) + ) { $this->requestedGroup = $par; $un = $request->getText( 'username' ); } elseif ( count( $parms ) == 2 ) { @@ -59,20 +62,25 @@ class UsersPager extends AlphabeticPager { $this->requestedGroup = $request->getVal( 'group' ); $un = ( $par != '' ) ? $par : $request->getText( 'username' ); } + if ( in_array( $this->requestedGroup, $symsForAll ) ) { $this->requestedGroup = ''; } $this->editsOnly = $request->getBool( 'editsOnly' ); $this->creationSort = $request->getBool( 'creationSort' ); $this->including = $including; + $this->mDefaultDirection = $request->getBool( 'desc' ); $this->requestedUser = ''; + if ( $un != '' ) { $username = Title::makeTitleSafe( NS_USER, $un ); - if( ! is_null( $username ) ) { + + if ( !is_null( $username ) ) { $this->requestedUser = $username->getText(); } } + parent::__construct(); } @@ -89,27 +97,28 @@ class UsersPager extends AlphabeticPager { function getQueryInfo() { $dbr = wfGetDB( DB_SLAVE ); $conds = array(); + // Don't show hidden names - if( !$this->getUser()->isAllowed( 'hideuser' ) ) { + if ( !$this->getUser()->isAllowed( 'hideuser' ) ) { $conds[] = 'ipb_deleted IS NULL OR ipb_deleted = 0'; } $options = array(); - if( $this->requestedGroup != '' ) { + if ( $this->requestedGroup != '' ) { $conds['ug_group'] = $this->requestedGroup; - } else { - //$options['USE INDEX'] = $this->creationSort ? 'PRIMARY' : 'user_name'; } - if( $this->requestedUser != '' ) { + + if ( $this->requestedUser != '' ) { # Sorted either by account creation or name - if( $this->creationSort ) { + if ( $this->creationSort ) { $conds[] = 'user_id >= ' . intval( User::idFromName( $this->requestedUser ) ); } else { $conds[] = 'user_name >= ' . $dbr->addQuotes( $this->requestedUser ); } } - if( $this->editsOnly ) { + + if ( $this->editsOnly ) { $conds[] = 'user_editcount > 0'; } @@ -129,15 +138,18 @@ class UsersPager extends AlphabeticPager { 'options' => $options, 'join_conds' => array( 'user_groups' => array( 'LEFT JOIN', 'user_id=ug_user' ), - 'ipblocks' => array( 'LEFT JOIN', array( - 'user_id=ipb_user', - 'ipb_auto' => 0 - )), + 'ipblocks' => array( + 'LEFT JOIN', array( + 'user_id=ipb_user', + 'ipb_auto' => 0 + ) + ), ), 'conds' => $conds ); wfRunHooks( 'SpecialListusersQueryInfo', array( $this, &$query ) ); + return $query; } @@ -153,42 +165,55 @@ class UsersPager extends AlphabeticPager { $userName = $row->user_name; $ulinks = Linker::userLink( $row->user_id, $userName ); - $ulinks .= Linker::userToolLinksRedContribs( $row->user_id, $userName, intval( $row->edits ) ); + $ulinks .= Linker::userToolLinksRedContribs( + $row->user_id, + $userName, + (int)$row->edits + ); $lang = $this->getLanguage(); $groups = ''; $groups_list = self::getGroups( $row->user_id ); - if( !$this->including && count( $groups_list ) > 0 ) { + + if ( !$this->including && count( $groups_list ) > 0 ) { $list = array(); - foreach( $groups_list as $group ) + foreach ( $groups_list as $group ) { $list[] = self::buildGroupLink( $group, $userName ); + } $groups = $lang->commaList( $list ); } $item = $lang->specialList( $ulinks, $groups ); - if( $row->ipb_deleted ) { + + if ( $row->ipb_deleted ) { $item = "$item"; } $edits = ''; global $wgEdititis; if ( !$this->including && $wgEdititis ) { - $edits = ' [' . $this->msg( 'usereditcount' )->numParams( $row->edits )->escaped() . ']'; + // @fixme i18n issue: Hardcoded square brackets. + $edits = ' [' . + $this->msg( 'usereditcount' )->numParams( $row->edits )->escaped() . + ']'; } $created = ''; - # Some rows may be NULL - if( !$this->including && $row->creation ) { + # Some rows may be null + if ( !$this->including && $row->creation ) { $user = $this->getUser(); $d = $lang->userDate( $row->creation, $user ); $t = $lang->userTime( $row->creation, $user ); $created = $this->msg( 'usercreated', $d, $t, $row->user_name )->escaped(); $created = ' ' . $this->msg( 'parentheses' )->rawParams( $created )->escaped(); } - $blocked = !is_null( $row->ipb_deleted ) ? ' ' . $this->msg( 'listusers-blocked', $userName )->escaped() : ''; + $blocked = !is_null( $row->ipb_deleted ) ? + ' ' . $this->msg( 'listusers-blocked', $userName )->escaped() : + ''; wfRunHooks( 'SpecialListusersFormatRow', array( &$item, $row ) ); + return Html::rawElement( 'li', array(), "{$item}{$edits}{$created}{$blocked}" ); } @@ -212,7 +237,10 @@ class UsersPager extends AlphabeticPager { list( $self ) = explode( '/', $this->getTitle()->getPrefixedDBkey() ); # Form tag - $out = Xml::openElement( 'form', array( 'method' => 'get', 'action' => $wgScript, 'id' => 'mw-listusers-form' ) ) . + $out = Xml::openElement( + 'form', + array( 'method' => 'get', 'action' => $wgScript, 'id' => 'mw-listusers-form' ) + ) . Xml::fieldset( $this->msg( 'listusers' )->text() ) . Html::hidden( 'title', $self ); @@ -233,12 +261,30 @@ class UsersPager extends AlphabeticPager { $out .= Xml::label( $this->msg( 'group' )->text(), 'group' ) . ' ' . Xml::openElement( 'select', array( 'name' => 'group', 'id' => 'group' ) ) . Xml::option( $this->msg( 'group-all' )->text(), '' ); - foreach( $this->getAllGroups() as $group => $groupText ) + foreach ( $this->getAllGroups() as $group => $groupText ) { $out .= Xml::option( $groupText, $group, $group == $this->requestedGroup ); + } $out .= Xml::closeElement( 'select' ) . '
    '; - $out .= Xml::checkLabel( $this->msg( 'listusers-editsonly' )->text(), 'editsOnly', 'editsOnly', $this->editsOnly ); + $out .= Xml::checkLabel( + $this->msg( 'listusers-editsonly' )->text(), + 'editsOnly', + 'editsOnly', + $this->editsOnly + ); + $out .= ' '; + $out .= Xml::checkLabel( + $this->msg( 'listusers-creationsort' )->text(), + 'creationSort', + 'creationSort', + $this->creationSort + ); $out .= ' '; - $out .= Xml::checkLabel( $this->msg( 'listusers-creationsort' )->text(), 'creationSort', 'creationSort', $this->creationSort ); + $out .= Xml::checkLabel( + $this->msg( 'listusers-desc' )->text(), + 'desc', + 'desc', + $this->mDefaultDirection + ); $out .= '
    '; wfRunHooks( 'SpecialListusersHeaderForm', array( $this, &$out ) ); @@ -259,10 +305,11 @@ class UsersPager extends AlphabeticPager { */ function getAllGroups() { $result = array(); - foreach( User::getAllGroups() as $group ) { + foreach ( User::getAllGroups() as $group ) { $result[$group] = User::getGroupName( $group ); } asort( $result ); + return $result; } @@ -272,13 +319,14 @@ class UsersPager extends AlphabeticPager { */ function getDefaultQuery() { $query = parent::getDefaultQuery(); - if( $this->requestedGroup != '' ) { + if ( $this->requestedGroup != '' ) { $query['group'] = $this->requestedGroup; } - if( $this->requestedUser != '' ) { + if ( $this->requestedUser != '' ) { $query['username'] = $this->requestedUser; } wfRunHooks( 'SpecialListusersDefaultQuery', array( $this, &$query ) ); + return $query; } @@ -291,6 +339,7 @@ class UsersPager extends AlphabeticPager { protected static function getGroups( $uid ) { $user = User::newFromId( $uid ); $groups = array_diff( $user->getEffectiveGroups(), User::getImplicitGroups() ); + return $groups; } @@ -302,7 +351,10 @@ class UsersPager extends AlphabeticPager { * @return string */ protected static function buildGroupLink( $group, $username ) { - return User::makeGroupLinkHtml( $group, htmlspecialchars( User::getGroupMember( $group, $username ) ) ); + return User::makeGroupLinkHtml( + $group, + htmlspecialchars( User::getGroupMember( $group, $username ) ) + ); } } @@ -310,7 +362,6 @@ class UsersPager extends AlphabeticPager { * @ingroup SpecialPage */ class SpecialListUsers extends IncludableSpecialPage { - /** * Constructor */ @@ -337,7 +388,7 @@ class SpecialListUsers extends IncludableSpecialPage { $s = $up->getPageHeader(); } - if( $usersbody ) { + if ( $usersbody ) { $s .= $up->getNavigationBar(); $s .= Html::rawElement( 'ul', array(), $usersbody ); $s .= $up->getNavigationBar(); diff --git a/includes/specials/SpecialLog.php b/includes/specials/SpecialLog.php index 4fc0f6e8..2ffdd89d 100644 --- a/includes/specials/SpecialLog.php +++ b/includes/specials/SpecialLog.php @@ -29,7 +29,6 @@ * @ingroup SpecialPage */ class SpecialLog extends SpecialPage { - /** * List log type for which the target is a user * Thus if the given target is in NS_MAIN we can alter it to be an NS_USER @@ -75,14 +74,14 @@ class SpecialLog extends SpecialPage { $opts->setValue( 'month', '' ); } - // Reset the log type to default (nothing) if it's invalid or if the - // user does not possess the right to view it + // If the user doesn't have the right permission to view the specific + // log type, throw a PermissionsError + // If the log type is invalid, just show all public logs $type = $opts->getValue( 'type' ); - if ( !LogPage::isLogType( $type ) - || ( isset( $wgLogRestrictions[$type] ) - && !$this->getUser()->isAllowed( $wgLogRestrictions[$type] ) ) - ) { + if ( !LogPage::isLogType( $type ) ) { $opts->setValue( 'type', '' ); + } elseif ( isset( $wgLogRestrictions[$type] ) && !$this->getUser()->isAllowed( $wgLogRestrictions[$type] ) ) { + throw new PermissionsError( $wgLogRestrictions[$type] ); } # Handle type-specific inputs @@ -99,10 +98,10 @@ class SpecialLog extends SpecialPage { # Some log types are only for a 'User:' title but we might have been given # only the username instead of the full title 'User:username'. This part try # to lookup for a user by that name and eventually fix user input. See bug 1697. - if( in_array( $opts->getValue( 'type' ), $this->typeOnUser ) ) { + if ( in_array( $opts->getValue( 'type' ), $this->typeOnUser ) ) { # ok we have a type of log which expect a user title. $target = Title::newFromText( $opts->getValue( 'page' ) ); - if( $target && $target->getNamespace() === NS_MAIN ) { + if ( $target && $target->getNamespace() === NS_MAIN ) { # User forgot to add 'User:', we are adding it for him $opts->setValue( 'page', Title::makeTitleSafe( NS_USER, $opts->getValue( 'page' ) ) @@ -117,9 +116,11 @@ class SpecialLog extends SpecialPage { global $wgLogTypes; # Get parameters - $parms = explode( '/', ($par = ( $par !== null ) ? $par : '' ) ); + $parms = explode( '/', ( $par = ( $par !== null ) ? $par : '' ) ); $symsForAll = array( '*', 'all' ); - if ( $parms[0] != '' && ( in_array( $par, $wgLogTypes ) || in_array( $par, $symsForAll ) ) ) { + if ( $parms[0] != '' && + ( in_array( $par, $wgLogTypes ) || in_array( $par, $symsForAll ) ) + ) { $opts->setValue( 'type', $par ); } elseif ( count( $parms ) == 2 ) { $opts->setValue( 'type', $parms[0] ); @@ -131,10 +132,22 @@ class SpecialLog extends SpecialPage { private function show( FormOptions $opts, array $extraConds ) { # Create a LogPager item to get the results and a LogEventsList item to format them... - $loglist = new LogEventsList( $this->getContext(), null, LogEventsList::USE_REVDEL_CHECKBOXES ); - $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' ) ); + $loglist = new LogEventsList( + $this->getContext(), + null, + LogEventsList::USE_REVDEL_CHECKBOXES + ); + $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' ) + ); $this->addHeader( $opts->getValue( 'type' ) ); @@ -144,16 +157,28 @@ class SpecialLog extends SpecialPage { } # Show form options - $loglist->showOptions( $pager->getType(), $opts->getValue( 'user' ), $pager->getPage(), $pager->getPattern(), - $pager->getYear(), $pager->getMonth(), $pager->getFilterParams(), $opts->getValue( 'tagfilter' ) ); + $loglist->showOptions( + $pager->getType(), + $opts->getValue( 'user' ), + $pager->getPage(), + $pager->getPattern(), + $pager->getYear(), + $pager->getMonth(), + $pager->getFilterParams(), + $opts->getValue( 'tagfilter' ) + ); # Insert list $logBody = $pager->getBody(); if ( $logBody ) { $this->getOutput()->addHTML( $pager->getNavigationBar() . - $this->getRevisionButton( $loglist->beginLogEventsList() . $logBody . $loglist->endLogEventsList() ) . - $pager->getNavigationBar() + $this->getRevisionButton( + $loglist->beginLogEventsList() . + $logBody . + $loglist->endLogEventsList() + ) . + $pager->getNavigationBar() ); } else { $this->getOutput()->addWikiMsg( 'logempty' ); @@ -161,19 +186,27 @@ class SpecialLog extends SpecialPage { } private function getRevisionButton( $formcontents ) { - # If the user doesn't have the ability to delete log entries, don't bother showing him/her the button. + # If the user doesn't have the ability to delete log entries, + # don't bother showing them the button. if ( !$this->getUser()->isAllowedAll( 'deletedhistory', 'deletelogentry' ) ) { return $formcontents; } # Show button to hide log entries global $wgScript; - $s = Html::openElement( 'form', array( 'action' => $wgScript, 'id' => 'mw-log-deleterevision-submit' ) ) . "\n"; + $s = Html::openElement( + 'form', + array( 'action' => $wgScript, 'id' => 'mw-log-deleterevision-submit' ) + ) . "\n"; $s .= Html::hidden( 'title', SpecialPage::getTitleFor( 'Revisiondelete' ) ) . "\n"; $s .= Html::hidden( 'target', SpecialPage::getTitleFor( 'Log' ) ) . "\n"; $s .= Html::hidden( 'type', 'logging' ) . "\n"; - $button = Html::element( 'button', - array( 'type' => 'submit', 'class' => "deleterevision-log-submit mw-log-deleterevision-button" ), + $button = Html::element( + 'button', + array( + 'type' => 'submit', + 'class' => "deleterevision-log-submit mw-log-deleterevision-button" + ), $this->msg( 'showhideselectedlogentries' )->text() ) . "\n"; $s .= $button . $formcontents . $button; diff --git a/includes/specials/SpecialLonelypages.php b/includes/specials/SpecialLonelypages.php index 8c6a88ac..7c7771d7 100644 --- a/includes/specials/SpecialLonelypages.php +++ b/includes/specials/SpecialLonelypages.php @@ -28,7 +28,6 @@ * @ingroup SpecialPage */ class LonelyPagesPage extends PageQueryPage { - function __construct( $name = 'Lonelypages' ) { parent::__construct( $name ); } @@ -50,32 +49,43 @@ class LonelyPagesPage extends PageQueryPage { } function getQueryInfo() { - return array ( - 'tables' => array ( 'page', 'pagelinks', - 'templatelinks' ), - 'fields' => array ( 'namespace' => 'page_namespace', - 'title' => 'page_title', - 'value' => 'page_title' ), - '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 ( + return array( + 'tables' => array( + 'page', 'pagelinks', + 'templatelinks' + ), + 'fields' => array( + 'namespace' => 'page_namespace', + 'title' => 'page_title', + 'value' => 'page_title' + ), + '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 ( + 'pl_title = page_title' + ) + ), + 'templatelinks' => array( + 'LEFT JOIN', array( 'tl_namespace = page_namespace', - 'tl_title = page_title' ) ) ) + 'tl_title = page_title' + ) + ) + ) ); } function getOrderFields() { // For some crazy reason ordering by a constant // causes a filesort in MySQL 5 - if( count( MWNamespace::getContentNamespaces() ) > 1 ) { + 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 c045f9e9..d90d2718 100644 --- a/includes/specials/SpecialLongpages.php +++ b/includes/specials/SpecialLongpages.php @@ -26,7 +26,6 @@ * @ingroup SpecialPage */ class LongPagesPage extends ShortPagesPage { - function __construct( $name = 'Longpages' ) { parent::__construct( $name ); } diff --git a/includes/specials/SpecialMIMEsearch.php b/includes/specials/SpecialMIMEsearch.php index c5a109d4..3eeae310 100644 --- a/includes/specials/SpecialMIMEsearch.php +++ b/includes/specials/SpecialMIMEsearch.php @@ -35,7 +35,7 @@ class MIMEsearchPage extends QueryPage { } function isExpensive() { - return true; + return false; } function isSyndicated() { @@ -51,19 +51,52 @@ class MIMEsearchPage extends QueryPage { } public function getQueryInfo() { - return array( + $qi = array( 'tables' => array( 'image' ), - 'fields' => array( 'namespace' => NS_FILE, - 'title' => 'img_name', - 'value' => 'img_major_mime', - 'img_size', - 'img_width', - 'img_height', - 'img_user_text', - 'img_timestamp' ), - 'conds' => array( 'img_major_mime' => $this->major, - 'img_minor_mime' => $this->minor ) + 'fields' => array( + 'namespace' => NS_FILE, + 'title' => 'img_name', + // Still have a value field just in case, + // but it isn't actually used for sorting. + 'value' => 'img_name', + 'img_size', + 'img_width', + 'img_height', + 'img_user_text', + 'img_timestamp' + ), + 'conds' => array( + 'img_major_mime' => $this->major, + 'img_minor_mime' => $this->minor, + // This is in order to trigger using + // the img_media_mime index in "range" mode. + 'img_media_type' => array( + MEDIATYPE_BITMAP, + MEDIATYPE_DRAWING, + MEDIATYPE_AUDIO, + MEDIATYPE_VIDEO, + MEDIATYPE_MULTIMEDIA, + MEDIATYPE_UNKNOWN, + MEDIATYPE_OFFICE, + MEDIATYPE_TEXT, + MEDIATYPE_EXECUTABLE, + MEDIATYPE_ARCHIVE, + ), + ), ); + return $qi; + } + + /** + * The index is on (img_media_type, img_major_mime, img_minor_mime) + * which unfortunately doesn't have img_name at the end for sorting. + * So tell db to sort it however it wishes (Its not super important + * that this report gives results in a logical order). As an aditional + * note, mysql seems to by default order things by img_name ASC, which + * is what we ideally want, so everything works out fine anyhow. + */ + function getOrderFields() { + return array(); } function execute( $par ) { @@ -74,24 +107,36 @@ class MIMEsearchPage extends QueryPage { $this->setHeaders(); $this->outputHeader(); $this->getOutput()->addHTML( - Xml::openElement( 'form', array( 'id' => 'specialmimesearch', 'method' => 'get', 'action' => $wgScript ) ) . - Xml::openElement( 'fieldset' ) . - Html::hidden( 'title', $this->getTitle()->getPrefixedText() ) . - Xml::element( 'legend', null, $this->msg( 'mimesearch' )->text() ) . - Xml::inputLabel( $this->msg( 'mimetype' )->text(), 'mime', 'mime', 20, $mime ) . ' ' . - Xml::submitButton( $this->msg( 'ilsubmit' )->text() ) . - Xml::closeElement( 'fieldset' ) . - Xml::closeElement( 'form' ) + Xml::openElement( + 'form', + array( 'id' => 'specialmimesearch', 'method' => 'get', 'action' => $wgScript ) + ) . + Xml::openElement( 'fieldset' ) . + Html::hidden( 'title', $this->getTitle()->getPrefixedText() ) . + Xml::element( 'legend', null, $this->msg( 'mimesearch' )->text() ) . + Xml::inputLabel( $this->msg( 'mimetype' )->text(), 'mime', 'mime', 20, $mime ) . + ' ' . + Xml::submitButton( $this->msg( 'ilsubmit' )->text() ) . + Xml::closeElement( 'fieldset' ) . + Xml::closeElement( 'form' ) ); list( $this->major, $this->minor ) = File::splitMime( $mime ); + if ( $this->major == '' || $this->minor == '' || $this->minor == 'unknown' || - !self::isValidType( $this->major ) ) { + !self::isValidType( $this->major ) + ) { return; } + parent::execute( $par ); } + /** + * @param Skin $skin + * @param object $result Result row + * @return string + */ function formatResult( $skin, $result ) { global $wgContLang; @@ -108,8 +153,13 @@ class MIMEsearchPage extends QueryPage { $bytes = htmlspecialchars( $lang->formatSize( $result->img_size ) ); $dimensions = $this->msg( 'widthheight' )->numParams( $result->img_width, $result->img_height )->escaped(); - $user = Linker::link( Title::makeTitle( NS_USER, $result->img_user_text ), htmlspecialchars( $result->img_user_text ) ); - $time = htmlspecialchars( $lang->userTimeAndDate( $result->img_timestamp, $this->getUser() ) ); + $user = Linker::link( + Title::makeTitle( NS_USER, $result->img_user_text ), + htmlspecialchars( $result->img_user_text ) + ); + + $time = $lang->userTimeAndDate( $result->img_timestamp, $this->getUser() ); + $time = htmlspecialchars( $time ); return "$download $plink . . $dimensions . . $bytes . . $user . . $time"; } @@ -131,6 +181,7 @@ class MIMEsearchPage extends QueryPage { 'model', 'multipart' ); + return in_array( $type, $types ); } diff --git a/includes/specials/SpecialMergeHistory.php b/includes/specials/SpecialMergeHistory.php index 1476e156..fb5ea657 100644 --- a/includes/specials/SpecialMergeHistory.php +++ b/includes/specials/SpecialMergeHistory.php @@ -52,14 +52,14 @@ 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' ); $this->mMerge = $request->wasPosted() && $this->getUser()->matchEditToken( $request->getVal( 'wpEditToken' ) ); // target page - if( $this->mSubmitted ) { + if ( $this->mSubmitted ) { $this->mTargetObj = Title::newFromURL( $this->mTarget ); $this->mDestObj = Title::newFromURL( $this->mDest ); } else { @@ -75,7 +75,7 @@ class SpecialMergeHistory extends SpecialPage { */ function preCacheMessages() { // Precache various messages - if( !isset( $this->message ) ) { + if ( !isset( $this->message ) ) { $this->message['last'] = $this->msg( 'last' )->escaped(); } } @@ -89,20 +89,22 @@ 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 ) { $this->merge(); + return; } if ( !$this->mSubmitted ) { $this->showMergeForm(); + return; } $errors = array(); if ( !$this->mTargetObj instanceof Title ) { $errors[] = $this->msg( 'mergehistory-invalid-source' )->parseAsBlock(); - } elseif( !$this->mTargetObj->exists() ) { + } elseif ( !$this->mTargetObj->exists() ) { $errors[] = $this->msg( 'mergehistory-no-source', array( 'parse' ), wfEscapeWikiText( $this->mTargetObj->getPrefixedText() ) )->parseAsBlock(); @@ -110,7 +112,7 @@ class SpecialMergeHistory extends SpecialPage { if ( !$this->mDestObj instanceof Title ) { $errors[] = $this->msg( 'mergehistory-invalid-destination' )->parseAsBlock(); - } elseif( !$this->mDestObj->exists() ) { + } elseif ( !$this->mDestObj->exists() ) { $errors[] = $this->msg( 'mergehistory-no-destination', array( 'parse' ), wfEscapeWikiText( $this->mDestObj->getPrefixedText() ) )->parseAsBlock(); @@ -126,7 +128,6 @@ class SpecialMergeHistory extends SpecialPage { } else { $this->showHistory(); } - } function showMergeForm() { @@ -138,25 +139,25 @@ class SpecialMergeHistory extends SpecialPage { Xml::openElement( 'form', array( 'method' => 'get', 'action' => $wgScript ) ) . - '
    ' . - Xml::element( 'legend', array(), - $this->msg( 'mergehistory-box' )->text() ) . - Html::hidden( 'title', $this->getTitle()->getPrefixedDBkey() ) . - Html::hidden( 'submitted', '1' ) . - Html::hidden( 'mergepoint', $this->mTimestamp ) . - Xml::openElement( 'table' ) . - ' + '
    ' . + Xml::element( 'legend', array(), + $this->msg( 'mergehistory-box' )->text() ) . + Html::hidden( 'title', $this->getTitle()->getPrefixedDBkey() ) . + Html::hidden( 'submitted', '1' ) . + Html::hidden( 'mergepoint', $this->mTimestamp ) . + Xml::openElement( 'table' ) . + ' ' . Xml::label( $this->msg( 'mergehistory-from' )->text(), 'target' ) . ' ' . Xml::input( 'target', 30, $this->mTarget, array( 'id' => 'target' ) ) . ' ' . Xml::label( $this->msg( 'mergehistory-into' )->text(), 'dest' ) . ' ' . Xml::input( 'dest', 30, $this->mDest, array( 'id' => 'dest' ) ) . ' ' . - Xml::submitButton( $this->msg( 'mergehistory-go' )->text() ) . - '' . - Xml::closeElement( 'table' ) . - '
    ' . - '' + Xml::submitButton( $this->msg( 'mergehistory-go' )->text() ) . + '' . + Xml::closeElement( 'table' ) . + '
    ' . + '' ); } @@ -183,40 +184,40 @@ class SpecialMergeHistory extends SpecialPage { ); $out->addHTML( $top ); - if( $haveRevisions ) { + if ( $haveRevisions ) { # Format the user-visible controls (comment field, submission button) # in a nice little table $table = Xml::openElement( 'fieldset' ) . - $this->msg( 'mergehistory-merge', $this->mTargetObj->getPrefixedText(), - $this->mDestObj->getPrefixedText() )->parse() . - Xml::openElement( 'table', array( 'id' => 'mw-mergehistory-table' ) ) . + $this->msg( 'mergehistory-merge', $this->mTargetObj->getPrefixedText(), + $this->mDestObj->getPrefixedText() )->parse() . + Xml::openElement( 'table', array( 'id' => 'mw-mergehistory-table' ) ) . ' ' . - Xml::label( $this->msg( 'mergehistory-reason' )->text(), 'wpComment' ) . - ' - ' . - Xml::input( 'wpComment', 50, $this->mComment, array( 'id' => 'wpComment' ) ) . - ' + Xml::label( $this->msg( 'mergehistory-reason' )->text(), 'wpComment' ) . + ' + ' . + Xml::input( 'wpComment', 50, $this->mComment, array( 'id' => 'wpComment' ) ) . + '   ' . - Xml::submitButton( $this->msg( 'mergehistory-submit' )->text(), array( 'name' => 'merge', 'id' => 'mw-merge-submit' ) ) . - ' + Xml::submitButton( $this->msg( 'mergehistory-submit' )->text(), array( 'name' => 'merge', 'id' => 'mw-merge-submit' ) ) . + ' ' . - Xml::closeElement( 'table' ) . - Xml::closeElement( 'fieldset' ); + Xml::closeElement( 'table' ) . + Xml::closeElement( 'fieldset' ); $out->addHTML( $table ); } $out->addHTML( '

    ' . - $this->msg( 'mergehistory-list' )->escaped() . "

    \n" + $this->msg( 'mergehistory-list' )->escaped() . "\n" ); - if( $haveRevisions ) { + if ( $haveRevisions ) { $out->addHTML( $revisions->getNavigationBar() ); $out->addHTML( '
      ' ); $out->addHTML( $revisions->getBody() ); @@ -261,14 +262,14 @@ class SpecialMergeHistory extends SpecialPage { array(), array( 'oldid' => $rev->getId() ) ); - if( $rev->isDeleted( Revision::DELETED_TEXT ) ) { + if ( $rev->isDeleted( Revision::DELETED_TEXT ) ) { $pageLink = '' . $pageLink . ''; } # Last link - if( !$rev->userCan( Revision::DELETED_TEXT, $user ) ) { + if ( !$rev->userCan( Revision::DELETED_TEXT, $user ) ) { $last = $this->message['last']; - } elseif( isset( $this->prevId[$row->rev_id] ) ) { + } elseif ( isset( $this->prevId[$row->rev_id] ) ) { $last = Linker::linkKnown( $rev->getTitle(), $this->message['last'], @@ -283,7 +284,7 @@ class SpecialMergeHistory extends SpecialPage { $userLink = Linker::revUserTools( $rev ); $size = $row->rev_len; - if( !is_null( $size ) ) { + if ( !is_null( $size ) ) { $stxt = Linker::formatRevisionSize( $size ); } $comment = Linker::revComment( $rev ); @@ -298,10 +299,10 @@ 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 @@ -317,8 +318,9 @@ class SpecialMergeHistory extends SpecialPage { __METHOD__ ); # Destination page must exist with revisions - if( !$maxtimestamp ) { + if ( !$maxtimestamp ) { $this->getOutput()->addWikiMsg( 'mergehistory-fail' ); + return false; } # Get the latest timestamp of the source @@ -329,12 +331,13 @@ class SpecialMergeHistory extends SpecialPage { __METHOD__ ); # $this->mTimestamp must be older than $maxtimestamp - if( $this->mTimestamp >= $maxtimestamp ) { + if ( $this->mTimestamp >= $maxtimestamp ) { $this->getOutput()->addWikiMsg( 'mergehistory-fail' ); + return false; } # Update the revisions - if( $this->mTimestamp ) { + if ( $this->mTimestamp ) { $timewhere = "rev_timestamp <= {$this->mTimestamp}"; $timestampLimit = wfTimestamp( TS_MW, $this->mTimestamp ); } else { @@ -354,12 +357,12 @@ class SpecialMergeHistory extends SpecialPage { $haveRevisions = $dbw->selectField( 'revision', 'rev_timestamp', - array( 'rev_page' => $this->mTargetID ), + array( 'rev_page' => $this->mTargetID ), __METHOD__, array( 'FOR UPDATE' ) ); - if( !$haveRevisions ) { - if( $this->mComment ) { + if ( !$haveRevisions ) { + if ( $this->mComment ) { $comment = $this->msg( 'mergehistory-comment', $targetTitle->getPrefixedText(), @@ -380,8 +383,8 @@ class SpecialMergeHistory extends SpecialPage { if ( $redirectContent ) { $redirectPage = WikiPage::factory( $targetTitle ); $redirectRevision = new Revision( array( - 'title' => $targetTitle, - 'page' => $this->mTargetID, + 'title' => $targetTitle, + 'page' => $this->mTargetID, 'comment' => $comment, 'content' => $redirectContent ) ); $redirectRevision->insertOn( $dbw ); @@ -392,9 +395,9 @@ class SpecialMergeHistory extends SpecialPage { $dbw->delete( 'pagelinks', array( 'pl_from' => $this->mDestID ), __METHOD__ ); $dbw->insert( 'pagelinks', array( - 'pl_from' => $this->mDestID, + 'pl_from' => $this->mDestID, 'pl_namespace' => $destTitle->getNamespace(), - 'pl_title' => $destTitle->getDBkey() ), + 'pl_title' => $destTitle->getDBkey() ), __METHOD__ ); } else { @@ -405,15 +408,16 @@ class SpecialMergeHistory extends SpecialPage { } $destTitle->invalidateCache(); // update histories # Check if this did anything - if( !$count ) { + if ( !$count ) { $this->getOutput()->addWikiMsg( 'mergehistory-fail' ); + return false; } # Update our logs $log = new LogPage( 'merge' ); $log->addEntry( 'merge', $targetTitle, $this->mComment, - array( $destTitle->getPrefixedText(), $timestampLimit ) + array( $destTitle->getPrefixedText(), $timestampLimit ), $this->getUser() ); $this->getOutput()->addWikiMsg( 'mergehistory-success', @@ -462,9 +466,9 @@ class MergeHistoryPager extends ReverseChronologicalPager { $batch->addObj( Title::makeTitleSafe( NS_USER_TALK, $row->user_name ) ); $rev_id = isset( $rev_id ) ? $rev_id : $row->rev_id; - if( $rev_id > $row->rev_id ) { + if ( $rev_id > $row->rev_id ) { $this->mForm->prevId[$rev_id] = $row->rev_id; - } elseif( $rev_id < $row->rev_id ) { + } elseif ( $rev_id < $row->rev_id ) { $this->mForm->prevId[$row->rev_id] = $rev_id; } @@ -475,6 +479,7 @@ class MergeHistoryPager extends ReverseChronologicalPager { $this->mResult->seek( 0 ); wfProfileOut( __METHOD__ ); + return ''; } @@ -486,10 +491,11 @@ class MergeHistoryPager extends ReverseChronologicalPager { $conds = $this->mConds; $conds['rev_page'] = $this->articleID; $conds[] = "rev_timestamp < {$this->maxTimestamp}"; + return array( 'tables' => array( 'revision', 'page', 'user' ), 'fields' => array_merge( Revision::selectFields(), Revision::selectUserFields() ), - 'conds' => $conds, + 'conds' => $conds, 'join_conds' => array( 'page' => Revision::pageJoinCond(), 'user' => Revision::userJoinCond() ) diff --git a/includes/specials/SpecialMostcategories.php b/includes/specials/SpecialMostcategories.php index 11f26bd7..9b67f343 100644 --- a/includes/specials/SpecialMostcategories.php +++ b/includes/specials/SpecialMostcategories.php @@ -30,7 +30,6 @@ * @ingroup SpecialPage */ class MostcategoriesPage extends QueryPage { - function __construct( $name = 'Mostcategories' ) { parent::__construct( $name ); } @@ -44,22 +43,30 @@ class MostcategoriesPage extends QueryPage { } function getQueryInfo() { - return array ( - 'tables' => array ( 'categorylinks', 'page' ), - 'fields' => array ( 'namespace' => 'page_namespace', - 'title' => 'page_title', - 'value' => 'COUNT(*)' ), - 'conds' => array ( 'page_namespace' => MWNamespace::getContentNamespaces() ), - 'options' => array ( 'HAVING' => 'COUNT(*) > 1', - 'GROUP BY' => array( 'page_namespace', 'page_title' ) ), - 'join_conds' => array ( 'page' => array ( 'LEFT JOIN', - 'page_id = cl_from' ) ) + return array( + 'tables' => array( 'categorylinks', 'page' ), + 'fields' => array( + 'namespace' => 'page_namespace', + 'title' => 'page_title', + 'value' => 'COUNT(*)' + ), + 'conds' => array( 'page_namespace' => MWNamespace::getContentNamespaces() ), + 'options' => array( + 'HAVING' => 'COUNT(*) > 1', + 'GROUP BY' => array( 'page_namespace', 'page_title' ) + ), + 'join_conds' => array( + 'page' => array( + 'LEFT JOIN', + 'page_id = cl_from' + ) + ) ); } /** - * @param $db DatabaseBase - * @param $res + * @param DatabaseBase $db + * @param ResultWrapper $res */ function preprocessResults( $db, $res ) { # There's no point doing a batch check if we aren't caching results; @@ -78,15 +85,22 @@ class MostcategoriesPage extends QueryPage { } /** - * @param $skin Skin - * @param $result + * @param Skin $skin + * @param object $result Result row * @return string */ function formatResult( $skin, $result ) { $title = Title::makeTitleSafe( $result->namespace, $result->title ); if ( !$title ) { - return Html::element( 'span', array( 'class' => 'mw-invalidtitle' ), - Linker::getInvalidTitleDescription( $this->getContext(), $result->namespace, $result->title ) ); + return Html::element( + 'span', + array( 'class' => 'mw-invalidtitle' ), + Linker::getInvalidTitleDescription( + $this->getContext(), + $result->namespace, + $result->title + ) + ); } if ( $this->isCached() ) { diff --git a/includes/specials/SpecialMostimages.php b/includes/specials/SpecialMostimages.php index 78b2d911..98d8da3a 100644 --- a/includes/specials/SpecialMostimages.php +++ b/includes/specials/SpecialMostimages.php @@ -30,7 +30,6 @@ * @ingroup SpecialPage */ class MostimagesPage extends ImageQueryPage { - function __construct( $name = 'Mostimages' ) { parent::__construct( $name ); } @@ -44,13 +43,17 @@ class MostimagesPage extends ImageQueryPage { } function getQueryInfo() { - return array ( - 'tables' => array ( 'imagelinks' ), - 'fields' => array ( 'namespace' => NS_FILE, - 'title' => 'il_to', - 'value' => 'COUNT(*)' ), - 'options' => array ( 'GROUP BY' => 'il_to', - 'HAVING' => 'COUNT(*) > 1' ) + return array( + 'tables' => array( 'imagelinks' ), + 'fields' => array( + 'namespace' => NS_FILE, + 'title' => 'il_to', + 'value' => 'COUNT(*)' + ), + 'options' => array( + 'GROUP BY' => 'il_to', + 'HAVING' => 'COUNT(*) > 1' + ) ); } diff --git a/includes/specials/SpecialMostinterwikis.php b/includes/specials/SpecialMostinterwikis.php index 574a9afb..98dd68e9 100644 --- a/includes/specials/SpecialMostinterwikis.php +++ b/includes/specials/SpecialMostinterwikis.php @@ -30,7 +30,6 @@ * @ingroup SpecialPage */ class MostinterwikisPage extends QueryPage { - function __construct( $name = 'Mostinterwikis' ) { parent::__construct( $name ); } @@ -44,24 +43,24 @@ class MostinterwikisPage extends QueryPage { } function getQueryInfo() { - return array ( - 'tables' => array ( + return array( + 'tables' => array( 'langlinks', 'page' - ), 'fields' => array ( + ), 'fields' => array( 'namespace' => 'page_namespace', 'title' => 'page_title', 'value' => 'COUNT(*)' - ), 'conds' => array ( + ), 'conds' => array( 'page_namespace' => MWNamespace::getContentNamespaces() - ), 'options' => array ( + ), 'options' => array( 'HAVING' => 'COUNT(*) > 1', - 'GROUP BY' => array ( + 'GROUP BY' => array( 'page_namespace', 'page_title' ) - ), 'join_conds' => array ( - 'page' => array ( + ), 'join_conds' => array( + 'page' => array( 'LEFT JOIN', 'page_id = ll_from' ) @@ -72,8 +71,8 @@ class MostinterwikisPage extends QueryPage { /** * Pre-fill the link cache * - * @param $db DatabaseBase - * @param $res + * @param DatabaseBase $db + * @param ResultWrapper $res */ function preprocessResults( $db, $res ) { # There's no point doing a batch check if we aren't caching results; @@ -100,8 +99,15 @@ class MostinterwikisPage extends QueryPage { function formatResult( $skin, $result ) { $title = Title::makeTitleSafe( $result->namespace, $result->title ); if ( !$title ) { - return Html::element( 'span', array( 'class' => 'mw-invalidtitle' ), - Linker::getInvalidTitleDescription( $this->getContext(), $result->namespace, $result->title ) ); + return Html::element( + 'span', + array( 'class' => 'mw-invalidtitle' ), + Linker::getInvalidTitleDescription( + $this->getContext(), + $result->namespace, + $result->title + ) + ); } if ( $this->isCached() ) { diff --git a/includes/specials/SpecialMostlinked.php b/includes/specials/SpecialMostlinked.php index 4b6e5670..37593bf9 100644 --- a/includes/specials/SpecialMostlinked.php +++ b/includes/specials/SpecialMostlinked.php @@ -31,7 +31,6 @@ * @ingroup SpecialPage */ class MostlinkedPage extends QueryPage { - function __construct( $name = 'Mostlinked' ) { parent::__construct( $name ); } @@ -45,33 +44,47 @@ class MostlinkedPage extends QueryPage { } function getQueryInfo() { - return array ( - 'tables' => array ( 'pagelinks', 'page' ), - 'fields' => array ( 'namespace' => 'pl_namespace', - 'title' => 'pl_title', - 'value' => 'COUNT(*)', - 'page_namespace' ), - 'options' => array ( 'HAVING' => 'COUNT(*) > 1', - 'GROUP BY' => array( 'pl_namespace', 'pl_title', - 'page_namespace' ) ), - 'join_conds' => array ( 'page' => array ( 'LEFT JOIN', - array ( 'page_namespace = pl_namespace', - 'page_title = pl_title' ) ) ) + return array( + 'tables' => array( 'pagelinks', 'page' ), + 'fields' => array( + 'namespace' => 'pl_namespace', + 'title' => 'pl_title', + 'value' => 'COUNT(*)', + 'page_namespace' + ), + 'options' => array( + 'HAVING' => 'COUNT(*) > 1', + 'GROUP BY' => array( + '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 + * @param DatabaseBase $db + * @param ResultWrapper $res */ function preprocessResults( $db, $res ) { if ( $res->numRows() > 0 ) { $linkBatch = new LinkBatch(); + foreach ( $res as $row ) { $linkBatch->add( $row->namespace, $row->title ); } + $res->seek( 0 ); $linkBatch->execute(); } @@ -86,25 +99,37 @@ class MostlinkedPage extends QueryPage { */ function makeWlhLink( $title, $caption ) { $wlh = SpecialPage::getTitleFor( 'Whatlinkshere', $title->getPrefixedDBkey() ); + return Linker::linkKnown( $wlh, $caption ); } /** - * Make links to the page corresponding to the item, and the "what links here" page for it + * Make links to the page corresponding to the item, + * and the "what links here" page for it * - * @param $skin Skin to be used - * @param $result Result row + * @param Skin $skin Skin to be used + * @param object $result Result row * @return string */ function formatResult( $skin, $result ) { $title = Title::makeTitleSafe( $result->namespace, $result->title ); if ( !$title ) { - return Html::element( 'span', array( 'class' => 'mw-invalidtitle' ), - Linker::getInvalidTitleDescription( $this->getContext(), $result->namespace, $result->title ) ); + return Html::element( + 'span', + array( 'class' => 'mw-invalidtitle' ), + Linker::getInvalidTitleDescription( + $this->getContext(), + $result->namespace, + $result->title ) + ); } + $link = Linker::link( $title ); - $wlh = $this->makeWlhLink( $title, - $this->msg( 'nlinks' )->numParams( $result->value )->escaped() ); + $wlh = $this->makeWlhLink( + $title, + $this->msg( 'nlinks' )->numParams( $result->value )->escaped() + ); + return $this->getLanguage()->specialList( $link, $wlh ); } diff --git a/includes/specials/SpecialMostlinkedcategories.php b/includes/specials/SpecialMostlinkedcategories.php index a1bce45d..0d4641b1 100644 --- a/includes/specials/SpecialMostlinkedcategories.php +++ b/includes/specials/SpecialMostlinkedcategories.php @@ -30,7 +30,6 @@ * @ingroup SpecialPage */ class MostlinkedCategoriesPage extends QueryPage { - function __construct( $name = 'Mostlinkedcategories' ) { parent::__construct( $name ); } @@ -40,11 +39,11 @@ class MostlinkedCategoriesPage extends QueryPage { } function getQueryInfo() { - return array ( - 'tables' => array ( 'category' ), - 'fields' => array ( 'title' => 'cat_title', - 'namespace' => NS_CATEGORY, - 'value' => 'cat_pages' ), + return array( + 'tables' => array( 'category' ), + 'fields' => array( 'title' => 'cat_title', + 'namespace' => NS_CATEGORY, + 'value' => 'cat_pages' ), ); } @@ -55,8 +54,8 @@ class MostlinkedCategoriesPage extends QueryPage { /** * Fetch user page links and cache their existence * - * @param $db DatabaseBase - * @param $res DatabaseResult + * @param DatabaseBase $db + * @param ResultWrapper $res */ function preprocessResults( $db, $res ) { if ( !$res->numRows() ) { @@ -74,8 +73,8 @@ class MostlinkedCategoriesPage extends QueryPage { } /** - * @param $skin Skin - * @param $result + * @param Skin $skin + * @param object $result Result row * @return string */ function formatResult( $skin, $result ) { @@ -83,15 +82,20 @@ class MostlinkedCategoriesPage extends QueryPage { $nt = Title::makeTitleSafe( NS_CATEGORY, $result->title ); if ( !$nt ) { - return Html::element( 'span', array( 'class' => 'mw-invalidtitle' ), - Linker::getInvalidTitleDescription( $this->getContext(), NS_CATEGORY, $result->title ) ); + return Html::element( + 'span', + array( 'class' => 'mw-invalidtitle' ), + Linker::getInvalidTitleDescription( + $this->getContext(), + NS_CATEGORY, + $result->title ) + ); } $text = $wgContLang->convert( $nt->getText() ); - $plink = Linker::link( $nt, htmlspecialchars( $text ) ); - $nlinks = $this->msg( 'nmembers' )->numParams( $result->value )->escaped(); + return $this->getLanguage()->specialList( $plink, $nlinks ); } diff --git a/includes/specials/SpecialMostlinkedtemplates.php b/includes/specials/SpecialMostlinkedtemplates.php index 506e6b22..c90acb1f 100644 --- a/includes/specials/SpecialMostlinkedtemplates.php +++ b/includes/specials/SpecialMostlinkedtemplates.php @@ -29,7 +29,6 @@ * @ingroup SpecialPage */ class MostlinkedTemplatesPage extends QueryPage { - function __construct( $name = 'Mostlinkedtemplates' ) { parent::__construct( $name ); } @@ -62,12 +61,14 @@ class MostlinkedTemplatesPage extends QueryPage { } public function getQueryInfo() { - return array ( - 'tables' => array ( 'templatelinks' ), - 'fields' => array ( 'namespace' => 'tl_namespace', - 'title' => 'tl_title', - 'value' => 'COUNT(*)' ), - 'conds' => array ( 'tl_namespace' => NS_TEMPLATE ), + return array( + 'tables' => array( 'templatelinks' ), + 'fields' => array( + 'namespace' => 'tl_namespace', + 'title' => 'tl_title', + 'value' => 'COUNT(*)' + ), + 'conds' => array( 'tl_namespace' => NS_TEMPLATE ), 'options' => array( 'GROUP BY' => array( 'tl_namespace', 'tl_title' ) ) ); } @@ -76,7 +77,7 @@ class MostlinkedTemplatesPage extends QueryPage { * Pre-cache page existence to speed up link generation * * @param $db DatabaseBase connection - * @param $res ResultWrapper + * @param ResultWrapper $res */ public function preprocessResults( $db, $res ) { if ( !$res->numRows() ) { @@ -95,15 +96,22 @@ class MostlinkedTemplatesPage extends QueryPage { /** * Format a result row * - * @param $skin Skin to use for UI elements - * @param $result Result row - * @return String + * @param Skin $skin + * @param object $result Result row + * @return string */ public function formatResult( $skin, $result ) { $title = Title::makeTitleSafe( $result->namespace, $result->title ); if ( !$title ) { - return Html::element( 'span', array( 'class' => 'mw-invalidtitle' ), - Linker::getInvalidTitleDescription( $this->getContext(), $result->namespace, $result->title ) ); + return Html::element( + 'span', + array( 'class' => 'mw-invalidtitle' ), + Linker::getInvalidTitleDescription( + $this->getContext(), + $result->namespace, + $result->title + ) + ); } return $this->getLanguage()->specialList( @@ -115,13 +123,14 @@ class MostlinkedTemplatesPage extends QueryPage { /** * Make a "what links here" link for a given title * - * @param $title Title to make the link for - * @param $result Result row + * @param Title $title Title to make the link for + * @param object $result Result row * @return String */ private function makeWlhLink( $title, $result ) { $wlh = SpecialPage::getTitleFor( 'Whatlinkshere', $title->getPrefixedText() ); $label = $this->msg( 'ntransclusions' )->numParams( $result->value )->escaped(); + return Linker::link( $wlh, $label ); } diff --git a/includes/specials/SpecialMovepage.php b/includes/specials/SpecialMovepage.php index 4adb0371..253e6cc3 100644 --- a/includes/specials/SpecialMovepage.php +++ b/includes/specials/SpecialMovepage.php @@ -27,13 +27,15 @@ * @ingroup SpecialPage */ class MovePageForm extends UnlistedSpecialPage { - /** + * Objects * @var Title */ - var $oldTitle, $newTitle; # Objects - var $reason; # Text input - var $moveTalk, $deleteAndMove, $moveSubpages, $fixRedirects, $leaveRedirect, $moveOverShared; # Checks + var $oldTitle, $newTitle; + // Text input + var $reason; + // Checks + var $moveTalk, $deleteAndMove, $moveSubpages, $fixRedirects, $leaveRedirect, $moveOverShared; private $watch = false; @@ -55,10 +57,10 @@ class MovePageForm extends UnlistedSpecialPage { $oldTitleText = $request->getVal( 'wpOldTitle', $target ); $this->oldTitle = Title::newFromText( $oldTitleText ); - if( is_null( $this->oldTitle ) ) { + if ( is_null( $this->oldTitle ) ) { throw new ErrorPageError( 'notargettitle', 'notargettext' ); } - if( !$this->oldTitle->exists() ) { + if ( !$this->oldTitle->exists() ) { throw new ErrorPageError( 'nopagetitle', 'nopagetext' ); } @@ -93,7 +95,8 @@ class MovePageForm extends UnlistedSpecialPage { $this->watch = $request->getCheck( 'wpWatch' ) && $user->isLoggedIn(); if ( 'submit' == $request->getVal( 'action' ) && $request->wasPosted() - && $user->matchEditToken( $request->getVal( 'wpEditToken' ) ) ) { + && $user->matchEditToken( $request->getVal( 'wpEditToken' ) ) + ) { $this->doSubmit(); } else { $this->showForm( array() ); @@ -129,7 +132,7 @@ class MovePageForm extends UnlistedSpecialPage { # link, check for validity. We can then show some diagnostic # information and save a click. $newerr = $this->oldTitle->isValidMoveOperation( $newTitle ); - if( is_array( $newerr ) ) { + if ( is_array( $newerr ) ) { $err = $newerr; } } @@ -146,16 +149,26 @@ class MovePageForm extends UnlistedSpecialPage { " . - Xml::checkLabel( $this->msg( 'delete_and_move_confirm' )->text(), 'wpConfirm', 'wpConfirm' ) . - " + Xml::checkLabel( + $this->msg( 'delete_and_move_confirm' )->text(), + 'wpConfirm', + 'wpConfirm' + ) . + " "; $err = array(); } else { if ( $this->oldTitle->getNamespace() == NS_USER && !$this->oldTitle->isSubpage() ) { - $out->wrapWikiMsg( "
      \n$1\n
      ", 'moveuserpage-warning' ); + $out->wrapWikiMsg( + "
      \n$1\n
      ", + 'moveuserpage-warning' + ); } - $out->addWikiMsg( $wgFixDoubleRedirects ? 'movepagetext' : - 'movepagetext-noredirectfixer' ); + + $out->addWikiMsg( $wgFixDoubleRedirects ? + 'movepagetext' : + 'movepagetext-noredirectfixer' + ); $movepagebtn = $this->msg( 'movepagebtn' )->text(); $submitVar = 'wpMove'; $confirm = false; @@ -205,6 +218,7 @@ class MovePageForm extends UnlistedSpecialPage { if ( count( $err ) == 1 ) { $errMsg = $err[0]; $errMsgName = array_shift( $errMsg ); + if ( $errMsgName == 'hookaborted' ) { $out->addHTML( "

      {$errMsg[0]}

      \n" ); } else { @@ -212,8 +226,9 @@ class MovePageForm extends UnlistedSpecialPage { } } else { $errStr = array(); - foreach( $err as $errMsg ) { - if( $errMsg[0] == 'hookaborted' ) { + + foreach ( $err as $errMsg ) { + if ( $errMsg[0] == 'hookaborted' ) { $errStr[] = $errMsg[1]; } else { $errMsgName = array_shift( $errMsg ); @@ -238,7 +253,13 @@ class MovePageForm extends UnlistedSpecialPage { } $out->addHTML( "
      \n" ); $out->addWikiMsg( $noticeMsg ); - LogEventsList::showLogExtract( $out, 'protect', $this->oldTitle, '', array( 'lim' => 1 ) ); + LogEventsList::showLogExtract( + $out, + 'protect', + $this->oldTitle, + '', + array( 'lim' => 1 ) + ); $out->addHTML( "
      \n" ); } @@ -256,13 +277,20 @@ class MovePageForm extends UnlistedSpecialPage { $handler = ContentHandler::getForTitle( $this->oldTitle ); $out->addHTML( - Xml::openElement( 'form', array( 'method' => 'post', 'action' => $this->getTitle()->getLocalURL( 'action=submit' ), 'id' => 'movepage' ) ) . - Xml::openElement( 'fieldset' ) . - Xml::element( 'legend', null, $this->msg( 'move-page-legend' )->text() ) . - Xml::openElement( 'table', array( 'id' => 'mw-movepage-table' ) ) . - " + Xml::openElement( + 'form', + array( + 'method' => 'post', + 'action' => $this->getTitle()->getLocalURL( 'action=submit' ), + 'id' => 'movepage' + ) + ) . + Xml::openElement( 'fieldset' ) . + Xml::element( 'legend', null, $this->msg( 'move-page-legend' )->text() ) . + Xml::openElement( 'table', array( 'id' => 'mw-movepage-table' ) ) . + " " . - $this->msg( 'movearticle' )->escaped() . + $this->msg( 'movearticle' )->escaped() . " {$oldTitleLink} @@ -270,41 +298,54 @@ class MovePageForm extends UnlistedSpecialPage { " . - Xml::label( $this->msg( 'newtitle' )->text(), 'wpNewTitleMain' ) . + Xml::label( $this->msg( 'newtitle' )->text(), 'wpNewTitleMain' ) . " " . - Html::namespaceSelector( - array( - 'selected' => $newTitle->getNamespace(), - 'exclude' => $immovableNamespaces - ), - array( 'name' => 'wpNewTitleNs', 'id' => 'wpNewTitleNs' ) - ) . - Xml::input( 'wpNewTitleMain', 60, $wgContLang->recodeForEdit( $newTitle->getText() ), array( + Html::namespaceSelector( + array( + 'selected' => $newTitle->getNamespace(), + 'exclude' => $immovableNamespaces + ), + array( 'name' => 'wpNewTitleNs', 'id' => 'wpNewTitleNs' ) + ) . + Xml::input( + 'wpNewTitleMain', + 60, + $wgContLang->recodeForEdit( $newTitle->getText() ), + array( 'type' => 'text', 'id' => 'wpNewTitleMain', - 'maxlength' => 255, - ) ) . - Html::hidden( 'wpOldTitle', $this->oldTitle->getPrefixedText() ) . + 'maxlength' => 255 + ) + ) . + Html::hidden( 'wpOldTitle', $this->oldTitle->getPrefixedText() ) . " " . - Xml::label( $this->msg( 'movereason' )->text(), 'wpReason' ) . + Xml::label( $this->msg( 'movereason' )->text(), 'wpReason' ) . " " . - Html::element( 'textarea', array( 'name' => 'wpReason', 'id' => 'wpReason', 'cols' => 60, 'rows' => 2, - 'maxlength' => 200 ), $this->reason ) . + Xml::input( 'wpReason', 60, $this->reason, array( + 'type' => 'text', + 'id' => 'wpReason', + 'maxlength' => 200, + ) ) . " " ); - if( $considerTalk ) { + if ( $considerTalk ) { $out->addHTML( " " . - Xml::checkLabel( $this->msg( 'movetalk' )->text(), 'wpMovetalk', 'wpMovetalk', $this->moveTalk ) . + Xml::checkLabel( + $this->msg( 'movetalk' )->text(), + 'wpMovetalk', + 'wpMovetalk', + $this->moveTalk + ) . " " ); @@ -315,8 +356,12 @@ class MovePageForm extends UnlistedSpecialPage { " . - Xml::checkLabel( $this->msg( 'move-leave-redirect' )->text(), 'wpLeaveRedirect', - 'wpLeaveRedirect', $this->leaveRedirect ) . + Xml::checkLabel( + $this->msg( 'move-leave-redirect' )->text(), + 'wpLeaveRedirect', + 'wpLeaveRedirect', + $this->leaveRedirect + ) . " " ); @@ -327,32 +372,36 @@ class MovePageForm extends UnlistedSpecialPage { " . - Xml::checkLabel( $this->msg( 'fix-double-redirects' )->text(), 'wpFixRedirects', - 'wpFixRedirects', $this->fixRedirects ) . + Xml::checkLabel( + $this->msg( 'fix-double-redirects' )->text(), + 'wpFixRedirects', + 'wpFixRedirects', + $this->fixRedirects + ) . " " ); } - if( $canMoveSubpage ) { + if ( $canMoveSubpage ) { $out->addHTML( " " . - Xml::check( - 'wpMovesubpages', - # Don't check the box if we only have talk subpages to - # move and we aren't moving the talk page. - $this->moveSubpages && ( $this->oldTitle->hasSubpages() || $this->moveTalk ), - array( 'id' => 'wpMovesubpages' ) - ) . ' ' . - Xml::tags( 'label', array( 'for' => 'wpMovesubpages' ), - $this->msg( - ( $this->oldTitle->hasSubpages() - ? 'move-subpages' - : 'move-talk-subpages' ) + Xml::check( + 'wpMovesubpages', + # Don't check the box if we only have talk subpages to + # move and we aren't moving the talk page. + $this->moveSubpages && ( $this->oldTitle->hasSubpages() || $this->moveTalk ), + array( 'id' => 'wpMovesubpages' ) + ) . ' ' . + Xml::tags( 'label', array( 'for' => 'wpMovesubpages' ), + $this->msg( + ( $this->oldTitle->hasSubpages() + ? 'move-subpages' + : 'move-talk-subpages' ) )->numParams( $wgMaximumMovedPages )->params( $wgMaximumMovedPages )->parse() - ) . + ) . " " ); @@ -361,14 +410,19 @@ class MovePageForm extends UnlistedSpecialPage { $watchChecked = $user->isLoggedIn() && ( $this->watch || $user->getBoolOption( 'watchmoves' ) || $user->isWatched( $this->oldTitle ) ); # Don't allow watching if user is not logged in - if( $user->isLoggedIn() ) { + if ( $user->isLoggedIn() ) { $out->addHTML( " " . - Xml::checkLabel( $this->msg( 'move-watch' )->text(), 'wpWatch', 'watch', $watchChecked ) . + Xml::checkLabel( + $this->msg( 'move-watch' )->text(), + 'wpWatch', + 'watch', + $watchChecked + ) . " - "); + " ); } $out->addHTML( " @@ -376,19 +430,18 @@ class MovePageForm extends UnlistedSpecialPage {   " . - Xml::submitButton( $movepagebtn, array( 'name' => $submitVar ) ) . + Xml::submitButton( $movepagebtn, array( 'name' => $submitVar ) ) . " " . - Xml::closeElement( 'table' ) . - Html::hidden( 'wpEditToken', $user->getEditToken() ) . - Xml::closeElement( 'fieldset' ) . - Xml::closeElement( 'form' ) . - "\n" + Xml::closeElement( 'table' ) . + Html::hidden( 'wpEditToken', $user->getEditToken() ) . + Xml::closeElement( 'fieldset' ) . + Xml::closeElement( 'form' ) . + "\n" ); $this->showLogFragment( $this->oldTitle ); $this->showSubpages( $this->oldTitle ); - } function doSubmit() { @@ -406,6 +459,7 @@ class MovePageForm extends UnlistedSpecialPage { # don't allow moving to pages with # in if ( !$nt || $nt->getFragment() != '' ) { $this->showForm( array( array( 'badtitletext' ) ) ); + return; } @@ -413,11 +467,11 @@ class MovePageForm extends UnlistedSpecialPage { if ( $nt->getNamespace() == NS_FILE && !( $this->moveOverShared && $user->isAllowed( 'reupload-shared' ) ) && !RepoGroup::singleton()->getLocalRepo()->findFile( $nt ) - && wfFindFile( $nt ) ) - { + && wfFindFile( $nt ) + ) { $this->showForm( array( array( 'file-exists-sharedrepo' ) ) ); - return; + return; } # Delete to make way if requested @@ -426,6 +480,7 @@ class MovePageForm extends UnlistedSpecialPage { if ( count( $permErrors ) ) { # Only show the first error $this->showForm( $permErrors ); + return; } @@ -444,6 +499,7 @@ class MovePageForm extends UnlistedSpecialPage { $deleteStatus = $page->doDeleteArticleReal( $reason, false, 0, true, $error, $user ); if ( !$deleteStatus->isGood() ) { $this->showForm( $deleteStatus->getErrorsArray() ); + return; } } @@ -462,6 +518,7 @@ class MovePageForm extends UnlistedSpecialPage { $error = $ot->moveTo( $nt, true, $this->reason, $createRedirect ); if ( $error !== true ) { $this->showForm( $error ); + return; } @@ -502,7 +559,7 @@ class MovePageForm extends UnlistedSpecialPage { # Now we move extra pages we've been asked to move: subpages and talk # pages. First, if the old page or the new page is a talk page, we # can't move any talk pages: cancel that. - if( $ot->isTalkPage() || $nt->isTalkPage() ) { + if ( $ot->isTalkPage() || $nt->isTalkPage() ) { $this->moveTalk = false; } @@ -524,24 +581,26 @@ class MovePageForm extends UnlistedSpecialPage { // @todo FIXME: Use Title::moveSubpages() here $dbr = wfGetDB( DB_MASTER ); - if( $this->moveSubpages && ( + if ( $this->moveSubpages && ( MWNamespace::hasSubpages( $nt->getNamespace() ) || ( $this->moveTalk && - MWNamespace::hasSubpages( $nt->getTalkPage()->getNamespace() ) + MWNamespace::hasSubpages( $nt->getTalkPage()->getNamespace() ) ) ) ) { $conds = array( 'page_title' . $dbr->buildLike( $ot->getDBkey() . '/', $dbr->anyString() ) - .' OR page_title = ' . $dbr->addQuotes( $ot->getDBkey() ) + . ' OR page_title = ' . $dbr->addQuotes( $ot->getDBkey() ) ); $conds['page_namespace'] = array(); - if( MWNamespace::hasSubpages( $nt->getNamespace() ) ) { + if ( MWNamespace::hasSubpages( $nt->getNamespace() ) ) { $conds['page_namespace'][] = $ot->getNamespace(); } - if( $this->moveTalk && MWNamespace::hasSubpages( $nt->getTalkPage()->getNamespace() ) ) { + if ( $this->moveTalk && + MWNamespace::hasSubpages( $nt->getTalkPage()->getNamespace() ) + ) { $conds['page_namespace'][] = $ot->getTalkPage()->getNamespace(); } - } elseif( $this->moveTalk ) { + } elseif ( $this->moveTalk ) { $conds = array( 'page_namespace' => $ot->getTalkPage()->getNamespace(), 'page_title' => $ot->getDBkey() @@ -552,7 +611,7 @@ class MovePageForm extends UnlistedSpecialPage { } $extraPages = array(); - if( !is_null( $conds ) ) { + if ( !is_null( $conds ) ) { $extraPages = TitleArray::newFromResult( $dbr->select( 'page', array( 'page_id', 'page_namespace', 'page_title' ), @@ -564,29 +623,31 @@ class MovePageForm extends UnlistedSpecialPage { $extraOutput = array(); $count = 1; - foreach( $extraPages as $oldSubpage ) { - if( $ot->equals( $oldSubpage ) ) { + foreach ( $extraPages as $oldSubpage ) { + if ( $ot->equals( $oldSubpage ) || $nt->equals( $oldSubpage ) ) { # Already did this one. continue; } $newPageName = preg_replace( - '#^'.preg_quote( $ot->getDBkey(), '#' ).'#', + '#^' . preg_quote( $ot->getDBkey(), '#' ) . '#', StringUtils::escapeRegexReplacement( $nt->getDBkey() ), # bug 21234 $oldSubpage->getDBkey() ); - if( $oldSubpage->isTalkPage() ) { + + if ( $oldSubpage->isTalkPage() ) { $newNs = $nt->getTalkPage()->getNamespace(); } else { $newNs = $nt->getSubjectPage()->getNamespace(); } + # Bug 14385: we need makeTitleSafe because the new page names may # be longer than 255 characters. $newSubpage = Title::makeTitleSafe( $newNs, $newPageName ); - if( !$newSubpage ) { + if ( !$newSubpage ) { $oldLink = Linker::linkKnown( $oldSubpage ); - $extraOutput[] = $this->msg( 'movepage-page-unmoved' )->rawParams( $oldLink - )->params( Title::makeName( $newNs, $newPageName ) )->escaped(); + $extraOutput[] = $this->msg( 'movepage-page-unmoved' )->rawParams( $oldLink ) + ->params( Title::makeName( $newNs, $newPageName ) )->escaped(); continue; } @@ -596,7 +657,8 @@ class MovePageForm extends UnlistedSpecialPage { $extraOutput[] = $this->msg( 'movepage-page-exists' )->rawParams( $link )->escaped(); } else { $success = $oldSubpage->moveTo( $newSubpage, true, $this->reason, $createRedirect ); - if( $success === true ) { + + if ( $success === true ) { if ( $this->fixRedirects ) { DoubleRedirectJob::fixRedirects( 'move', $oldSubpage, $newSubpage ); } @@ -606,10 +668,12 @@ class MovePageForm extends UnlistedSpecialPage { array(), array( 'redirect' => 'no' ) ); + $newLink = Linker::linkKnown( $newSubpage ); $extraOutput[] = $this->msg( 'movepage-page-moved' )->rawParams( $oldLink, $newLink )->escaped(); ++$count; - if( $count >= $wgMaximumMovedPages ) { + + if ( $count >= $wgMaximumMovedPages ) { $extraOutput[] = $this->msg( 'movepage-max-pages' )->numParams( $wgMaximumMovedPages )->escaped(); break; } @@ -619,28 +683,15 @@ class MovePageForm extends UnlistedSpecialPage { $extraOutput[] = $this->msg( 'movepage-page-unmoved' )->rawParams( $oldLink, $newLink )->escaped(); } } - } - if( $extraOutput !== array() ) { + if ( $extraOutput !== array() ) { $out->addHTML( "
        \n
      • " . implode( "
      • \n
      • ", $extraOutput ) . "
      • \n
      " ); } # Deal with watches (we don't watch subpages) - if( $this->watch && $user->isLoggedIn() ) { - $user->addWatch( $ot ); - $user->addWatch( $nt ); - } else { - $user->removeWatch( $ot ); - $user->removeWatch( $nt ); - } - - # Re-clear the file redirect cache, which may have been polluted by - # parsing in messages above. See CR r56745. - # @todo FIXME: Needs a more robust solution inside FileRepo. - if( $ot->getNamespace() == NS_FILE ) { - RepoGroup::singleton()->getLocalRepo()->invalidateImageRedirect( $ot ); - } + WatchAction::doWatchOrUnwatch( $this->watch, $ot, $user ); + WatchAction::doWatchOrUnwatch( $this->watch, $nt, $user ); } function showLogFragment( $title ) { @@ -651,8 +702,9 @@ class MovePageForm extends UnlistedSpecialPage { } function showSubpages( $title ) { - if( !MWNamespace::hasSubpages( $title->getNamespace() ) ) + if ( !MWNamespace::hasSubpages( $title->getNamespace() ) ) { return; + } $subpages = $title->getSubpages(); $count = $subpages instanceof TitleArray ? $subpages->count() : 0; @@ -663,13 +715,14 @@ class MovePageForm extends UnlistedSpecialPage { # No subpages. if ( $count == 0 ) { $out->addWikiMsg( 'movenosubpage' ); + return; } $out->addWikiMsg( 'movesubpagetext', $this->getLanguage()->formatNum( $count ) ); $out->addHTML( "
        \n" ); - foreach( $subpages as $subpage ) { + foreach ( $subpages as $subpage ) { $link = Linker::link( $subpage ); $out->addHTML( "
      • $link
      • \n" ); } diff --git a/includes/specials/SpecialNewimages.php b/includes/specials/SpecialNewimages.php index 52cbc3aa..37d29734 100644 --- a/includes/specials/SpecialNewimages.php +++ b/includes/specials/SpecialNewimages.php @@ -21,7 +21,6 @@ * @ingroup SpecialPage */ class SpecialNewFiles extends IncludableSpecialPage { - public function __construct() { parent::__construct( 'Newimages' ); } @@ -37,6 +36,7 @@ class SpecialNewFiles extends IncludableSpecialPage { $form->prepareForm(); $form->displayForm( '' ); } + $this->getOutput()->addHTML( $pager->getBody() ); if ( !$this->including() ) { $this->getOutput()->addHTML( $pager->getNavigationBar() ); @@ -52,7 +52,6 @@ class SpecialNewFiles extends IncludableSpecialPage { * @ingroup SpecialPage Pager */ class NewFilesPager extends ReverseChronologicalPager { - /** * @var ImageGallery */ @@ -73,9 +72,10 @@ class NewFilesPager extends ReverseChronologicalPager { $conds = $jconds = array(); $tables = array( 'image' ); - if( !$this->showbots ) { + if ( !$this->showbots ) { $groupsWithBotPermission = User::getGroupsWithPermission( 'bot' ); - if( count( $groupsWithBotPermission ) ) { + + if ( count( $groupsWithBotPermission ) ) { $tables[] = 'user_groups'; $conds[] = 'ug_group IS NULL'; $jconds['user_groups'] = array( @@ -88,11 +88,15 @@ class NewFilesPager extends ReverseChronologicalPager { } } - if( !$wgMiserMode && $this->like !== null ) { + 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() ); + if ( $likeObj instanceof Title ) { + $like = $dbr->buildLike( + $dbr->anyString(), + strtolower( $likeObj->getDBkey() ), + $dbr->anyString() + ); $conds[] = "LOWER(img_name) $like"; } } @@ -113,8 +117,17 @@ class NewFilesPager extends ReverseChronologicalPager { function getStartBody() { if ( !$this->gallery ) { - $this->gallery = new ImageGallery(); + // Note that null for mode is taken to mean use default. + $mode = $this->getRequest()->getVal( 'gallerymode', null ); + try { + $this->gallery = ImageGalleryBase::factory( $mode ); + } catch ( MWException $e ) { + // User specified something invalid, fallback to default. + $this->gallery = ImageGalleryBase::factory(); + } + $this->gallery->setContext( $this->getContext() ); } + return ''; } @@ -128,11 +141,12 @@ class NewFilesPager extends ReverseChronologicalPager { $title = Title::makeTitle( NS_FILE, $name ); $ul = Linker::link( $user->getUserpage(), $user->getName() ); + $time = $this->getLanguage()->userTimeAndDate( $row->img_timestamp, $this->getUser() ); $this->gallery->add( $title, "$ul
        \n" - . htmlspecialchars( $this->getLanguage()->userTimeAndDate( $row->img_timestamp, $this->getUser() ) ) + . htmlspecialchars( $time ) . "
        \n" ); } @@ -150,7 +164,6 @@ class NewFilesPager extends ReverseChronologicalPager { 'type' => 'check', 'label' => $this->msg( 'showhidebots', $this->msg( 'show' )->plain() )->escaped(), 'name' => 'showbots', - # 'default' => $this->getRequest()->getBool( 'showbots', 0 ), ), 'limit' => array( 'type' => 'hidden', @@ -164,12 +177,13 @@ class NewFilesPager extends ReverseChronologicalPager { ), ); - if( $wgMiserMode ) { + if ( $wgMiserMode ) { unset( $fields['like'] ); } - $form = new HTMLForm( $fields, $this->getContext() ); - $form->setTitle( $this->getTitle() ); + $context = new DerivativeContext( $this->getContext() ); + $context->setTitle( $this->getTitle() ); // Remove subpage + $form = new HTMLForm( $fields, $context ); $form->setSubmitTextMsg( 'ilsubmit' ); $form->setMethod( 'get' ); $form->setWrapperLegendMsg( 'newimages-legend' ); diff --git a/includes/specials/SpecialNewpages.php b/includes/specials/SpecialNewpages.php index ebb3021d..43d48558 100644 --- a/includes/specials/SpecialNewpages.php +++ b/includes/specials/SpecialNewpages.php @@ -27,7 +27,6 @@ * @ingroup SpecialPage */ class SpecialNewpages extends IncludableSpecialPage { - // Stored objects /** @@ -63,17 +62,19 @@ class SpecialNewpages extends IncludableSpecialPage { $this->customFilters = array(); wfRunHooks( 'SpecialNewPagesFilters', array( $this, &$this->customFilters ) ); - foreach( $this->customFilters as $key => $params ) { + foreach ( $this->customFilters as $key => $params ) { $opts->add( $key, $params['default'] ); } // Set values $opts->fetchValuesFromRequest( $this->getRequest() ); - if ( $par ) $this->parseParams( $par ); + if ( $par ) { + $this->parseParams( $par ); + } // Validate $opts->validateIntBounds( 'limit', 0, 5000 ); - if( !$wgEnableNewpagesUserFilter ) { + if ( !$wgEnableNewpagesUserFilter ) { $opts->setValue( 'username', '' ); } } @@ -113,7 +114,7 @@ class SpecialNewpages extends IncludableSpecialPage { } if ( preg_match( '/^namespace=(.*)$/', $bit, $m ) ) { $ns = $this->getLanguage()->getNsIndex( $m[1] ); - if( $ns !== false ) { + if ( $ns !== false ) { $this->opts->setValue( 'namespace', $ns ); } } @@ -135,13 +136,14 @@ class SpecialNewpages extends IncludableSpecialPage { $this->showNavigation = !$this->including(); // Maybe changed in setup $this->setup( $par ); - if( !$this->including() ) { + if ( !$this->including() ) { // Settings $this->form(); $feedType = $this->opts->getValue( 'feed' ); - if( $feedType ) { + if ( $feedType ) { $this->feed( $feedType ); + return; } @@ -154,7 +156,7 @@ class SpecialNewpages extends IncludableSpecialPage { $pager->mLimit = $this->opts->getValue( 'limit' ); $pager->mOffset = $this->opts->getValue( 'offset' ); - if( $pager->getNumRows() ) { + if ( $pager->getNumRows() ) { $navigation = ''; if ( $this->showNavigation ) { $navigation = $pager->getNavigationBar(); @@ -196,7 +198,7 @@ class SpecialNewpages extends IncludableSpecialPage { foreach ( $filters as $key => $msg ) { $onoff = 1 - $this->opts->getValue( $key ); $link = Linker::link( $self, $showhide[$onoff], array(), - array( $key => $onoff ) + $changed + array( $key => $onoff ) + $changed ); $links[$key] = $this->msg( $msg )->rawParams( $link )->escaped(); } @@ -236,55 +238,55 @@ class SpecialNewpages extends IncludableSpecialPage { Xml::openElement( 'table', array( 'id' => 'mw-newpages-table' ) ) . ' ' . - Xml::label( $this->msg( 'namespace' )->text(), 'namespace' ) . - ' - ' . - Html::namespaceSelector( - array( - 'selected' => $namespace, - 'all' => 'all', - ), array( - 'name' => 'namespace', - 'id' => 'namespace', - 'class' => 'namespaceselector', - ) - ) . ' ' . - Xml::checkLabel( - $this->msg( 'invert' )->text(), - 'invert', - 'nsinvert', - $nsinvert, - array( 'title' => $this->msg( 'tooltip-invert' )->text() ) - ) . - ' + Xml::label( $this->msg( 'namespace' )->text(), 'namespace' ) . + ' + ' . + Html::namespaceSelector( + array( + 'selected' => $namespace, + 'all' => 'all', + ), array( + 'name' => 'namespace', + 'id' => 'namespace', + 'class' => 'namespaceselector', + ) + ) . ' ' . + Xml::checkLabel( + $this->msg( 'invert' )->text(), + 'invert', + 'nsinvert', + $nsinvert, + array( 'title' => $this->msg( 'tooltip-invert' )->text() ) + ) . + ' ' . ( $tagFilter ? ( ' ' . - $tagFilterLabel . + $tagFilterLabel . ' ' . - $tagFilterSelector . + $tagFilterSelector . ' ' ) : '' ) . ( $wgEnableNewpagesUserFilter ? - ' + ' ' . Xml::label( $this->msg( 'newpages-username' )->text(), 'mw-np-username' ) . - ' + ' ' . Xml::input( 'username', 30, $userText, array( 'id' => 'mw-np-username' ) ) . - ' + ' ' : '' ) . ' ' . - Xml::submitButton( $this->msg( 'allpagessubmit' )->text() ) . - ' - ' . + Xml::submitButton( $this->msg( 'allpagessubmit' )->text() ) . + ' + ' . ' ' . - $this->filterLinks() . - ' + $this->filterLinks() . + ' ' . Xml::closeElement( 'table' ) . Xml::closeElement( 'fieldset' ) . @@ -295,9 +297,10 @@ class SpecialNewpages extends IncludableSpecialPage { } /** - * Format a row, providing the timestamp, links to the page/history, size, user links, and a comment + * Format a row, providing the timestamp, links to the page/history, + * size, user links, and a comment * - * @param $result Result row + * @param object $result Result row * @return String */ public function formatRow( $result ) { @@ -331,11 +334,8 @@ class SpecialNewpages extends IncludableSpecialPage { $query = array( 'redirect' => 'no' ); - if( $this->patrollable( $result ) ) { - $query['rcid'] = $result->rc_id; - } - - // Linker::linkKnown() uses 'known' and 'noclasses' options. This breaks the colouration for stubs. + // Linker::linkKnown() uses 'known' and 'noclasses' options. + // This breaks the colouration for stubs. $plink = Linker::link( $title, null, @@ -352,8 +352,12 @@ class SpecialNewpages extends IncludableSpecialPage { $hist = Html::rawElement( 'span', array( 'class' => 'mw-newpages-history' ), $this->msg( 'parentheses' )->rawParams( $histLink )->escaped() ); - $length = Html::element( 'span', array( 'class' => 'mw-newpages-length' ), - $this->msg( 'brackets' )->params( $this->msg( 'nbytes' )->numParams( $result->length )->text() ) + $length = Html::element( + 'span', + array( 'class' => 'mw-newpages-length' ), + $this->msg( 'brackets' )->params( $this->msg( 'nbytes' ) + ->numParams( $result->length )->text() + ) ); $ulink = Linker::revUserTools( $rev ); @@ -369,8 +373,11 @@ class SpecialNewpages extends IncludableSpecialPage { } # Tags, if any. - if( isset( $result->ts_tags ) ) { - list( $tagDisplay, $newClasses ) = ChangeTags::formatSummaryRow( $result->ts_tags, 'newpages' ); + if ( isset( $result->ts_tags ) ) { + list( $tagDisplay, $newClasses ) = ChangeTags::formatSummaryRow( + $result->ts_tags, + 'newpages' + ); $classes = array_merge( $classes, $newClasses ); } else { $tagDisplay = ''; @@ -381,8 +388,10 @@ class SpecialNewpages extends IncludableSpecialPage { # Display the old title if the namespace/title has been changed $oldTitleText = ''; $oldTitle = Title::makeTitle( $result->rc_namespace, $result->rc_title ); + if ( !$title->equals( $oldTitle ) ) { - $oldTitleText = $this->msg( 'rc-old-title' )->params( $oldTitle->getPrefixedText() )->escaped(); + $oldTitleText = $oldTitle->getPrefixedText(); + $oldTitleText = $this->msg( 'rc-old-title' )->params( $oldTitleText )->escaped(); } return "{$time} {$dm}{$plink} {$hist} {$dm}{$length} {$dm}{$ulink} {$comment} {$tagDisplay} {$oldTitleText}\n"; @@ -391,7 +400,7 @@ class SpecialNewpages extends IncludableSpecialPage { /** * Should a specific result row provide "patrollable" links? * - * @param $result Result row + * @param object $result Result row * @return Boolean */ protected function patrollable( $result ) { @@ -408,18 +417,20 @@ class SpecialNewpages extends IncludableSpecialPage { if ( !$wgFeed ) { $this->getOutput()->addWikiMsg( 'feed-unavailable' ); + return; } - if( !isset( $wgFeedClasses[$type] ) ) { + if ( !isset( $wgFeedClasses[$type] ) ) { $this->getOutput()->addWikiMsg( 'feed-invalid' ); + return; } $feed = new $wgFeedClasses[$type]( $this->feedTitle(), $this->msg( 'tagline' )->text(), - $this->getTitle()->getFullUrl() + $this->getTitle()->getFullURL() ); $pager = new NewPagesPager( $this, $this->opts ); @@ -427,7 +438,7 @@ class SpecialNewpages extends IncludableSpecialPage { $pager->mLimit = min( $limit, $wgFeedLimit ); $feed->outHeader(); - if( $pager->getNumRows() > 0 ) { + if ( $pager->getNumRows() > 0 ) { foreach ( $pager->mResult as $row ) { $feed->outItem( $this->feedItem( $row ) ); } @@ -438,12 +449,13 @@ class SpecialNewpages extends IncludableSpecialPage { protected function feedTitle() { global $wgLanguageCode, $wgSitename; $desc = $this->getDescription(); + return "$wgSitename - $desc [$wgLanguageCode]"; } protected function feedItem( $row ) { $title = Title::makeTitle( intval( $row->rc_namespace ), $row->rc_title ); - if( $title ) { + if ( $title ) { $date = $row->rc_timestamp; $comments = $title->getTalkPage()->getFullURL(); @@ -466,7 +478,7 @@ class SpecialNewpages extends IncludableSpecialPage { protected function feedItemDesc( $row ) { $revision = Revision::newFromId( $row->rev_id ); - if( $revision ) { + if ( $revision ) { //XXX: include content model/type in feed item? return '

        ' . htmlspecialchars( $revision->getUserText() ) . $this->msg( 'colon-separator' )->inContentLanguage()->escaped() . @@ -474,6 +486,7 @@ class SpecialNewpages extends IncludableSpecialPage { "

        \n
        \n
        " . nl2br( htmlspecialchars( $revision->getContent()->serialize() ) ) . "
        "; } + return ''; } @@ -511,7 +524,7 @@ class NewPagesPager extends ReverseChronologicalPager { $username = $this->opts->getValue( 'username' ); $user = Title::makeTitleSafe( NS_USER, $username ); - if( $namespace !== false ) { + if ( $namespace !== false ) { if ( $this->opts->getValue( 'invert' ) ) { $conds[] = 'rc_namespace != ' . $this->mDb->addQuotes( $namespace ); } else { @@ -523,18 +536,22 @@ class NewPagesPager extends ReverseChronologicalPager { } # $wgEnableNewpagesUserFilter - temp WMF hack - if( $wgEnableNewpagesUserFilter && $user ) { + if ( $wgEnableNewpagesUserFilter && $user ) { $conds['rc_user_text'] = $user->getText(); $rcIndexes = 'rc_user_text'; - # If anons cannot make new pages, don't "exclude logged in users"! - } elseif( User::groupHasPermission( '*', 'createpage' ) && $this->opts->getValue( 'hideliu' ) ) { + } elseif ( User::groupHasPermission( '*', 'createpage' ) && + $this->opts->getValue( 'hideliu' ) + ) { + # If anons cannot make new pages, don't "exclude logged in users"! $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' ) && $this->getUser()->useNPPatrol() ) { + if ( $this->opts->getValue( 'hidepatrolled' ) && $this->getUser()->useNPPatrol() ) { $conds['rc_patrolled'] = 0; } - if( $this->opts->getValue( 'hidebots' ) ) { + + if ( $this->opts->getValue( 'hidebots' ) ) { $conds['rc_bot'] = 0; } @@ -546,7 +563,7 @@ class NewPagesPager extends ReverseChronologicalPager { $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', + 'rc_comment', 'rc_timestamp', 'rc_patrolled', 'rc_id', 'rc_deleted', 'length' => 'page_len', 'rev_id' => 'page_latest', 'rc_this_oldid', 'page_namespace', 'page_title' ); @@ -556,10 +573,10 @@ class NewPagesPager extends ReverseChronologicalPager { array( &$this, $this->opts, &$conds, &$tables, &$fields, &$join_conds ) ); $info = array( - 'tables' => $tables, - 'fields' => $fields, - 'conds' => $conds, - 'options' => array( 'USE INDEX' => array( 'recentchanges' => $rcIndexes ) ), + 'tables' => $tables, + 'fields' => $fields, + 'conds' => $conds, + 'options' => array( 'USE INDEX' => array( 'recentchanges' => $rcIndexes ) ), 'join_conds' => $join_conds ); @@ -593,6 +610,7 @@ class NewPagesPager extends ReverseChronologicalPager { $linkBatch->add( $row->rc_namespace, $row->rc_title ); } $linkBatch->execute(); + return '
          '; } diff --git a/includes/specials/SpecialPagesWithProp.php b/includes/specials/SpecialPagesWithProp.php index 8f8c981e..e22b42a3 100644 --- a/includes/specials/SpecialPagesWithProp.php +++ b/includes/specials/SpecialPagesWithProp.php @@ -23,7 +23,6 @@ * @author Brad Jorsch */ - /** * Special:PagesWithProp to search the page_props table * @ingroup SpecialPage @@ -43,6 +42,7 @@ class SpecialPagesWithProp extends QueryPage { function execute( $par ) { $this->setHeaders(); $this->outputHeader(); + $this->getOutput()->addModuleStyles( 'mediawiki.special.pagesWithProp' ); $request = $this->getRequest(); $propname = $request->getVal( 'propname', $par ); @@ -55,6 +55,7 @@ class SpecialPagesWithProp extends QueryPage { __METHOD__, array( 'DISTINCT', 'ORDER BY' => 'pp_propname' ) ); + $propnames = array(); foreach ( $res as $row ) { $propnames[$row->pp_propname] = $row->pp_propname; } @@ -70,9 +71,8 @@ class SpecialPagesWithProp extends QueryPage { ), ), $this->getContext() ); $form->setMethod( 'get' ); - $form->setAction( $this->getTitle()->getFullUrl() ); $form->setSubmitCallback( array( $this, 'onSubmit' ) ); - $form->setWrapperLegend( $this->msg( 'pageswithprop-legend' ) ); + $form->setWrapperLegendMsg( 'pageswithprop-legend' ); $form->addHeaderText( $this->msg( 'pageswithprop-text' )->parseAsBlock() ); $form->setSubmitTextMsg( 'pageswithprop-submit' ); @@ -120,15 +120,33 @@ class SpecialPagesWithProp extends QueryPage { return array( 'page_id' ); } + /** + * @param Skin $skin + * @param object $result Result row + * @return string + */ function formatResult( $skin, $result ) { $title = Title::newFromRow( $result ); $ret = Linker::link( $title, null, array(), array(), array( 'known' ) ); if ( $result->pp_value !== '' ) { - $value = $this->msg( 'parentheses' ) - ->rawParams( Xml::span( $result->pp_value, 'prop-value' ) ) - ->escaped(); - $ret .= " $value"; + // Do not show very long or binary values on the special page + $valueLength = strlen( $result->pp_value ); + $isBinary = strpos( $result->pp_value, "\0" ) !== false; + $isTooLong = $valueLength > 1024; + + if ( $isBinary || $isTooLong ) { + $message = $this + ->msg( $isBinary ? 'pageswithprop-prophidden-binary' : 'pageswithprop-prophidden-long' ) + ->params( $this->getLanguage()->formatSize( $valueLength ) ); + + $propValue = Html::element( 'span', array( 'class' => 'prop-value-hidden' ), $message->text() ); + } else { + $propValue = Html::element( 'span', array( 'class' => 'prop-value' ), $result->pp_value ); + } + + $ret .= $this->msg( 'colon-separator' )->escaped() . $propValue; } + return $ret; } diff --git a/includes/specials/SpecialPasswordReset.php b/includes/specials/SpecialPasswordReset.php index 90b0ac80..c486ba01 100644 --- a/includes/specials/SpecialPasswordReset.php +++ b/includes/specials/SpecialPasswordReset.php @@ -27,19 +27,23 @@ * @ingroup SpecialPage */ class SpecialPasswordReset extends FormSpecialPage { - /** * @var Message */ private $email; + /** + * @var User + */ + private $firstUser; + /** * @var Status */ private $result; public function __construct() { - parent::__construct( 'PasswordReset' ); + parent::__construct( 'PasswordReset', 'editmyprivateinfo' ); } public function userCanExecute( User $user ) { @@ -65,7 +69,8 @@ class SpecialPasswordReset extends FormSpecialPage { 'type' => 'text', 'label-message' => 'passwordreset-username', ); - if( $this->getUser()->isLoggedIn() ) { + + if ( $this->getUser()->isLoggedIn() ) { $a['Username']['default'] = $this->getUser()->getName(); } } @@ -86,7 +91,7 @@ class SpecialPasswordReset extends FormSpecialPage { ); } - if( $this->getUser()->isAllowed( 'passwordreset' ) ) { + if ( $this->getUser()->isAllowed( 'passwordreset' ) ) { $a['Capture'] = array( 'type' => 'check', 'label-message' => 'passwordreset-capture', @@ -98,11 +103,15 @@ class SpecialPasswordReset extends FormSpecialPage { } public function alterForm( HTMLForm $form ) { - $form->setSubmitTextMsg( 'mailmypassword' ); - } - - protected function preText() { global $wgPasswordResetRoutes; + + $form->setDisplayFormat( 'vform' ); + // Turn the old-school line around the form off. + // XXX This wouldn't be necessary here if we could set the format of + // the HTMLForm to 'vform' at its creation, but there's no way to do so + // from a FormSpecialPage class. + $form->setWrapperLegend( false ); + $i = 0; if ( isset( $wgPasswordResetRoutes['username'] ) && $wgPasswordResetRoutes['username'] ) { $i++; @@ -113,7 +122,11 @@ class SpecialPasswordReset extends FormSpecialPage { if ( isset( $wgPasswordResetRoutes['domain'] ) && $wgPasswordResetRoutes['domain'] ) { $i++; } - return $this->msg( 'passwordreset-pretext', $i )->parseAsBlock(); + + $message = ( $i > 1 ) ? 'passwordreset-text-many' : 'passwordreset-text-one'; + + $form->setHeaderText( $this->msg( $message, $i )->parseAsBlock() ); + $form->setSubmitTextMsg( 'mailmypassword' ); } /** @@ -136,8 +149,9 @@ class SpecialPasswordReset extends FormSpecialPage { } } - if( isset( $data['Capture'] ) && !$this->getUser()->isAllowed( 'passwordreset' ) ) { - // The user knows they don't have the passwordreset permission, but they tried to spoof the form. That's naughty + if ( isset( $data['Capture'] ) && !$this->getUser()->isAllowed( 'passwordreset' ) ) { + // The user knows they don't have the passwordreset permission, + // but they tried to spoof the form. That's naughty throw new PermissionsError( 'passwordreset' ); } @@ -151,8 +165,8 @@ class SpecialPasswordReset extends FormSpecialPage { $users = array( User::newFromName( $data['Username'] ) ); } elseif ( isset( $data['Email'] ) && $data['Email'] !== '' - && Sanitizer::validateEmail( $data['Email'] ) ) - { + && Sanitizer::validateEmail( $data['Email'] ) + ) { $method = 'email'; $res = wfGetDB( DB_SLAVE )->select( 'user', @@ -160,9 +174,11 @@ class SpecialPasswordReset extends FormSpecialPage { array( 'user_email' => $data['Email'] ), __METHOD__ ); + if ( $res ) { $users = array(); - foreach( $res as $row ) { + + foreach ( $res as $row ) { $users[] = User::newFromRow( $row ); } } else { @@ -180,8 +196,8 @@ class SpecialPasswordReset extends FormSpecialPage { return array( $error ); } - if( count( $users ) == 0 ) { - if( $method == 'email' ) { + if ( count( $users ) == 0 ) { + if ( $method == 'email' ) { // Don't reveal whether or not an email address is in use return true; } else { @@ -204,9 +220,13 @@ class SpecialPasswordReset extends FormSpecialPage { 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 ) ) ); + return array( array( + 'throttled-mailpassword', + round( $wgPasswordReminderResendTime, 3 ) + ) ); } } @@ -239,8 +259,8 @@ class SpecialPasswordReset extends FormSpecialPage { $password = $user->randomPassword(); $user->setNewpassword( $password ); $user->saveSettings(); - $passwords[] = $this->msg( 'passwordreset-emailelement', $user->getName(), $password - )->inLanguage( $userLanguage )->text(); // We'll escape the whole thing later + $passwords[] = $this->msg( 'passwordreset-emailelement', $user->getName(), $password ) + ->inLanguage( $userLanguage )->text(); // We'll escape the whole thing later } $passwordBlock = implode( "\n\n", $passwords ); @@ -249,7 +269,7 @@ class SpecialPasswordReset extends FormSpecialPage { $username, $passwordBlock, count( $passwords ), - '<' . Title::newMainPage()->getCanonicalUrl() . '>', + '<' . Title::newMainPage()->getCanonicalURL() . '>', round( $wgNewPasswordExpiry / 86400 ) ); @@ -257,31 +277,36 @@ class SpecialPasswordReset extends FormSpecialPage { $this->result = $firstUser->sendMail( $title->escaped(), $this->email->text() ); - // Blank the email if the user is not supposed to see it - if( !isset( $data['Capture'] ) || !$data['Capture'] ) { + if ( isset( $data['Capture'] ) && $data['Capture'] ) { + // Save the user, will be used if an error occurs when sending the email + $this->firstUser = $firstUser; + } else { + // Blank the email if the user is not supposed to see it $this->email = null; } if ( $this->result->isGood() ) { return true; - } elseif( isset( $data['Capture'] ) && $data['Capture'] ) { + } elseif ( isset( $data['Capture'] ) && $data['Capture'] ) { // The email didn't send, but maybe they knew that and that's why they captured it 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... :( + // @todo FIXME: The email wasn't sent, 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', $this->result->getMessage() ) ); } } public function onSuccess() { - if( $this->getUser()->isAllowed( 'passwordreset' ) && $this->email != null ) { - // @todo: Logging + if ( $this->getUser()->isAllowed( 'passwordreset' ) && $this->email != null ) { + // @todo Logging - if( $this->result->isGood() ) { + if ( $this->result->isGood() ) { $this->getOutput()->addWikiMsg( 'passwordreset-emailsent-capture' ); } else { - $this->getOutput()->addWikiMsg( 'passwordreset-emailerror-capture', $this->result->getMessage() ); + $this->getOutput()->addWikiMsg( 'passwordreset-emailerror-capture', + $this->result->getMessage(), $this->firstUser->getName() ); } $this->getOutput()->addHTML( Html::rawElement( 'pre', array(), $this->email->escaped() ) ); @@ -292,12 +317,12 @@ class SpecialPasswordReset extends FormSpecialPage { } protected function canChangePassword( User $user ) { - global $wgPasswordResetRoutes, $wgAuth; + global $wgPasswordResetRoutes, $wgEnableEmail, $wgAuth; // Maybe password resets are disabled, or there are no allowable routes if ( !is_array( $wgPasswordResetRoutes ) || - !in_array( true, array_values( $wgPasswordResetRoutes ) ) ) - { + !in_array( true, array_values( $wgPasswordResetRoutes ) ) + ) { return 'passwordreset-disabled'; } @@ -306,6 +331,11 @@ class SpecialPasswordReset extends FormSpecialPage { return 'resetpass_forbidden'; } + // Maybe email features have been disabled + if ( !$wgEnableEmail ) { + return 'passwordreset-emaildisabled'; + } + // 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() ) { diff --git a/includes/specials/SpecialPopularpages.php b/includes/specials/SpecialPopularpages.php index 7ce8c13f..2a80f651 100644 --- a/includes/specials/SpecialPopularpages.php +++ b/includes/specials/SpecialPopularpages.php @@ -27,7 +27,6 @@ * @ingroup SpecialPage */ class PopularPagesPage extends QueryPage { - function __construct( $name = 'Popularpages' ) { parent::__construct( $name ); } @@ -42,27 +41,37 @@ class PopularPagesPage extends QueryPage { } function getQueryInfo() { - return array ( + return array( 'tables' => array( 'page' ), - 'fields' => array( 'namespace' => 'page_namespace', - 'title' => 'page_title', - 'value' => 'page_counter' ), - 'conds' => array( 'page_is_redirect' => 0, - 'page_namespace' => MWNamespace::getContentNamespaces() ) ); + 'fields' => array( + 'namespace' => 'page_namespace', + 'title' => 'page_title', + 'value' => 'page_counter' ), + 'conds' => array( + 'page_is_redirect' => 0, + 'page_namespace' => MWNamespace::getContentNamespaces() + ) + ); } /** - * @param $skin Skin - * @param $result + * @param Skin $skin + * @param object $result Result row * @return string */ function formatResult( $skin, $result ) { global $wgContLang; $title = Title::makeTitleSafe( $result->namespace, $result->title ); - if( !$title ) { - return Html::element( 'span', array( 'class' => 'mw-invalidtitle' ), - Linker::getInvalidTitleDescription( $this->getContext(), $result->namespace, $result->title ) ); + if ( !$title ) { + return Html::element( + 'span', + array( 'class' => 'mw-invalidtitle' ), + Linker::getInvalidTitleDescription( + $this->getContext(), + $result->namespace, + $result->title ) + ); } $link = Linker::linkKnown( @@ -70,6 +79,7 @@ class PopularPagesPage extends QueryPage { htmlspecialchars( $wgContLang->convert( $title->getPrefixedText() ) ) ); $nv = $this->msg( 'nviews' )->numParams( $result->value )->escaped(); + return $this->getLanguage()->specialList( $link, $nv ); } diff --git a/includes/specials/SpecialPreferences.php b/includes/specials/SpecialPreferences.php index a50e7c18..ecee0bb7 100644 --- a/includes/specials/SpecialPreferences.php +++ b/includes/specials/SpecialPreferences.php @@ -35,16 +35,21 @@ class SpecialPreferences extends SpecialPage { $this->setHeaders(); $this->outputHeader(); $out = $this->getOutput(); - $out->disallowUserJs(); # Prevent hijacked user scripts from sniffing passwords etc. + $out->disallowUserJs(); # Prevent hijacked user scripts from sniffing passwords etc. $user = $this->getUser(); if ( $user->isAnon() ) { - throw new ErrorPageError( 'prefsnologin', 'prefsnologintext', array( $this->getTitle()->getPrefixedDBkey() ) ); + throw new ErrorPageError( + 'prefsnologin', + 'prefsnologintext', + array( $this->getTitle()->getPrefixedDBkey() ) + ); } $this->checkReadOnly(); if ( $par == 'reset' ) { $this->showResetForm(); + return; } @@ -52,7 +57,7 @@ class SpecialPreferences extends SpecialPage { if ( $this->getRequest()->getCheck( 'success' ) ) { $out->wrapWikiMsg( - "
          \n$1\n
          ", + "
          \n$1\n
          ", 'savedprefs' ); } @@ -64,12 +69,17 @@ class SpecialPreferences extends SpecialPage { } private function showResetForm() { + if ( !$this->getUser()->isAllowed( 'editmyoptions' ) ) { + throw new PermissionsError( 'editmyoptions' ); + } + $this->getOutput()->addWikiMsg( 'prefs-reset-intro' ); - $htmlForm = new HTMLForm( array(), $this->getContext(), 'prefs-restore' ); + $context = new DerivativeContext( $this->getContext() ); + $context->setTitle( $this->getTitle( 'reset' ) ); // Reset subpage + $htmlForm = new HTMLForm( array(), $context, 'prefs-restore' ); $htmlForm->setSubmitTextMsg( 'restoreprefs' ); - $htmlForm->setTitle( $this->getTitle( 'reset' ) ); $htmlForm->setSubmitCallback( array( $this, 'submitReset' ) ); $htmlForm->suppressReset(); @@ -77,8 +87,12 @@ class SpecialPreferences extends SpecialPage { } public function submitReset( $formData ) { + if ( !$this->getUser()->isAllowed( 'editmyoptions' ) ) { + throw new PermissionsError( 'editmyoptions' ); + } + $user = $this->getUser(); - $user->resetOptions( 'all' ); + $user->resetOptions( 'all', $this->getContext() ); $user->saveSettings(); $url = $this->getTitle()->getFullURL( 'success' ); diff --git a/includes/specials/SpecialPrefixindex.php b/includes/specials/SpecialPrefixindex.php index 6affa735..28d07ffc 100644 --- a/includes/specials/SpecialPrefixindex.php +++ b/includes/specials/SpecialPrefixindex.php @@ -27,6 +27,15 @@ * @ingroup SpecialPage */ class SpecialPrefixindex extends SpecialAllpages { + + /** + * Whether to remove the searched prefix from the displayed link. Useful + * for inclusion of a set of sub pages in a root page. + */ + protected $stripPrefix = false; + + protected $hideRedirects = false; + // Inherit $maxPerPage function __construct() { @@ -52,7 +61,8 @@ class SpecialPrefixindex extends SpecialAllpages { $prefix = $request->getVal( 'prefix', '' ); $ns = $request->getIntOrNull( 'namespace' ); $namespace = (int)$ns; // if no namespace given, use 0 (NS_MAIN). - $hideredirects = $request->getBool( 'hideredirects', false ); + $this->hideRedirects = $request->getBool( 'hideredirects', $this->hideRedirects ); + $this->stripPrefix = $request->getBool( 'stripprefix', $this->stripPrefix ); $namespaces = $wgContLang->getNamespaces(); $out->setPageTitle( @@ -62,11 +72,11 @@ class SpecialPrefixindex extends SpecialAllpages { ); $showme = ''; - if( isset( $par ) ) { + if ( isset( $par ) ) { $showme = $par; - } elseif( $prefix != '' ) { + } elseif ( $prefix != '' ) { $showme = $prefix; - } elseif( $from != '' && $ns === null ) { + } elseif ( $from != '' && $ns === null ) { // For back-compat with Special:Allpages // Don't do this if namespace is passed, so paging works when doing NS views. $showme = $from; @@ -74,9 +84,9 @@ class SpecialPrefixindex extends SpecialAllpages { // Bug 27864: if transcluded, show all pages instead of the form. if ( $this->including() || $showme != '' || $ns !== null ) { - $this->showPrefixChunk( $namespace, $showme, $from, $hideredirects ); + $this->showPrefixChunk( $namespace, $showme, $from ); } else { - $out->addHTML( $this->namespacePrefixForm( $namespace, null, $hideredirects ) ); + $out->addHTML( $this->namespacePrefixForm( $namespace, null ) ); } } @@ -84,10 +94,9 @@ class SpecialPrefixindex extends SpecialAllpages { * HTML for the top form * @param $namespace Integer: a namespace constant (default NS_MAIN). * @param string $from dbKey we are starting listing at. - * @param bool $hideredirects hide redirects (default FALSE) * @return string */ - function namespacePrefixForm( $namespace = NS_MAIN, $from = '', $hideredirects = false ) { + protected function namespacePrefixForm( $namespace = NS_MAIN, $from = '' ) { global $wgScript; $out = Xml::openElement( 'div', array( 'class' => 'namespaceoptions' ) ); @@ -98,37 +107,44 @@ class SpecialPrefixindex extends SpecialAllpages { $out .= Xml::openElement( 'table', array( 'id' => 'nsselect', 'class' => 'allpages' ) ); $out .= " " . - Xml::label( $this->msg( 'allpagesprefix' )->text(), 'nsfrom' ) . - " + Xml::label( $this->msg( 'allpagesprefix' )->text(), 'nsfrom' ) . + " " . - Xml::input( 'prefix', 30, str_replace( '_', ' ', $from ), array( 'id' => 'nsfrom' ) ) . - " + Xml::input( 'prefix', 30, str_replace( '_', ' ', $from ), array( 'id' => 'nsfrom' ) ) . + " - " . - Xml::label( $this->msg( 'namespace' )->text(), 'namespace' ) . - " + " . + Xml::label( $this->msg( 'namespace' )->text(), 'namespace' ) . + " " . - Html::namespaceSelector( array( - 'selected' => $namespace, - ), array( - 'name' => 'namespace', - 'id' => 'namespace', - 'class' => 'namespaceselector', - ) ) . - Xml::checkLabel( - $this->msg( 'allpages-hide-redirects' )->text(), - 'hideredirects', - 'hideredirects', - $hideredirects - ) . ' ' . - Xml::submitButton( $this->msg( 'allpagessubmit' )->text() ) . - " + Html::namespaceSelector( array( + 'selected' => $namespace, + ), array( + 'name' => 'namespace', + 'id' => 'namespace', + 'class' => 'namespaceselector', + ) ) . + Xml::checkLabel( + $this->msg( 'allpages-hide-redirects' )->text(), + 'hideredirects', + 'hideredirects', + $this->hideRedirects + ) . ' ' . + Xml::checkLabel( + $this->msg( 'prefixindex-strip' )->text(), + 'stripprefix', + 'stripprefix', + $this->stripPrefix + ) . ' ' . + Xml::submitButton( $this->msg( 'allpagessubmit' )->text() ) . + " "; $out .= Xml::closeElement( 'table' ); $out .= Xml::closeElement( 'fieldset' ); $out .= Xml::closeElement( 'form' ); $out .= Xml::closeElement( 'div' ); + return $out; } @@ -136,9 +152,8 @@ class SpecialPrefixindex extends SpecialAllpages { * @param $namespace Integer, default NS_MAIN * @param $prefix String * @param string $from list all pages from this name (default FALSE) - * @param bool $hideredirects hide redirects (default FALSE) */ - function showPrefixChunk( $namespace = NS_MAIN, $prefix, $from = null, $hideredirects = false ) { + protected function showPrefixChunk( $namespace = NS_MAIN, $prefix, $from = null ) { global $wgContLang; if ( $from === null ) { @@ -169,7 +184,7 @@ class SpecialPrefixindex extends SpecialAllpages { 'page_title >= ' . $dbr->addQuotes( $fromKey ), ); - if ( $hideredirects ) { + if ( $this->hideRedirects ) { $conds['page_is_redirect'] = 0; } @@ -178,8 +193,8 @@ class SpecialPrefixindex extends SpecialAllpages { $conds, __METHOD__, array( - 'ORDER BY' => 'page_title', - 'LIMIT' => $this->maxPerPage + 1, + 'ORDER BY' => 'page_title', + 'LIMIT' => $this->maxPerPage + 1, 'USE INDEX' => 'name_title', ) ); @@ -187,34 +202,42 @@ class SpecialPrefixindex extends SpecialAllpages { ### @todo FIXME: Side link to previous $n = 0; - if( $res->numRows() > 0 ) { + if ( $res->numRows() > 0 ) { $out = Xml::openElement( 'table', array( 'id' => 'mw-prefixindex-list-table' ) ); - while( ( $n < $this->maxPerPage ) && ( $s = $res->fetchObject() ) ) { + $prefixLength = strlen( $prefix ); + while ( ( $n < $this->maxPerPage ) && ( $s = $res->fetchObject() ) ) { $t = Title::makeTitle( $s->page_namespace, $s->page_title ); - if( $t ) { - $link = ($s->page_is_redirect ? '
          ' : '' ) . + if ( $t ) { + $displayed = $t->getText(); + // Try not to generate unclickable links + if ( $this->stripPrefix && $prefixLength !== strlen( $displayed ) ) { + $displayed = substr( $displayed, $prefixLength ); + } + $link = ( $s->page_is_redirect ? '
          ' : '' ) . Linker::linkKnown( $t, - htmlspecialchars( $t->getText() ), + htmlspecialchars( $displayed ), $s->page_is_redirect ? array( 'class' => 'mw-redirect' ) : array() ) . - ($s->page_is_redirect ? '
          ' : '' ); + ( $s->page_is_redirect ? '
          ' : '' ); } else { $link = '[[' . htmlspecialchars( $s->page_title ) . ']]'; } - if( $n % 3 == 0 ) { + if ( $n % 3 == 0 ) { $out .= ''; } $out .= "$link"; $n++; - if( $n % 3 == 0 ) { + if ( $n % 3 == 0 ) { $out .= ''; } } - if( ($n % 3) != 0 ) { + + if ( $n % 3 != 0 ) { $out .= ''; } + $out .= Xml::closeElement( 'table' ); } else { $out = ''; @@ -225,37 +248,45 @@ class SpecialPrefixindex extends SpecialAllpages { if ( $this->including() ) { $out2 = ''; } else { - $nsForm = $this->namespacePrefixForm( $namespace, $prefix, $hideredirects ); + $nsForm = $this->namespacePrefixForm( $namespace, $prefix ); $self = $this->getTitle(); $out2 = Xml::openElement( 'table', array( 'id' => 'mw-prefixindex-nav-table' ) ) . ' ' . - $nsForm . - ' - '; + $nsForm . + ' + '; - if( isset( $res ) && $res && ( $n == $this->maxPerPage ) && ( $s = $res->fetchObject() ) ) { + if ( isset( $res ) && $res && ( $n == $this->maxPerPage ) && + ( $s = $res->fetchObject() ) + ) { $query = array( 'from' => $s->page_title, 'prefix' => $prefix, - 'hideredirects' => $hideredirects, + 'hideredirects' => $this->hideRedirects, ); - if( $namespace || $prefix == '' ) { + if ( $namespace || $prefix == '' ) { // Keep the namespace even if it's 0 for empty prefixes. // This tells us we're not just a holdover from old links. $query['namespace'] = $namespace; } + $nextLink = Linker::linkKnown( - $self, - $this->msg( 'nextpage', str_replace( '_', ' ', $s->page_title ) )->escaped(), - array(), - $query - ); + $self, + $this->msg( 'nextpage', str_replace( '_', ' ', $s->page_title ) )->escaped(), + array(), + $query + ); + $out2 .= $nextLink; - $footer = "\n" . Html::element( "hr" ) - . Html::rawElement( "div", array( "class" => "mw-prefixindex-nav" ), $nextLink ); + $footer = "\n" . Html::element( 'hr' ) . + Html::rawElement( + 'div', + array( 'class' => 'mw-prefixindex-nav' ), + $nextLink + ); } $out2 .= "" . Xml::closeElement( 'table' ); diff --git a/includes/specials/SpecialProtectedpages.php b/includes/specials/SpecialProtectedpages.php index cdf053ec..3de6ea24 100644 --- a/includes/specials/SpecialProtectedpages.php +++ b/includes/specials/SpecialProtectedpages.php @@ -40,7 +40,7 @@ class SpecialProtectedpages extends SpecialPage { $this->outputHeader(); // Purge expired entries on one in every 10 queries - if( !mt_rand( 0, 10 ) ) { + if ( !mt_rand( 0, 10 ) ) { Title::purgeExpiredRestrictions(); } @@ -49,19 +49,37 @@ class SpecialProtectedpages extends SpecialPage { $level = $request->getVal( $this->IdLevel ); $sizetype = $request->getVal( 'sizetype' ); $size = $request->getIntOrNull( 'size' ); - $NS = $request->getIntOrNull( 'namespace' ); + $ns = $request->getIntOrNull( 'namespace' ); $indefOnly = $request->getBool( 'indefonly' ) ? 1 : 0; $cascadeOnly = $request->getBool( 'cascadeonly' ) ? 1 : 0; - $pager = new ProtectedPagesPager( $this, array(), $type, $level, $NS, $sizetype, $size, $indefOnly, $cascadeOnly ); - - $this->getOutput()->addHTML( $this->showOptions( $NS, $type, $level, $sizetype, $size, $indefOnly, $cascadeOnly ) ); + $pager = new ProtectedPagesPager( + $this, + array(), + $type, + $level, + $ns, + $sizetype, + $size, + $indefOnly, + $cascadeOnly + ); - if( $pager->getNumRows() ) { + $this->getOutput()->addHTML( $this->showOptions( + $ns, + $type, + $level, + $sizetype, + $size, + $indefOnly, + $cascadeOnly + ) ); + + if ( $pager->getNumRows() ) { $this->getOutput()->addHTML( $pager->getNavigationBar() . - '
            ' . $pager->getBody() . '
          ' . - $pager->getNavigationBar() + '
            ' . $pager->getBody() . '
          ' . + $pager->getNavigationBar() ); } else { $this->getOutput()->addWikiMsg( 'protectedpagesempty' ); @@ -78,26 +96,39 @@ class SpecialProtectedpages extends SpecialPage { static $infinity = null; - if( is_null( $infinity ) ) { + if ( is_null( $infinity ) ) { $infinity = wfGetDB( DB_SLAVE )->getInfinity(); } $title = Title::makeTitleSafe( $row->page_namespace, $row->page_title ); - if( !$title ) { - return Html::rawElement( 'li', array(), - Html::element( 'span', array( 'class' => 'mw-invalidtitle' ), - Linker::getInvalidTitleDescription( $this->getContext(), $row->page_namespace, $row->page_title ) ) ) . "\n"; + if ( !$title ) { + wfProfileOut( __METHOD__ ); + + return Html::rawElement( + 'li', + array(), + Html::element( + 'span', + array( 'class' => 'mw-invalidtitle' ), + Linker::getInvalidTitleDescription( + $this->getContext(), + $row->page_namespace, + $row->page_title + ) + ) + ) . "\n"; } $link = Linker::link( $title ); - $description_items = array (); + $description_items = array(); + // Messages: restriction-level-sysop, restriction-level-autoconfirmed $protType = $this->msg( 'restriction-level-' . $row->pr_level )->escaped(); $description_items[] = $protType; - if( $row->pr_cascade ) { + if ( $row->pr_cascade ) { $description_items[] = $this->msg( 'protect-summary-cascade' )->text(); } @@ -105,7 +136,7 @@ class SpecialProtectedpages extends SpecialPage { $lang = $this->getLanguage(); $expiry = $lang->formatExpiry( $row->pr_expiry, TS_MW ); - if( $expiry != $infinity ) { + if ( $expiry != $infinity ) { $user = $this->getUser(); $description_items[] = $this->msg( 'protect-expiring-local', @@ -115,12 +146,13 @@ class SpecialProtectedpages extends SpecialPage { )->escaped(); } - if( !is_null( $size = $row->page_len ) ) { + if ( !is_null( $size = $row->page_len ) ) { $stxt = $lang->getDirMark() . ' ' . Linker::formatRevisionSize( $size ); } - # Show a link to the change protection form for allowed users otherwise a link to the protection log - if( $this->getUser()->isAllowed( 'protect' ) ) { + // Show a link to the change protection form for allowed users otherwise + // a link to the protection log + if ( $this->getUser()->isAllowed( 'protect' ) ) { $changeProtection = Linker::linkKnown( $title, $this->msg( 'protect_change' )->escaped(), @@ -140,14 +172,17 @@ class SpecialProtectedpages extends SpecialPage { ); } - $changeProtection = ' ' . $this->msg( 'parentheses' )->rawParams( $changeProtection )->escaped(); + $changeProtection = ' ' . $this->msg( 'parentheses' )->rawParams( $changeProtection ) + ->escaped(); wfProfileOut( __METHOD__ ); return Html::rawElement( 'li', array(), - $lang->specialList( $link . $stxt, $lang->commaList( $description_items ), false ) . $changeProtection ) . "\n"; + $lang->specialList( $link . $stxt, $lang->commaList( $description_items ), false ) . + $changeProtection + ) . "\n"; } /** @@ -160,9 +195,13 @@ class SpecialProtectedpages extends SpecialPage { * @param $cascadeOnly Boolean: only cascading protection * @return String: input form */ - protected function showOptions( $namespace, $type = 'edit', $level, $sizetype, $size, $indefOnly, $cascadeOnly ) { + protected function showOptions( $namespace, $type = 'edit', $level, $sizetype, + $size, $indefOnly, $cascadeOnly + ) { global $wgScript; + $title = $this->getTitle(); + return Xml::openElement( 'form', array( 'method' => 'get', 'action' => $wgScript ) ) . Xml::openElement( 'fieldset' ) . Xml::element( 'legend', array(), $this->msg( 'protectedpages' )->text() ) . @@ -196,8 +235,8 @@ class SpecialProtectedpages extends SpecialPage { 'all' => '', 'label' => $this->msg( 'namespace' )->text() ), array( - 'name' => 'namespace', - 'id' => 'namespace', + 'name' => 'namespace', + 'id' => 'namespace', 'class' => 'namespaceselector', ) ) @@ -205,31 +244,54 @@ class SpecialProtectedpages extends SpecialPage { } /** + * @param bool $indefOnly * @return string Formatted HTML */ protected function getExpiryCheck( $indefOnly ) { - return - Xml::checkLabel( $this->msg( 'protectedpages-indef' )->text(), 'indefonly', 'indefonly', $indefOnly ) . "\n"; + return Xml::checkLabel( + $this->msg( 'protectedpages-indef' )->text(), + 'indefonly', + 'indefonly', + $indefOnly + ) . "\n"; } /** + * @param bool $cascadeOnly * @return string Formatted HTML */ protected function getCascadeCheck( $cascadeOnly ) { - return - Xml::checkLabel( $this->msg( 'protectedpages-cascade' )->text(), 'cascadeonly', 'cascadeonly', $cascadeOnly ) . "\n"; + return Xml::checkLabel( + $this->msg( 'protectedpages-cascade' )->text(), + 'cascadeonly', + 'cascadeonly', + $cascadeOnly + ) . "\n"; } /** + * @param string $sizetype "min" or "max" + * @param mixed $size * @return string Formatted HTML */ protected function getSizeLimit( $sizetype, $size ) { $max = $sizetype === 'max'; - return - Xml::radioLabel( $this->msg( 'minimum-size' )->text(), 'sizetype', 'min', 'wpmin', !$max ) . + return Xml::radioLabel( + $this->msg( 'minimum-size' )->text(), + 'sizetype', + 'min', + 'wpmin', + !$max + ) . ' ' . - Xml::radioLabel( $this->msg( 'maximum-size' )->text(), 'sizetype', 'max', 'wpmax', $max ) . + Xml::radioLabel( + $this->msg( 'maximum-size' )->text(), + 'sizetype', + 'max', + 'wpmax', + $max + ) . ' ' . Xml::input( 'size', 9, $size, array( 'id' => 'wpsize' ) ) . ' ' . @@ -246,14 +308,15 @@ class SpecialProtectedpages extends SpecialPage { $options = array(); // First pass to load the log names - foreach( Title::getFilteredRestrictionTypes( true ) as $type ) { + foreach ( Title::getFilteredRestrictionTypes( true ) as $type ) { + // Messages: restriction-edit, restriction-move, restriction-create, restriction-upload $text = $this->msg( "restriction-$type" )->text(); $m[$text] = $type; } // Third pass generates sorted XHTML content - foreach( $m as $text => $type ) { - $selected = ($type == $pr_type ); + foreach ( $m as $text => $type ) { + $selected = ( $type == $pr_type ); $options[] = Xml::option( $text, $type, $selected ) . "\n"; } @@ -272,21 +335,22 @@ class SpecialProtectedpages extends SpecialPage { protected function getLevelMenu( $pr_level ) { global $wgRestrictionLevels; - $m = array( $this->msg( 'restriction-level-all' )->text() => 0 ); // Temporary array + // Temporary array + $m = array( $this->msg( 'restriction-level-all' )->text() => 0 ); $options = array(); // First pass to load the log names - foreach( $wgRestrictionLevels as $type ) { + foreach ( $wgRestrictionLevels as $type ) { // Messages used can be 'restriction-level-sysop' and 'restriction-level-autoconfirmed' - if( $type != '' && $type != '*' ) { + if ( $type != '' && $type != '*' ) { $text = $this->msg( "restriction-level-$type" )->text(); $m[$text] = $type; } } // Third pass generates sorted XHTML content - foreach( $m as $text => $type ) { - $selected = ($type == $pr_level ); + foreach ( $m as $text => $type ) { + $selected = ( $type == $pr_level ); $options[] = Xml::option( $text, $type, $selected ); } @@ -310,9 +374,9 @@ 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, - $indefonly = false, $cascadeonly = false ) - { + function __construct( $form, $conds = array(), $type, $level, $namespace, + $sizetype = '', $size = 0, $indefonly = false, $cascadeonly = false + ) { $this->mForm = $form; $this->mConds = $conds; $this->type = ( $type ) ? $type : 'edit'; @@ -332,6 +396,7 @@ class ProtectedPagesPager extends AlphabeticPager { $lb->add( $row->page_namespace, $row->page_title ); } $lb->execute(); + return ''; } @@ -342,27 +407,31 @@ class ProtectedPagesPager extends AlphabeticPager { function getQueryInfo() { $conds = $this->mConds; $conds[] = '(pr_expiry>' . $this->mDb->addQuotes( $this->mDb->timestamp() ) . - 'OR pr_expiry IS NULL)'; + 'OR pr_expiry IS NULL)'; $conds[] = 'page_id=pr_page'; $conds[] = 'pr_type=' . $this->mDb->addQuotes( $this->type ); - if( $this->sizetype == 'min' ) { + if ( $this->sizetype == 'min' ) { $conds[] = 'page_len>=' . $this->size; - } elseif( $this->sizetype == 'max' ) { + } elseif ( $this->sizetype == 'max' ) { $conds[] = 'page_len<=' . $this->size; } - if( $this->indefonly ) { - $conds[] = "pr_expiry = {$this->mDb->addQuotes( $this->mDb->getInfinity() )} OR pr_expiry IS NULL"; + if ( $this->indefonly ) { + $infinity = $this->mDb->addQuotes( $this->mDb->getInfinity() ); + $conds[] = "pr_expiry = $infinity OR pr_expiry IS NULL"; } - if( $this->cascadeonly ) { + if ( $this->cascadeonly ) { $conds[] = 'pr_cascade = 1'; } - if( $this->level ) + if ( $this->level ) { $conds[] = 'pr_level=' . $this->mDb->addQuotes( $this->level ); - if( !is_null( $this->namespace ) ) + } + if ( !is_null( $this->namespace ) ) { $conds[] = 'page_namespace=' . $this->mDb->addQuotes( $this->namespace ); + } + return array( 'tables' => array( 'page_restrictions', 'page' ), 'fields' => array( 'pr_id', 'page_namespace', 'page_title', 'page_len', diff --git a/includes/specials/SpecialProtectedtitles.php b/includes/specials/SpecialProtectedtitles.php index 0cba5ebd..078e7b12 100644 --- a/includes/specials/SpecialProtectedtitles.php +++ b/includes/specials/SpecialProtectedtitles.php @@ -27,7 +27,6 @@ * @ingroup SpecialPage */ class SpecialProtectedtitles extends SpecialPage { - protected $IdLevel = 'level'; protected $IdType = 'type'; @@ -58,8 +57,8 @@ class SpecialProtectedtitles extends SpecialPage { if ( $pager->getNumRows() ) { $this->getOutput()->addHTML( $pager->getNavigationBar() . - '
            ' . $pager->getBody() . '
          ' . - $pager->getNavigationBar() + '
            ' . $pager->getBody() . '
          ' . + $pager->getNavigationBar() ); } else { $this->getOutput()->addWikiMsg( 'protectedtitlesempty' ); @@ -69,6 +68,7 @@ class SpecialProtectedtitles extends SpecialPage { /** * Callback function to output a restriction * + * @param object $row Database row * @return string */ function formatRow( $row ) { @@ -76,28 +76,40 @@ class SpecialProtectedtitles extends SpecialPage { static $infinity = null; - if( is_null( $infinity ) ) { + if ( is_null( $infinity ) ) { $infinity = wfGetDB( DB_SLAVE )->getInfinity(); } $title = Title::makeTitleSafe( $row->pt_namespace, $row->pt_title ); - if( !$title ) { - return Html::rawElement( 'li', array(), - Html::element( 'span', array( 'class' => 'mw-invalidtitle' ), - Linker::getInvalidTitleDescription( $this->getContext(), $row->pt_namespace, $row->pt_title ) ) ) . "\n"; + if ( !$title ) { + wfProfileOut( __METHOD__ ); + + return Html::rawElement( + 'li', + array(), + Html::element( + 'span', + array( 'class' => 'mw-invalidtitle' ), + Linker::getInvalidTitleDescription( + $this->getContext(), + $row->pt_namespace, + $row->pt_title + ) + ) + ) . "\n"; } $link = Linker::link( $title ); - - $description_items = array (); - + $description_items = array(); + // Messages: restriction-level-sysop, restriction-level-autoconfirmed $protType = $this->msg( 'restriction-level-' . $row->pt_create_perm )->escaped(); - $description_items[] = $protType; - $lang = $this->getLanguage(); - $expiry = strlen( $row->pt_expiry ) ? $lang->formatExpiry( $row->pt_expiry, TS_MW ) : $infinity; - if( $expiry != $infinity ) { + $expiry = strlen( $row->pt_expiry ) ? + $lang->formatExpiry( $row->pt_expiry, TS_MW ) : + $infinity; + + if ( $expiry != $infinity ) { $user = $this->getUser(); $description_items[] = $this->msg( 'protect-expiring-local', @@ -109,6 +121,7 @@ class SpecialProtectedtitles extends SpecialPage { wfProfileOut( __METHOD__ ); + // @todo i18n: This should use a comma separator instead of a hard coded comma, right? return '
        • ' . $lang->specialList( $link, implode( $description_items, ', ' ) ) . "
        • \n"; } @@ -124,6 +137,7 @@ class SpecialProtectedtitles extends SpecialPage { $action = htmlspecialchars( $wgScript ); $title = $this->getTitle(); $special = htmlspecialchars( $title->getPrefixedDBkey() ); + return "
          \n" . '
          ' . Xml::element( 'legend', array(), $this->msg( 'protectedtitles' )->text() ) . @@ -148,42 +162,45 @@ class SpecialProtectedtitles extends SpecialPage { 'all' => '', 'label' => $this->msg( 'namespace' )->text() ), array( - 'name' => 'namespace', - 'id' => 'namespace', + 'name' => 'namespace', + 'id' => 'namespace', 'class' => 'namespaceselector', ) ); } /** + * @param string $pr_level Determines which option is selected as default * @return string Formatted HTML * @private */ function getLevelMenu( $pr_level ) { global $wgRestrictionLevels; - $m = array( $this->msg( 'restriction-level-all' )->text() => 0 ); // Temporary array + // Temporary array + $m = array( $this->msg( 'restriction-level-all' )->text() => 0 ); $options = array(); // First pass to load the log names - foreach( $wgRestrictionLevels as $type ) { + foreach ( $wgRestrictionLevels as $type ) { if ( $type != '' && $type != '*' ) { + // Messages: restriction-level-sysop, restriction-level-autoconfirmed $text = $this->msg( "restriction-level-$type" )->text(); $m[$text] = $type; } } + // Is there only one level (aside from "all")? - if( count( $m ) <= 2 ) { + if ( count( $m ) <= 2 ) { return ''; } // Third pass generates sorted XHTML content - foreach( $m as $text => $type ) { - $selected = ($type == $pr_level ); + foreach ( $m as $text => $type ) { + $selected = ( $type == $pr_level ); $options[] = Xml::option( $text, $type, $selected ); } - return - Xml::label( $this->msg( 'restriction-level' )->text(), $this->IdLevel ) . ' ' . + return Xml::label( $this->msg( 'restriction-level' )->text(), $this->IdLevel ) . ' ' . Xml::tags( 'select', array( 'id' => $this->IdLevel, 'name' => $this->IdLevel ), implode( "\n", $options ) ); @@ -201,12 +218,14 @@ class SpecialProtectedtitles extends SpecialPage { class ProtectedTitlesPager extends AlphabeticPager { public $mForm, $mConds; - function __construct( $form, $conds = array(), $type, $level, $namespace, $sizetype = '', $size = 0 ) { + function __construct( $form, $conds = array(), $type, $level, $namespace, + $sizetype = '', $size = 0 + ) { $this->mForm = $form; $this->mConds = $conds; $this->level = $level; $this->namespace = $namespace; - $this->size = intval($size); + $this->size = intval( $size ); parent::__construct( $form->getContext() ); } @@ -222,6 +241,7 @@ class ProtectedTitlesPager extends AlphabeticPager { $lb->execute(); wfProfileOut( __METHOD__ ); + return ''; } @@ -242,10 +262,14 @@ class ProtectedTitlesPager extends AlphabeticPager { function getQueryInfo() { $conds = $this->mConds; $conds[] = 'pt_expiry>' . $this->mDb->addQuotes( $this->mDb->timestamp() ); - if( $this->level ) + if ( $this->level ) { $conds['pt_create_perm'] = $this->level; - if( !is_null( $this->namespace ) ) + } + + if ( !is_null( $this->namespace ) ) { $conds[] = 'pt_namespace=' . $this->mDb->addQuotes( $this->namespace ); + } + return array( 'tables' => 'protected_titles', 'fields' => array( 'pt_namespace', 'pt_title', 'pt_create_perm', diff --git a/includes/specials/SpecialRandomInCategory.php b/includes/specials/SpecialRandomInCategory.php new file mode 100644 index 00000000..0e022bfa --- /dev/null +++ b/includes/specials/SpecialRandomInCategory.php @@ -0,0 +1,291 @@ +category = $cat; + $this->maxTimestamp = null; + $this->minTimestamp = null; + } + + public function execute( $par ) { + global $wgScript; + + $cat = false; + + $categoryStr = $this->getRequest()->getText( 'category', $par ); + + if ( $categoryStr ) { + $cat = Title::newFromText( $categoryStr, NS_CATEGORY ); + } + + if ( $cat && $cat->getNamespace() !== NS_CATEGORY ) { + // Someone searching for something like "Wikipedia:Foo" + $cat = Title::makeTitleSafe( NS_CATEGORY, $categoryStr ); + } + + if ( $cat ) { + $this->setCategory( $cat ); + } + + + if ( !$this->category && $categoryStr ) { + $this->setHeaders(); + $this->getOutput()->addWikiMsg( 'randomincategory-invalidcategory', + wfEscapeWikiText( $categoryStr ) ); + + return; + } elseif ( !$this->category ) { + $this->setHeaders(); + $input = Html::input( 'category' ); + $submitText = $this->msg( 'randomincategory-selectcategory-submit' )->text(); + $submit = Html::input( '', $submitText, 'submit' ); + + $msg = $this->msg( 'randomincategory-selectcategory' ); + $form = Html::rawElement( 'form', array( 'action' => $wgScript ), + Html::hidden( 'title', $this->getTitle()->getPrefixedText() ) . + $msg->rawParams( $input, $submit )->parse() + ); + $this->getOutput()->addHtml( $form ); + + return; + } + + $title = $this->getRandomTitle(); + + if ( is_null( $title ) ) { + $this->setHeaders(); + $this->getOutput()->addWikiMsg( 'randomincategory-nopages', + $this->category->getText() ); + + return; + } + + $query = $this->getRequest()->getValues(); + unset( $query['title'] ); + unset( $query['category'] ); + $this->getOutput()->redirect( $title->getFullURL( $query ) ); + } + + /** + * Choose a random title. + * @return Title object (or null if nothing to choose from) + */ + public function getRandomTitle() { + // Convert to float, since we do math with the random number. + $rand = (float)wfRandom(); + $title = null; + + // Given that timestamps are rather unevenly distributed, we also + // use an offset between 0 and 30 to make any biases less noticeable. + $offset = mt_rand( 0, $this->maxOffset ); + + if ( mt_rand( 0, 1 ) ) { + $up = true; + } else { + $up = false; + } + + $row = $this->selectRandomPageFromDB( $rand, $offset, $up ); + + // Try again without the timestamp offset (wrap around the end) + if ( !$row ) { + $row = $this->selectRandomPageFromDB( false, $offset, $up ); + } + + // Maybe the category is really small and offset too high + if ( !$row ) { + $row = $this->selectRandomPageFromDB( $rand, 0, $up ); + } + + // Just get the first entry. + if ( !$row ) { + $row = $this->selectRandomPageFromDB( false, 0, true ); + } + + if ( $row ) { + return Title::makeTitle( $row->page_namespace, $row->page_title ); + } + + return null; + } + + /** + * @param float $rand Random number between 0 and 1 + * @param int $offset Extra offset to fudge randomness + * @param bool $up True to get the result above the random number, false for below + * + * @note The $up parameter is supposed to counteract what would happen if there + * was a large gap in the distribution of cl_timestamp values. This way instead + * of things to the right of the gap being favoured, both sides of the gap + * are favoured. + * @return Array Query information. + */ + protected function getQueryInfo( $rand, $offset, $up ) { + $op = $up ? '>=' : '<='; + $dir = $up ? 'ASC' : 'DESC'; + if ( !$this->category instanceof Title ) { + throw new MWException( 'No category set' ); + } + $qi = array( + 'tables' => array( 'categorylinks', 'page' ), + 'fields' => array( 'page_title', 'page_namespace' ), + 'conds' => array_merge( array( + 'cl_to' => $this->category->getDBKey(), + ), $this->extra ), + 'options' => array( + 'ORDER BY' => 'cl_timestamp ' . $dir, + 'LIMIT' => 1, + 'OFFSET' => $offset + ), + 'join_conds' => array( + 'page' => array( 'INNER JOIN', 'cl_from = page_id' ) + ) + ); + + $dbr = wfGetDB( DB_SLAVE ); + $minClTime = $this->getTimestampOffset( $rand ); + if ( $minClTime ) { + $qi['conds'][] = 'cl_timestamp ' . $op . ' ' . + $dbr->addQuotes( $dbr->timestamp( $minClTime ) ); + } + return $qi; + } + + /** + * @param float $rand Random number between 0 and 1 + * + * @return int|bool A random (unix) timestamp from the range of the category or false on failure + */ + protected function getTimestampOffset( $rand ) { + if ( $rand === false ) { + return false; + } + if ( !$this->minTimestamp || !$this->maxTimestamp ) { + try { + list( $this->minTimestamp, $this->maxTimestamp ) = $this->getMinAndMaxForCat( $this->category ); + } catch ( MWException $e ) { + // Possibly no entries in category. + return false; + } + } + + $ts = ( $this->maxTimestamp - $this->minTimestamp ) * $rand + $this->minTimestamp; + return intval( $ts ); + } + + /** + * Get the lowest and highest timestamp for a category. + * + * @param Title $category + * @return Array The lowest and highest timestamp + * @throws MWException if category has no entries. + */ + protected function getMinAndMaxForCat( Title $category ) { + $dbr = wfGetDB( DB_SLAVE ); + $res = $dbr->selectRow( + 'categorylinks', + array( + 'low' => 'MIN( cl_timestamp )', + 'high' => 'MAX( cl_timestamp )' + ), + array( + 'cl_to' => $this->category->getDBKey(), + ), + __METHOD__, + array( + 'LIMIT' => 1 + ) + ); + if ( !$res ) { + throw new MWException( 'No entries in category' ); + } + return array( wfTimestamp( TS_UNIX, $res->low ), wfTimestamp( TS_UNIX, $res->high ) ); + } + + /** + * @param float $rand A random number that is converted to a random timestamp + * @param int $offset A small offset to make the result seem more "random" + * @param bool $up Get the result above the random value + * @param String $fname The name of the calling method + * @return Array Info for the title selected. + */ + private function selectRandomPageFromDB( $rand, $offset, $up, $fname = __METHOD__ ) { + $dbr = wfGetDB( DB_SLAVE ); + + $query = $this->getQueryInfo( $rand, $offset, $up ); + $res = $dbr->select( + $query['tables'], + $query['fields'], + $query['conds'], + $fname, + $query['options'], + $query['join_conds'] + ); + + return $res->fetchObject(); + } + + protected function getGroupName() { + return 'redirects'; + } +} diff --git a/includes/specials/SpecialRandompage.php b/includes/specials/SpecialRandompage.php index b59f8349..c94d2b35 100644 --- a/includes/specials/SpecialRandompage.php +++ b/includes/specials/SpecialRandompage.php @@ -41,8 +41,8 @@ class RandomPage extends SpecialPage { return $this->namespaces; } - public function setNamespace ( $ns ) { - if( !$ns || $ns < NS_MAIN ) { + public function setNamespace( $ns ) { + if ( !$ns || $ns < NS_MAIN ) { $ns = NS_MAIN; } $this->namespaces = array( $ns ); @@ -62,17 +62,19 @@ class RandomPage extends SpecialPage { $title = $this->getRandomTitle(); - if( is_null( $title ) ) { + if ( is_null( $title ) ) { $this->setHeaders(); + // Message: randompage-nopages, randomredirect-nopages $this->getOutput()->addWikiMsg( strtolower( $this->getName() ) . '-nopages', $this->getNsList(), count( $this->namespaces ) ); + return; } $redirectParam = $this->isRedirect() ? array( 'redirect' => 'no' ) : array(); $query = array_merge( $this->getRequest()->getValues(), $redirectParam ); unset( $query['title'] ); - $this->getOutput()->redirect( $title->getFullUrl( $query ) ); + $this->getOutput()->redirect( $title->getFullURL( $query ) ); } /** @@ -83,13 +85,14 @@ class RandomPage extends SpecialPage { private function getNsList() { global $wgContLang; $nsNames = array(); - foreach( $this->namespaces as $n ) { - if( $n === NS_MAIN ) { + foreach ( $this->namespaces as $n ) { + if ( $n === NS_MAIN ) { $nsNames[] = $this->msg( 'blanknamespace' )->plain(); } else { $nsNames[] = $wgContLang->getNsText( $n ); } } + return $wgContLang->commaList( $nsNames ); } @@ -100,10 +103,14 @@ 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 ); /* If we picked a value that was higher than any in @@ -113,15 +120,15 @@ 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 { - return null; } + + return null; } protected function getQueryInfo( $randstr ) { diff --git a/includes/specials/SpecialRandomredirect.php b/includes/specials/SpecialRandomredirect.php index 51783a2f..7c36a28a 100644 --- a/includes/specials/SpecialRandomredirect.php +++ b/includes/specials/SpecialRandomredirect.php @@ -32,5 +32,4 @@ class SpecialRandomredirect extends RandomPage { parent::__construct( 'Randomredirect' ); $this->isRedir = true; } - } diff --git a/includes/specials/SpecialRecentchanges.php b/includes/specials/SpecialRecentchanges.php index 008678f7..a42a2171 100644 --- a/includes/specials/SpecialRecentchanges.php +++ b/includes/specials/SpecialRecentchanges.php @@ -41,16 +41,17 @@ class SpecialRecentChanges extends IncludableSpecialPage { */ public function getDefaultOptions() { $opts = new FormOptions(); + $user = $this->getUser(); - $opts->add( 'days', $this->getUser()->getIntOption( 'rcdays' ) ); - $opts->add( 'limit', $this->getUser()->getIntOption( 'rclimit' ) ); + $opts->add( 'days', $user->getIntOption( 'rcdays' ) ); + $opts->add( 'limit', $user->getIntOption( 'rclimit' ) ); $opts->add( 'from', '' ); - $opts->add( 'hideminor', $this->getUser()->getBoolOption( 'hideminor' ) ); - $opts->add( 'hidebots', true ); + $opts->add( 'hideminor', $user->getBoolOption( 'hideminor' ) ); + $opts->add( 'hidebots', true ); $opts->add( 'hideanons', false ); $opts->add( 'hideliu', false ); - $opts->add( 'hidepatrolled', $this->getUser()->getBoolOption( 'hidepatrolled' ) ); + $opts->add( 'hidepatrolled', $user->getBoolOption( 'hidepatrolled' ) ); $opts->add( 'hidemyself', false ); $opts->add( 'namespace', '', FormOptions::INTNULL ); @@ -60,44 +61,47 @@ class SpecialRecentChanges extends IncludableSpecialPage { $opts->add( 'categories', '' ); $opts->add( 'categories_any', false ); $opts->add( 'tagfilter', '' ); + return $opts; } /** * Create a FormOptions object with options as specified by the user * - * @param $parameters array + * @param array $parameters * * @return FormOptions */ public function setup( $parameters ) { $opts = $this->getDefaultOptions(); - foreach( $this->getCustomFilters() as $key => $params ) { + foreach ( $this->getCustomFilters() as $key => $params ) { $opts->add( $key, $params['default'] ); } $opts->fetchValuesFromRequest( $this->getRequest() ); // Give precedence to subpage syntax - if( $parameters !== null ) { + if ( $parameters !== null ) { $this->parseParameters( $parameters, $opts ); } $opts->validateIntBounds( 'limit', 0, 5000 ); + return $opts; } /** * Get custom show/hide filters * - * @return Array Map of filter URL param names to properties (msg/default) + * @return array Map of filter URL param names to properties (msg/default) */ protected function getCustomFilters() { if ( $this->customFilters === null ) { $this->customFilters = array(); wfRunHooks( 'SpecialRecentChangesFilters', array( $this, &$this->customFilters ) ); } + return $this->customFilters; } @@ -111,6 +115,7 @@ class SpecialRecentChanges extends IncludableSpecialPage { $opts = $this->getDefaultOptions(); $opts->fetchValuesFromRequest( $this->getRequest() ); $opts->validateIntBounds( 'limit', 0, $wgFeedLimit ); + return $opts; } @@ -126,13 +131,14 @@ class SpecialRecentChanges extends IncludableSpecialPage { } $this->rcOptions = $isFeed ? $this->feedSetup() : $this->setup( $this->rcSubpage ); } + return $this->rcOptions; } /** * Main execution point * - * @param $subpage String + * @param string $subpage */ public function execute( $subpage ) { $this->rcSubpage = $subpage; @@ -142,36 +148,38 @@ class SpecialRecentChanges extends IncludableSpecialPage { $this->getOutput()->setSquidMaxage( 10 ); # Check if the client has a cached version $lastmod = $this->checkLastModified( $feedFormat ); - if( $lastmod === false ) { + if ( $lastmod === false ) { return; } $opts = $this->getOptions(); $this->setHeaders(); $this->outputHeader(); - $this->addRecentChangesJS(); + $this->addModules(); // Fetch results, prepare a batch link existence check query $conds = $this->buildMainQueryConds( $opts ); $rows = $this->doMainQuery( $conds, $opts ); - if( $rows === false ) { - if( !$this->including() ) { + if ( $rows === false ) { + if ( !$this->including() ) { $this->doHeader( $opts ); } + return; } - if( !$feedFormat ) { + if ( !$feedFormat ) { $batch = new LinkBatch; - foreach( $rows as $row ) { + foreach ( $rows as $row ) { $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(); } - if( $feedFormat ) { + if ( $feedFormat ) { list( $changesFeed, $formatter ) = $this->getFeedObject( $feedFormat ); + /** @var ChangesFeed $changesFeed */ $changesFeed->execute( $formatter, $rows, $lastmod, $opts ); } else { $this->webOutput( $rows, $opts ); @@ -183,7 +191,8 @@ class SpecialRecentChanges extends IncludableSpecialPage { /** * Return an array with a ChangesFeed object and ChannelFeed object * - * @return Array + * @param string $feedFormat Feed's format (either 'rss' or 'atom') + * @return array */ public function getFeedObject( $feedFormat ) { $changesFeed = new ChangesFeed( $feedFormat, 'rcfeed' ); @@ -192,6 +201,7 @@ class SpecialRecentChanges extends IncludableSpecialPage { $this->msg( 'recentchanges-feed-description' )->inContentLanguage()->text(), $this->getTitle()->getFullURL() ); + return array( $changesFeed, $formatter ); } @@ -199,49 +209,49 @@ class SpecialRecentChanges extends IncludableSpecialPage { * Process $par and put options found if $opts * Mainly used when including the page * - * @param $par String - * @param $opts FormOptions + * @param string $par + * @param FormOptions $opts */ public function parseParameters( $par, FormOptions $opts ) { $bits = preg_split( '/\s*,\s*/', trim( $par ) ); - foreach( $bits as $bit ) { - if( 'hidebots' === $bit ) { + foreach ( $bits as $bit ) { + if ( 'hidebots' === $bit ) { $opts['hidebots'] = true; } - if( 'bots' === $bit ) { + if ( 'bots' === $bit ) { $opts['hidebots'] = false; } - if( 'hideminor' === $bit ) { + if ( 'hideminor' === $bit ) { $opts['hideminor'] = true; } - if( 'minor' === $bit ) { + if ( 'minor' === $bit ) { $opts['hideminor'] = false; } - if( 'hideliu' === $bit ) { + if ( 'hideliu' === $bit ) { $opts['hideliu'] = true; } - if( 'hidepatrolled' === $bit ) { + if ( 'hidepatrolled' === $bit ) { $opts['hidepatrolled'] = true; } - if( 'hideanons' === $bit ) { + if ( 'hideanons' === $bit ) { $opts['hideanons'] = true; } - if( 'hidemyself' === $bit ) { + if ( 'hidemyself' === $bit ) { $opts['hidemyself'] = true; } - if( is_numeric( $bit ) ) { + if ( is_numeric( $bit ) ) { $opts['limit'] = $bit; } $m = array(); - if( preg_match( '/^limit=(\d+)$/', $bit, $m ) ) { + if ( preg_match( '/^limit=(\d+)$/', $bit, $m ) ) { $opts['limit'] = $m[1]; } - if( preg_match( '/^days=(\d+)$/', $bit, $m ) ) { + if ( preg_match( '/^days=(\d+)$/', $bit, $m ) ) { $opts['days'] = $m[1]; } - if( preg_match( '/^namespace=(\d+)$/', $bit, $m ) ) { + if ( preg_match( '/^namespace=(\d+)$/', $bit, $m ) ) { $opts['namespace'] = $m[1]; } } @@ -252,25 +262,26 @@ class SpecialRecentChanges extends IncludableSpecialPage { * Don't use this if we are using the patrol feature, patrol changes don't * update the timestamp * - * @param $feedFormat String - * @return String or false + * @param string $feedFormat + * @return string|bool */ public function checkLastModified( $feedFormat ) { $dbr = wfGetDB( DB_SLAVE ); $lastmod = $dbr->selectField( 'recentchanges', 'MAX(rc_timestamp)', false, __METHOD__ ); - if( $feedFormat || !$this->getUser()->useRCPatrol() ) { - if( $lastmod && $this->getOutput()->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; } } + return $lastmod; } /** * Return an array of conditions depending of options set in $opts * - * @param $opts FormOptions + * @param FormOptions $opts * @return array */ public function buildMainQueryConds( FormOptions $opts ) { @@ -280,9 +291,9 @@ class SpecialRecentChanges extends IncludableSpecialPage { # It makes no sense to hide both anons and logged-in users # Where this occurs, force anons to be shown $forcebot = false; - if( $opts['hideanons'] && $opts['hideliu'] ) { + if ( $opts['hideanons'] && $opts['hideliu'] ) { # Check if the user wants to show bots only - if( $opts['hidebots'] ) { + if ( $opts['hidebots'] ) { $opts['hideanons'] = false; } else { $forcebot = true; @@ -292,11 +303,11 @@ class SpecialRecentChanges extends IncludableSpecialPage { // Calculate cutoff $cutoff_unixtime = time() - ( $opts['days'] * 86400 ); - $cutoff_unixtime = $cutoff_unixtime - ($cutoff_unixtime % 86400); + $cutoff_unixtime = $cutoff_unixtime - ( $cutoff_unixtime % 86400 ); $cutoff = $dbr->timestamp( $cutoff_unixtime ); $fromValid = preg_match( '/^[0-9]{14}$/', $opts['from'] ); - if( $fromValid && $opts['from'] > wfTimestamp( TS_MW, $cutoff ) ) { + if ( $fromValid && $opts['from'] > wfTimestamp( TS_MW, $cutoff ) ) { $cutoff = $dbr->timestamp( $opts['from'] ); } else { $opts->reset( 'from' ); @@ -308,27 +319,27 @@ class SpecialRecentChanges extends IncludableSpecialPage { $hideLoggedInUsers = $opts['hideliu'] && !$forcebot; $hideAnonymousUsers = $opts['hideanons'] && !$forcebot; - if( $opts['hideminor'] ) { + if ( $opts['hideminor'] ) { $conds['rc_minor'] = 0; } - if( $opts['hidebots'] ) { + if ( $opts['hidebots'] ) { $conds['rc_bot'] = 0; } - if( $hidePatrol ) { + if ( $hidePatrol ) { $conds['rc_patrolled'] = 0; } - if( $forcebot ) { + if ( $forcebot ) { $conds['rc_bot'] = 1; } - if( $hideLoggedInUsers ) { + if ( $hideLoggedInUsers ) { $conds[] = 'rc_user = 0'; } - if( $hideAnonymousUsers ) { + if ( $hideAnonymousUsers ) { $conds[] = 'rc_user != 0'; } - if( $opts['hidemyself'] ) { - if( $this->getUser()->getId() ) { + if ( $opts['hidemyself'] ) { + if ( $this->getUser()->getId() ) { $conds[] = 'rc_user != ' . $dbr->addQuotes( $this->getUser()->getId() ); } else { $conds[] = 'rc_user_text != ' . $dbr->addQuotes( $this->getUser()->getName() ); @@ -336,13 +347,13 @@ class SpecialRecentChanges extends IncludableSpecialPage { } # Namespace filtering - if( $opts['namespace'] !== '' ) { + if ( $opts['namespace'] !== '' ) { $selectedNS = $dbr->addQuotes( $opts['namespace'] ); - $operator = $opts['invert'] ? '!=' : '='; + $operator = $opts['invert'] ? '!=' : '='; $boolean = $opts['invert'] ? 'AND' : 'OR'; # namespace association (bug 2429) - if( !$opts['associated'] ) { + if ( !$opts['associated'] ) { $condition = "rc_namespace $operator $selectedNS"; } else { # Also add the associated namespace @@ -356,15 +367,16 @@ class SpecialRecentChanges extends IncludableSpecialPage { $conds[] = $condition; } + return $conds; } /** * Process the query * - * @param $conds Array - * @param $opts FormOptions - * @return bool|ResultWrapper result or false (for Recentchangeslinked only) + * @param array $conds + * @param FormOptions $opts + * @return bool|ResultWrapper Result or false (for Recentchangeslinked only) */ public function doMainQuery( $conds, $opts ) { $tables = array( 'recentchanges' ); @@ -382,7 +394,7 @@ class SpecialRecentChanges extends IncludableSpecialPage { $fields = RecentChange::selectFields(); // JOIN on watchlist for users - if ( $uid ) { + if ( $uid && $this->getUser()->isAllowed( 'viewmywatchlist' ) ) { $tables[] = 'watchlist'; $fields[] = 'wl_user'; $fields[] = 'wl_notificationtimestamp'; @@ -390,7 +402,7 @@ class SpecialRecentChanges extends IncludableSpecialPage { 'wl_user' => $uid, 'wl_title=rc_title', 'wl_namespace=rc_namespace' - )); + ) ); } if ( $this->getUser()->isAllowed( 'rollback' ) ) { $tables[] = 'page'; @@ -408,91 +420,40 @@ class SpecialRecentChanges extends IncludableSpecialPage { ); if ( !wfRunHooks( 'SpecialRecentChangesQuery', - array( &$conds, &$tables, &$join_conds, $opts, &$query_options, &$fields ) ) ) - { + 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 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( $namespace === '' - || ( $invert || $associated ) - || $opts['tagfilter'] != '' - || !$dbr->unionSupportsOrderAndLimit() ) - { - $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, - $fields, - array( 'rc_new' => 1 ) + $conds, - __METHOD__, - array( - 'ORDER BY' => 'rc_timestamp DESC', - 'LIMIT' => $limit, - 'USE INDEX' => array( 'recentchanges' => 'new_name_timestamp' ) - ), - $join_conds - ); - // Old pages - $sqlOld = $dbr->selectSQLText( - $tables, - $fields, - array( 'rc_new' => 0 ) + $conds, - __METHOD__, - 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 ); - $res = $dbr->query( $sql, __METHOD__ ); - } - - return $res; + // rc_new is not an ENUM, but adding a redundant rc_new IN (0,1) gives mysql enough + // knowledge to use an index merge if it wants (it may use some other index though). + return $dbr->select( + $tables, + $fields, + $conds + array( 'rc_new' => array( 0, 1 ) ), + __METHOD__, + array( 'ORDER BY' => 'rc_timestamp DESC', 'LIMIT' => $limit ) + $query_options, + $join_conds + ); } /** * Send output to the OutputPage object, only called if not used feeds * - * @param array $rows of database rows - * @param $opts FormOptions + * @param array $rows Database rows + * @param FormOptions $opts */ public function webOutput( $rows, $opts ) { global $wgRCShowWatchingUsers, $wgShowUpdatedMarker, $wgAllowCategorizedRecentChanges; - $limit = $opts['limit']; - - if( !$this->including() ) { - // Output options box - $this->doHeader( $opts ); - } - - // And now for the content - $feedQuery = $this->getFeedQuery(); - if ( $feedQuery !== '' ) { - $this->getOutput()->setFeedAppendQuery( $feedQuery ); - } else { - $this->getOutput()->setFeedAppendQuery( false ); - } + // Build the final data - if( $wgAllowCategorizedRecentChanges ) { + if ( $wgAllowCategorizedRecentChanges ) { $this->filterByCategories( $rows, $opts ); } + $limit = $opts['limit']; + $showWatcherCount = $wgRCShowWatchingUsers && $this->getUser()->getOption( 'shownumberswatching' ); $watcherCache = array(); @@ -501,23 +462,23 @@ class SpecialRecentChanges extends IncludableSpecialPage { $counter = 1; $list = ChangesList::newFromContext( $this->getContext() ); - $s = $list->beginRecentChangesList(); - foreach( $rows as $obj ) { - if( $limit == 0 ) { + $rclistOutput = $list->beginRecentChangesList(); + foreach ( $rows as $obj ) { + 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 ) ) { + 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 ( $showWatcherCount && $obj->rc_namespace >= 0 ) { + if ( !isset( $watcherCache[$obj->rc_namespace][$obj->rc_title] ) ) { $watcherCache[$obj->rc_namespace][$obj->rc_title] = $dbr->selectField( 'watchlist', @@ -534,12 +495,34 @@ class SpecialRecentChanges extends IncludableSpecialPage { $changeLine = $list->recentChangesLine( $rc, !empty( $obj->wl_user ), $counter ); if ( $changeLine !== false ) { - $s .= $changeLine; + $rclistOutput .= $changeLine; --$limit; } } - $s .= $list->endRecentChangesList(); - $this->getOutput()->addHTML( $s ); + $rclistOutput .= $list->endRecentChangesList(); + + // Print things out + + if ( !$this->including() ) { + // Output options box + $this->doHeader( $opts ); + } + + // And now for the content + $feedQuery = $this->getFeedQuery(); + if ( $feedQuery !== '' ) { + $this->getOutput()->setFeedAppendQuery( $feedQuery ); + } else { + $this->getOutput()->setFeedAppendQuery( false ); + } + + if ( $rows->numRows() === 0 ) { + $this->getOutput()->wrapWikiMsg( + "
          \n$1\n
          ", 'recentchanges-noresult' + ); + } else { + $this->getOutput()->addHTML( $rclistOutput ); + } } /** @@ -567,8 +550,8 @@ class SpecialRecentChanges extends IncludableSpecialPage { /** * Return the text to be displayed above the changes * - * @param $opts FormOptions - * @return String: XHTML + * @param FormOptions $opts + * @return string XHTML */ public function doHeader( $opts ) { global $wgScript; @@ -577,10 +560,6 @@ class SpecialRecentChanges extends IncludableSpecialPage { $defaults = $opts->getAllValues(); $nondefaults = $opts->getChangedValues(); - $opts->consumeValues( array( - 'namespace', 'invert', 'associated', 'tagfilter', - 'categories', 'categories_any' - ) ); $panel = array(); $panel[] = $this->optionsPanel( $defaults, $nondefaults ); @@ -592,24 +571,36 @@ class SpecialRecentChanges extends IncludableSpecialPage { $submit = ' ' . Xml::submitbutton( $this->msg( 'allpagessubmit' )->text() ); $out = Xml::openElement( 'table', array( 'class' => 'mw-recentchanges-table' ) ); - foreach( $extraOpts as $name => $optionRow ) { + foreach ( $extraOpts as $name => $optionRow ) { # Add submit button to the last row only ++$count; $addSubmit = ( $count === $extraOptsCount ) ? $submit : ''; $out .= Xml::openElement( 'tr' ); - if( is_array( $optionRow ) ) { - $out .= Xml::tags( 'td', array( 'class' => 'mw-label mw-' . $name . '-label' ), $optionRow[0] ); - $out .= Xml::tags( 'td', array( 'class' => 'mw-input' ), $optionRow[1] . $addSubmit ); + if ( is_array( $optionRow ) ) { + $out .= Xml::tags( + 'td', + array( 'class' => 'mw-label mw-' . $name . '-label' ), + $optionRow[0] + ); + $out .= Xml::tags( + 'td', + array( 'class' => 'mw-input' ), + $optionRow[1] . $addSubmit + ); } else { - $out .= Xml::tags( 'td', array( 'class' => 'mw-input', 'colspan' => 2 ), $optionRow . $addSubmit ); + $out .= Xml::tags( + 'td', + array( 'class' => 'mw-input', 'colspan' => 2 ), + $optionRow . $addSubmit + ); } $out .= Xml::closeElement( 'tr' ); } $out .= Xml::closeElement( 'table' ); $unconsumed = $opts->getUnconsumedValues(); - foreach( $unconsumed as $key => $value ) { + foreach ( $unconsumed as $key => $value ) { $out .= Html::hidden( $key, $value ); } @@ -620,7 +611,11 @@ class SpecialRecentChanges extends IncludableSpecialPage { $panelString = implode( "\n", $panel ); $this->getOutput()->addHTML( - Xml::fieldset( $this->msg( 'recentchanges-legend' )->text(), $panelString, array( 'class' => 'rcoptions' ) ) + Xml::fieldset( + $this->msg( 'recentchanges-legend' )->text(), + $panelString, + array( 'class' => 'rcoptions' ) + ) ); $this->setBottomText( $opts ); @@ -629,15 +624,19 @@ class SpecialRecentChanges extends IncludableSpecialPage { /** * Get options to be displayed in a form * - * @param $opts FormOptions - * @return Array + * @param FormOptions $opts + * @return array */ function getExtraOptions( $opts ) { + $opts->consumeValues( array( + 'namespace', 'invert', 'associated', 'tagfilter', 'categories', 'categories_any' + ) ); + $extraOpts = array(); $extraOpts['namespace'] = $this->namespaceFilterForm( $opts ); global $wgAllowCategorizedRecentChanges; - if( $wgAllowCategorizedRecentChanges ) { + if ( $wgAllowCategorizedRecentChanges ) { $extraOpts['category'] = $this->categoryFilterForm( $opts ); } @@ -646,14 +645,18 @@ class SpecialRecentChanges extends IncludableSpecialPage { $extraOpts['tagfilter'] = $tagFilter; } - wfRunHooks( 'SpecialRecentChangesPanel', array( &$extraOpts, $opts ) ); + // Don't fire the hook for subclasses. (Or should we?) + if ( $this->getName() === 'Recentchanges' ) { + wfRunHooks( 'SpecialRecentChangesPanel', array( &$extraOpts, $opts ) ); + } + return $extraOpts; } /** * Send the text to be displayed above the options * - * @param $opts FormOptions + * @param FormOptions $opts Unused */ function setTopText( FormOptions $opts ) { global $wgContLang; @@ -672,19 +675,19 @@ class SpecialRecentChanges extends IncludableSpecialPage { } /** - * Send the text to be displayed after the options, for use in - * Recentchangeslinked + * Send the text to be displayed after the options, for use in subclasses. * - * @param $opts FormOptions + * @param FormOptions $opts */ - function setBottomText( FormOptions $opts ) {} + function setBottomText( FormOptions $opts ) { + } /** * Creates the choose namespace selection * * @todo Uses radio buttons (HASHAR) - * @param $opts FormOptions - * @return String + * @param FormOptions $opts + * @return string */ protected function namespaceFilterForm( FormOptions $opts ) { $nsSelect = Html::namespaceSelector( @@ -702,14 +705,15 @@ class SpecialRecentChanges extends IncludableSpecialPage { $opts['associated'], array( 'title' => $this->msg( 'tooltip-namespace_association' )->text() ) ); + return array( $nsLabel, "$nsSelect $invert $associated" ); } /** * Create a input to filter changes by categories * - * @param $opts FormOptions - * @return Array + * @param FormOptions $opts + * @return array */ protected function categoryFilterForm( FormOptions $opts ) { list( $label, $input ) = Xml::inputLabelSep( $this->msg( 'rc_categories' )->text(), @@ -724,21 +728,21 @@ class SpecialRecentChanges extends IncludableSpecialPage { /** * Filter $rows by categories set in $opts * - * @param array $rows of database rows - * @param $opts FormOptions + * @param array $rows Database rows + * @param FormOptions $opts */ function filterByCategories( &$rows, FormOptions $opts ) { $categories = array_map( 'trim', explode( '|', $opts['categories'] ) ); - if( !count( $categories ) ) { + if ( !count( $categories ) ) { return; } # Filter categories $cats = array(); - foreach( $categories as $cat ) { + foreach ( $categories as $cat ) { $cat = trim( $cat ); - if( $cat == '' ) { + if ( $cat == '' ) { continue; } $cats[] = $cat; @@ -748,16 +752,16 @@ 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 ) { + if ( $id == 0 ) { continue; # Page might have been deleted... } - if( !in_array( $id, $articles ) ) { + if ( !in_array( $id, $articles ) ) { $articles[] = $id; } - if( !isset( $a2r[$id] ) ) { + if ( !isset( $a2r[$id] ) ) { $a2r[$id] = array(); } $a2r[$id][] = $k; @@ -765,7 +769,7 @@ class SpecialRecentChanges extends IncludableSpecialPage { } # Shortcut? - if( !count( $articles ) || !count( $cats ) ) { + if ( !count( $articles ) || !count( $cats ) ) { return; } @@ -776,8 +780,8 @@ class SpecialRecentChanges extends IncludableSpecialPage { # 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]; } @@ -788,10 +792,10 @@ class SpecialRecentChanges extends IncludableSpecialPage { /** * Makes change an option link which carries all the other options * - * @param $title Title - * @param array $override options to override - * @param array $options current options - * @param $active Boolean: whether to show the link in bold + * @param string $title Title + * @param array $override Options to override + * @param array $options Current options + * @param bool $active Whether to show the link in bold * @return string */ function makeOptionsLink( $title, $override, $options, $active = false ) { @@ -810,14 +814,15 @@ class SpecialRecentChanges extends IncludableSpecialPage { if ( $active ) { $text = '' . $text . ''; } + return Linker::linkKnown( $this->getTitle(), $text, array(), $params ); } /** * Creates the options panel. * - * @param $defaults Array - * @param $nondefaults Array + * @param array $defaults + * @param array $nondefaults * @return string */ function optionsPanel( $defaults, $nondefaults ) { @@ -827,13 +832,13 @@ class SpecialRecentChanges extends IncludableSpecialPage { $note = ''; $msg = $this->msg( 'rclegend' ); - if( !$msg->isDisabled() ) { + if ( !$msg->isDisabled() ) { $note .= '
          ' . $msg->parse() . "
          \n"; } $lang = $this->getLanguage(); $user = $this->getUser(); - if( $options['from'] ) { + if ( $options['from'] ) { $note .= $this->msg( 'rcnotefrom' )->numParams( $options['limit'] )->params( $lang->userTimeAndDate( $options['from'], $user ), $lang->userDate( $options['from'], $user ), @@ -841,22 +846,27 @@ class SpecialRecentChanges extends IncludableSpecialPage { } # Sort data for display and make sure it's unique after we've added user data. - $wgRCLinkLimits[] = $options['limit']; - $wgRCLinkDays[] = $options['days']; - sort( $wgRCLinkLimits ); - sort( $wgRCLinkDays ); - $wgRCLinkLimits = array_unique( $wgRCLinkLimits ); - $wgRCLinkDays = array_unique( $wgRCLinkDays ); + $linkLimits = $wgRCLinkLimits; + $linkLimits[] = $options['limit']; + sort( $linkLimits ); + $linkLimits = array_unique( $linkLimits ); + + $linkDays = $wgRCLinkDays; + $linkDays[] = $options['days']; + sort( $linkDays ); + $linkDays = array_unique( $linkDays ); // limit links - foreach( $wgRCLinkLimits as $value ) { + $cl = array(); + foreach ( $linkLimits as $value ) { $cl[] = $this->makeOptionsLink( $lang->formatNum( $value ), array( 'limit' => $value ), $nondefaults, $value == $options['limit'] ); } $cl = $lang->pipeList( $cl ); // day links, reset 'from' to none - foreach( $wgRCLinkDays as $value ) { + $dl = array(); + foreach ( $linkDays as $value ) { $dl[] = $this->makeOptionsLink( $lang->formatNum( $value ), array( 'days' => $value, 'from' => '' ), $nondefaults, $value == $options['days'] ); } @@ -865,12 +875,12 @@ class SpecialRecentChanges extends IncludableSpecialPage { // show/hide links $showhide = array( $this->msg( 'show' )->text(), $this->msg( 'hide' )->text() ); $filters = array( - 'hideminor' => 'rcshowhideminor', - 'hidebots' => 'rcshowhidebots', - 'hideanons' => 'rcshowhideanons', - 'hideliu' => 'rcshowhideliu', + 'hideminor' => 'rcshowhideminor', + 'hidebots' => 'rcshowhidebots', + 'hideanons' => 'rcshowhideanons', + 'hideliu' => 'rcshowhideliu', 'hidepatrolled' => 'rcshowhidepatr', - 'hidemyself' => 'rcshowhidemine' + 'hidemyself' => 'rcshowhidemine' ); foreach ( $this->getCustomFilters() as $key => $params ) { $filters[$key] = $params['msg']; @@ -883,7 +893,7 @@ class SpecialRecentChanges extends IncludableSpecialPage { $links = array(); foreach ( $filters as $key => $msg ) { $link = $this->makeOptionsLink( $showhide[1 - $options[$key]], - array( $key => 1-$options[$key] ), $nondefaults ); + array( $key => 1 - $options[$key] ), $nondefaults ); $links[] = $this->msg( $msg )->rawParams( $link )->escaped(); } @@ -894,15 +904,17 @@ class SpecialRecentChanges extends IncludableSpecialPage { $now, array( 'from' => $timestamp ), $nondefaults ); - $rclinks = $this->msg( 'rclinks' )->rawParams( $cl, $dl, $lang->pipeList( $links ) )->parse(); + $rclinks = $this->msg( 'rclinks' )->rawParams( $cl, $dl, $lang->pipeList( $links ) ) + ->parse(); $rclistfrom = $this->msg( 'rclistfrom' )->rawParams( $tl )->parse(); + return "{$note}$rclinks
          $rclistfrom"; } /** - * add javascript specific to the [[Special:RecentChanges]] page + * Add page-specific modules. */ - function addRecentChangesJS() { + protected function addModules() { $this->getOutput()->addModules( array( 'mediawiki.special.recentchanges', ) ); diff --git a/includes/specials/SpecialRecentchangeslinked.php b/includes/specials/SpecialRecentchangeslinked.php index 391c4a7f..a8447046 100644 --- a/includes/specials/SpecialRecentchangeslinked.php +++ b/includes/specials/SpecialRecentchangeslinked.php @@ -56,7 +56,7 @@ class SpecialRecentchangeslinked extends SpecialRecentChanges { $this->msg( 'recentchangeslinked-title', $this->getTargetTitle()->getPrefixedText() ) ->inContentLanguage()->text(), $this->msg( 'recentchangeslinked-feed' )->inContentLanguage()->text(), - $this->getTitle()->getFullUrl() + $this->getTitle()->getFullURL() ); return array( $feed, $feedObj ); } @@ -71,8 +71,8 @@ class SpecialRecentchangeslinked extends SpecialRecentChanges { } $outputPage = $this->getOutput(); $title = Title::newFromURL( $target ); - if( !$title || $title->getInterwiki() != '' ) { - $outputPage->wrapWikiMsg( "
          \n$1\n

          ", 'allpagesbadtitle' ); + if ( !$title || $title->getInterwiki() != '' ) { + $outputPage->wrapWikiMsg( "
          \n$1\n
          ", 'allpagesbadtitle' ); return false; } @@ -99,7 +99,7 @@ class SpecialRecentchangeslinked extends SpecialRecentChanges { // left join with watchlist table to highlight watched rows $uid = $this->getUser()->getId(); - if( $uid ) { + if ( $uid && $this->getUser()->isAllowed( 'viewmywatchlist' ) ) { $tables[] = 'watchlist'; $select[] = 'wl_user'; $join_conds['watchlist'] = array( 'LEFT JOIN', array( @@ -126,7 +126,7 @@ class SpecialRecentchangeslinked extends SpecialRecentChanges { return false; } - if( $ns == NS_CATEGORY && !$showlinkedto ) { + if ( $ns == NS_CATEGORY && !$showlinkedto ) { // special handling for categories // XXX: should try to make this less kludgy $link_tables = array( 'categorylinks' ); @@ -135,12 +135,12 @@ class SpecialRecentchangeslinked extends SpecialRecentChanges { // for now, always join on these tables; really should be configurable as in whatlinkshere $link_tables = array( 'pagelinks', 'templatelinks' ); // imagelinks only contains links to pages in NS_FILE - if( $ns == NS_FILE || !$showlinkedto ) { + if ( $ns == NS_FILE || !$showlinkedto ) { $link_tables[] = 'imagelinks'; } } - if( $id == 0 && !$showlinkedto ) { + if ( $id == 0 && !$showlinkedto ) { return false; // nonexistent pages can't link to any pages } @@ -149,22 +149,22 @@ class SpecialRecentchangeslinked extends SpecialRecentChanges { $subsql = array(); // SELECT statements to combine with UNION - foreach( $link_tables as $link_table ) { + foreach ( $link_tables as $link_table ) { $pfx = $prefix[$link_table]; // imagelinks and categorylinks tables have no xx_namespace field, and have xx_to instead of xx_title - if( $link_table == 'imagelinks' ) { + if ( $link_table == 'imagelinks' ) { $link_ns = NS_FILE; - } elseif( $link_table == 'categorylinks' ) { + } elseif ( $link_table == 'categorylinks' ) { $link_ns = NS_CATEGORY; } else { $link_ns = 0; } - if( $showlinkedto ) { + if ( $showlinkedto ) { // find changes to pages linking to this page - if( $link_ns ) { - if( $ns != $link_ns ) { + if ( $link_ns ) { + if ( $ns != $link_ns ) { continue; } // should never happen, but check anyway $subconds = array( "{$pfx}_to" => $dbkey ); @@ -175,7 +175,7 @@ class SpecialRecentchangeslinked extends SpecialRecentChanges { } else { // find changes to pages linked from this page $subconds = array( "{$pfx}_from" => $id ); - if( $link_table == 'imagelinks' || $link_table == 'categorylinks' ) { + if ( $link_table == 'imagelinks' || $link_table == 'categorylinks' ) { $subconds["rc_namespace"] = $link_ns; $subjoin = "rc_title = {$pfx}_to"; } else { @@ -183,7 +183,7 @@ class SpecialRecentchangeslinked extends SpecialRecentChanges { } } - if( $dbr->unionSupportsOrderAndLimit()) { + if ( $dbr->unionSupportsOrderAndLimit() ) { $order = array( 'ORDER BY' => 'rc_timestamp DESC' ); } else { $order = array(); @@ -198,16 +198,17 @@ class SpecialRecentchangeslinked extends SpecialRecentChanges { $join_conds + array( $link_table => array( 'INNER JOIN', $subjoin ) ) ); - if( $dbr->unionSupportsOrderAndLimit()) + if ( $dbr->unionSupportsOrderAndLimit() ) { $query = $dbr->limitResult( $query, $limit ); + } $subsql[] = $query; } - if( count( $subsql ) == 0 ) { + if ( count( $subsql ) == 0 ) { return false; // should never happen } - if( count( $subsql ) == 1 && $dbr->unionSupportsOrderAndLimit() ) { + if ( count( $subsql ) == 1 && $dbr->unionSupportsOrderAndLimit() ) { $sql = $subsql[0]; } else { // need to resort and relimit after union @@ -217,7 +218,7 @@ class SpecialRecentchangeslinked extends SpecialRecentChanges { $res = $dbr->query( $sql, __METHOD__ ); - if( $res->numRows() == 0 ) { + if ( $res->numRows() == 0 ) { $this->mResultEmpty = true; } @@ -225,21 +226,21 @@ class SpecialRecentchangeslinked extends SpecialRecentChanges { } /** - * @param $opts FormOptions + * Get options to be displayed in a form + * + * @param FormOptions $opts * @return array */ function getExtraOptions( $opts ) { - $opts->consumeValues( array( 'showlinkedto', 'target', 'tagfilter' ) ); - $extraOpts = array(); - $extraOpts['namespace'] = $this->namespaceFilterForm( $opts ); + $extraOpts = parent::getExtraOptions( $opts ); + + $opts->consumeValues( array( 'showlinkedto', 'target' ) ); + $extraOpts['target'] = array( $this->msg( 'recentchangeslinked-page' )->escaped(), Xml::input( 'target', 40, str_replace( '_', ' ', $opts['target'] ) ) . Xml::check( 'showlinkedto', $opts['showlinkedto'], array( 'id' => 'showlinkedto' ) ) . ' ' . Xml::label( $this->msg( 'recentchangeslinked-to' )->text(), 'showlinkedto' ) ); - $tagFilter = ChangeTags::buildTagFilterSelector( $opts['tagfilter'] ); - if ( $tagFilter ) { - $extraOpts['tagfilter'] = $tagFilter; - } + return $extraOpts; } @@ -260,14 +261,8 @@ class SpecialRecentchangeslinked extends SpecialRecentChanges { function setTopText( FormOptions $opts ) { $target = $this->getTargetTitle(); - if( $target ) { + if ( $target ) { $this->getOutput()->addBacklinkSubtitle( $target ); } } - - function setBottomText( FormOptions $opts ) { - if( isset( $this->mResultEmpty ) && $this->mResultEmpty ) { - $this->getOutput()->addWikiMsg( 'recentchangeslinked-noresult' ); - } - } } diff --git a/includes/specials/SpecialRedirect.php b/includes/specials/SpecialRedirect.php new file mode 100644 index 00000000..f05dacbc --- /dev/null +++ b/includes/specials/SpecialRedirect.php @@ -0,0 +1,235 @@ +mType = null; + $this->mValue = null; + } + + /** + * Set $mType and $mValue based on parsed value of $subpage. + */ + function setParameter( $subpage ) { + // parse $subpage to pull out the parts + $parts = explode( '/', $subpage, 2 ); + $this->mType = count( $parts ) > 0 ? $parts[0] : null; + $this->mValue = count( $parts ) > 1 ? $parts[1] : null; + } + + /** + * Handle Special:Redirect/user/xxxx (by redirecting to User:YYYY) + * + * @return string|null url to redirect to, or null if $mValue is invalid. + */ + function dispatchUser() { + if ( !ctype_digit( $this->mValue ) ) { + return null; + } + $user = User::newFromId( (int)$this->mValue ); + $username = $user->getName(); // load User as side-effect + if ( $user->isAnon() ) { + return null; + } + $userpage = Title::makeTitle( NS_USER, $username ); + return $userpage->getFullURL( '', false, PROTO_CURRENT ); + } + + /** + * Handle Special:Redirect/file/xxxx + * + * @return string|null url to redirect to, or null if $mValue is not found. + */ + function dispatchFile() { + $title = Title::makeTitleSafe( NS_FILE, $this->mValue ); + + if ( ! $title instanceof Title ) { + return null; + } + $file = wfFindFile( $title ); + + if ( !$file || !$file->exists() ) { + return null; + } + // Default behavior: Use the direct link to the file. + $url = $file->getURL(); + $request = $this->getRequest(); + $width = $request->getInt( 'width', -1 ); + $height = $request->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(); + } + } + return $url; + } + + /** + * Handle Special:Redirect/revision/xxx + * (by redirecting to index.php?oldid=xxx) + * + * @return string|null url to redirect to, or null if $mValue is invalid. + */ + function dispatchRevision() { + $oldid = $this->mValue; + if ( !ctype_digit( $oldid ) ) { + return null; + } + $oldid = (int)$oldid; + if ( $oldid === 0 ) { + return null; + } + return wfAppendQuery( wfScript( 'index' ), array( + 'oldid' => $oldid + ) ); + } + + /** + * Use appropriate dispatch* method to obtain a redirection URL, + * and either: redirect, set a 404 error code and error message, + * or do nothing (if $mValue wasn't set) allowing the form to be + * displayed. + * + * @return bool true if a redirect was successfully handled. + */ + function dispatch() { + // the various namespaces supported by Special:Redirect + switch ( $this->mType ) { + case 'user': + $url = $this->dispatchUser(); + break; + case 'file': + $url = $this->dispatchFile(); + break; + case 'revision': + $url = $this->dispatchRevision(); + break; + default: + $this->getOutput()->setStatusCode( 404 ); + $url = null; + break; + } + if ( $url ) { + $this->getOutput()->redirect( $url ); + return true; + } + if ( !is_null( $this->mValue ) ) { + $this->getOutput()->setStatusCode( 404 ); + // Message: redirect-not-exists + $msg = $this->getMessagePrefix() . '-not-exists'; + return Status::newFatal( $msg ); + } + return false; + } + + protected function getFormFields() { + $mp = $this->getMessagePrefix(); + $ns = array( + // subpage => message + // Messages: redirect-user, redirect-revision, redirect-file + 'user' => $mp . '-user', + 'revision' => $mp . '-revision', + 'file' => $mp . '-file', + ); + $a = array(); + $a['type'] = array( + 'type' => 'select', + 'label-message' => $mp . '-lookup', // Message: redirect-lookup + 'options' => array(), + 'default' => current( array_keys( $ns ) ), + ); + foreach ( $ns as $n => $m ) { + $m = $this->msg( $m )->text(); + $a['type']['options'][$m] = $n; + } + $a['value'] = array( + 'type' => 'text', + 'label-message' => $mp . '-value' // Message: redirect-value + ); + // set the defaults according to the parsed subpage path + if ( !empty( $this->mType ) ) { + $a['type']['default'] = $this->mType; + } + if ( !empty( $this->mValue ) ) { + $a['value']['default'] = $this->mValue; + } + return $a; + } + + public function onSubmit( array $data ) { + if ( !empty( $data['type'] ) && !empty( $data['value'] ) ) { + $this->setParameter( $data['type'] . '/' . $data['value'] ); + } + /* if this returns false, will show the form */ + return $this->dispatch(); + } + + public function onSuccess() { + /* do nothing, we redirect in $this->dispatch if successful. */ + } + + protected function alterForm( HTMLForm $form ) { + /* display summary at top of page */ + $this->outputHeader(); + // tweak label on submit button + // Message: redirect-submit + $form->setSubmitTextMsg( $this->getMessagePrefix() . '-submit' ); + /* submit form every time */ + $form->setMethod( 'get' ); + } + + protected function getGroupName() { + return 'redirects'; + } +} diff --git a/includes/specials/SpecialResetTokens.php b/includes/specials/SpecialResetTokens.php new file mode 100644 index 00000000..ef2a45da --- /dev/null +++ b/includes/specials/SpecialResetTokens.php @@ -0,0 +1,145 @@ +tokensList ) ) { + $tokens = array( + array( 'preference' => 'watchlisttoken', 'label-message' => 'resettokens-watchlist-token' ), + ); + wfRunHooks( 'SpecialResetTokensTokens', array( &$tokens ) ); + + $tokens = array_filter( $tokens, function ( $tok ) use ( $wgHiddenPrefs ) { + return !in_array( $tok['preference'], $wgHiddenPrefs ); + } ); + + $this->tokensList = $tokens; + } + + return $this->tokensList; + } + + public function execute( $par ) { + // This is a preferences page, so no user JS for y'all. + $this->getOutput()->disallowUserJs(); + + parent::execute( $par ); + + $this->getOutput()->addReturnTo( SpecialPage::getTitleFor( 'Preferences' ) ); + } + + public function onSuccess() { + $this->getOutput()->wrapWikiMsg( + "
          \n$1\n
          ", + 'resettokens-done' + ); + } + + /** + * Display appropriate message if there's nothing to do. + * The submit button is also suppressed in this case (see alterForm()). + */ + protected function getFormFields() { + $user = $this->getUser(); + $tokens = $this->getTokensList(); + + if ( $tokens ) { + $tokensForForm = array(); + foreach ( $tokens as $tok ) { + $label = $this->msg( 'resettokens-token-label' ) + ->rawParams( $this->msg( $tok['label-message'] )->parse() ) + ->params( $user->getTokenFromOption( $tok['preference'] ) ) + ->escaped(); + $tokensForForm[ $label ] = $tok['preference']; + } + + $desc = array( + 'label-message' => 'resettokens-tokens', + 'type' => 'multiselect', + 'options' => $tokensForForm, + ); + } else { + $desc = array( + 'label-message' => 'resettokens-no-tokens', + 'type' => 'info', + ); + } + + return array( + 'tokens' => $desc, + ); + } + + /** + * Suppress the submit button if there's nothing to do; + * provide additional message on it otherwise. + */ + protected function alterForm( HTMLForm $form ) { + if ( $this->getTokensList() ) { + $form->setSubmitTextMsg( 'resettokens-resetbutton' ); + } else { + $form->suppressDefaultSubmit(); + } + } + + public function onSubmit( array $formData ) { + if ( $formData['tokens'] ) { + $user = $this->getUser(); + foreach ( $formData['tokens'] as $tokenPref ) { + $user->resetTokenFromOption( $tokenPref ); + } + $user->saveSettings(); + + return true; + } + + return false; + } + + protected function getGroupName() { + return 'users'; + } + + public function isListed() { + return (bool)$this->getTokensList(); + } +} diff --git a/includes/specials/SpecialRevisiondelete.php b/includes/specials/SpecialRevisiondelete.php index 5a5f8ffb..825be6c4 100644 --- a/includes/specials/SpecialRevisiondelete.php +++ b/includes/specials/SpecialRevisiondelete.php @@ -49,68 +49,43 @@ class SpecialRevisionDelete extends UnlistedSpecialPage { /** Array of checkbox specs (message, name, deletion bits) */ var $checks; - /** Information about the current type */ - var $typeInfo; + /** UI Labels about the current type */ + var $typeLabels; /** The RevDel_List object, storing the list of items to be deleted/undeleted */ var $list; /** - * Assorted information about each type, needed by the special page. - * TODO Move some of this to the list class + * UI labels for each type. */ - static $allowedTypes = array( + static $UILabels = array( 'revision' => array( 'check-label' => 'revdelete-hide-text', - 'deletion-bits' => Revision::DELETED_TEXT, 'success' => 'revdelete-success', 'failure' => 'revdelete-failure', - 'list-class' => 'RevDel_RevisionList', - 'permission' => 'deleterevision', ), 'archive' => array( 'check-label' => 'revdelete-hide-text', - 'deletion-bits' => Revision::DELETED_TEXT, 'success' => 'revdelete-success', 'failure' => 'revdelete-failure', - 'list-class' => 'RevDel_ArchiveList', - 'permission' => 'deleterevision', ), - 'oldimage'=> array( + 'oldimage' => array( 'check-label' => 'revdelete-hide-image', - 'deletion-bits' => File::DELETED_FILE, 'success' => 'revdelete-success', 'failure' => 'revdelete-failure', - 'list-class' => 'RevDel_FileList', - 'permission' => 'deleterevision', ), 'filearchive' => array( 'check-label' => 'revdelete-hide-image', - 'deletion-bits' => File::DELETED_FILE, 'success' => 'revdelete-success', 'failure' => 'revdelete-failure', - 'list-class' => 'RevDel_ArchivedFileList', - 'permission' => 'deleterevision', ), 'logging' => array( 'check-label' => 'revdelete-hide-name', - 'deletion-bits' => LogPage::DELETED_ACTION, 'success' => 'logdelete-success', 'failure' => 'logdelete-failure', - 'list-class' => 'RevDel_LogList', - 'permission' => 'deletelogentry', ), ); - /** Type map to support old log entries */ - static $deprecatedTypeMap = array( - 'oldid' => 'revision', - 'artimestamp' => 'archive', - 'oldimage' => 'oldimage', - 'fileid' => 'filearchive', - 'logid' => 'logging', - ); - public function __construct() { parent::__construct( 'Revisiondelete', 'deletedhistory' ); } @@ -147,19 +122,6 @@ class SpecialRevisionDelete extends UnlistedSpecialPage { } else { $this->typeName = $request->getVal( 'type' ); $this->targetObj = Title::newFromText( $request->getText( 'target' ) ); - if ( $this->targetObj && $this->targetObj->isSpecial( 'Log' ) && count( $this->ids ) !== 0 ) { - $result = wfGetDB( DB_SLAVE )->select( 'logging', - 'log_type', - array( 'log_id' => $this->ids ), - __METHOD__, - array( 'DISTINCT' ) - ); - - if ( $result->numRows() == 1 ) { - // If there's only one type, the target can be set to include it. - $this->targetObj = SpecialPage::getTitleFor( 'Log', $result->current()->log_type ); - } - } } # For reviewing deleted files... @@ -170,28 +132,21 @@ class SpecialRevisionDelete extends UnlistedSpecialPage { return; } - if ( isset( self::$deprecatedTypeMap[$this->typeName] ) ) { - $this->typeName = self::$deprecatedTypeMap[$this->typeName]; - } + $this->typeName = RevisionDeleter::getCanonicalTypeName( $this->typeName ); # No targets? - if( !isset( self::$allowedTypes[$this->typeName] ) || count( $this->ids ) == 0 ) { + if ( !$this->typeName || count( $this->ids ) == 0 ) { throw new ErrorPageError( 'revdelete-nooldid-title', 'revdelete-nooldid-text' ); } - $this->typeInfo = self::$allowedTypes[$this->typeName]; - $this->mIsAllowed = $user->isAllowed( $this->typeInfo['permission'] ); - - # If we have revisions, get the title from the first one - # 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->typeLabels = self::$UILabels[$this->typeName]; + $this->mIsAllowed = $user->isAllowed( RevisionDeleter::getRestriction( $this->typeName ) ); + + # Allow the list type to adjust the passed target + $this->targetObj = RevisionDeleter::suggestTarget( $this->typeName, $this->targetObj, $this->ids ); $this->otherReason = $request->getVal( 'wpReason' ); # We need a target page! - if( is_null( $this->targetObj ) ) { + if ( is_null( $this->targetObj ) ) { $output->addWikiMsg( 'undelete-header' ); return; } @@ -200,17 +155,19 @@ class SpecialRevisionDelete extends UnlistedSpecialPage { # Initialise checkboxes $this->checks = array( - array( $this->typeInfo['check-label'], 'wpHidePrimary', $this->typeInfo['deletion-bits'] ), + array( $this->typeLabels['check-label'], 'wpHidePrimary', + RevisionDeleter::getRevdelConstant( $this->typeName ) + ), array( 'revdelete-hide-comment', 'wpHideComment', Revision::DELETED_COMMENT ), array( 'revdelete-hide-user', 'wpHideUser', Revision::DELETED_USER ) ); - if( $user->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 ) { + if ( $this->mIsAllowed && $this->submitClicked ) { $this->submit( $request ); } else { $this->showForm(); @@ -223,7 +180,7 @@ class SpecialRevisionDelete extends UnlistedSpecialPage { LogEventsList::showLogExtract( $output, 'delete', $this->targetObj, '', array( 'lim' => 25, 'conds' => $qc ) ); # Show relevant lines from the suppression log - if( $user->isAllowed( 'suppressionlog' ) ) { + if ( $user->isAllowed( 'suppressionlog' ) ) { $suppressLogPage = new LogPage( 'suppress' ); $output->addHTML( "

          " . $suppressLogPage->getName()->escaped() . "

          \n" ); LogEventsList::showLogExtract( $output, 'suppress', @@ -236,7 +193,7 @@ class SpecialRevisionDelete extends UnlistedSpecialPage { */ protected function showConvenienceLinks() { # Give a link to the logs/hist for this page - if( $this->targetObj ) { + if ( $this->targetObj ) { $links = array(); $links[] = Linker::linkKnown( SpecialPage::getTitleFor( 'Log' ), @@ -253,7 +210,7 @@ class SpecialRevisionDelete extends UnlistedSpecialPage { array( 'action' => 'history' ) ); # Link to deleted edits - if( $this->getUser()->isAllowed( 'undelete' ) ) { + if ( $this->getUser()->isAllowed( 'undelete' ) ) { $undelete = SpecialPage::getTitleFor( 'Undelete' ); $links[] = Linker::linkKnown( $undelete, @@ -296,8 +253,8 @@ class SpecialRevisionDelete extends UnlistedSpecialPage { return; } $user = $this->getUser(); - if( !$oimage->userCan( File::DELETED_FILE, $user ) ) { - if( $oimage->isDeleted( File::DELETED_RESTRICTED ) ) { + if ( !$oimage->userCan( File::DELETED_FILE, $user ) ) { + if ( $oimage->isDeleted( File::DELETED_RESTRICTED ) ) { throw new PermissionsError( 'suppressrevision' ); } else { throw new PermissionsError( 'deletedtext' ); @@ -312,10 +269,11 @@ class SpecialRevisionDelete extends UnlistedSpecialPage { $this->getOutput()->addHTML( Xml::openElement( 'form', array( 'method' => 'POST', - 'action' => $this->getTitle()->getLocalUrl( - 'target=' . urlencode( $this->targetObj->getPrefixedDBkey() ) . - '&file=' . urlencode( $archiveName ) . - '&token=' . urlencode( $user->getEditToken( $archiveName ) ) ) + 'action' => $this->getTitle()->getLocalURL( array( + 'target' => $this->targetObj->getPrefixedDBkey(), + 'file' => $archiveName, + 'token' => $user->getEditToken( $archiveName ), + ) ) ) ) . Xml::submitButton( $this->msg( 'revdelete-show-file-submit' )->text() ) . @@ -342,8 +300,9 @@ class SpecialRevisionDelete extends UnlistedSpecialPage { */ protected function getList() { if ( is_null( $this->list ) ) { - $class = $this->typeInfo['list-class']; - $this->list = new $class( $this->getContext(), $this->targetObj, $this->ids ); + $this->list = RevisionDeleter::createList( + $this->typeName, $this->getContext(), $this->targetObj, $this->ids + ); } return $this->list; } @@ -370,7 +329,7 @@ class SpecialRevisionDelete extends UnlistedSpecialPage { for ( $list->reset(); $list->current(); $list->next() ) { $item = $list->current(); if ( !$item->canView() ) { - if( !$this->submitClicked ) { + if ( !$this->submitClicked ) { throw new PermissionsError( 'suppressrevision' ); } $UserAllowed = false; @@ -379,7 +338,7 @@ class SpecialRevisionDelete extends UnlistedSpecialPage { $this->getOutput()->addHTML( $item->getHTML() ); } - if( !$numRevisions ) { + if ( !$numRevisions ) { throw new ErrorPageError( 'revdelete-nooldid-title', 'revdelete-nooldid-text' ); } @@ -388,12 +347,14 @@ class SpecialRevisionDelete extends UnlistedSpecialPage { $this->addUsageText(); // Normal sysops can always see what they did, but can't always change it - if( !$UserAllowed ) return; + if ( !$UserAllowed ) { + return; + } // Show form if the user can submit - if( $this->mIsAllowed ) { + 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( $this->msg( 'revdelete-legend' )->text() ) . $this->buildCheckBoxes() . @@ -406,7 +367,7 @@ class SpecialRevisionDelete extends UnlistedSpecialPage { Xml::listDropDown( 'wpRevDeleteReasonList', $this->msg( 'revdelete-reason-dropdown' )->inContentLanguage()->text(), $this->msg( 'revdelete-reasonotherlist' )->inContentLanguage()->text(), - '', 'wpReasonDropDown', 1 + $this->getRequest()->getText( 'wpRevDeleteReasonList', 'other' ), 'wpReasonDropDown', 1 ) . '' . "\n" . @@ -432,10 +393,10 @@ class SpecialRevisionDelete extends UnlistedSpecialPage { } else { $out = ''; } - if( $this->mIsAllowed ) { + if ( $this->mIsAllowed ) { $out .= Xml::closeElement( 'form' ) . "\n"; // Show link to edit the dropdown reasons - if( $this->getUser()->isAllowed( 'editinterface' ) ) { + if ( $this->getUser()->isAllowed( 'editinterface' ) ) { $title = Title::makeTitle( NS_MEDIAWIKI, 'Revdelete-reason-dropdown' ); $link = Linker::link( $title, @@ -455,10 +416,10 @@ class SpecialRevisionDelete extends UnlistedSpecialPage { */ protected function addUsageText() { $this->getOutput()->addWikiMsg( 'revdelete-text' ); - if( $this->getUser()->isAllowed( 'suppressrevision' ) ) { + if ( $this->getUser()->isAllowed( 'suppressrevision' ) ) { $this->getOutput()->addWikiMsg( 'revdelete-suppress-text' ); } - if( $this->mIsAllowed ) { + if ( $this->mIsAllowed ) { $this->getOutput()->addWikiMsg( 'revdelete-confirm' ); } } @@ -470,17 +431,18 @@ class SpecialRevisionDelete extends UnlistedSpecialPage { $html = ''; // If there is just one item, use checkboxes $list = $this->getList(); - if( $list->length() == 1 ) { + if ( $list->length() == 1 ) { $list->reset(); $bitfield = $list->current()->getBits(); // existing field - if( $this->submitClicked ) { + if ( $this->submitClicked ) { $bitfield = $this->extractBitfield( $this->extractBitParams(), $bitfield ); } - foreach( $this->checks as $item ) { + foreach ( $this->checks as $item ) { list( $message, $name, $field ) = $item; $innerHTML = Xml::checkLabel( $this->msg( $message )->text(), $name, $name, $bitfield & $field ); - if( $field == Revision::DELETED_RESTRICTED ) + if ( $field == Revision::DELETED_RESTRICTED ) { $innerHTML = "$innerHTML"; + } $line = Xml::tags( 'td', array( 'class' => 'mw-input' ), $innerHTML ); $html .= "$line\n"; } @@ -491,10 +453,10 @@ class SpecialRevisionDelete extends UnlistedSpecialPage { $html .= ''; $html .= ''; $html .= "\n"; - foreach( $this->checks as $item ) { + foreach ( $this->checks as $item ) { list( $message, $name, $field ) = $item; // If there are several items, use third state by default... - if( $this->submitClicked ) { + if ( $this->submitClicked ) { $selected = $this->getRequest()->getInt( $name, 0 /* unchecked */ ); } else { $selected = -1; // use existing field @@ -503,7 +465,7 @@ class SpecialRevisionDelete extends UnlistedSpecialPage { $line .= ''; $line .= ''; $label = $this->msg( $message )->escaped(); - if( $field == Revision::DELETED_RESTRICTED ) { + if ( $field == Revision::DELETED_RESTRICTED ) { $label = "$label"; } $line .= ""; @@ -523,21 +485,21 @@ class SpecialRevisionDelete extends UnlistedSpecialPage { protected function submit() { # Check edit token on submission $token = $this->getRequest()->getVal( 'wpEditToken' ); - if( $this->submitClicked && !$this->getUser()->matchEditToken( $token ) ) { + if ( $this->submitClicked && !$this->getUser()->matchEditToken( $token ) ) { $this->getOutput()->addWikiMsg( 'sessionfailure' ); return false; } $bitParams = $this->extractBitParams(); $listReason = $this->getRequest()->getText( 'wpRevDeleteReasonList', 'other' ); // from dropdown $comment = $listReason; - if( $comment != 'other' && $this->otherReason != '' ) { + if ( $comment != 'other' && $this->otherReason != '' ) { // Entry from drop down menu + additional comment $comment .= $this->msg( 'colon-separator' )->inContentLanguage()->text() . $this->otherReason; - } elseif( $comment == 'other' ) { + } elseif ( $comment == 'other' ) { $comment = $this->otherReason; } # Can the user set this field? - if( $bitParams[Revision::DELETED_RESTRICTED] == 1 && !$this->getUser()->isAllowed( 'suppressrevision' ) ) { + if ( $bitParams[Revision::DELETED_RESTRICTED] == 1 && !$this->getUser()->isAllowed( 'suppressrevision' ) ) { throw new PermissionsError( 'suppressrevision' ); } # If the save went through, go to success message... @@ -557,7 +519,7 @@ class SpecialRevisionDelete extends UnlistedSpecialPage { */ protected function success() { $this->getOutput()->setPageTitle( $this->msg( 'actioncomplete' ) ); - $this->getOutput()->wrapWikiMsg( "\n$1\n", $this->typeInfo['success'] ); + $this->getOutput()->wrapWikiMsg( "\n$1\n", $this->typeLabels['success'] ); $this->list->reloadFromMaster(); $this->showForm(); } @@ -567,7 +529,7 @@ class SpecialRevisionDelete extends UnlistedSpecialPage { */ protected function failure( $status ) { $this->getOutput()->setPageTitle( $this->msg( 'actionfailed' ) ); - $this->getOutput()->addWikiText( $status->getWikiText( $this->typeInfo['failure'] ) ); + $this->getOutput()->addWikiText( $status->getWikiText( $this->typeLabels['failure'] ) ); $this->showForm(); } @@ -578,15 +540,15 @@ class SpecialRevisionDelete extends UnlistedSpecialPage { */ protected function extractBitParams() { $bitfield = array(); - foreach( $this->checks as $item ) { + foreach ( $this->checks as $item ) { list( /* message */, $name, $field ) = $item; $val = $this->getRequest()->getInt( $name, 0 /* unchecked */ ); - if( $val < -1 || $val > 1) { + if ( $val < -1 || $val > 1 ) { $val = -1; // -1 for existing value } $bitfield[$field] = $val; } - if( !isset( $bitfield[Revision::DELETED_RESTRICTED] ) ) { + if ( !isset( $bitfield[Revision::DELETED_RESTRICTED] ) ) { $bitfield[Revision::DELETED_RESTRICTED] = 0; } return $bitfield; @@ -594,21 +556,13 @@ class SpecialRevisionDelete extends UnlistedSpecialPage { /** * Put together a rev_deleted bitfield + * @deprecated since 1.22, use RevisionDeleter::extractBitfield instead * @param array $bitPars extractBitParams() params * @param int $oldfield current bitfield * @return array */ public static function extractBitfield( $bitPars, $oldfield ) { - // Build the actual new rev_deleted bitfield - $newBits = 0; - foreach( $bitPars as $const => $val ) { - if( $val == 1 ) { - $newBits |= $const; // $const is the *_deleted const - } elseif( $val == -1 ) { - $newBits |= ($oldfield & $const); // use existing - } - } - return $newBits; + return RevisionDeleter::extractBitfield( $bitPars, $oldfield ); } /** diff --git a/includes/specials/SpecialSearch.php b/includes/specials/SpecialSearch.php index 6c401486..8609c740 100644 --- a/includes/specials/SpecialSearch.php +++ b/includes/specials/SpecialSearch.php @@ -42,6 +42,9 @@ class SpecialSearch extends SpecialPage { /// Search engine protected $searchEngine; + /// Search engine type, if not default + protected $searchEngineType; + /// For links protected $extraParams = array(); @@ -98,6 +101,8 @@ class SpecialSearch extends SpecialPage { $this->load(); + $this->searchEngineType = $request->getVal( 'srbackend' ); + if ( $request->getVal( 'fulltext' ) || !is_null( $request->getVal( 'offset' ) ) || !is_null( $request->getVal( 'searchx' ) ) ) @@ -137,7 +142,7 @@ class SpecialSearch extends SpecialPage { if ( $profile === null ) { // BC with old request format $profile = 'advanced'; - foreach( $profiles as $key => $data ) { + foreach ( $profiles as $key => $data ) { if ( $nslist === $data['namespaces'] && $key !== 'advanced' ) { $profile = $key; } @@ -173,7 +178,7 @@ class SpecialSearch extends SpecialPage { # Try to go to page as entered. $t = Title::newFromText( $term ); # If the string cannot be used to create a title - if( is_null( $t ) ) { + if ( is_null( $t ) ) { $this->showResults( $term ); return; } @@ -185,19 +190,19 @@ class SpecialSearch extends SpecialPage { return; } - if( !is_null( $t ) ) { + if ( !is_null( $t ) ) { $this->getOutput()->redirect( $t->getFullURL() ); return; } # No match, generate an edit URL $t = Title::newFromText( $term ); - if( !is_null( $t ) ) { + if ( !is_null( $t ) ) { global $wgGoToEdit; wfRunHooks( 'SpecialSearchNogomatch', array( &$t ) ); wfDebugLog( 'nogomatch', $t->getText(), false ); # If the feature is enabled, go straight to the edit page - if( $wgGoToEdit ) { + if ( $wgGoToEdit ) { $this->getOutput()->redirect( $t->getFullURL( array( 'action' => 'edit' ) ) ); return; } @@ -253,18 +258,24 @@ class SpecialSearch extends SpecialPage { $rewritten = $search->replacePrefixes( $term ); $titleMatches = $search->searchTitle( $rewritten ); - if( !( $titleMatches instanceof SearchResultTooMany ) ) { + if ( !( $titleMatches instanceof SearchResultTooMany ) ) { $textMatches = $search->searchText( $rewritten ); } + $textStatus = null; + if ( $textMatches instanceof Status ) { + $textStatus = $textMatches; + $textMatches = null; + } + // did you mean... suggestions - if( $textMatches && $textMatches->hasSuggestion() ) { + if ( $textMatches && !$textStatus && $textMatches->hasSuggestion() ) { $st = SpecialPage::getTitleFor( 'Search' ); # mirror Go/Search behavior of original request .. $didYouMeanParams = array( 'search' => $textMatches->getSuggestionQuery() ); - if( $this->fulltext != null ) { + if ( $this->fulltext != null ) { $didYouMeanParams['fulltext'] = $this->fulltext; } @@ -275,7 +286,7 @@ class SpecialSearch extends SpecialPage { $suggestionSnippet = $textMatches->getSuggestionSnippet(); - if( $suggestionSnippet == '' ) { + if ( $suggestionSnippet == '' ) { $suggestionSnippet = null; } @@ -317,14 +328,14 @@ class SpecialSearch extends SpecialPage { ); // Sometimes the search engine knows there are too many hits - if( $titleMatches instanceof SearchResultTooMany ) { + if ( $titleMatches instanceof SearchResultTooMany ) { $out->wrapWikiMsg( "==$1==\n", 'toomanymatches' ); wfProfileOut( __METHOD__ ); return; } $filePrefix = $wgContLang->getFormattedNsText( NS_FILE ) . ':'; - if( trim( $term ) === '' || $filePrefix === trim( $term ) ) { + if ( trim( $term ) === '' || $filePrefix === trim( $term ) ) { $out->addHTML( $this->formHeader( $term, 0, 0 ) ); $out->addHtml( $this->getProfileForm( $this->profile, $term ) ); $out->addHTML( '' ); @@ -347,10 +358,12 @@ class SpecialSearch extends SpecialPage { // get total number of results if backend can calculate it $totalRes = 0; - if( $titleMatches && !is_null( $titleMatches->getTotalHits() ) ) + if ( $titleMatches && !is_null( $titleMatches->getTotalHits() ) ) { $totalRes += $titleMatches->getTotalHits(); - if( $textMatches && !is_null( $textMatches->getTotalHits() ) ) + } + if ( $textMatches && !is_null( $textMatches->getTotalHits() ) ) { $totalRes += $textMatches->getTotalHits(); + } // show number of results and current offset $out->addHTML( $this->formHeader( $term, $num, $totalRes ) ); @@ -360,7 +373,7 @@ class SpecialSearch extends SpecialPage { $out->addHtml( "
          " ); // prev/next links - if( $num || $this->offset ) { + if ( $num || $this->offset ) { // Show the create link ahead $this->showCreateLink( $t ); $prevnext = $this->getLanguage()->viewPrevNext( $this->getTitle(), $this->offset, $this->limit, @@ -374,40 +387,46 @@ class SpecialSearch extends SpecialPage { } $out->parserOptions()->setEditSection( false ); - if( $titleMatches ) { - if( $numTitleMatches > 0 ) { + if ( $titleMatches ) { + if ( $numTitleMatches > 0 ) { $out->wrapWikiMsg( "==$1==\n", 'titlematches' ); $out->addHTML( $this->showMatches( $titleMatches ) ); } $titleMatches->free(); } - if( $textMatches ) { + if ( $textMatches && !$textStatus ) { // output appropriate heading - if( $numTextMatches > 0 && $numTitleMatches > 0 ) { + if ( $numTextMatches > 0 && $numTitleMatches > 0 ) { // if no title matches the heading is redundant $out->wrapWikiMsg( "==$1==\n", 'textmatches' ); - } elseif( $totalRes == 0 ) { + } elseif ( $totalRes == 0 ) { # Don't show the 'no text matches' if we received title matches # $out->wrapWikiMsg( "==$1==\n", 'notextmatches' ); } // show interwiki results if any - if( $textMatches->hasInterwikiResults() ) { + if ( $textMatches->hasInterwikiResults() ) { $out->addHTML( $this->showInterwiki( $textMatches->getInterwikiResults(), $term ) ); } // show results - if( $numTextMatches > 0 ) { + if ( $numTextMatches > 0 ) { $out->addHTML( $this->showMatches( $textMatches ) ); } $textMatches->free(); } - if( $num === 0 ) { - $out->wrapWikiMsg( "

          \n$1

          ", array( 'search-nonefound', wfEscapeWikiText( $term ) ) ); - $this->showCreateLink( $t ); + if ( $num === 0 ) { + if ( $textStatus ) { + $out->addHTML( '
          ' . + htmlspecialchars( $textStatus->getWikiText( 'search-error' ) ) . '
          ' ); + } else { + $out->wrapWikiMsg( "

          \n$1

          ", + array( 'search-nonefound', wfEscapeWikiText( $term ) ) ); + $this->showCreateLink( $t ); + } } $out->addHtml( "
          " ); - if( $num || $this->offset ) { + if ( $num || $this->offset ) { $out->addHTML( "

          {$prevnext}

          \n" ); } wfRunHooks( 'SpecialSearchResultsAppend', array( $this, $out, $term ) ); @@ -421,16 +440,16 @@ class SpecialSearch extends SpecialPage { // show direct page/create link if applicable // Check DBkey !== '' in case of fragment link only. - if( is_null( $t ) || $t->getDBkey() === '' ) { + if ( is_null( $t ) || $t->getDBkey() === '' ) { // invalid title // preserve the paragraph for margins etc... $this->getOutput()->addHtml( '

          ' ); return; } - if( $t->isKnown() ) { + if ( $t->isKnown() ) { $messageName = 'searchmenu-exists'; - } elseif( $t->userCan( 'create', $this->getUser() ) ) { + } elseif ( $t->userCan( 'create', $this->getUser() ) ) { $messageName = 'searchmenu-new'; } else { $messageName = 'searchmenu-new-nocreate'; @@ -439,7 +458,7 @@ class SpecialSearch extends SpecialPage { wfRunHooks( 'SpecialSearchCreateLink', array( $t, &$params ) ); // Extensions using the hook might still return an empty $messageName - if( $messageName ) { + if ( $messageName ) { $this->getOutput()->wrapWikiMsg( "

          \n$1

          ", $params ); } else { // preserve the paragraph for margins etc... @@ -452,9 +471,9 @@ class SpecialSearch extends SpecialPage { */ protected function setupPage( $term ) { # Should advanced UI be used? - $this->searchAdvanced = ($this->profile === 'advanced'); + $this->searchAdvanced = ( $this->profile === 'advanced' ); $out = $this->getOutput(); - if( strval( $term ) !== '' ) { + if ( strval( $term ) !== '' ) { $out->setPageTitle( $this->msg( 'searchresults' ) ); $out->setHTMLTitle( $this->msg( 'pagetitle' )->rawParams( $this->msg( 'searchresults-title' )->rawParams( $term )->text() @@ -473,8 +492,8 @@ class SpecialSearch extends SpecialPage { */ protected function powerSearch( &$request ) { $arr = array(); - foreach( SearchEngine::searchableNamespaces() as $ns => $name ) { - if( $request->getCheck( 'ns' . $ns ) ) { + foreach ( SearchEngine::searchableNamespaces() as $ns => $name ) { + if ( $request->getCheck( 'ns' . $ns ) ) { $arr[] = $ns; } } @@ -490,10 +509,10 @@ class SpecialSearch extends SpecialPage { protected function powerSearchOptions() { $opt = array(); $opt['redirs'] = $this->searchRedirects ? 1 : 0; - if( $this->profile !== 'advanced' ) { + if ( $this->profile !== 'advanced' ) { $opt['profile'] = $this->profile; } else { - foreach( $this->namespaces as $n ) { + foreach ( $this->namespaces as $n ) { $opt['ns' . $n] = 1; } } @@ -515,12 +534,12 @@ class SpecialSearch extends SpecialPage { $out = ""; $infoLine = $matches->getInfo(); - if( !is_null( $infoLine ) ) { + if ( !is_null( $infoLine ) ) { $out .= "\n\n"; } $out .= "
            \n"; $result = $matches->next(); - while( $result ) { + while ( $result ) { $out .= $this->showHit( $result, $terms ); $result = $matches->next(); } @@ -543,7 +562,7 @@ class SpecialSearch extends SpecialPage { protected function showHit( $result, $terms ) { wfProfileIn( __METHOD__ ); - if( $result->isBrokenTitle() ) { + if ( $result->isBrokenTitle() ) { wfProfileOut( __METHOD__ ); return "\n"; } @@ -552,8 +571,9 @@ class SpecialSearch extends SpecialPage { $titleSnippet = $result->getTitleSnippet( $terms ); - if( $titleSnippet == '' ) + if ( $titleSnippet == '' ) { $titleSnippet = null; + } $link_t = clone $t; @@ -568,7 +588,7 @@ class SpecialSearch extends SpecialPage { //If page content is not readable, just return the title. //This is not quite safe, but better than showing excerpts from non-readable pages //Note that hiding the entry entirely would screw up paging. - if( !$t->userCan( 'read', $this->getUser() ) ) { + if ( !$t->userCan( 'read', $this->getUser() ) ) { wfProfileOut( __METHOD__ ); return "
          • {$link}
          • \n"; } @@ -576,7 +596,7 @@ class SpecialSearch extends SpecialPage { // If the page doesn't *exist*... our search index is out of date. // The least confusing at this point is to drop the result. // You may get less results, but... oh well. :P - if( $result->isMissingRevision() ) { + if ( $result->isMissingRevision() ) { wfProfileOut( __METHOD__ ); return "\n"; } @@ -588,9 +608,10 @@ class SpecialSearch extends SpecialPage { $sectionText = $result->getSectionSnippet( $terms ); $redirect = ''; - if( !is_null( $redirectTitle ) ) { - if( $redirectText == '' ) + if ( !is_null( $redirectTitle ) ) { + if ( $redirectText == '' ) { $redirectText = null; + } $redirect = "" . $this->msg( 'search-redirect' )->rawParams( @@ -600,9 +621,10 @@ class SpecialSearch extends SpecialPage { $section = ''; - if( !is_null( $sectionTitle ) ) { - if( $sectionText == '' ) + if ( !is_null( $sectionTitle ) ) { + if ( $sectionText == '' ) { $sectionText = null; + } $section = "" . $this->msg( 'search-section' )->rawParams( @@ -616,7 +638,7 @@ class SpecialSearch extends SpecialPage { $lang = $this->getLanguage(); // format score - if( is_null( $result->getScore() ) ) { + if ( is_null( $result->getScore() ) ) { // Search engine doesn't report scoring info $score = ''; } else { @@ -632,7 +654,7 @@ class SpecialSearch extends SpecialPage { $size = $this->msg( 'search-result-size', $lang->formatSize( $byteSize ) ) ->numParams( $wordCount )->escaped(); - if( $t->getNamespace() == NS_CATEGORY ) { + if ( $t->getNamespace() == NS_CATEGORY ) { $cat = Category::newFromTitle( $t ); $size = $this->msg( 'search-result-category-size' ) ->numParams( $cat->getPageCount(), $cat->getSubcatCount(), $cat->getFileCount() ) @@ -643,7 +665,7 @@ class SpecialSearch extends SpecialPage { // link to related articles if supported $related = ''; - if( $result->hasRelated() ) { + if ( $result->hasRelated() ) { $st = SpecialPage::getTitleFor( 'Search' ); $stParams = array_merge( $this->powerSearchOptions(), @@ -663,11 +685,11 @@ class SpecialSearch extends SpecialPage { } // Include a thumbnail for media files... - if( $t->getNamespace() == NS_FILE ) { + if ( $t->getNamespace() == NS_FILE ) { $img = wfFindFile( $t ); - if( $img ) { + if ( $img ) { $thumb = $img->transform( array( 'width' => 120, 'height' => 120 ) ); - if( $thumb ) { + if ( $thumb ) { $desc = $this->msg( 'parentheses' )->rawParams( $img->getShortDesc() )->escaped(); wfProfileOut( __METHOD__ ); // Float doesn't seem to interact well with the bullets. @@ -693,7 +715,7 @@ class SpecialSearch extends SpecialPage { $html = null; - if ( wfRunHooks( 'ShowSearchHit', array ( + if ( wfRunHooks( 'ShowSearchHit', array( $this, $result, $terms, &$link, &$redirect, &$section, &$extract, &$score, &$size, &$date, &$related, @@ -721,23 +743,23 @@ class SpecialSearch extends SpecialPage { wfProfileIn( __METHOD__ ); $terms = $wgContLang->convertForSearchResult( $matches->termMatches() ); - $out = "
            ". + $out = "
            " . $this->msg( 'search-interwiki-caption' )->text() . "
            \n"; $out .= "
              \n"; // work out custom project captions $customCaptions = array(); $customLines = explode( "\n", $this->msg( 'search-interwiki-custom' )->text() ); // format per line :
          ' . $this->msg( 'revdelete-radio-unset' )->escaped() . '' . $this->msg( 'revdelete-radio-set' )->escaped() . '
          ' . Xml::radio( $name, 0, $selected == 0 ) . '' . Xml::radio( $name, 1, $selected == 1 ) . '$label
          - foreach( $customLines as $line ) { + foreach ( $customLines as $line ) { $parts = explode( ":", $line, 2 ); - if( count( $parts ) == 2 ) { // validate line + if ( count( $parts ) == 2 ) { // validate line $customCaptions[$parts[0]] = $parts[1]; } } $prev = null; $result = $matches->next(); - while( $result ) { + while ( $result ) { $out .= $this->showInterwikiHit( $result, $prev, $terms, $query, $customCaptions ); $prev = $result->getInterwikiPrefix(); $result = $matches->next(); @@ -762,10 +784,10 @@ class SpecialSearch extends SpecialPage { * * @return string */ - protected function showInterwikiHit( $result, $lastInterwiki, $terms, $query, $customCaptions) { + protected function showInterwikiHit( $result, $lastInterwiki, $terms, $query, $customCaptions ) { wfProfileIn( __METHOD__ ); - if( $result->isBrokenTitle() ) { + if ( $result->isBrokenTitle() ) { wfProfileOut( __METHOD__ ); return "\n"; } @@ -774,8 +796,9 @@ class SpecialSearch extends SpecialPage { $titleSnippet = $result->getTitleSnippet( $terms ); - if( $titleSnippet == '' ) + if ( $titleSnippet == '' ) { $titleSnippet = null; + } $link = Linker::linkKnown( $t, @@ -786,9 +809,10 @@ class SpecialSearch extends SpecialPage { $redirectTitle = $result->getRedirectTitle(); $redirectText = $result->getRedirectSnippet( $terms ); $redirect = ''; - if( !is_null( $redirectTitle ) ) { - if( $redirectText == '' ) + if ( !is_null( $redirectTitle ) ) { + if ( $redirectText == '' ) { $redirectText = null; + } $redirect = "" . $this->msg( 'search-redirect' )->rawParams( @@ -798,8 +822,8 @@ class SpecialSearch extends SpecialPage { $out = ""; // display project name - if( is_null( $lastInterwiki ) || $lastInterwiki != $t->getInterwiki() ) { - if( array_key_exists( $t->getInterwiki(), $customCaptions ) ) { + if ( is_null( $lastInterwiki ) || $lastInterwiki != $t->getInterwiki() ) { + if ( array_key_exists( $t->getInterwiki(), $customCaptions ) ) { // captions from 'search-interwiki-custom' $caption = $customCaptions[$t->getInterwiki()]; } else { @@ -856,17 +880,21 @@ class SpecialSearch extends SpecialPage { * @return String: HTML form */ protected function powerSearchBox( $term, $opts ) { + global $wgContLang; + // Groups namespaces into rows according to subject $rows = array(); - foreach( SearchEngine::searchableNamespaces() as $namespace => $name ) { + foreach ( SearchEngine::searchableNamespaces() as $namespace => $name ) { $subject = MWNamespace::getSubject( $namespace ); - if( !array_key_exists( $subject, $rows ) ) { + if ( !array_key_exists( $subject, $rows ) ) { $rows[$subject] = ""; } - $name = str_replace( '_', ' ', $name ); - if( $name == '' ) { + + $name = $wgContLang->getConverter()->convertNamespace( $namespace ); + if ( $name == '' ) { $name = $this->msg( 'blanknamespace' )->text(); } + $rows[$subject] .= Xml::openElement( 'td', array( 'style' => 'white-space: nowrap' ) @@ -879,27 +907,30 @@ class SpecialSearch extends SpecialPage { ) . Xml::closeElement( 'td' ); } + $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 = ''; - for( $i = 0; $i < $numRows; $i += 4 ) { + for ( $i = 0; $i < $numRows; $i += 4 ) { $namespaceTables .= Xml::openElement( 'table', array( 'cellpadding' => 0, 'cellspacing' => 0 ) ); - for( $j = $i; $j < $i + 4 && $j < $numRows; $j++ ) { + + for ( $j = $i; $j < $i + 4 && $j < $numRows; $j++ ) { $namespaceTables .= Xml::tags( 'tr', null, $rows[$j] ); } + $namespaceTables .= Xml::closeElement( 'table' ); } $showSections = array( 'namespaceTables' => $namespaceTables ); // Show redirects check only if backend supports it - if( $this->getSearchEngine()->supports( 'list-redirects' ) ) { + if ( $this->getSearchEngine()->supports( 'list-redirects' ) ) { $showSections['redirects'] = Xml::checkLabel( $this->msg( 'powersearch-redir' )->text(), 'redirs', 'redirs', $this->searchRedirects ); } @@ -908,12 +939,11 @@ class SpecialSearch extends SpecialPage { $hidden = ''; unset( $opts['redirs'] ); - foreach( $opts as $key => $value ) { + foreach ( $opts as $key => $value ) { $hidden .= Html::hidden( $key, $value ); } // Return final output - return - Xml::openElement( + return Xml::openElement( 'fieldset', array( 'id' => 'mw-searchoptions', 'style' => 'margin:0em;' ) ) . @@ -969,8 +999,10 @@ class SpecialSearch extends SpecialPage { wfRunHooks( 'SpecialSearchProfiles', array( &$profiles ) ); - foreach( $profiles as &$data ) { - if ( !is_array( $data['namespaces'] ) ) continue; + foreach ( $profiles as &$data ) { + if ( !is_array( $data['namespaces'] ) ) { + continue; + } sort( $data['namespaces'] ); } @@ -987,7 +1019,7 @@ class SpecialSearch extends SpecialPage { $out = Xml::openElement( 'div', array( 'class' => 'mw-search-formheader' ) ); $bareterm = $term; - if( $this->startsWithImage( $term ) ) { + if ( $this->startsWithImage( $term ) ) { // Deletes prefixes $bareterm = substr( $term, strpos( $term, ':' ) + 1 ); } @@ -1081,7 +1113,7 @@ class SpecialSearch extends SpecialPage { */ protected function makeSearchLink( $term, $namespaces, $label, $tooltip, $params = array() ) { $opt = $params; - foreach( $namespaces as $n ) { + foreach ( $namespaces as $n ) { $opt['ns' . $n] = 1; } $opt['redirs'] = $this->searchRedirects; @@ -1098,7 +1130,8 @@ class SpecialSearch extends SpecialPage { 'a', array( 'href' => $this->getTitle()->getLocalURL( $stParams ), - 'title' => $tooltip), + 'title' => $tooltip + ), $label ); } @@ -1113,7 +1146,7 @@ class SpecialSearch extends SpecialPage { global $wgContLang; $p = explode( ':', $term ); - if( count( $p ) > 1 ) { + if ( count( $p ) > 1 ) { return $wgContLang->getNsIndex( $p[0] ) == NS_FILE; } return false; @@ -1130,7 +1163,7 @@ class SpecialSearch extends SpecialPage { $allkeyword = $this->msg( 'searchall' )->inContentLanguage()->text(); $p = explode( ':', $term ); - if( count( $p ) > 1 ) { + if ( count( $p ) > 1 ) { return $p[0] == $allkeyword; } return false; @@ -1143,7 +1176,8 @@ class SpecialSearch extends SpecialPage { */ public function getSearchEngine() { if ( $this->searchEngine === null ) { - $this->searchEngine = SearchEngine::create(); + $this->searchEngine = $this->searchEngineType ? + SearchEngine::create( $this->searchEngineType ) : SearchEngine::create(); } return $this->searchEngine; } @@ -1162,6 +1196,6 @@ class SpecialSearch extends SpecialPage { } protected function getGroupName() { - return 'redirects'; + return 'pages'; } } diff --git a/includes/specials/SpecialShortpages.php b/includes/specials/SpecialShortpages.php index 1be7fbed..9b50875a 100644 --- a/includes/specials/SpecialShortpages.php +++ b/includes/specials/SpecialShortpages.php @@ -38,15 +38,15 @@ class ShortPagesPage extends QueryPage { } function getQueryInfo() { - return array ( - 'tables' => array ( 'page' ), - 'fields' => array ( 'namespace' => 'page_namespace', + return array( + 'tables' => array( 'page' ), + 'fields' => array( 'namespace' => 'page_namespace', 'title' => 'page_title', 'value' => 'page_len' ), - 'conds' => array ( 'page_namespace' => + 'conds' => array( 'page_namespace' => MWNamespace::getContentNamespaces(), 'page_is_redirect' => 0 ), - 'options' => array ( 'USE INDEX' => 'page_redirect_namespace_len' ) + 'options' => array( 'USE INDEX' => 'page_redirect_namespace_len' ) ); } @@ -56,8 +56,7 @@ class ShortPagesPage extends QueryPage { /** * @param $db DatabaseBase - * @param $res - * @return void + * @param ResultWrapper $res */ function preprocessResults( $db, $res ) { # There's no point doing a batch check if we aren't caching results; @@ -79,6 +78,11 @@ class ShortPagesPage extends QueryPage { return false; } + /** + * @param Skin $skin + * @param object $result Result row + * @return string + */ function formatResult( $skin, $result ) { $dm = $this->getLanguage()->getDirMark(); diff --git a/includes/specials/SpecialSpecialpages.php b/includes/specials/SpecialSpecialpages.php index 57fffb84..47c89d0d 100644 --- a/includes/specials/SpecialSpecialpages.php +++ b/includes/specials/SpecialSpecialpages.php @@ -53,17 +53,18 @@ class SpecialSpecialpages extends UnlistedSpecialPage { $pages = SpecialPageFactory::getUsablePages( $this->getUser() ); - if( !count( $pages ) ) { + if ( !count( $pages ) ) { # Yeah, that was pointless. Thanks for coming. return false; } /** Put them into a sortable array */ $groups = array(); + /** @var SpecialPage $page */ foreach ( $pages as $page ) { if ( $page->isListed() ) { $group = $page->getFinalGroupName(); - if( !isset( $groups[$group] ) ) { + if ( !isset( $groups[$group] ) ) { $groups[$group] = array(); } $groups[$group][$page->getDescription()] = array( @@ -76,13 +77,13 @@ class SpecialSpecialpages extends UnlistedSpecialPage { /** Sort */ if ( $wgSortSpecialPages ) { - foreach( $groups as $group => $sortedPages ) { + foreach ( $groups as $group => $sortedPages ) { ksort( $groups[$group] ); } } /** Always move "other" to end */ - if( array_key_exists( 'other', $groups ) ) { + if ( array_key_exists( 'other', $groups ) ) { $other = $groups['other']; unset( $groups['other'] ); $groups['other'] = $other; @@ -104,12 +105,12 @@ class SpecialSpecialpages extends UnlistedSpecialPage { $out->wrapWikiMsg( "

          $1

          \n", "specialpages-group-$group" ); $out->addHTML( - Html::openElement( 'table', array( 'style' => 'width:100%;', 'class' => 'mw-specialpages-table' ) ) ."\n" . + 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 ) { + foreach ( $sortedPages as $desc => $specialpage ) { list( $title, $restricted, $cached ) = $specialpage; $pageClasses = array(); @@ -117,7 +118,7 @@ class SpecialSpecialpages extends UnlistedSpecialPage { $includesCachedPages = true; $pageClasses[] = 'mw-specialpagecached'; } - if( $restricted ) { + if ( $restricted ) { $includesRestrictedPages = true; $pageClasses[] = 'mw-specialpagerestricted'; } @@ -127,7 +128,7 @@ class SpecialSpecialpages extends UnlistedSpecialPage { # Split up the larger groups $count++; - if( $total > 3 && $count == $middle ) { + if ( $total > 3 && $count == $middle ) { $out->addHTML( Html::closeElement( 'ul' ) . Html::closeElement( 'td' ) . Html::element( 'td', array( 'style' => 'width:10%' ), '' ) . diff --git a/includes/specials/SpecialStatistics.php b/includes/specials/SpecialStatistics.php index ee768263..f26d1a60 100644 --- a/includes/specials/SpecialStatistics.php +++ b/includes/specials/SpecialStatistics.php @@ -53,18 +53,18 @@ class SpecialStatistics extends SpecialPage { # Staticic - views $viewsStats = ''; - if( !$wgDisableCounters ) { + if ( !$wgDisableCounters ) { $viewsStats = $this->getViewsStats(); } # Set active user count - if( !$wgMiserMode ) { + if ( !$wgMiserMode ) { $key = wfMemcKey( 'sitestats', 'activeusers-updated' ); // Re-calculate the count if the last tally is old... - if( !$wgMemc->get( $key ) ) { + if ( !$wgMemc->get( $key ) ) { $dbw = wfGetDB( DB_MASTER ); SiteStatsUpdate::cacheUpdate( $dbw ); - $wgMemc->set( $key, '1', 24*3600 ); // don't update for 1 day + $wgMemc->set( $key, '1', 24 * 3600 ); // don't update for 1 day } } @@ -84,13 +84,13 @@ class SpecialStatistics extends SpecialPage { $text .= $viewsStats; # Statistic - popular pages - if( !$wgDisableCounters && !$wgMiserMode ) { + if ( !$wgDisableCounters && !$wgMiserMode ) { $text .= $this->getMostViewedPages(); } # Statistic - other $extraStats = array(); - if( wfRunHooks( 'SpecialStatsAddExtra', array( &$extraStats ) ) ) { + if ( wfRunHooks( 'SpecialStatsAddExtra', array( &$extraStats ) ) ) { $text .= $this->getOtherStats( $extraStats ); } @@ -111,15 +111,15 @@ class SpecialStatistics extends SpecialPage { * @param $number Float: a statistical number * @param $trExtraParams Array: params to table row, see Html::elememt * @param $descMsg String: message key - * @param $descMsgParam Array: message params + * @param array|string $descMsgParam Message parameters * @return string table row in HTML format */ private function formatRow( $text, $number, $trExtraParams = array(), $descMsg = '', $descMsgParam = '' ) { - if( $descMsg ) { + if ( $descMsg ) { $msg = $this->msg( $descMsg, $descMsgParam ); if ( $msg->exists() ) { $descriptionText = $this->msg( 'parentheses' )->rawParams( $msg->parse() )->escaped(); - $text .= "
          " . Xml::element( 'small', array( 'class' => 'mw-statistic-desc'), + $text .= "
          " . Xml::element( 'small', array( 'class' => 'mw-statistic-desc' ), " $descriptionText" ); } } @@ -185,7 +185,7 @@ class SpecialStatistics extends SpecialPage { private function getGroupStats() { global $wgGroupPermissions, $wgImplicitGroups; $text = ''; - foreach( $wgGroupPermissions as $group => $permissions ) { + foreach ( $wgGroupPermissions as $group => $permissions ) { # Skip generic * and implicit groups if ( in_array( $group, $wgImplicitGroups ) || $group == '*' ) { continue; @@ -217,7 +217,7 @@ class SpecialStatistics extends SpecialPage { # Add a class when a usergroup contains no members to allow hiding these rows $classZero = ''; $countUsers = SiteStats::numberingroup( $groupname ); - if( $countUsers == 0 ) { + if ( $countUsers == 0 ) { $classZero = ' statistics-group-zero'; } $text .= $this->formatRow( $grouppage . ' ' . $grouplink, @@ -233,11 +233,11 @@ class SpecialStatistics extends SpecialPage { Xml::closeElement( 'tr' ) . $this->formatRow( $this->msg( 'statistics-views-total' )->parse(), $this->getLanguage()->formatNum( $this->views ), - array ( 'class' => 'mw-statistics-views-total' ), 'statistics-views-total-desc' ) . + array( 'class' => 'mw-statistics-views-total' ), 'statistics-views-total-desc' ) . $this->formatRow( $this->msg( 'statistics-views-peredit' )->parse(), $this->getLanguage()->formatNum( sprintf( '%.2f', $this->edits ? $this->views / $this->edits : 0 ) ), - array ( 'class' => 'mw-statistics-views-peredit' ) ); + array( 'class' => 'mw-statistics-views-peredit' ) ); } private function getMostViewedPages() { @@ -260,13 +260,13 @@ class SpecialStatistics extends SpecialPage { 'LIMIT' => 10, ) ); - if( $res->numRows() > 0 ) { + if ( $res->numRows() > 0 ) { $text .= Xml::openElement( 'tr' ); $text .= Xml::tags( 'th', array( 'colspan' => '2' ), $this->msg( 'statistics-mostpopular' )->parse() ); $text .= Xml::closeElement( 'tr' ); foreach ( $res as $row ) { $title = Title::makeTitleSafe( $row->page_namespace, $row->page_title ); - if( $title instanceof Title ) { + if ( $title instanceof Title ) { $text .= $this->formatRow( Linker::link( $title ), $this->getLanguage()->formatNum( $row->page_counter ) ); @@ -287,8 +287,7 @@ class SpecialStatistics extends SpecialPage { private function getOtherStats( array $stats ) { $return = ''; - foreach( $stats as $header => $items ) { - + foreach ( $stats as $header => $items ) { // Identify the structure used if ( is_array( $items ) ) { @@ -298,11 +297,11 @@ class SpecialStatistics extends SpecialPage { } // Collect all items that belong to the same header - foreach( $items as $key => $value ) { + foreach ( $items as $key => $value ) { $name = $this->msg( $key )->parse(); $number = htmlspecialchars( $value ); - $return .= $this->formatRow( $name, $this->getLanguage()->formatNum( $number ), array( 'class' => 'mw-statistics-hook' ) ); + $return .= $this->formatRow( $name, $this->getLanguage()->formatNum( $number ), array( 'class' => 'mw-statistics-hook', 'id' => 'mw-' . $key ) ); } } else { // Create the legacy header only once diff --git a/includes/specials/SpecialTags.php b/includes/specials/SpecialTags.php index 6d161031..077e7cbc 100644 --- a/includes/specials/SpecialTags.php +++ b/includes/specials/SpecialTags.php @@ -27,6 +27,10 @@ * @ingroup SpecialPage */ class SpecialTags extends SpecialPage { + /** + * @var array List of defined tags + */ + public $definedTags; function __construct() { parent::__construct( 'Tags' ); @@ -44,51 +48,66 @@ class SpecialTags extends SpecialPage { $html = Xml::tags( 'tr', null, Xml::tags( 'th', null, $this->msg( 'tags-tag' )->parse() ) . Xml::tags( 'th', null, $this->msg( 'tags-display-header' )->parse() ) . Xml::tags( 'th', null, $this->msg( 'tags-description-header' )->parse() ) . + Xml::tags( 'th', null, $this->msg( 'tags-active-header' )->parse() ) . Xml::tags( 'th', null, $this->msg( 'tags-hitcount-header' )->parse() ) ); - $dbr = wfGetDB( DB_SLAVE ); - $res = $dbr->select( 'change_tag', array( 'ct_tag', 'hitcount' => 'count(*)' ), - array(), __METHOD__, array( 'GROUP BY' => 'ct_tag', 'ORDER BY' => 'hitcount DESC' ) ); - foreach ( $res as $row ) { - $html .= $this->doTagRow( $row->ct_tag, $row->hitcount ); - } + // Used in #doTagRow() + $this->definedTags = array_fill_keys( ChangeTags::listDefinedTags(), true ); - foreach( ChangeTags::listDefinedTags() as $tag ) { - $html .= $this->doTagRow( $tag, 0 ); + foreach ( ChangeTags::tagUsageStatistics() as $tag => $hitcount ) { + $html .= $this->doTagRow( $tag, $hitcount ); } - $out->addHTML( Xml::tags( 'table', array( 'class' => 'wikitable mw-tags-table' ), $html ) ); + $out->addHTML( Xml::tags( + 'table', + array( 'class' => 'wikitable sortable mw-tags-table' ), + $html + ) ); } function doTagRow( $tag, $hitcount ) { - static $doneTags = array(); - - if ( in_array( $tag, $doneTags ) ) { - return ''; - } - + $user = $this->getUser(); $newRow = ''; $newRow .= Xml::tags( 'td', null, Xml::element( 'code', null, $tag ) ); $disp = ChangeTags::tagDescription( $tag ); - $disp .= ' '; - $editLink = Linker::link( Title::makeTitle( NS_MEDIAWIKI, "Tag-$tag" ), $this->msg( 'tags-edit' )->escaped() ); - $disp .= $this->msg( 'parentheses' )->rawParams( $editLink )->escaped(); + if ( $user->isAllowed( 'editinterface' ) ) { + $disp .= ' '; + $editLink = Linker::link( + Title::makeTitle( NS_MEDIAWIKI, "Tag-$tag" ), + $this->msg( 'tags-edit' )->escaped() + ); + $disp .= $this->msg( 'parentheses' )->rawParams( $editLink )->escaped(); + } $newRow .= Xml::tags( 'td', null, $disp ); $msg = $this->msg( "tag-$tag-description" ); $desc = !$msg->exists() ? '' : $msg->parse(); - $desc .= ' '; - $editDescLink = Linker::link( Title::makeTitle( NS_MEDIAWIKI, "Tag-$tag-description" ), $this->msg( 'tags-edit' )->escaped() ); - $desc .= $this->msg( 'parentheses' )->rawParams( $editDescLink )->escaped(); + if ( $user->isAllowed( 'editinterface' ) ) { + $desc .= ' '; + $editDescLink = Linker::link( + Title::makeTitle( NS_MEDIAWIKI, "Tag-$tag-description" ), + $this->msg( 'tags-edit' )->escaped() + ); + $desc .= $this->msg( 'parentheses' )->rawParams( $editDescLink )->escaped(); + } $newRow .= Xml::tags( 'td', null, $desc ); - $hitcount = $this->msg( 'tags-hitcount' )->numParams( $hitcount )->escaped(); - $hitcount = Linker::link( SpecialPage::getTitleFor( 'Recentchanges' ), $hitcount, array(), array( 'tagfilter' => $tag ) ); - $newRow .= Xml::tags( 'td', null, $hitcount ); + $active = isset( $this->definedTags[$tag] ) ? 'tags-active-yes' : 'tags-active-no'; + $active = $this->msg( $active )->escaped(); + $newRow .= Xml::tags( 'td', null, $active ); + + $hitcountLabel = $this->msg( 'tags-hitcount' )->numParams( $hitcount )->escaped(); + $hitcountLink = Linker::link( + SpecialPage::getTitleFor( 'Recentchanges' ), + $hitcountLabel, + array(), + array( 'tagfilter' => $tag ) + ); - $doneTags[] = $tag; + // add raw $hitcount for sorting, because tags-hitcount contains numbers and letters + $newRow .= Xml::tags( 'td', array( 'data-sort-value' => $hitcount ), $hitcountLink ); return Xml::tags( 'tr', null, $newRow ) . "\n"; } diff --git a/includes/specials/SpecialUnblock.php b/includes/specials/SpecialUnblock.php index c4a53cf0..ca93b6d1 100644 --- a/includes/specials/SpecialUnblock.php +++ b/includes/specials/SpecialUnblock.php @@ -56,8 +56,8 @@ class SpecialUnblock extends SpecialPage { $form->setSubmitTextMsg( 'ipusubmit' ); $form->addPreText( $this->msg( 'unblockiptext' )->parseAsBlock() ); - if( $form->show() ) { - switch( $this->type ) { + if ( $form->show() ) { + switch ( $this->type ) { case Block::TYPE_USER: case Block::TYPE_IP: $out->addWikiMsg( 'unblocked', wfEscapeWikiText( $this->target ) ); @@ -92,21 +92,21 @@ class SpecialUnblock extends SpecialPage { ) ); - if( $this->block instanceof Block ) { + 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 ) { + 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 ) { + switch ( $type ) { case Block::TYPE_USER: case Block::TYPE_IP: $fields['Name']['default'] = Linker::link( @@ -138,6 +138,8 @@ class SpecialUnblock extends SpecialPage { /** * Submit callback for an HTMLForm object + * @param array $data + * @param HTMLForm $form * @return Array( Array(message key, parameters) */ public static function processUIUnblock( array $data, HTMLForm $form ) { @@ -157,7 +159,7 @@ class SpecialUnblock extends SpecialPage { $target = $data['Target']; $block = Block::newFromTarget( $data['Target'] ); - if( !$block instanceof Block ) { + if ( !$block instanceof Block ) { return array( array( 'ipb_cant_unblock', $target ) ); } @@ -172,14 +174,14 @@ class SpecialUnblock extends SpecialPage { # 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 ) { + 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( !$performer->isAllowed( 'hideuser' ) && $block->mHideName ) { + if ( !$performer->isAllowed( 'hideuser' ) && $block->mHideName ) { return array( 'unblock-hideuser' ); } @@ -189,7 +191,7 @@ class SpecialUnblock extends SpecialPage { } # Unset _deleted fields as needed - if( $block->mHideName ) { + 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() @@ -209,7 +211,7 @@ class SpecialUnblock extends SpecialPage { # Make log entry $log = new LogPage( 'block' ); - $log->addEntry( 'unblock', $page, $data['Reason'] ); + $log->addEntry( 'unblock', $page, $data['Reason'], array(), $performer ); return true; } diff --git a/includes/specials/SpecialUncategorizedcategories.php b/includes/specials/SpecialUncategorizedcategories.php index 54b20dde..1cc40a9e 100644 --- a/includes/specials/SpecialUncategorizedcategories.php +++ b/includes/specials/SpecialUncategorizedcategories.php @@ -34,11 +34,11 @@ class UncategorizedCategoriesPage extends UncategorizedPagesPage { /** * Formats the result - * @param $skin The current skin - * @param $result The query result + * @param Skin $skin The current skin + * @param object $result The query result * @return string The category link */ - function formatResult ( $skin, $result ) { + function formatResult( $skin, $result ) { $title = Title::makeTitle( NS_CATEGORY, $result->title ); $text = $title->getText(); diff --git a/includes/specials/SpecialUncategorizedimages.php b/includes/specials/SpecialUncategorizedimages.php index 53aa3f34..3bfcedec 100644 --- a/includes/specials/SpecialUncategorizedimages.php +++ b/includes/specials/SpecialUncategorizedimages.php @@ -47,7 +47,7 @@ class UncategorizedImagesPage extends ImageQueryPage { } function getQueryInfo() { - return array ( + return array( 'tables' => array( 'page', 'categorylinks' ), 'fields' => array( 'namespace' => 'page_namespace', 'title' => 'page_title', diff --git a/includes/specials/SpecialUncategorizedpages.php b/includes/specials/SpecialUncategorizedpages.php index b518e6fb..8bc9e489 100644 --- a/includes/specials/SpecialUncategorizedpages.php +++ b/includes/specials/SpecialUncategorizedpages.php @@ -47,17 +47,17 @@ class UncategorizedPagesPage extends PageQueryPage { } function getQueryInfo() { - return array ( - 'tables' => array ( 'page', 'categorylinks' ), - 'fields' => array ( 'namespace' => 'page_namespace', + return array( + 'tables' => array( 'page', 'categorylinks' ), + 'fields' => array( 'namespace' => 'page_namespace', 'title' => 'page_title', 'value' => 'page_title' ), // default for page_namespace is all content namespaces (if requestedNamespace is false) // otherwise, page_namespace is requestedNamespace - 'conds' => array ( 'cl_from IS NULL', + 'conds' => array( 'cl_from IS NULL', 'page_namespace' => ( $this->requestedNamespace !== false ? $this->requestedNamespace : MWNamespace::getContentNamespaces() ), 'page_is_redirect' => 0 ), - 'join_conds' => array ( 'categorylinks' => array ( + 'join_conds' => array( 'categorylinks' => array( 'LEFT JOIN', 'cl_from = page_id' ) ) ); } @@ -65,8 +65,9 @@ class UncategorizedPagesPage extends PageQueryPage { function getOrderFields() { // For some crazy reason ordering by a constant // causes a filesort - if( $this->requestedNamespace === false && count( MWNamespace::getContentNamespaces() ) > 1 ) + if ( $this->requestedNamespace === false && count( MWNamespace::getContentNamespaces() ) > 1 ) { return array( 'page_namespace', 'page_title' ); + } return array( 'page_title' ); } diff --git a/includes/specials/SpecialUndelete.php b/includes/specials/SpecialUndelete.php index e0363481..d4aed113 100644 --- a/includes/specials/SpecialUndelete.php +++ b/includes/specials/SpecialUndelete.php @@ -27,7 +27,6 @@ * @ingroup SpecialPage */ class PageArchive { - /** * @var Title */ @@ -44,7 +43,7 @@ class PageArchive { protected $revisionStatus; function __construct( $title ) { - if( is_null( $title ) ) { + if ( is_null( $title ) ) { throw new MWException( __METHOD__ . ' given a null title.' ); } $this->title = $title; @@ -67,14 +66,14 @@ class PageArchive { * given title prefix. * Returns result wrapper with (ar_namespace, ar_title, count) fields. * - * @param string $prefix title prefix + * @param string $prefix Title prefix * @return ResultWrapper */ public static function listPagesByPrefix( $prefix ) { $dbr = wfGetDB( DB_SLAVE ); $title = Title::newFromText( $prefix ); - if( $title ) { + if ( $title ) { $ns = $title->getNamespace(); $prefix = $title->getDBkey(); } else { @@ -82,36 +81,36 @@ class PageArchive { // @todo handle bare namespace names cleanly? $ns = 0; } + $conds = array( 'ar_namespace' => $ns, 'ar_title' . $dbr->buildLike( $prefix, $dbr->anyString() ), ); + return self::listPages( $dbr, $conds ); } /** - * @param $dbr DatabaseBase - * @param $condition + * @param DatabaseBase $dbr + * @param string|array $condition * @return bool|ResultWrapper */ protected static function listPages( $dbr, $condition ) { - return $dbr->resultObject( - $dbr->select( - array( 'archive' ), - array( - 'ar_namespace', - 'ar_title', - 'count' => 'COUNT(*)' - ), - $condition, - __METHOD__, - array( - 'GROUP BY' => array( 'ar_namespace', 'ar_title' ), - 'ORDER BY' => array( 'ar_namespace', 'ar_title' ), - 'LIMIT' => 100, - ) + return $dbr->resultObject( $dbr->select( + array( 'archive' ), + array( + 'ar_namespace', + 'ar_title', + 'count' => 'COUNT(*)' + ), + $condition, + __METHOD__, + array( + 'GROUP BY' => array( 'ar_namespace', 'ar_title' ), + 'ORDER BY' => array( 'ar_namespace', 'ar_title' ), + 'LIMIT' => 100, ) - ); + ) ); } /** @@ -141,8 +140,8 @@ class PageArchive { 'ar_title' => $this->title->getDBkey() ), __METHOD__, array( 'ORDER BY' => 'ar_timestamp DESC' ) ); - $ret = $dbr->resultObject( $res ); - return $ret; + + return $dbr->resultObject( $res ); } /** @@ -154,26 +153,28 @@ class PageArchive { * @todo Does this belong in Image for fuller encapsulation? */ function listFiles() { - if( $this->title->getNamespace() == NS_FILE ) { - $dbr = wfGetDB( DB_SLAVE ); - $res = $dbr->select( - 'filearchive', - ArchivedFile::selectFields(), - array( 'fa_name' => $this->title->getDBkey() ), - __METHOD__, - array( 'ORDER BY' => 'fa_timestamp DESC' ) ); - $ret = $dbr->resultObject( $res ); - return $ret; + if ( $this->title->getNamespace() != NS_FILE ) { + return null; } - return null; + + $dbr = wfGetDB( DB_SLAVE ); + $res = $dbr->select( + 'filearchive', + ArchivedFile::selectFields(), + array( 'fa_name' => $this->title->getDBkey() ), + __METHOD__, + array( 'ORDER BY' => 'fa_timestamp DESC' ) + ); + + return $dbr->resultObject( $res ); } /** * Return a Revision object containing data for the deleted revision. * Note that the result *may* or *may not* have a null page ID. * - * @param $timestamp String - * @return Revision + * @param string $timestamp + * @return Revision|null */ function getRevision( $timestamp ) { global $wgContentHandlerUseDB; @@ -203,14 +204,15 @@ class PageArchive { $row = $dbr->selectRow( 'archive', $fields, 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 ) { + + if ( $row ) { return Revision::newFromArchiveRow( $row, array( 'title' => $this->title ) ); - } else { - return null; } + + return null; } /** @@ -220,8 +222,8 @@ class PageArchive { * May produce unexpected results in case of history merges or other * unusual time issues. * - * @param $timestamp String - * @return Revision or null + * @param string $timestamp + * @return Revision|null Null when there is no previous revision */ function getPreviousRevision( $timestamp ) { $dbr = wfGetDB( DB_SLAVE ); @@ -246,7 +248,7 @@ class PageArchive { 'page_title' => $this->title->getDBkey(), 'page_id = rev_page', 'rev_timestamp < ' . - $dbr->addQuotes( $dbr->timestamp( $timestamp ) ) ), + $dbr->addQuotes( $dbr->timestamp( $timestamp ) ) ), __METHOD__, array( 'ORDER BY' => 'rev_timestamp DESC', @@ -254,38 +256,39 @@ class PageArchive { $prevLive = $row ? wfTimestamp( TS_MW, $row->rev_timestamp ) : false; $prevLiveId = $row ? intval( $row->rev_id ) : null; - if( $prevLive && $prevLive > $prevDeleted ) { + if ( $prevLive && $prevLive > $prevDeleted ) { // Most prior revision was live return Revision::newFromId( $prevLiveId ); - } elseif( $prevDeleted ) { + } elseif ( $prevDeleted ) { // Most prior revision was deleted return $this->getRevision( $prevDeleted ); - } else { - // No prior revision on this page. - return null; } + + // No prior revision on this page. + return null; } /** * Get the text from an archive row containing ar_text, ar_flags and ar_text_id * - * @param $row Object: database row - * @return Revision + * @param object $row Database row + * @return string */ function getTextFromRow( $row ) { - if( is_null( $row->ar_text_id ) ) { + 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_' ); - } else { - // New-style: keyed to the text storage backend. - $dbr = wfGetDB( DB_SLAVE ); - $text = $dbr->selectRow( 'text', - array( 'old_text', 'old_flags' ), - array( 'old_id' => $row->ar_text_id ), - __METHOD__ ); - return Revision::getRevisionText( $text ); } + + // New-style: keyed to the text storage backend. + $dbr = wfGetDB( DB_SLAVE ); + $text = $dbr->selectRow( 'text', + array( 'old_text', 'old_flags' ), + array( 'old_id' => $row->ar_text_id ), + __METHOD__ ); + + return Revision::getRevisionText( $text ); } /** @@ -294,7 +297,7 @@ class PageArchive { * * If there are no archived revisions for the page, returns NULL. * - * @return String + * @return string|null */ function getLastRevisionText() { $dbr = wfGetDB( DB_SLAVE ); @@ -304,17 +307,18 @@ class PageArchive { 'ar_title' => $this->title->getDBkey() ), __METHOD__, array( 'ORDER BY' => 'ar_timestamp DESC' ) ); - if( $row ) { + + if ( $row ) { return $this->getTextFromRow( $row ); - } else { - return null; } + + return null; } /** * Quick check if any archived revisions are present for the page. * - * @return Boolean + * @return boolean */ function isDeleted() { $dbr = wfGetDB( DB_SLAVE ); @@ -323,6 +327,7 @@ class PageArchive { 'ar_title' => $this->title->getDBkey() ), __METHOD__ ); + return ( $n > 0 ); } @@ -331,11 +336,11 @@ class PageArchive { * Once restored, the items will be removed from the archive tables. * The deletion log will be updated with an undeletion notice. * - * @param array $timestamps pass an empty array to restore all revisions, otherwise list the ones to undelete. - * @param $comment String - * @param $fileVersions Array - * @param $unsuppress Boolean - * @param $user User doing the action, or null to use $wgUser + * @param array $timestamps Pass an empty array to restore all revisions, otherwise list the ones to undelete. + * @param string $comment + * @param array $fileVersions + * @param bool $unsuppress + * @param User $user User performing the action, or null to use $wgUser * * @return array(number of file revisions restored, number of image revisions restored, log message) * on success, false on failure @@ -348,7 +353,7 @@ class PageArchive { $restoreText = $restoreAll || !empty( $timestamps ); $restoreFiles = $restoreAll || !empty( $fileVersions ); - if( $restoreFiles && $this->title->getNamespace() == NS_FILE ) { + if ( $restoreFiles && $this->title->getNamespace() == NS_FILE ) { $img = wfLocalFile( $this->title ); $this->fileStatus = $img->restore( $fileVersions, $unsuppress ); if ( !$this->fileStatus->isOK() ) { @@ -359,9 +364,9 @@ class PageArchive { $filesRestored = 0; } - if( $restoreText ) { + if ( $restoreText ) { $this->revisionStatus = $this->undeleteRevisions( $timestamps, $unsuppress, $comment ); - if( !$this->revisionStatus->isOK() ) { + if ( !$this->revisionStatus->isOK() ) { return false; } @@ -372,13 +377,13 @@ class PageArchive { // Touch the log! - if( $textRestored && $filesRestored ) { + if ( $textRestored && $filesRestored ) { $reason = wfMessage( 'undeletedrevisions-files' ) ->numParams( $textRestored, $filesRestored )->inContentLanguage()->text(); - } elseif( $textRestored ) { + } elseif ( $textRestored ) { $reason = wfMessage( 'undeletedrevisions' )->numParams( $textRestored ) ->inContentLanguage()->text(); - } elseif( $filesRestored ) { + } elseif ( $filesRestored ) { $reason = wfMessage( 'undeletedfiles' )->numParams( $filesRestored ) ->inContentLanguage()->text(); } else { @@ -386,7 +391,7 @@ class PageArchive { return false; } - if( trim( $comment ) != '' ) { + if ( trim( $comment ) != '' ) { $reason .= wfMessage( 'colon-separator' )->inContentLanguage()->text() . $comment; } @@ -413,12 +418,11 @@ class PageArchive { * to the cur/old tables. If the page currently exists, all revisions will * be stuffed into old, otherwise the most recent will go into cur. * - * @param array $timestamps pass an empty array to restore all revisions, otherwise list the ones to undelete. - * @param $unsuppress Boolean: remove all ar_deleted/fa_deleted restrictions of seletected revs - * - * @param $comment String + * @param array $timestamps Pass an empty array to restore all revisions, otherwise list the ones to undelete. + * @param bool $unsuppress Remove all ar_deleted/fa_deleted restrictions of seletected revs + * @param string $comment * @throws ReadOnlyError - * @return Status, containing the number of revisions restored on success + * @return Status Object containing the number of revisions restored on success */ private function undeleteRevisions( $timestamps, $unsuppress = false, $comment = '' ) { global $wgContentHandlerUseDB; @@ -426,8 +430,8 @@ class PageArchive { if ( wfReadOnly() ) { throw new ReadOnlyError(); } - $restoreAll = empty( $timestamps ); + $restoreAll = empty( $timestamps ); $dbw = wfGetDB( DB_MASTER ); # Does this page already exist? We'll have to update it... @@ -443,7 +447,8 @@ class PageArchive { __METHOD__, array( 'FOR UPDATE' ) // lock page ); - if( $page ) { + + if ( $page ) { $makepage = false; # Page already exists. Import the history, and if necessary # we'll update the latest revision field in the record. @@ -455,7 +460,7 @@ class PageArchive { array( 'rev_id' => $previousRevId ), __METHOD__ ); - if( $previousTimestamp === false ) { + if ( $previousTimestamp === false ) { wfDebug( __METHOD__ . ": existing page refers to a page_latest that does not exist\n" ); $status = Status::newGood( 0 ); @@ -470,7 +475,7 @@ class PageArchive { $previousTimestamp = 0; } - if( $restoreAll ) { + if ( $restoreAll ) { $oldones = '1 = 1'; # All revisions... } else { $oldts = implode( ',', @@ -509,14 +514,15 @@ class PageArchive { $fields, /* WHERE */ array( 'ar_namespace' => $this->title->getNamespace(), - 'ar_title' => $this->title->getDBkey(), + 'ar_title' => $this->title->getDBkey(), $oldones ), __METHOD__, /* options */ array( 'ORDER BY' => 'ar_timestamp' ) ); $ret = $dbw->resultObject( $result ); $rev_count = $dbw->numRows( $result ); - if( !$rev_count ) { + + if ( !$rev_count ) { wfDebug( __METHOD__ . ": no revisions to restore\n" ); $status = Status::newGood( 0 ); @@ -544,9 +550,9 @@ class PageArchive { return $status; } - if( $makepage ) { + 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 Status::newFatal( "undeleterevdel" ); } // Safe to insert now... @@ -554,9 +560,9 @@ class PageArchive { $pageId = $newid; } else { // Check if a deleted revision will become the current revision... - if( $row->ar_timestamp > $previousTimestamp ) { + 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 Status::newFatal( "undeleterevdel" ); } } @@ -570,10 +576,10 @@ class PageArchive { foreach ( $ret as $row ) { // Check for key dupes due to shitty archive integrity. - if( $row->ar_rev_id ) { + if ( $row->ar_rev_id ) { $exists = $dbw->selectField( 'revision', '1', array( 'rev_id' => $row->ar_rev_id ), __METHOD__ ); - if( $exists ) { + if ( $exists ) { continue; // don't throw DB errors } } @@ -616,7 +622,7 @@ class PageArchive { wfRunHooks( 'ArticleUndelete', array( &$this->title, $created, $comment ) ); - if( $this->title->getNamespace() == NS_FILE ) { + if ( $this->title->getNamespace() == NS_FILE ) { $update = new HTMLCacheUpdate( $this->title, 'imagelinks' ); $update->doUpdate(); } @@ -627,12 +633,16 @@ class PageArchive { /** * @return Status */ - function getFileStatus() { return $this->fileStatus; } + function getFileStatus() { + return $this->fileStatus; + } /** * @return Status */ - function getRevisionStatus() { return $this->revisionStatus; } + function getRevisionStatus() { + return $this->revisionStatus; + } } /** @@ -664,10 +674,13 @@ class SpecialUndelete extends SpecialPage { } else { $this->mTarget = $request->getVal( 'target' ); } + $this->mTargetObj = null; + if ( $this->mTarget !== null && $this->mTarget !== '' ) { $this->mTargetObj = Title::newFromURL( $this->mTarget ); } + $this->mSearchPrefix = $request->getText( 'prefix' ); $time = $request->getVal( 'timestamp' ); $this->mTimestamp = $time ? wfTimestamp( TS_MW, $time ) : ''; @@ -698,16 +711,16 @@ class SpecialUndelete extends SpecialPage { $this->mRestore = false; } - if( $this->mRestore || $this->mInvert ) { + if ( $this->mRestore || $this->mInvert ) { $timestamps = array(); $this->mFileVersions = array(); - foreach( $request->getValues() as $key => $val ) { + foreach ( $request->getValues() as $key => $val ) { $matches = array(); - if( preg_match( '/^ts(\d{14})$/', $key, $matches ) ) { + if ( preg_match( '/^ts(\d{14})$/', $key, $matches ) ) { array_push( $timestamps, $matches[1] ); } - if( preg_match( '/^fileid(\d+)$/', $key, $matches ) ) { + if ( preg_match( '/^fileid(\d+)$/', $key, $matches ) ) { $this->mFileVersions[] = intval( $matches[1] ); } } @@ -747,13 +760,13 @@ class SpecialUndelete extends SpecialPage { if ( $this->mTimestamp !== '' ) { $this->showRevision( $this->mTimestamp ); - } elseif ( $this->mFilename !== null ) { + } elseif ( $this->mFilename !== null && $this->mTargetObj->inNamespace( NS_FILE ) ) { $file = new ArchivedFile( $this->mTargetObj, '', $this->mFilename ); // Check if user is allowed to see this file if ( !$file->exists() ) { $out->addWikiMsg( 'filedelete-nofile', $this->mFilename ); } elseif ( !$file->userCan( File::DELETED_FILE, $user ) ) { - if( $file->isDeleted( File::DELETED_RESTRICTED ) ) { + if ( $file->isDeleted( File::DELETED_RESTRICTED ) ) { throw new PermissionsError( 'suppressrevision' ); } else { throw new PermissionsError( 'deletedtext' ); @@ -776,22 +789,27 @@ class SpecialUndelete extends SpecialPage { $out = $this->getOutput(); $out->setPageTitle( $this->msg( 'undelete-search-title' ) ); $out->addHTML( - Xml::openElement( 'form', array( - 'method' => 'get', - 'action' => $wgScript ) ) . - Xml::fieldset( $this->msg( 'undelete-search-box' )->text() ) . - Html::hidden( 'title', - $this->getTitle()->getPrefixedDBkey() ) . - Xml::inputLabel( $this->msg( 'undelete-search-prefix' )->text(), - 'prefix', 'prefix', 20, - $this->mSearchPrefix ) . ' ' . - Xml::submitButton( $this->msg( 'undelete-search-submit' )->text() ) . - Xml::closeElement( 'fieldset' ) . - Xml::closeElement( 'form' ) + Xml::openElement( 'form', array( 'method' => 'get', 'action' => $wgScript ) ) . + Xml::fieldset( $this->msg( 'undelete-search-box' )->text() ) . + Html::hidden( 'title', $this->getTitle()->getPrefixedDBkey() ) . + Html::rawElement( + 'label', + array( 'for' => 'prefix' ), + $this->msg( 'undelete-search-prefix' )->parse() + ) . + Xml::input( + 'prefix', + 20, + $this->mSearchPrefix, + array( 'id' => 'prefix', 'autofocus' => true ) + ) . ' ' . + Xml::submitButton( $this->msg( 'undelete-search-submit' )->text() ) . + Xml::closeElement( 'fieldset' ) . + Xml::closeElement( 'form' ) ); # List undeletable articles - if( $this->mSearchPrefix ) { + if ( $this->mSearchPrefix ) { $result = PageArchive::listPagesByPrefix( $this->mSearchPrefix ); $this->showList( $result ); } @@ -800,13 +818,13 @@ class SpecialUndelete extends SpecialPage { /** * Generic list of deleted pages * - * @param $result ResultWrapper + * @param ResultWrapper $result * @return bool */ private function showList( $result ) { $out = $this->getOutput(); - if( $result->numRows() == 0 ) { + if ( $result->numRows() == 0 ) { $out->addWikiMsg( 'undelete-no-results' ); return false; } @@ -826,8 +844,15 @@ class SpecialUndelete extends SpecialPage { ); } else { // The title is no longer valid, show as text - $item = Html::element( 'span', array( 'class' => 'mw-invalidtitle' ), - Linker::getInvalidTitleDescription( $this->getContext(), $row->ar_namespace, $row->ar_title ) ); + $item = Html::element( + 'span', + array( 'class' => 'mw-invalidtitle' ), + Linker::getInvalidTitleDescription( + $this->getContext(), + $row->ar_namespace, + $row->ar_title + ) + ); } $revs = $this->msg( 'undeleterevisions' )->numParams( $row->count )->parse(); $out->addHTML( "
        • {$item} ({$revs})
        • \n" ); @@ -839,7 +864,7 @@ class SpecialUndelete extends SpecialPage { } private function showRevision( $timestamp ) { - if( !preg_match( '/[0-9]{14}/', $timestamp ) ) { + if ( !preg_match( '/[0-9]{14}/', $timestamp ) ) { return; } @@ -852,31 +877,37 @@ class SpecialUndelete extends SpecialPage { $out = $this->getOutput(); $user = $this->getUser(); - if( !$rev ) { + if ( !$rev ) { $out->addWikiMsg( 'undeleterevision-missing' ); return; } - if( $rev->isDeleted( Revision::DELETED_TEXT ) ) { - if( !$rev->userCan( Revision::DELETED_TEXT, $user ) ) { - $out->wrapWikiMsg( "\n", 'rev-deleted-text-permission' ); + if ( $rev->isDeleted( Revision::DELETED_TEXT ) ) { + if ( !$rev->userCan( Revision::DELETED_TEXT, $user ) ) { + $out->wrapWikiMsg( + "\n", + 'rev-deleted-text-permission' + ); return; - } else { - $out->wrapWikiMsg( "\n", 'rev-deleted-text-view' ); - $out->addHTML( '
          ' ); - // and we are allowed to see... } + + $out->wrapWikiMsg( + "\n", + 'rev-deleted-text-view' + ); + $out->addHTML( '
          ' ); + // and we are allowed to see... } - if( $this->mDiff ) { + if ( $this->mDiff ) { $previousRev = $archive->getPreviousRevision( $timestamp ); - if( $previousRev ) { + if ( $previousRev ) { $this->showDiff( $previousRev, $rev ); - if( $this->mDiffOnly ) { + if ( $this->mDiffOnly ) { return; - } else { - $out->addHTML( '
          ' ); } + + $out->addHTML( '
          ' ); } else { $out->addWikiMsg( 'undelete-nodiff' ); } @@ -900,7 +931,7 @@ class SpecialUndelete extends SpecialPage { $isText = ( $content instanceof TextContent ); - if( $this->mPreview || $isText ) { + if ( $this->mPreview || $isText ) { $openDiv = '
          '; } else { $openDiv = '
          '; @@ -922,7 +953,7 @@ class SpecialUndelete extends SpecialPage { return; } - if( $this->mPreview || !$isText ) { + if ( $this->mPreview || !$isText ) { // NOTE: non-text content has no source view, so always use rendered preview // Hide [edit]s @@ -935,16 +966,21 @@ class SpecialUndelete extends SpecialPage { if ( $isText ) { // source view for textual content - $sourceView = Xml::element( 'textarea', array( - 'readonly' => 'readonly', - 'cols' => $user->getIntOption( 'cols' ), - 'rows' => $user->getIntOption( 'rows' ) ), - $content->getNativeData() . "\n" ); + $sourceView = Xml::element( + 'textarea', + array( + 'readonly' => 'readonly', + 'cols' => $user->getIntOption( 'cols' ), + 'rows' => $user->getIntOption( 'rows' ) + ), + $content->getNativeData() . "\n" + ); $previewButton = Xml::element( 'input', array( 'type' => 'submit', 'name' => 'preview', - 'value' => $this->msg( 'showpreview' )->text() ) ); + 'value' => $this->msg( 'showpreview' )->text() + ) ); } else { $sourceView = ''; $previewButton = ''; @@ -957,36 +993,37 @@ class SpecialUndelete extends SpecialPage { $out->addHTML( $sourceView . - Xml::openElement( 'div', array( - 'style' => 'clear: both' ) ) . - Xml::openElement( 'form', array( - 'method' => 'post', - 'action' => $this->getTitle()->getLocalURL( array( 'action' => 'submit' ) ) ) ) . - Xml::element( 'input', array( - 'type' => 'hidden', - 'name' => 'target', - 'value' => $this->mTargetObj->getPrefixedDBkey() ) ) . - Xml::element( 'input', array( - 'type' => 'hidden', - 'name' => 'timestamp', - 'value' => $timestamp ) ) . - Xml::element( 'input', array( - 'type' => 'hidden', - 'name' => 'wpEditToken', - 'value' => $user->getEditToken() ) ) . - $previewButton . - $diffButton . - Xml::closeElement( 'form' ) . - Xml::closeElement( 'div' ) ); + Xml::openElement( 'div', array( + 'style' => 'clear: both' ) ) . + Xml::openElement( 'form', array( + 'method' => 'post', + 'action' => $this->getTitle()->getLocalURL( array( 'action' => 'submit' ) ) ) ) . + Xml::element( 'input', array( + 'type' => 'hidden', + 'name' => 'target', + 'value' => $this->mTargetObj->getPrefixedDBkey() ) ) . + Xml::element( 'input', array( + 'type' => 'hidden', + 'name' => 'timestamp', + 'value' => $timestamp ) ) . + Xml::element( 'input', array( + 'type' => 'hidden', + 'name' => 'wpEditToken', + 'value' => $user->getEditToken() ) ) . + $previewButton . + $diffButton . + Xml::closeElement( 'form' ) . + Xml::closeElement( 'div' ) + ); } /** * Build a diff display between this and the previous either deleted * or non-deleted edit. * - * @param $previousRev Revision - * @param $currentRev Revision - * @return String: HTML + * @param Revision $previousRev + * @param Revision $currentRev + * @return string HTML */ function showDiff( $previousRev, $currentRev ) { $diffContext = clone $this->getContext(); @@ -995,20 +1032,19 @@ class SpecialUndelete extends SpecialPage { $diffEngine = $currentRev->getContentHandler()->createDifferenceEngine( $diffContext ); $diffEngine->showDiffStyle(); - $this->getOutput()->addHTML( - "
          " . + $this->getOutput()->addHTML( "
          " . "" . "" . "" . "" . "" . "" . - "\n" . - "\n" . + "\n" . + "\n" . "" . $diffEngine->generateContentDiffBody( $previousRev->getContent( Revision::FOR_THIS_USER, $this->getUser() ), @@ -1019,13 +1055,13 @@ class SpecialUndelete extends SpecialPage { } /** - * @param $rev Revision - * @param $prefix + * @param Revision $rev + * @param string $prefix * @return string */ private function diffHeader( $rev, $prefix ) { $isDeleted = !( $rev->getId() && $rev->getTitle() ); - if( $isDeleted ) { + if ( $isDeleted ) { /// @todo FIXME: $rev->getTitle() is null for deleted revs...? $targetPage = $this->getTitle(); $targetQuery = array( @@ -1037,30 +1073,34 @@ class SpecialUndelete extends SpecialPage { $targetPage = $rev->getTitle(); $targetQuery = array( 'oldid' => $rev->getId() ); } + // Add show/hide deletion links if available $user = $this->getUser(); $lang = $this->getLanguage(); $rdel = Linker::getRevDeleteLink( $user, $rev, $this->mTargetObj ); - if ( $rdel ) $rdel = " $rdel"; - return - '
          ' . - Linker::link( - $targetPage, - $this->msg( - 'revisionasof', - $lang->userTimeAndDate( $rev->getTimestamp(), $user ), - $lang->userDate( $rev->getTimestamp(), $user ), - $lang->userTime( $rev->getTimestamp(), $user ) - )->escaped(), - array(), - $targetQuery - ) . + + if ( $rdel ) { + $rdel = " $rdel"; + } + + return '
          ' . + Linker::link( + $targetPage, + $this->msg( + 'revisionasof', + $lang->userTimeAndDate( $rev->getTimestamp(), $user ), + $lang->userDate( $rev->getTimestamp(), $user ), + $lang->userTime( $rev->getTimestamp(), $user ) + )->escaped(), + array(), + $targetQuery + ) . '
          ' . '
          ' . - Linker::revUserTools( $rev ) . '
          ' . + Linker::revUserTools( $rev ) . '
          ' . '
          ' . '
          ' . - Linker::revComment( $rev ) . $rdel . '
          ' . + Linker::revComment( $rev ) . $rdel . '
          ' . '
          '; } @@ -1078,15 +1118,16 @@ class SpecialUndelete extends SpecialPage { $lang->userTime( $file->getTimestamp(), $user ) ); $out->addHTML( Xml::openElement( 'form', array( - 'method' => 'POST', - 'action' => $this->getTitle()->getLocalURL( - 'target=' . urlencode( $this->mTarget ) . - '&file=' . urlencode( $key ) . - '&token=' . urlencode( $user->getEditToken( $key ) ) ) + 'method' => 'POST', + 'action' => $this->getTitle()->getLocalURL( array( + 'target' => $this->mTarget, + 'file' => $key, + 'token' => $user->getEditToken( $key ), + ) ), ) ) . - Xml::submitButton( $this->msg( 'undelete-show-file-submit' )->text() ) . - '' + Xml::submitButton( $this->msg( 'undelete-show-file-submit' )->text() ) . + '' ); } @@ -1112,7 +1153,7 @@ class SpecialUndelete extends SpecialPage { private function showHistory() { $out = $this->getOutput(); - if( $this->mAllowed ) { + if ( $this->mAllowed ) { $out->addModules( 'mediawiki.special.undelete' ); } $out->wrapWikiMsg( @@ -1146,7 +1187,7 @@ class SpecialUndelete extends SpecialPage { $haveFiles = $files && $files->numRows() > 0; # Batch existence check on user and talk pages - if( $haveRevisions ) { + if ( $haveRevisions ) { $batch = new LinkBatch(); foreach ( $revisions as $row ) { $batch->addObj( Title::makeTitleSafe( NS_USER, $row->ar_user_text ) ); @@ -1155,7 +1196,7 @@ class SpecialUndelete extends SpecialPage { $batch->execute(); $revisions->seek( 0 ); } - if( $haveFiles ) { + if ( $haveFiles ) { $batch = new LinkBatch(); foreach ( $files as $row ) { $batch->addObj( Title::makeTitleSafe( NS_USER, $row->fa_user_text ) ); @@ -1168,7 +1209,10 @@ class SpecialUndelete extends SpecialPage { if ( $this->mAllowed ) { $action = $this->getTitle()->getLocalURL( array( 'action' => 'submit' ) ); # Start the form here - $top = Xml::openElement( 'form', array( 'method' => 'post', 'action' => $action, 'id' => 'undelete' ) ); + $top = Xml::openElement( + 'form', + array( 'method' => 'post', 'action' => $action, 'id' => 'undelete' ) + ); $out->addHTML( $top ); } @@ -1178,59 +1222,60 @@ class SpecialUndelete extends SpecialPage { LogEventsList::showLogExtract( $out, 'delete', $this->mTargetObj ); # Show relevant lines from the suppression log: $suppressLogPage = new LogPage( 'suppress' ); - if( $this->getUser()->isAllowed( 'suppressionlog' ) ) { + if ( $this->getUser()->isAllowed( 'suppressionlog' ) ) { $out->addHTML( Xml::element( 'h2', null, $suppressLogPage->getName()->text() ) . "\n" ); LogEventsList::showLogExtract( $out, 'suppress', $this->mTargetObj ); } - if( $this->mAllowed && ( $haveRevisions || $haveFiles ) ) { + if ( $this->mAllowed && ( $haveRevisions || $haveFiles ) ) { # Format the user-visible controls (comment field, submission button) # in a nice little table - if( $this->getUser()->isAllowed( 'suppressrevision' ) ) { + if ( $this->getUser()->isAllowed( 'suppressrevision' ) ) { $unsuppressBox = "
          "; } else { $unsuppressBox = ''; } + $table = Xml::fieldset( $this->msg( 'undelete-fieldset-title' )->text() ) . - Xml::openElement( 'table', array( 'id' => 'mw-undelete-table' ) ) . + Xml::openElement( 'table', array( 'id' => 'mw-undelete-table' ) ) . " - - - - - - - - - " . + $this->msg( 'undeleteextrahelp' )->parseAsBlock() . + " + + + + + + + + + " . $unsuppressBox . - Xml::closeElement( 'table' ) . - Xml::closeElement( 'fieldset' ); + Xml::closeElement( 'table' ) . + Xml::closeElement( 'fieldset' ); $out->addHTML( $table ); } $out->addHTML( Xml::element( 'h2', null, $this->msg( 'history' )->text() ) . "\n" ); - if( $haveRevisions ) { + if ( $haveRevisions ) { # The page's stored (deleted) history: $out->addHTML( '
            ' ); $remaining = $revisions->numRows(); @@ -1246,7 +1291,7 @@ class SpecialUndelete extends SpecialPage { $out->addWikiMsg( 'nohistory' ); } - if( $haveFiles ) { + if ( $haveFiles ) { $out->addHTML( Xml::element( 'h2', null, $this->msg( 'filehist' )->text() ) . "\n" ); $out->addHTML( '
              ' ); foreach ( $files as $row ) { @@ -1276,9 +1321,9 @@ class SpecialUndelete extends SpecialPage { $revTextSize = ''; $ts = wfTimestamp( TS_MW, $row->ar_timestamp ); // Build checkboxen... - if( $this->mAllowed ) { - if( $this->mInvert ) { - if( in_array( $ts, $this->mTargetTimestamp ) ) { + if ( $this->mAllowed ) { + if ( $this->mInvert ) { + if ( in_array( $ts, $this->mTargetTimestamp ) ) { $checkBox = Xml::check( "ts$ts" ); } else { $checkBox = Xml::check( "ts$ts", true ); @@ -1289,15 +1334,16 @@ class SpecialUndelete extends SpecialPage { } else { $checkBox = ''; } - $user = $this->getUser(); + // Build page & diff links... - if( $this->mCanView ) { + $user = $this->getUser(); + if ( $this->mCanView ) { $titleObj = $this->getTitle(); # Last link - if( !$rev->userCan( Revision::DELETED_TEXT, $this->getUser() ) ) { + if ( !$rev->userCan( Revision::DELETED_TEXT, $this->getUser() ) ) { $pageLink = htmlspecialchars( $this->getLanguage()->userTimeAndDate( $ts, $user ) ); $last = $this->msg( 'diff' )->escaped(); - } elseif( $remaining > 0 || ( $earliestLiveTime && $ts > $earliestLiveTime ) ) { + } elseif ( $remaining > 0 || ( $earliestLiveTime && $ts > $earliestLiveTime ) ) { $pageLink = $this->getPageLink( $rev, $titleObj, $ts ); $last = Linker::linkKnown( $titleObj, @@ -1317,28 +1363,35 @@ class SpecialUndelete extends SpecialPage { $pageLink = htmlspecialchars( $this->getLanguage()->userTimeAndDate( $ts, $user ) ); $last = $this->msg( 'diff' )->escaped(); } + // User links $userLink = Linker::revUserTools( $rev ); + // Revision text size $size = $row->ar_len; - if( !is_null( $size ) ) { + if ( !is_null( $size ) ) { $revTextSize = Linker::formatRevisionSize( $size ); } + // Edit summary $comment = Linker::revComment( $rev ); + // Revision delete links $revdlink = Linker::getRevDeleteLink( $user, $rev, $this->mTargetObj ); - $revisionRow = $this->msg( 'undelete-revisionrow' )->rawParams( $checkBox, $revdlink, $last, $pageLink, $userLink, $revTextSize, $comment )->escaped(); + $revisionRow = $this->msg( 'undelete-revisionrow' ) + ->rawParams( $checkBox, $revdlink, $last, $pageLink, $userLink, $revTextSize, $comment ) + ->escaped(); + return "
            • $revisionRow
            • "; } private function formatFileRow( $row ) { $file = ArchivedFile::newFromRow( $row ); - $ts = wfTimestamp( TS_MW, $row->fa_timestamp ); $user = $this->getUser(); - if( $this->mAllowed && $row->fa_storage_key ) { + + if ( $this->mAllowed && $row->fa_storage_key ) { $checkBox = Xml::check( 'fileid' . $row->fa_id ); $key = urlencode( $row->fa_storage_key ); $pageLink = $this->getFileLink( $file, $this->getTitle(), $ts, $key ); @@ -1348,15 +1401,18 @@ class SpecialUndelete extends SpecialPage { } $userLink = $this->getFileUser( $file ); $data = $this->msg( 'widthheight' )->numParams( $row->fa_width, $row->fa_height )->text(); - $bytes = $this->msg( 'parentheses' )->rawParams( $this->msg( 'nbytes' )->numParams( $row->fa_size )->text() )->plain(); + $bytes = $this->msg( 'parentheses' ) + ->rawParams( $this->msg( 'nbytes' )->numParams( $row->fa_size )->text() ) + ->plain(); $data = htmlspecialchars( $data . ' ' . $bytes ); $comment = $this->getFileComment( $file ); // Add show/hide deletion links if available $canHide = $user->isAllowed( 'deleterevision' ); - if( $canHide || ( $file->getVisibility() && $user->isAllowed( 'deletedhistory' ) ) ) { - if( !$file->userCan( File::DELETED_RESTRICTED, $user ) ) { - $revdlink = Linker::revDeleteLinkDisabled( $canHide ); // revision was hidden from sysops + if ( $canHide || ( $file->getVisibility() && $user->isAllowed( 'deletedhistory' ) ) ) { + if ( !$file->userCan( File::DELETED_RESTRICTED, $user ) ) { + // Revision was hidden from sysops + $revdlink = Linker::revDeleteLinkDisabled( $canHide ); } else { $query = array( 'type' => 'filearchive', @@ -1376,8 +1432,8 @@ class SpecialUndelete extends SpecialPage { /** * Fetch revision text link if it's available to all users * - * @param $rev Revision - * @param $titleObj Title + * @param Revision $rev + * @param Title $titleObj * @param string $ts Timestamp * @return string */ @@ -1385,95 +1441,105 @@ class SpecialUndelete extends SpecialPage { $user = $this->getUser(); $time = $this->getLanguage()->userTimeAndDate( $ts, $user ); - if( !$rev->userCan( Revision::DELETED_TEXT, $user ) ) { + if ( !$rev->userCan( Revision::DELETED_TEXT, $user ) ) { return '' . $time . ''; - } else { - $link = Linker::linkKnown( - $titleObj, - htmlspecialchars( $time ), - array(), - array( - 'target' => $this->mTargetObj->getPrefixedText(), - 'timestamp' => $ts - ) - ); - if( $rev->isDeleted( Revision::DELETED_TEXT ) ) { - $link = '' . $link . ''; - } - return $link; } + + $link = Linker::linkKnown( + $titleObj, + htmlspecialchars( $time ), + array(), + array( + 'target' => $this->mTargetObj->getPrefixedText(), + 'timestamp' => $ts + ) + ); + + if ( $rev->isDeleted( Revision::DELETED_TEXT ) ) { + $link = '' . $link . ''; + } + + return $link; } /** * Fetch image view link if it's available to all users * - * @param $file File - * @param $titleObj Title + * @param File|ArchivedFile $file + * @param Title $titleObj * @param string $ts A timestamp * @param string $key a storage key * - * @return String: HTML fragment + * @return string HTML fragment */ function getFileLink( $file, $titleObj, $ts, $key ) { $user = $this->getUser(); $time = $this->getLanguage()->userTimeAndDate( $ts, $user ); - if( !$file->userCan( File::DELETED_FILE, $user ) ) { + if ( !$file->userCan( File::DELETED_FILE, $user ) ) { return '' . $time . ''; - } else { - $link = Linker::linkKnown( - $titleObj, - htmlspecialchars( $time ), - array(), - array( - 'target' => $this->mTargetObj->getPrefixedText(), - 'file' => $key, - 'token' => $user->getEditToken( $key ) - ) - ); - if( $file->isDeleted( File::DELETED_FILE ) ) { - $link = '' . $link . ''; - } - return $link; } + + $link = Linker::linkKnown( + $titleObj, + htmlspecialchars( $time ), + array(), + array( + 'target' => $this->mTargetObj->getPrefixedText(), + 'file' => $key, + 'token' => $user->getEditToken( $key ) + ) + ); + + if ( $file->isDeleted( File::DELETED_FILE ) ) { + $link = '' . $link . ''; + } + + return $link; } /** * Fetch file's user id if it's available to this user * - * @param $file File - * @return String: HTML fragment + * @param File|ArchivedFile $file + * @return string HTML fragment */ function getFileUser( $file ) { - if( !$file->userCan( File::DELETED_USER, $this->getUser() ) ) { - return '' . $this->msg( 'rev-deleted-user' )->escaped() . ''; - } else { - $link = Linker::userLink( $file->getRawUser(), $file->getRawUserText() ) . - Linker::userToolLinks( $file->getRawUser(), $file->getRawUserText() ); - if( $file->isDeleted( File::DELETED_USER ) ) { - $link = '' . $link . ''; - } - return $link; + if ( !$file->userCan( File::DELETED_USER, $this->getUser() ) ) { + return '' . + $this->msg( 'rev-deleted-user' )->escaped() . + ''; } + + $link = Linker::userLink( $file->getRawUser(), $file->getRawUserText() ) . + Linker::userToolLinks( $file->getRawUser(), $file->getRawUserText() ); + + if ( $file->isDeleted( File::DELETED_USER ) ) { + $link = '' . $link . ''; + } + + return $link; } /** * Fetch file upload comment if it's available to this user * - * @param $file File - * @return String: HTML fragment + * @param File|ArchivedFile $file + * @return string HTML fragment */ function getFileComment( $file ) { - if( !$file->userCan( File::DELETED_COMMENT, $this->getUser() ) ) { + if ( !$file->userCan( File::DELETED_COMMENT, $this->getUser() ) ) { return '' . $this->msg( 'rev-deleted-comment' )->escaped() . ''; - } else { - $link = Linker::commentBlock( $file->getRawDescription() ); - if( $file->isDeleted( File::DELETED_COMMENT ) ) { - $link = '' . $link . ''; - } - return $link; } + + $link = Linker::commentBlock( $file->getRawDescription() ); + + if ( $file->isDeleted( File::DELETED_COMMENT ) ) { + $link = '' . $link . ''; + } + + return $link; } function undelete() { @@ -1498,7 +1564,7 @@ class SpecialUndelete extends SpecialPage { $this->getUser() ); - if( is_array( $ok ) ) { + if ( is_array( $ok ) ) { if ( $ok[1] ) { // Undeleted file count wfRunHooks( 'FileUndeleteComplete', array( $this->mTargetObj, $this->mFileVersions, @@ -1513,13 +1579,13 @@ class SpecialUndelete extends SpecialPage { // Show revision undeletion warnings and errors $status = $archive->getRevisionStatus(); - if( $status && !$status->isGood() ) { + if ( $status && !$status->isGood() ) { $out->addWikiText( '
              ' . $status->getWikiText( 'cannotundelete', 'cannotundelete' ) . '
              ' ); } // Show file undeletion warnings and errors $status = $archive->getFileStatus(); - if( $status && !$status->isGood() ) { + if ( $status && !$status->isGood() ) { $out->addWikiText( '
              ' . $status->getWikiText( 'undelete-error-short', 'undelete-error-long' ) . '
              ' ); } } diff --git a/includes/specials/SpecialUnusedcategories.php b/includes/specials/SpecialUnusedcategories.php index 6b91dd39..b686a5b5 100644 --- a/includes/specials/SpecialUnusedcategories.php +++ b/includes/specials/SpecialUnusedcategories.php @@ -39,15 +39,15 @@ class UnusedCategoriesPage extends QueryPage { } function getQueryInfo() { - return array ( - 'tables' => array ( 'page', 'categorylinks' ), - 'fields' => array ( 'namespace' => 'page_namespace', + return array( + 'tables' => array( 'page', 'categorylinks' ), + 'fields' => array( 'namespace' => 'page_namespace', 'title' => 'page_title', 'value' => 'page_title' ), - 'conds' => array ( 'cl_from IS NULL', + 'conds' => array( 'cl_from IS NULL', 'page_namespace' => NS_CATEGORY, 'page_is_redirect' => 0 ), - 'join_conds' => array ( 'categorylinks' => array ( + 'join_conds' => array( 'categorylinks' => array( 'LEFT JOIN', 'cl_to = page_title' ) ) ); } @@ -60,6 +60,11 @@ class UnusedCategoriesPage extends QueryPage { return false; } + /** + * @param Skin $skin + * @param object $result Result row + * @return string + */ function formatResult( $skin, $result ) { $title = Title::makeTitle( NS_CATEGORY, $result->title ); return Linker::link( $title, htmlspecialchars( $title->getText() ) ); diff --git a/includes/specials/SpecialUnusedimages.php b/includes/specials/SpecialUnusedimages.php index 69553282..d332db75 100644 --- a/includes/specials/SpecialUnusedimages.php +++ b/includes/specials/SpecialUnusedimages.php @@ -45,28 +45,28 @@ class UnusedimagesPage extends ImageQueryPage { function getQueryInfo() { global $wgCountCategorizedImagesAsUsed; - $retval = array ( - 'tables' => array ( 'image', 'imagelinks' ), - 'fields' => array ( 'namespace' => NS_FILE, + $retval = array( + 'tables' => array( 'image', 'imagelinks' ), + 'fields' => array( 'namespace' => NS_FILE, 'title' => 'img_name', 'value' => 'img_timestamp', 'img_user', 'img_user_text', 'img_description' ), - 'conds' => array ( 'il_to IS NULL' ), - 'join_conds' => array ( 'imagelinks' => array ( + 'conds' => array( 'il_to IS NULL' ), + 'join_conds' => array( 'imagelinks' => array( 'LEFT JOIN', 'il_to = img_name' ) ) ); if ( $wgCountCategorizedImagesAsUsed ) { // Order is significant - $retval['tables'] = array ( 'image', 'page', 'categorylinks', + $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 ( + $retval['join_conds']['categorylinks'] = array( 'LEFT JOIN', 'cl_from = page_id' ); - $retval['join_conds']['imagelinks'] = array ( + $retval['join_conds']['imagelinks'] = array( 'LEFT JOIN', 'il_to = page_title' ); } return $retval; diff --git a/includes/specials/SpecialUnusedtemplates.php b/includes/specials/SpecialUnusedtemplates.php index 493e936a..1dc9f420 100644 --- a/includes/specials/SpecialUnusedtemplates.php +++ b/includes/specials/SpecialUnusedtemplates.php @@ -48,23 +48,23 @@ class UnusedtemplatesPage extends QueryPage { } function getQueryInfo() { - return array ( - 'tables' => array ( 'page', 'templatelinks' ), - 'fields' => array ( 'namespace' => 'page_namespace', + return array( + 'tables' => array( 'page', 'templatelinks' ), + 'fields' => array( 'namespace' => 'page_namespace', 'title' => 'page_title', 'value' => 'page_title' ), - 'conds' => array ( 'page_namespace' => NS_TEMPLATE, + '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', + 'join_conds' => array( 'templatelinks' => array( + 'LEFT JOIN', array( 'tl_title = page_title', 'tl_namespace = page_namespace' ) ) ) ); } /** - * @param $skin Skin - * @param $result + * @param Skin $skin + * @param object $result Result row * @return string */ function formatResult( $skin, $result ) { diff --git a/includes/specials/SpecialUnwatchedpages.php b/includes/specials/SpecialUnwatchedpages.php index 05ec6b02..954e3ffe 100644 --- a/includes/specials/SpecialUnwatchedpages.php +++ b/includes/specials/SpecialUnwatchedpages.php @@ -44,17 +44,17 @@ class UnwatchedpagesPage extends QueryPage { } function getQueryInfo() { - return array ( - 'tables' => array ( 'page', 'watchlist' ), - 'fields' => array ( 'namespace' => 'page_namespace', + return array( + 'tables' => array( 'page', 'watchlist' ), + 'fields' => array( 'namespace' => 'page_namespace', 'title' => 'page_title', 'value' => 'page_namespace' ), - 'conds' => array ( 'wl_title IS NULL', + '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', + 'join_conds' => array( 'watchlist' => array( + 'LEFT JOIN', array( 'wl_title = page_title', 'wl_namespace = page_namespace' ) ) ) ); } @@ -68,8 +68,8 @@ class UnwatchedpagesPage extends QueryPage { } /** - * @param $skin Skin - * @param $result + * @param Skin $skin + * @param object $result Result row * @return string */ function formatResult( $skin, $result ) { diff --git a/includes/specials/SpecialUpload.php b/includes/specials/SpecialUpload.php index 89c06b2a..09facf4f 100644 --- a/includes/specials/SpecialUpload.php +++ b/includes/specials/SpecialUpload.php @@ -90,10 +90,9 @@ class SpecialUpload extends SpecialPage { // Guess the desired name from the filename if not provided $this->mDesiredDestName = $request->getText( 'wpDestFile' ); - if( !$this->mDesiredDestName && $request->getFileName( 'wpUploadFile' ) !== null ) { + if ( !$this->mDesiredDestName && $request->getFileName( 'wpUploadFile' ) !== null ) { $this->mDesiredDestName = $request->getFileName( 'wpUploadFile' ); } - $this->mComment = $request->getText( 'wpUploadDescription' ); $this->mLicense = $request->getText( 'wpLicense' ); $this->mDestWarningAck = $request->getText( 'wpDestFileWarningAck' ); @@ -104,6 +103,14 @@ class SpecialUpload extends SpecialPage { $this->mCopyrightSource = $request->getText( 'wpUploadSource' ); $this->mForReUpload = $request->getBool( 'wpForReUpload' ); // updating a file + + $commentDefault = ''; + $commentMsg = wfMessage( 'upload-default-description' )->inContentLanguage(); + if ( !$this->mForReUpload && !$commentMsg->isDisabled() ) { + $commentDefault = $commentMsg->plain(); + } + $this->mComment = $request->getText( 'wpUploadDescription', $commentDefault ); + $this->mCancelUpload = $request->getCheck( 'wpCancelUpload' ) || $request->getCheck( 'wpReUpload' ); // b/w compat @@ -135,19 +142,19 @@ class SpecialUpload extends SpecialPage { $this->outputHeader(); # Check uploading enabled - if( !UploadBase::isEnabled() ) { + if ( !UploadBase::isEnabled() ) { throw new ErrorPageError( 'uploaddisabled', 'uploaddisabledtext' ); } # Check permissions $user = $this->getUser(); $permissionRequired = UploadBase::isAllowed( $user ); - if( $permissionRequired !== true ) { + if ( $permissionRequired !== true ) { throw new PermissionsError( $permissionRequired ); } # Check blocks - if( $user->isBlocked() ) { + if ( $user->isBlocked() ) { throw new UserBlockedError( $user->getBlock() ); } @@ -172,7 +179,7 @@ class SpecialUpload extends SpecialPage { $this->processUpload(); } else { # Backwards compatibility hook - if( !wfRunHooks( 'UploadForm:initial', array( &$this ) ) ) { + if ( !wfRunHooks( 'UploadForm:initial', array( &$this ) ) ) { wfDebug( "Hook 'UploadForm:initial' broke output of the upload form" ); return; } @@ -214,6 +221,8 @@ class SpecialUpload extends SpecialPage { */ protected function getUploadForm( $message = '', $sessionKey = '', $hideIgnoreWarning = false ) { # Initialize form + $context = new DerivativeContext( $this->getContext() ); + $context->setTitle( $this->getTitle() ); // Remove subpage $form = new UploadForm( array( 'watch' => $this->getWatchCheck(), 'forreupload' => $this->mForReUpload, @@ -225,11 +234,10 @@ class SpecialUpload extends SpecialPage { 'texttop' => $this->uploadFormTextTop, 'textaftersummary' => $this->uploadFormTextAfterSummary, 'destfile' => $this->mDesiredDestName, - ), $this->getContext() ); - $form->setTitle( $this->getTitle() ); + ), $context ); # Check the token, but only if necessary - if( + if ( !$this->mTokenOk && !$this->mCancelUpload && ( $this->mUpload && $this->mUploadClicked ) ) { @@ -275,7 +283,7 @@ class SpecialUpload extends SpecialPage { $title = Title::makeTitleSafe( NS_FILE, $this->mDesiredDestName ); $user = $this->getUser(); // Show a subtitle link to deleted revisions (to sysops et al only) - if( $title instanceof Title ) { + if ( $title instanceof Title ) { $count = $title->isDeleted(); if ( $count > 0 && $user->isAllowed( 'deletedhistory' ) ) { $restorelink = Linker::linkKnown( @@ -333,15 +341,15 @@ class SpecialUpload extends SpecialPage { $warningHtml = '

              ' . $this->msg( 'uploadwarning' )->escaped() . "

              \n" . '
                '; - foreach( $warnings as $warning => $args ) { - if( $warning == 'badfilename' ) { + foreach ( $warnings as $warning => $args ) { + if ( $warning == 'badfilename' ) { $this->mDesiredDestName = Title::makeTitle( NS_FILE, $args )->getText(); } - if( $warning == 'exists' ) { + if ( $warning == 'exists' ) { $msg = "\t
              • " . self::getExistsWarning( $args ) . "
              • \n"; - } elseif( $warning == 'duplicate' ) { - $msg = self::getDupeWarning( $args ); - } elseif( $warning == 'duplicate-archive' ) { + } elseif ( $warning == 'duplicate' ) { + $msg = $this->getDupeWarning( $args ); + } elseif ( $warning == 'duplicate-archive' ) { $msg = "\t
              • " . $this->msg( 'file-deleted-duplicate', Title::makeTitle( NS_FILE, $args )->getPrefixedText() )->parse() . "
              • \n"; @@ -387,12 +395,12 @@ class SpecialUpload extends SpecialPage { protected function processUpload() { // Fetch the file if required $status = $this->mUpload->fetchFile(); - if( !$status->isOK() ) { + if ( !$status->isOK() ) { $this->showUploadError( $this->getOutput()->parse( $status->getWikiText() ) ); return; } - if( !wfRunHooks( 'UploadForm:BeforeProcessing', array( &$this ) ) ) { + if ( !wfRunHooks( 'UploadForm:BeforeProcessing', array( &$this ) ) ) { wfDebug( "Hook 'UploadForm:BeforeProcessing' broke processing the file.\n" ); // This code path is deprecated. If you want to break upload processing // do so by hooking into the appropriate hooks in UploadBase::verifyUpload @@ -411,7 +419,7 @@ class SpecialUpload extends SpecialPage { // Verify permissions for this title $permErrors = $this->mUpload->verifyTitlePermissions( $this->getUser() ); - if( $permErrors !== true ) { + if ( $permErrors !== true ) { $code = array_shift( $permErrors[0] ); $this->showRecoverableUploadError( $this->msg( $code, $permErrors[0] )->parse() ); return; @@ -420,15 +428,15 @@ class SpecialUpload extends SpecialPage { $this->mLocalFile = $this->mUpload->getLocalFile(); // Check warnings if necessary - if( !$this->mIgnoreWarning ) { + if ( !$this->mIgnoreWarning ) { $warnings = $this->mUpload->checkWarnings(); - if( $this->showUploadWarning( $warnings ) ) { + if ( $this->showUploadWarning( $warnings ) ) { return; } } // Get the page text if this is not a reupload - if( !$this->mForReUpload ) { + if ( !$this->mForReUpload ) { $pageText = self::getInitialPageText( $this->mComment, $this->mLicense, $this->mCopyrightStatus, $this->mCopyrightSource ); } else { @@ -456,15 +464,14 @@ class SpecialUpload extends SpecialPage { */ public static function getInitialPageText( $comment = '', $license = '', $copyStatus = '', $source = '' ) { global $wgUseCopyrightUpload, $wgForceUIMsgAsContentMsg; - $wgForceUIMsgAsContentMsg = (array) $wgForceUIMsgAsContentMsg; $msg = array(); /* These messages are transcluded into the actual text of the description page. * Thus, forcing them as content messages makes the upload to produce an int: template * instead of hardcoding it there in the uploader language. */ - foreach( array( 'license-header', 'filedesc', 'filestatus', 'filesource' ) as $msgName ) { - if ( in_array( $msgName, $wgForceUIMsgAsContentMsg ) ) { + foreach ( array( 'license-header', 'filedesc', 'filestatus', 'filesource' ) as $msgName ) { + if ( in_array( $msgName, (array)$wgForceUIMsgAsContentMsg ) ) { $msg[$msgName] = "{{int:$msgName}}"; } else { $msg[$msgName] = wfMessage( $msgName )->inContentLanguage()->text(); @@ -505,13 +512,13 @@ class SpecialUpload extends SpecialPage { * @return Bool|String */ protected function getWatchCheck() { - if( $this->getUser()->getOption( 'watchdefault' ) ) { + if ( $this->getUser()->getOption( 'watchdefault' ) ) { // Watch all edits! return true; } $local = wfLocalFile( $this->mDesiredDestName ); - if( $local && $local->exists() ) { + if ( $local && $local->exists() ) { // We're uploading a new version of an existing file. // No creation, so don't watch it if we're not already. return $this->getUser()->isWatched( $local->getTitle() ); @@ -530,7 +537,7 @@ class SpecialUpload extends SpecialPage { protected function processVerificationError( $details ) { global $wgFileExtensions; - switch( $details['status'] ) { + switch ( $details['status'] ) { /** Statuses that only require name changing **/ case UploadBase::MIN_LENGTH_PARTNAME: @@ -564,8 +571,9 @@ class SpecialUpload extends SpecialPage { } else { $msg->params( $details['finalExt'] ); } - $msg->params( $this->getLanguage()->commaList( $wgFileExtensions ), - count( $wgFileExtensions ) ); + $extensions = array_unique( $wgFileExtensions ); + $msg->params( $this->getLanguage()->commaList( $extensions ), + count( $extensions ) ); // Add PLURAL support for the first parameter. This results // in a bit unlogical parameter sequence, but does not break @@ -635,10 +643,10 @@ class SpecialUpload extends SpecialPage { $filename = $file->getTitle()->getPrefixedText(); $warning = ''; - if( $exists['warning'] == 'exists' ) { + if ( $exists['warning'] == 'exists' ) { // Exact match $warning = wfMessage( 'fileexists', $filename )->parse(); - } elseif( $exists['warning'] == 'page-exists' ) { + } elseif ( $exists['warning'] == 'page-exists' ) { // Page exists but file does not $warning = wfMessage( 'filepageexists', $filename )->parse(); } elseif ( $exists['warning'] == 'exists-normalized' ) { @@ -673,43 +681,20 @@ class SpecialUpload extends SpecialPage { return $warning; } - /** - * Get a list of warnings - * - * @param string $filename local filename, e.g. 'file exists', 'non-descriptive filename' - * @return Array: list of warning messages - */ - public static function ajaxGetExistsWarning( $filename ) { - $file = wfFindFile( $filename ); - if( !$file ) { - // Force local file so we have an object to do further checks against - // if there isn't an exact match... - $file = wfLocalFile( $filename ); - } - $s = ' '; - if ( $file ) { - $exists = UploadBase::getExistsWarning( $file ); - $warning = self::getExistsWarning( $exists ); - if ( $warning !== '' ) { - $s = "
                $warning
                "; - } - } - return $s; - } - /** * Construct a warning and a gallery from an array of duplicate files. * @param $dupes array * @return string */ - public static function getDupeWarning( $dupes ) { + public function getDupeWarning( $dupes ) { if ( !$dupes ) { return ''; } - $gallery = new ImageGallery; + $gallery = ImageGalleryBase::factory(); + $gallery->setContext( $this->getContext() ); $gallery->setShowBytes( false ); - foreach( $dupes as $file ) { + foreach ( $dupes as $file ) { $gallery->add( $file->getTitle() ); } return '
              • ' . @@ -843,10 +828,13 @@ class UploadForm extends HTMLForm { 'upload-type' => 'File', 'radio' => &$radio, 'help' => $this->msg( 'upload-maxfilesize', - $this->getContext()->getLanguage()->formatSize( $this->mMaxUploadSize['file'] ) - )->parse() . ' ' . $this->msg( 'upload_source_file' )->escaped(), + $this->getContext()->getLanguage()->formatSize( $this->mMaxUploadSize['file'] ) ) + ->parse() . + $this->msg( 'word-separator' )->escaped() . + $this->msg( 'upload_source_file' )->escaped(), 'checked' => $selectedSourceType == 'file', ); + if ( $canUploadByUrl ) { $this->mMaxUploadSize['url'] = UploadBase::getMaxUploadSize( 'url' ); $descriptor['UploadFileURL'] = array( @@ -857,8 +845,10 @@ class UploadForm extends HTMLForm { 'upload-type' => 'url', 'radio' => &$radio, 'help' => $this->msg( 'upload-maxfilesize', - $this->getContext()->getLanguage()->formatSize( $this->mMaxUploadSize['url'] ) - )->parse() . ' ' . $this->msg( 'upload_source_url' )->escaped(), + $this->getContext()->getLanguage()->formatSize( $this->mMaxUploadSize['url'] ) ) + ->parse() . + $this->msg( 'word-separator' )->escaped() . + $this->msg( 'upload_source_url' )->escaped(), 'checked' => $selectedSourceType == 'url', ); } @@ -884,21 +874,21 @@ class UploadForm extends HTMLForm { global $wgCheckFileExtensions, $wgStrictFileExtensions, $wgFileExtensions, $wgFileBlacklist; - if( $wgCheckFileExtensions ) { - if( $wgStrictFileExtensions ) { + if ( $wgCheckFileExtensions ) { + if ( $wgStrictFileExtensions ) { # Everything not permitted is banned $extensionsList = '
                ' . - $this->msg( 'upload-permitted', $this->getContext()->getLanguage()->commaList( $wgFileExtensions ) )->parseAsBlock() . + $this->msg( 'upload-permitted', $this->getContext()->getLanguage()->commaList( array_unique( $wgFileExtensions ) ) )->parseAsBlock() . "
                \n"; } else { # We have to list both preferred and prohibited $extensionsList = '
                ' . - $this->msg( 'upload-preferred', $this->getContext()->getLanguage()->commaList( $wgFileExtensions ) )->parseAsBlock() . + $this->msg( 'upload-preferred', $this->getContext()->getLanguage()->commaList( array_unique( $wgFileExtensions ) ) )->parseAsBlock() . "
                \n" . '
                ' . - $this->msg( 'upload-prohibited', $this->getContext()->getLanguage()->commaList( $wgFileBlacklist ) )->parseAsBlock() . + $this->msg( 'upload-prohibited', $this->getContext()->getLanguage()->commaList( array_unique( $wgFileBlacklist ) ) )->parseAsBlock() . "
                \n"; } } else { diff --git a/includes/specials/SpecialUploadStash.php b/includes/specials/SpecialUploadStash.php index 066dcfc9..87b64428 100644 --- a/includes/specials/SpecialUploadStash.php +++ b/includes/specials/SpecialUploadStash.php @@ -88,19 +88,19 @@ class SpecialUploadStash extends UnlistedSpecialPage { } else { return $this->outputLocalFile( $params['file'] ); } - } catch( UploadStashFileNotFoundException $e ) { + } catch ( UploadStashFileNotFoundException $e ) { $code = 404; $message = $e->getMessage(); - } catch( UploadStashZeroLengthFileException $e ) { + } catch ( UploadStashZeroLengthFileException $e ) { $code = 500; $message = $e->getMessage(); - } catch( UploadStashBadPathException $e ) { + } catch ( UploadStashBadPathException $e ) { $code = 500; $message = $e->getMessage(); - } catch( SpecialUploadStashTooLargeException $e ) { + } catch ( SpecialUploadStashTooLargeException $e ) { $code = 500; $message = 'Cannot serve a file larger than ' . self::MAX_SERVE_BYTES . ' bytes. ' . $e->getMessage(); - } catch( Exception $e ) { + } catch ( Exception $e ) { $code = 500; $message = $e->getMessage(); } @@ -134,8 +134,13 @@ class SpecialUploadStash extends UnlistedSpecialPage { $paramString = substr( $thumbPart, 0, $srcNamePos - 1 ); $handler = $file->getHandler(); - $params = $handler->parseParamString( $paramString ); - return array( 'file' => $file, 'type' => $type, 'params' => $params ); + if ( $handler ) { + $params = $handler->parseParamString( $paramString ); + return array( 'file' => $file, 'type' => $type, 'params' => $params ); + } else { + throw new UploadStashBadPathException( 'No handler found for ' . + "mime {$file->getMimeType()} of file {$file->getPath()}" ); + } } return array( 'file' => $file, 'type' => $type ); @@ -222,7 +227,7 @@ class SpecialUploadStash extends UnlistedSpecialPage { global $wgUploadStashScalerBaseUrl; $scalerBaseUrl = $wgUploadStashScalerBaseUrl; - if( preg_match( '/^\/\//', $scalerBaseUrl ) ) { + if ( preg_match( '/^\/\//', $scalerBaseUrl ) ) { // this is apparently a protocol-relative URL, which makes no sense in this context, // since this is used for communication that's internal to the application. // default to http. @@ -303,8 +308,6 @@ 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 ); - // Bug 53032 - It shouldn't be a problem here, but let's be safe and not cache - header( 'Cache-Control: private' ); header( "Content-Length: $size", true ); } @@ -313,6 +316,7 @@ class SpecialUploadStash extends UnlistedSpecialPage { * 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. * + * @param array $formData * @return Status */ public static function tryClearStashedUploads( $formData ) { @@ -339,15 +343,16 @@ class SpecialUploadStash extends UnlistedSpecialPage { // 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? + $context = new DerivativeContext( $this->getContext() ); + $context->setTitle( $this->getTitle() ); // Remove subpage $form = new HTMLForm( array( 'Clear' => array( 'type' => 'hidden', 'default' => true, 'name' => 'clear', ) - ), $this->getContext(), 'clearStashedUploads' ); + ), $context, 'clearStashedUploads' ); $form->setSubmitCallback( array( __CLASS__, 'tryClearStashedUploads' ) ); - $form->setTitle( $this->getTitle() ); $form->setSubmitTextMsg( 'uploadstash-clear' ); $form->prepareForm(); diff --git a/includes/specials/SpecialUserlogin.php b/includes/specials/SpecialUserlogin.php index eef66914..5ac3e654 100644 --- a/includes/specials/SpecialUserlogin.php +++ b/includes/specials/SpecialUserlogin.php @@ -48,18 +48,21 @@ class LoginForm extends SpecialPage { var $mLoginattempt, $mRemember, $mEmail, $mDomain, $mLanguage; var $mSkipCookieCheck, $mReturnToQuery, $mToken, $mStickHTTPS; var $mType, $mReason, $mRealName; - var $mAbortLoginErrorMsg = 'login-abort-generic'; + var $mAbortLoginErrorMsg = null; private $mLoaded = false; + private $mSecureLoginUrl; /** - * @var ExternalUser + * @ var WebRequest */ - private $mExtUser = null; + private $mOverrideRequest = null; /** - * @ var WebRequest + * Effective request; set at the beginning of load + * + * @var WebRequest $mRequest */ - private $mOverrideRequest = null; + private $mRequest = null; /** * @param WebRequest $request @@ -86,6 +89,7 @@ class LoginForm extends SpecialPage { } else { $request = $this->mOverrideRequest; } + $this->mRequest = $request; $this->mType = $request->getText( 'type' ); $this->mUsername = $request->getText( 'wpName' ); @@ -101,25 +105,26 @@ class LoginForm extends SpecialPage { $this->mLoginattempt = $request->getCheck( 'wpLoginattempt' ); $this->mAction = $request->getVal( 'action' ); $this->mRemember = $request->getCheck( 'wpRemember' ); - $this->mStickHTTPS = $request->getCheck( 'wpStickHTTPS' ); + $this->mFromHTTP = $request->getBool( 'fromhttp', false ); + $this->mStickHTTPS = ( !$this->mFromHTTP && $request->detectProtocol() === 'https' ) || $request->getBool( 'wpForceHttps', false ); $this->mLanguage = $request->getText( 'uselang' ); $this->mSkipCookieCheck = $request->getCheck( 'wpSkipCookieCheck' ); $this->mToken = ( $this->mType == 'signup' ) ? $request->getVal( 'wpCreateaccountToken' ) : $request->getVal( 'wpLoginToken' ); $this->mReturnTo = $request->getVal( 'returnto', '' ); $this->mReturnToQuery = $request->getVal( 'returntoquery', '' ); - if( $wgEnableEmail ) { + if ( $wgEnableEmail ) { $this->mEmail = $request->getText( 'wpEmail' ); } else { $this->mEmail = ''; } - if( !in_array( 'realname', $wgHiddenPrefs ) ) { + if ( !in_array( 'realname', $wgHiddenPrefs ) ) { $this->mRealName = $request->getText( 'wpRealName' ); } else { $this->mRealName = ''; } - if( !$wgAuth->validDomain( $this->mDomain ) ) { + if ( !$wgAuth->validDomain( $this->mDomain ) ) { $this->mDomain = $wgAuth->getDomain(); } $wgAuth->setDomain( $this->mDomain ); @@ -128,7 +133,7 @@ class LoginForm extends SpecialPage { # 2. Do not return to PasswordReset after a successful password change # but goto Wiki start page (Main_Page) instead ( bug 33997 ) $returnToTitle = Title::newFromText( $this->mReturnTo ); - if( is_object( $returnToTitle ) && ( + if ( is_object( $returnToTitle ) && ( $returnToTitle->isSpecial( 'Userlogout' ) || $returnToTitle->isSpecial( 'PasswordReset' ) ) ) { $this->mReturnTo = ''; @@ -137,44 +142,61 @@ class LoginForm extends SpecialPage { } function getDescription() { - return $this->msg( $this->getUser()->isAllowed( 'createaccount' ) ? - 'userlogin' : 'userloginnocreate' )->text(); + if ( $this->mType === 'signup' ) { + return $this->msg( 'createaccount' )->text(); + } else { + return $this->msg( 'login' )->text(); + } } - public function execute( $par ) { + /* + * @param $subPage string|null + */ + public function execute( $subPage ) { if ( session_id() == '' ) { wfSetupSession(); } $this->load(); + + // Check for [[Special:Userlogin/signup]]. This affects form display and + // page title. + if ( $subPage == 'signup' ) { + $this->mType = 'signup'; + } $this->setHeaders(); + // If logging in and not on HTTPS, either redirect to it or offer a link. global $wgSecureLogin; - if ( - $this->mType !== 'signup' && - $wgSecureLogin && - WebRequest::detectProtocol() !== 'https' - ) { + if ( WebRequest::detectProtocol() !== 'https' ) { $title = $this->getFullTitle(); $query = array( 'returnto' => $this->mReturnTo, 'returntoquery' => $this->mReturnToQuery, - 'wpStickHTTPS' => $this->mStickHTTPS - ); + 'title' => null, + ) + $this->mRequest->getQueryValues(); $url = $title->getFullURL( $query, false, PROTO_HTTPS ); - $this->getOutput()->redirect( $url ); - return; - } - - if ( $par == 'signup' ) { # Check for [[Special:Userlogin/signup]] - $this->mType = 'signup'; + if ( $wgSecureLogin && wfCanIPUseHTTPS( $this->getRequest()->getIP() ) ) { + $url = wfAppendQuery( $url, 'fromhttp=1' ); + $this->getOutput()->redirect( $url ); + // Since we only do this redir to change proto, always vary + $this->getOutput()->addVaryHeader( 'X-Forwarded-Proto' ); + return; + } else { + // A wiki without HTTPS login support should set $wgServer to + // http://somehost, in which case the secure URL generated + // above won't actually start with https:// + if ( substr( $url, 0, 8 ) === 'https://' ) { + $this->mSecureLoginUrl = $url; + } + } } if ( !is_null( $this->mCookieCheck ) ) { $this->onCookieRedirectCheck( $this->mCookieCheck ); return; - } elseif( $this->mPosted ) { - if( $this->mCreateaccount ) { + } elseif ( $this->mPosted ) { + if ( $this->mCreateaccount ) { $this->addNewAccount(); return; } elseif ( $this->mCreateaccountMail ) { @@ -198,9 +220,9 @@ class LoginForm extends SpecialPage { } $status = $this->addNewaccountInternal(); - if( !$status->isGood() ) { - $error = $this->getOutput()->parse( $status->getWikiText() ); - $this->mainLoginForm( $error ); + if ( !$status->isGood() ) { + $error = $status->getMessage(); + $this->mainLoginForm( $error->toString() ); return; } @@ -217,7 +239,7 @@ class LoginForm extends SpecialPage { $out = $this->getOutput(); $out->setPageTitle( $this->msg( 'accmailtitle' ) ); - if( !$result->isGood() ) { + if ( !$result->isGood() ) { $this->mainLoginForm( $this->msg( 'mailerror', $result->getWikiText() )->text() ); } else { $out->addWikiMsg( 'accmailtext', $u->getName(), $u->getEmail() ); @@ -234,9 +256,9 @@ class LoginForm extends SpecialPage { # Create the account and abort if there's a problem doing so $status = $this->addNewAccountInternal(); - if( !$status->isGood() ) { - $error = $this->getOutput()->parse( $status->getWikiText() ); - $this->mainLoginForm( $error ); + if ( !$status->isGood() ) { + $error = $status->getMessage(); + $this->mainLoginForm( $error->toString() ); return false; } @@ -246,7 +268,7 @@ class LoginForm extends SpecialPage { if ( $this->getUser()->isAnon() ) { # If we showed up language selection links, and one was in use, be # smart (and sensible) and save that language as the user's preference - if( $wgLoginLanguageSelector && $this->mLanguage ) { + if ( $wgLoginLanguageSelector && $this->mLanguage ) { $u->setOption( 'language', $this->mLanguage ); } else { @@ -263,9 +285,9 @@ class LoginForm extends SpecialPage { $out = $this->getOutput(); # Send out an email authentication message if needed - if( $wgEmailAuthentication && Sanitizer::validateEmail( $u->getEmail() ) ) { + if ( $wgEmailAuthentication && Sanitizer::validateEmail( $u->getEmail() ) ) { $status = $u->sendConfirmationMail(); - if( $status->isGood() ) { + if ( $status->isGood() ) { $out->addWikiMsg( 'confirmemail_oncreate' ); } else { $out->addWikiText( $status->getWikiText( 'confirmemail_sendfailed' ) ); @@ -278,7 +300,7 @@ class LoginForm extends SpecialPage { # If not logged in, assume the new account as the current one and set # session cookies then show a "welcome" message or a "need cookies" # message as needed - if( $this->getUser()->isAnon() ) { + if ( $this->getUser()->isAnon() ) { $u->setCookies(); $wgUser = $u; // This should set it for OutputPage and the Skin @@ -287,7 +309,7 @@ class LoginForm extends SpecialPage { $this->getContext()->setUser( $u ); wfRunHooks( 'AddNewAccount', array( $u, false ) ); $u->addNewUserLogEntry( 'create' ); - if( $this->hasSessionCookie() ) { + if ( $this->hasSessionCookie() ) { $this->successfulCreation(); } else { $this->cookieRedirectCheck( 'new' ); @@ -314,7 +336,7 @@ class LoginForm extends SpecialPage { $wgMinimalPasswordLength, $wgEmailConfirmToEdit; // If the user passes an invalid domain, something is fishy - if( !$wgAuth->validDomain( $this->mDomain ) ) { + if ( !$wgAuth->validDomain( $this->mDomain ) ) { return Status::newFatal( 'wrongpassword' ); } @@ -323,8 +345,8 @@ class LoginForm extends SpecialPage { // cation server before they create an account (otherwise, they can // 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( + if ( 'local' != $this->mDomain && $this->mDomain != '' ) { + if ( !$wgAuth->canCreateAccounts() && ( !$wgAuth->userExists( $this->mUsername ) || @@ -422,10 +444,12 @@ class LoginForm extends SpecialPage { $u->setRealName( $this->mRealName ); $abortError = ''; - if( !wfRunHooks( 'AbortNewAccount', array( $u, &$abortError ) ) ) { + if ( !wfRunHooks( 'AbortNewAccount', array( $u, &$abortError ) ) ) { // Hook point to add extra creation throttles and blocks wfDebug( "LoginForm::addNewAccountInternal: a hook blocked creation\n" ); - return Status::newFatal( new RawMessage( $abortError ) ); + $abortError = new RawMessage( $abortError ); + $abortError->text(); + return Status::newFatal( $abortError ); } // Hook point to check for exempt from account creation throttle @@ -445,7 +469,7 @@ class LoginForm extends SpecialPage { } } - if( !$wgAuth->addUser( $u, $this->mPassword, $this->mEmail, $this->mRealName ) ) { + if ( !$wgAuth->addUser( $u, $this->mPassword, $this->mEmail, $this->mRealName ) ) { return Status::newFatal( 'externaldberror' ); } @@ -480,14 +504,6 @@ class LoginForm extends SpecialPage { $wgAuth->initUser( $u, $autocreate ); - if ( $this->mExtUser ) { - $this->mExtUser->linkToLocal( $u->getId() ); - $email = $this->mExtUser->getPref( 'emailaddress' ); - if ( $email && !$this->mEmail ) { - $u->setEmail( $email ); - } - } - $u->setOption( 'rememberpassword', $this->mRemember ? 1 : 0 ); $u->saveSettings(); @@ -550,12 +566,8 @@ class LoginForm extends SpecialPage { return self::SUCCESS; } - $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->mUsername ); - if( !( $u instanceof User ) || !User::isUsableName( $u->getName() ) ) { + if ( !( $u instanceof User ) || !User::isUsableName( $u->getName() ) ) { return self::ILLEGAL; } @@ -568,28 +580,20 @@ class LoginForm extends SpecialPage { $isAutoCreated = true; } } else { - global $wgExternalAuthType, $wgAutocreatePolicy; - if ( $wgExternalAuthType && $wgAutocreatePolicy != 'never' - && is_object( $this->mExtUser ) - && $this->mExtUser->authenticate( $this->mPassword ) - ) { - # The external user and local user have the same name and - # password, so we assume they're the same. - $this->mExtUser->linkToLocal( $u->getID() ); - } - $u->load(); } // Give general extensions, such as a captcha, a chance to abort logins $abort = self::ABORTED; - if( !wfRunHooks( 'AbortLogin', array( $u, $this->mPassword, &$abort, &$this->mAbortLoginErrorMsg ) ) ) { + $msg = null; + if ( !wfRunHooks( 'AbortLogin', array( $u, $this->mPassword, &$abort, &$msg ) ) ) { + $this->mAbortLoginErrorMsg = $msg; return $abort; } global $wgBlockDisablesLogin; if ( !$u->checkPassword( $this->mPassword ) ) { - if( $u->checkTemporaryPassword( $this->mPassword ) ) { + if ( $u->checkTemporaryPassword( $this->mPassword ) ) { // The e-mailed temporary password should not be used for actu- // al logins; that's a very sloppy habit, and insecure if an // attacker has a few seconds to click "search" on someone's o- @@ -606,7 +610,7 @@ class LoginForm extends SpecialPage { // As a side-effect, we can authenticate the user's e-mail ad- // dress if it's not already done, since the temporary password // was sent via e-mail. - if( !$u->isEmailConfirmed() ) { + if ( !$u->isEmailConfirmed() ) { $u->confirmEmail(); $u->saveSettings(); } @@ -696,44 +700,26 @@ class LoginForm extends SpecialPage { * @return integer Status code */ function attemptAutoCreate( $user ) { - global $wgAuth, $wgAutocreatePolicy; + global $wgAuth; if ( $this->getUser()->isBlockedFromCreateAccount() ) { wfDebug( __METHOD__ . ": user is blocked from account creation\n" ); return self::CREATE_BLOCKED; } - - /** - * If the external authentication plugin allows it, automatically cre- - * ate a new account for users that are externally defined but have not - * yet logged in. - */ - if ( $this->mExtUser ) { - # mExtUser is neither null nor false, so use the new ExternalAuth - # system. - if ( $wgAutocreatePolicy == 'never' ) { - return self::NOT_EXISTS; - } - if ( !$this->mExtUser->authenticate( $this->mPassword ) ) { - return self::WRONG_PLUGIN_PASS; - } - } else { - # Old AuthPlugin. - if ( !$wgAuth->autoCreate() ) { - return self::NOT_EXISTS; - } - if ( !$wgAuth->userExists( $user->getName() ) ) { - wfDebug( __METHOD__ . ": user does not exist\n" ); - return self::NOT_EXISTS; - } - if ( !$wgAuth->authenticate( $user->getName(), $this->mPassword ) ) { - wfDebug( __METHOD__ . ": \$wgAuth->authenticate() returned false, aborting\n" ); - return self::WRONG_PLUGIN_PASS; - } + if ( !$wgAuth->autoCreate() ) { + return self::NOT_EXISTS; + } + if ( !$wgAuth->userExists( $user->getName() ) ) { + wfDebug( __METHOD__ . ": user does not exist\n" ); + return self::NOT_EXISTS; + } + if ( !$wgAuth->authenticate( $user->getName(), $this->mPassword ) ) { + wfDebug( __METHOD__ . ": \$wgAuth->authenticate() returned false, aborting\n" ); + return self::WRONG_PLUGIN_PASS; } $abortError = ''; - if( !wfRunHooks( 'AbortAutoAccount', array( $user, &$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; @@ -753,20 +739,24 @@ class LoginForm extends SpecialPage { } function processLogin() { - global $wgMemc, $wgLang, $wgSecureLogin; + global $wgMemc, $wgLang, $wgSecureLogin, $wgPasswordAttemptThrottle; switch ( $this->authenticateUserData() ) { case self::SUCCESS: # We've verified now, update the real record $user = $this->getUser(); - if( (bool)$this->mRemember != $user->getBoolOption( 'rememberpassword' ) ) { + if ( (bool)$this->mRemember != $user->getBoolOption( 'rememberpassword' ) ) { $user->setOption( 'rememberpassword', $this->mRemember ? 1 : 0 ); $user->saveSettings(); } else { $user->invalidateCache(); } - if( $wgSecureLogin && !$this->mStickHTTPS ) { + if ( $user->requiresHTTPS() ) { + $this->mStickHTTPS = true; + } + + if ( $wgSecureLogin && !$this->mStickHTTPS ) { $user->setCookies( null, false ); } else { $user->setCookies(); @@ -778,7 +768,7 @@ class LoginForm extends SpecialPage { $key = wfMemcKey( 'password-throttle', $request->getIP(), md5( $this->mUsername ) ); $wgMemc->delete( $key ); - if( $this->hasSessionCookie() || $this->mSkipCookieCheck ) { + if ( $this->hasSessionCookie() || $this->mSkipCookieCheck ) { /* Replace the language object to provide user interface in * correct language immediately on this first page load. */ @@ -795,48 +785,62 @@ class LoginForm extends SpecialPage { break; case self::NEED_TOKEN: - $this->mainLoginForm( $this->msg( 'nocookiesforlogin' )->parse() ); + $error = $this->mAbortLoginErrorMsg ?: 'nocookiesforlogin'; + $this->mainLoginForm( $this->msg( $error )->parse() ); break; case self::WRONG_TOKEN: - $this->mainLoginForm( $this->msg( 'sessionfailure' )->text() ); + $error = $this->mAbortLoginErrorMsg ?: 'sessionfailure'; + $this->mainLoginForm( $this->msg( $error )->text() ); break; case self::NO_NAME: case self::ILLEGAL: - $this->mainLoginForm( $this->msg( 'noname' )->text() ); + $error = $this->mAbortLoginErrorMsg ?: 'noname'; + $this->mainLoginForm( $this->msg( $error )->text() ); break; case self::WRONG_PLUGIN_PASS: - $this->mainLoginForm( $this->msg( 'wrongpassword' )->text() ); + $error = $this->mAbortLoginErrorMsg ?: 'wrongpassword'; + $this->mainLoginForm( $this->msg( $error )->text() ); break; case self::NOT_EXISTS: - if( $this->getUser()->isAllowed( 'createaccount' ) ) { - $this->mainLoginForm( $this->msg( 'nosuchuser', + if ( $this->getUser()->isAllowed( 'createaccount' ) ) { + $error = $this->mAbortLoginErrorMsg ?: 'nosuchuser'; + $this->mainLoginForm( $this->msg( $error, wfEscapeWikiText( $this->mUsername ) )->parse() ); } else { - $this->mainLoginForm( $this->msg( 'nosuchusershort', + $error = $this->mAbortLoginErrorMsg ?: 'nosuchusershort'; + $this->mainLoginForm( $this->msg( $error, wfEscapeWikiText( $this->mUsername ) )->text() ); } break; case self::WRONG_PASS: - $this->mainLoginForm( $this->msg( 'wrongpassword' )->text() ); + $error = $this->mAbortLoginErrorMsg ?: 'wrongpassword'; + $this->mainLoginForm( $this->msg( $error )->text() ); break; case self::EMPTY_PASS: - $this->mainLoginForm( $this->msg( 'wrongpasswordempty' )->text() ); + $error = $this->mAbortLoginErrorMsg ?: 'wrongpasswordempty'; + $this->mainLoginForm( $this->msg( $error )->text() ); break; case self::RESET_PASS: - $this->resetLoginForm( $this->msg( 'resetpass_announce' )->text() ); + $error = $this->mAbortLoginErrorMsg ?: 'resetpass_announce'; + $this->resetLoginForm( $this->msg( $error )->text() ); break; case self::CREATE_BLOCKED: - $this->userBlockedMessage( $this->getUser()->mBlock ); + $this->userBlockedMessage( $this->getUser()->isBlockedFromCreateAccount() ); break; case self::THROTTLED: - $this->mainLoginForm( $this->msg( 'login-throttled' )->text() ); + $error = $this->mAbortLoginErrorMsg ?: 'login-throttled'; + $this->mainLoginForm( $this->msg( $error ) + ->params ( $this->getLanguage()->formatDuration( $wgPasswordAttemptThrottle['seconds'] ) ) + ->text() + ); break; case self::USER_BLOCKED: - $this->mainLoginForm( $this->msg( 'login-userblocked', - $this->mUsername )->escaped() ); + $error = $this->mAbortLoginErrorMsg ?: 'login-userblocked'; + $this->mainLoginForm( $this->msg( $error, $this->mUsername )->escaped() ); break; case self::ABORTED: - $this->mainLoginForm( $this->msg( $this->mAbortLoginErrorMsg )->text() ); + $error = $this->mAbortLoginErrorMsg ?: 'login-abort-generic'; + $this->mainLoginForm( $this->msg( $error )->text() ); break; default: throw new MWException( 'Unhandled case value' ); @@ -867,7 +871,7 @@ class LoginForm extends SpecialPage { return Status::newFatal( 'noemail', $u->getName() ); } $ip = $this->getRequest()->getIP(); - if( !$ip ) { + if ( !$ip ) { return Status::newFatal( 'badipaddress' ); } @@ -901,7 +905,7 @@ class LoginForm extends SpecialPage { $injected_html = ''; wfRunHooks( 'UserLoginComplete', array( &$currentUser, &$injected_html ) ); - if( $injected_html !== '' ) { + if ( $injected_html !== '' ) { $this->displaySuccessfulAction( $this->msg( 'loginsuccesstitle' ), 'loginsuccess', $injected_html ); } else { @@ -980,6 +984,29 @@ class LoginForm extends SpecialPage { ); } + /** + * Add a "return to" link or redirect to it. + * Extensions can use this to reuse the "return to" logic after + * inject steps (such as redirection) into the login process. + * + * @param $type string, one of the following: + * - error: display a return to link ignoring $wgRedirectOnLogin + * - success: display a return to link using $wgRedirectOnLogin if needed + * - successredirect: send an HTTP redirect using $wgRedirectOnLogin if needed + * @param string $returnTo + * @param array|string $returnToQuery + * @param bool $stickHTTPs Keep redirect link on HTTPs + * @since 1.22 + */ + public function showReturnToPage( + $type, $returnTo = '', $returnToQuery = '', $stickHTTPs = false + ) { + $this->mReturnTo = $returnTo; + $this->mReturnToQuery = $returnToQuery; + $this->mStickHTTPS = $stickHTTPs; + $this->executeReturnTo( $type ); + } + /** * Add a "return to" link or redirect to it. * @@ -1007,7 +1034,7 @@ class LoginForm extends SpecialPage { if ( $wgSecureLogin && !$this->mStickHTTPS ) { $options = array( 'http' ); $proto = PROTO_HTTP; - } elseif( $wgSecureLogin ) { + } elseif ( $wgSecureLogin ) { $options = array( 'https' ); $proto = PROTO_HTTPS; } else { @@ -1030,10 +1057,11 @@ class LoginForm extends SpecialPage { global $wgEnableEmail, $wgEnableUserEmail; global $wgHiddenPrefs, $wgLoginLanguageSelector; global $wgAuth, $wgEmailConfirmToEdit, $wgCookieExpiration; - global $wgSecureLogin, $wgSecureLoginDefaultHTTPS, $wgPasswordResetRoutes; + global $wgSecureLogin, $wgPasswordResetRoutes; $titleObj = $this->getTitle(); $user = $this->getUser(); + $out = $this->getOutput(); if ( $this->mType == 'signup' ) { // Block signup here if in readonly. Keeps user from @@ -1061,15 +1089,33 @@ class LoginForm extends SpecialPage { if ( $this->mType == 'signup' ) { $template = new UsercreateTemplate(); + + $out->addModuleStyles( array( + 'mediawiki.ui', + 'mediawiki.special.createaccount' + ) ); + // XXX hack pending RL or JS parse() support for complex content messages + // https://bugzilla.wikimedia.org/show_bug.cgi?id=25349 + $out->addJsConfigVars( 'wgCreateacctImgcaptchaHelp', + $this->msg( 'createacct-imgcaptcha-help' )->parse() ); + $out->addModules( array( + 'mediawiki.special.createaccount.js' + ) ); + // Must match number of benefits defined in messages + $template->set( 'benefitCount', 3 ); + $q = 'action=submitlogin&type=signup'; $linkq = 'type=login'; - $linkmsg = 'gotaccount'; - $this->getOutput()->addModules( 'mediawiki.special.userlogin.signup' ); } else { $template = new UserloginTemplate(); + + $out->addModuleStyles( array( + 'mediawiki.ui', + 'mediawiki.special.userlogin' + ) ); + $q = 'action=submitlogin&type=login'; $linkq = 'type=signup'; - $linkmsg = 'nologin'; } if ( $this->mReturnTo !== '' ) { @@ -1082,30 +1128,24 @@ class LoginForm extends SpecialPage { $linkq .= $returnto; } - # Don't show a "create account" link if the user can't - if( $this->showCreateOrLoginLink( $user ) ) { + # Don't show a "create account" link if the user can't. + if ( $this->showCreateOrLoginLink( $user ) ) { # Pass any language selection on to the mode switch link - if( $wgLoginLanguageSelector && $this->mLanguage ) { + if ( $wgLoginLanguageSelector && $this->mLanguage ) { $linkq .= '&uselang=' . $this->mLanguage; } - $link = Html::element( 'a', array( 'href' => $titleObj->getLocalURL( $linkq ) ), - $this->msg( $linkmsg . 'link' )->text() ); # Calling either 'gotaccountlink' or 'nologinlink' - - $template->set( 'link', $this->msg( $linkmsg )->rawParams( $link )->parse() ); + // Supply URL, login template creates the button. + $template->set( 'createOrLoginHref', $titleObj->getLocalURL( $linkq ) ); } else { $template->set( 'link', '' ); } - // Decide if we default stickHTTPS on - if ( $wgSecureLoginDefaultHTTPS && $this->mAction != 'submitlogin' && !$this->mLoginattempt ) { - $this->mStickHTTPS = true; - } - $resetLink = $this->mType == 'signup' ? null : is_array( $wgPasswordResetRoutes ) && in_array( true, array_values( $wgPasswordResetRoutes ) ); $template->set( 'header', '' ); + $template->set( 'skin', $this->getSkin() ); $template->set( 'name', $this->mUsername ); $template->set( 'password', $this->mPassword ); $template->set( 'retype', $this->mRetype ); @@ -1129,7 +1169,9 @@ class LoginForm extends SpecialPage { $template->set( 'usereason', $user->isLoggedIn() ); $template->set( 'remember', $user->getOption( 'rememberpassword' ) || $this->mRemember ); $template->set( 'cansecurelogin', ( $wgSecureLogin === true ) ); - $template->set( 'stickHTTPS', $this->mStickHTTPS ); + $template->set( 'stickhttps', (int)$this->mStickHTTPS ); + $template->set( 'loggedin', $user->isLoggedIn() ); + $template->set( 'loggedinuser', $user->getName() ); if ( $this->mType == 'signup' ) { if ( !self::getCreateaccountToken() ) { @@ -1144,15 +1186,16 @@ class LoginForm extends SpecialPage { } # Prepare language selection links as needed - if( $wgLoginLanguageSelector ) { + if ( $wgLoginLanguageSelector ) { $template->set( 'languages', $this->makeLanguageSelector() ); - if( $this->mLanguage ) { + if ( $this->mLanguage ) { $template->set( 'uselang', $this->mLanguage ); } } + $template->set( 'secureLoginUrl', $this->mSecureLoginUrl ); // Use loginend-https for HTTPS requests if it's not blank, loginend otherwise - // Ditto for signupend + // Ditto for signupend. New forms use neither. $usingHTTPS = WebRequest::detectProtocol() == 'https'; $loginendHTTPS = $this->msg( 'loginend-https' ); $signupendHTTPS = $this->msg( 'signupend-https' ); @@ -1175,22 +1218,21 @@ class LoginForm extends SpecialPage { wfRunHooks( 'UserLoginForm', array( &$template ) ); } - $out = $this->getOutput(); $out->disallowUserJs(); // just in case... $out->addTemplate( $template ); } /** - * @private + * Whether the login/create account form should display a link to the + * other form (in addition to whatever the skin provides). * * @param $user User - * - * @return Boolean + * @return bool */ - function showCreateOrLoginLink( &$user ) { - if( $this->mType == 'signup' ) { + private function showCreateOrLoginLink( &$user ) { + if ( $this->mType == 'signup' ) { return true; - } elseif( $user->isAllowed( 'createaccount' ) ) { + } elseif ( $user->isAllowed( 'createaccount' ) ) { return true; } else { return false; @@ -1269,22 +1311,11 @@ class LoginForm extends SpecialPage { */ private function renewSessionId() { global $wgSecureLogin, $wgCookieSecure; - if( $wgSecureLogin && !$this->mStickHTTPS ) { + if ( $wgSecureLogin && !$this->mStickHTTPS ) { $wgCookieSecure = false; } - // If either we don't trust PHP's entropy, or if we need - // to change cookie settings when logging in because of - // wpStickHTTPS, then change the session ID manually. - $cookieParams = session_get_cookie_params(); - if ( wfCheckEntropy() && $wgCookieSecure == $cookieParams['secure'] ) { - session_regenerate_id( false ); - } else { - $tmp = $_SESSION; - session_destroy(); - wfSetupSession( MWCryptRand::generateHex( 32 ) ); - $_SESSION = $tmp; - } + wfResetSessionID(); } /** @@ -1328,10 +1359,10 @@ class LoginForm extends SpecialPage { */ function makeLanguageSelector() { $msg = $this->msg( 'loginlanguagelinks' )->inContentLanguage(); - if( !$msg->isBlank() ) { + if ( !$msg->isBlank() ) { $langs = explode( "\n", $msg->text() ); $links = array(); - foreach( $langs as $lang ) { + foreach ( $langs as $lang ) { $lang = trim( $lang, '* ' ); $parts = explode( '|', $lang ); if ( count( $parts ) >= 2 ) { @@ -1354,15 +1385,15 @@ class LoginForm extends SpecialPage { * @return string */ function makeLanguageSelectorLink( $text, $lang ) { - if( $this->getLanguage()->getCode() == $lang ) { + if ( $this->getLanguage()->getCode() == $lang ) { // no link for currently used language return htmlspecialchars( $text ); } $query = array( 'uselang' => $lang ); - if( $this->mType == 'signup' ) { + if ( $this->mType == 'signup' ) { $query['type'] = 'signup'; } - if( $this->mReturnTo !== '' ) { + if ( $this->mReturnTo !== '' ) { $query['returnto'] = $this->mReturnTo; $query['returntoquery'] = $this->mReturnToQuery; } diff --git a/includes/specials/SpecialUserrights.php b/includes/specials/SpecialUserrights.php index d4baae28..4501736f 100644 --- a/includes/specials/SpecialUserrights.php +++ b/includes/specials/SpecialUserrights.php @@ -45,6 +45,11 @@ class UserrightsPage extends SpecialPage { return $this->userCanChangeRights( $user, false ); } + /** + * @param User $user + * @param bool $checkIfSelf + * @return bool + */ public function userCanChangeRights( $user, $checkIfSelf = true ) { $available = $this->changeableGroups(); if ( $user->getId() == 0 ) { @@ -75,13 +80,13 @@ class UserrightsPage extends SpecialPage { * (e.g. they don't have the userrights permission), then don't * allow them to use Special:UserRights. */ - if( $user->isBlocked() && !$user->isAllowed( 'userrights' ) ) { + if ( $user->isBlocked() && !$user->isAllowed( 'userrights' ) ) { throw new UserBlockedError( $user->getBlock() ); } $request = $this->getRequest(); - if( $par !== null ) { + if ( $par !== null ) { $this->mTarget = $par; } else { $this->mTarget = $request->getVal( 'user' ); @@ -95,15 +100,27 @@ class UserrightsPage extends SpecialPage { * edit their own groups, automatically set them as the * target. */ - if ( !count( $available['add'] ) && !count( $available['remove'] ) ) + if ( !count( $available['add'] ) && !count( $available['remove'] ) ) { $this->mTarget = $user->getName(); + } } if ( User::getCanonicalName( $this->mTarget ) == $user->getName() ) { $this->isself = true; } - if( !$this->userCanChangeRights( $user, true ) ) { + if ( !$this->userCanChangeRights( $user, true ) ) { + if ( $this->isself && $request->getCheck( 'success' ) ) { + // bug 48609: if the user just removed its own rights, this would + // leads it in a "permissions error" page. In that case, show a + // message that it can't anymore use this page instead of an error + $this->setHeaders(); + $out = $this->getOutput(); + $out->wrapWikiMsg( "
                \n$1\n
                ", 'userrights-removed-self' ); + $out->returnToMain(); + return; + } + // @todo FIXME: There may be intermediate groups we can mention. $msg = $user->isAnon() ? 'userrights-nologin' : 'userrights-notallowed'; throw new PermissionsError( null, array( array( $msg ) ) ); @@ -122,31 +139,42 @@ class UserrightsPage extends SpecialPage { $this->switchForm(); } - if( $request->wasPosted() ) { + if ( + $request->wasPosted() && + $request->getCheck( 'saveusergroups' ) && + $user->matchEditToken( $request->getVal( 'wpEditToken' ), $this->mTarget ) + ) { // save settings - if( $request->getCheck( 'saveusergroups' ) ) { - $reason = $request->getVal( 'user-reason' ); - $tok = $request->getVal( 'wpEditToken' ); - if( $user->matchEditToken( $tok, $this->mTarget ) ) { - $this->saveUserGroups( - $this->mTarget, - $reason - ); - - $out->redirect( $this->getSuccessURL() ); - return; - } + $status = $this->fetchUser( $this->mTarget ); + if ( !$status->isOK() ) { + $this->getOutput()->addWikiText( $status->getWikiText() ); + return; + } + + $targetUser = $status->value; + + if ( $request->getVal( 'conflictcheck-originalgroups' ) !== implode( ',', $targetUser->getGroups() ) ) { + $out->addWikiMsg( 'userrights-conflict' ); + } else { + $this->saveUserGroups( + $this->mTarget, + $request->getVal( 'user-reason' ), + $targetUser + ); + + $out->redirect( $this->getSuccessURL() ); + return; } } // show some more forms - if( $this->mTarget !== null ) { + if ( $this->mTarget !== null ) { $this->editUserGroupsForm( $this->mTarget ); } } function getSuccessURL() { - return $this->getTitle( $this->mTarget )->getFullURL(); + return $this->getTitle( $this->mTarget )->getFullURL( array( 'success' => 1 ) ); } /** @@ -155,17 +183,10 @@ class UserrightsPage extends SpecialPage { * * @param string $username username to apply changes to. * @param string $reason reason for group change + * @param User|UserRightsProxy $user Target user object. * @return null */ - function saveUserGroups( $username, $reason = '' ) { - $status = $this->fetchUser( $username ); - if( !$status->isOK() ) { - $this->getOutput()->addWikiText( $status->getWikiText() ); - return; - } else { - $user = $status->value; - } - + function saveUserGroups( $username, $reason, $user ) { $allgroups = $this->getAllGroups(); $addgroup = array(); $removegroup = array(); @@ -195,6 +216,8 @@ class UserrightsPage extends SpecialPage { * @return Array: Tuple of added, then removed groups */ function doSaveUserGroups( $user, $add, $remove, $reason = '' ) { + global $wgAuth; + // Validate input set... $isself = ( $user->getName() == $this->getUser()->getName() ); $groups = $user->getGroups(); @@ -213,15 +236,15 @@ class UserrightsPage extends SpecialPage { $newGroups = $oldGroups; // remove then add groups - if( $remove ) { + if ( $remove ) { $newGroups = array_diff( $newGroups, $remove ); - foreach( $remove as $group ) { + foreach ( $remove as $group ) { $user->removeGroup( $group ); } } - if( $add ) { + if ( $add ) { $newGroups = array_merge( $newGroups, $add ); - foreach( $add as $group ) { + foreach ( $add as $group ) { $user->addGroup( $group ); } } @@ -230,11 +253,14 @@ class UserrightsPage extends SpecialPage { // Ensure that caches are cleared $user->invalidateCache(); + // update groups in external authentication database + $wgAuth->updateExternalDBGroups( $user, $add, $remove ); + wfDebug( 'oldGroups: ' . print_r( $oldGroups, true ) ); wfDebug( 'newGroups: ' . print_r( $newGroups, true ) ); wfRunHooks( 'UserRights', array( &$user, $add, $remove ) ); - if( $newGroups != $oldGroups ) { + if ( $newGroups != $oldGroups ) { $this->addLogEntry( $user, $oldGroups, $newGroups, $reason ); } return array( $add, $remove ); @@ -262,7 +288,7 @@ class UserrightsPage extends SpecialPage { */ function editUserGroupsForm( $username ) { $status = $this->fetchUser( $username ); - if( !$status->isOK() ) { + if ( !$status->isOK() ) { $this->getOutput()->addWikiText( $status->getWikiText() ); return; } else { @@ -283,63 +309,64 @@ class UserrightsPage extends SpecialPage { * return a user (or proxy) object for manipulating it. * * Side effects: error output for invalid access + * @param string $username * @return Status object */ public function fetchUser( $username ) { global $wgUserrightsInterwikiDelimiter; $parts = explode( $wgUserrightsInterwikiDelimiter, $username ); - if( count( $parts ) < 2 ) { + if ( count( $parts ) < 2 ) { $name = trim( $username ); $database = ''; } else { list( $name, $database ) = array_map( 'trim', $parts ); - if( $database == wfWikiID() ) { + if ( $database == wfWikiID() ) { $database = ''; } else { - if( !$this->getUser()->isAllowed( 'userrights-interwiki' ) ) { + if ( !$this->getUser()->isAllowed( 'userrights-interwiki' ) ) { return Status::newFatal( 'userrights-no-interwiki' ); } - if( !UserRightsProxy::validDatabase( $database ) ) { + if ( !UserRightsProxy::validDatabase( $database ) ) { return Status::newFatal( 'userrights-nodatabase', $database ); } } } - if( $name === '' ) { + if ( $name === '' ) { 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 ) ); - if( $database == '' ) { + if ( $database == '' ) { $name = User::whoIs( $id ); } else { $name = UserRightsProxy::whoIs( $database, $id ); } - if( !$name ) { + if ( !$name ) { return Status::newFatal( 'noname' ); } } else { $name = User::getCanonicalName( $name ); - if( $name === false ) { + if ( $name === false ) { // invalid name return Status::newFatal( 'nosuchusershort', $username ); } } - if( $database == '' ) { + if ( $database == '' ) { $user = User::newFromName( $name ); } else { $user = UserRightsProxy::newFromName( $database, $name ); } - if( !$user || $user->isAnon() ) { + if ( !$user || $user->isAnon() ) { return Status::newFatal( 'nosuchusershort', $username ); } @@ -347,7 +374,7 @@ class UserrightsPage extends SpecialPage { } function makeGroupNameList( $ids ) { - if( empty( $ids ) ) { + if ( empty( $ids ) ) { return $this->msg( 'rightsnone' )->inContentLanguage()->text(); } else { return implode( ', ', $ids ); @@ -364,7 +391,7 @@ class UserrightsPage extends SpecialPage { function makeGroupNameListForLog( $ids ) { wfDeprecated( __METHOD__, '1.21' ); - if( empty( $ids ) ) { + if ( empty( $ids ) ) { return ''; } else { return $this->makeGroupNameList( $ids ); @@ -380,7 +407,7 @@ class UserrightsPage extends SpecialPage { Html::openElement( 'form', array( 'method' => 'get', 'action' => $wgScript, 'name' => 'uluser', 'id' => 'mw-userrights-form1' ) ) . Html::hidden( 'title', $this->getTitle()->getPrefixedText() ) . Xml::fieldset( $this->msg( 'userrights-lookup-user' )->text() ) . - Xml::inputLabel( $this->msg( 'userrights-user-editname' )->text(), 'user', 'username', 30, str_replace( '_', ' ', $this->mTarget ) ) . ' ' . + Xml::inputLabel( $this->msg( 'userrights-user-editname' )->text(), 'user', 'username', 30, str_replace( '_', ' ', $this->mTarget ), array( 'autofocus' => true ) ) . ' ' . Xml::submitButton( $this->msg( 'editusergroup' )->text() ) . Html::closeElement( 'fieldset' ) . Html::closeElement( 'form' ) . "\n" @@ -419,7 +446,7 @@ class UserrightsPage extends SpecialPage { protected function showEditUserGroupsForm( $user, $groups ) { $list = array(); $membersList = array(); - foreach( $groups as $group ) { + foreach ( $groups as $group ) { $list[] = self::buildGroupLink( $group ); $membersList[] = self::buildGroupMemberLink( $group ); } @@ -427,7 +454,7 @@ class UserrightsPage extends SpecialPage { $autoList = array(); $autoMembersList = array(); if ( $user instanceof User ) { - foreach( Autopromote::getAutopromoteGroups( $user ) as $group ) { + foreach ( Autopromote::getAutopromoteGroups( $user ) as $group ) { $autoList[] = self::buildGroupLink( $group ); $autoMembersList[] = self::buildGroupMemberLink( $group ); } @@ -447,12 +474,12 @@ class UserrightsPage extends SpecialPage { $count = count( $list ); if ( $count > 0 ) { $grouplist = $this->msg( 'userrights-groupsmember', $count, $user->getName() )->parse(); - $grouplist = '

                ' . $grouplist . ' ' . $displayedList . "

                \n"; + $grouplist = '

                ' . $grouplist . ' ' . $displayedList . "

                \n"; } $count = count( $autoList ); if ( $count > 0 ) { $autogrouplistintro = $this->msg( 'userrights-groupsmember-auto', $count, $user->getName() )->parse(); - $grouplist .= '

                ' . $autogrouplistintro . ' ' . $displayedAutolist . "

                \n"; + $grouplist .= '

                ' . $autogrouplistintro . ' ' . $displayedAutolist . "

                \n"; } $userToolLinks = Linker::userToolLinks( @@ -466,6 +493,7 @@ class UserrightsPage extends SpecialPage { Xml::openElement( 'form', array( 'method' => 'post', 'action' => $this->getTitle()->getLocalURL(), 'name' => 'editGroup', 'id' => 'mw-userrights-form2' ) ) . Html::hidden( 'user', $this->mTarget ) . Html::hidden( 'wpEditToken', $this->getUser()->getEditToken( $this->mTarget ) ) . + Html::hidden( 'conflictcheck-originalgroups', implode( ',', $user->getGroups() ) ) . // Conflict detection Xml::openElement( 'fieldset' ) . Xml::element( 'legend', array(), $this->msg( 'userrights-editusergroup', $user->getName() )->text() ) . $this->msg( 'editinguser' )->params( wfEscapeWikiText( $user->getName() ) )->rawParams( $userToolLinks )->parse() . @@ -535,17 +563,17 @@ class UserrightsPage extends SpecialPage { $allgroups = $this->getAllGroups(); $ret = ''; - # Put all column info into an associative array so that extensions can - # more easily manage it. + // Put all column info into an associative array so that extensions can + // more easily manage it. $columns = array( 'unchangeable' => array(), 'changeable' => array() ); - foreach( $allgroups as $group ) { + foreach ( $allgroups as $group ) { $set = in_array( $group, $usergroups ); - # Should the checkbox be disabled? + // Should the checkbox be disabled? $disabled = !( ( $set && $this->canRemove( $group ) ) || ( !$set && $this->canAdd( $group ) ) ); - # Do we need to point out that this action is irreversible? + // Do we need to point out that this action is irreversible? $irreversible = !$disabled && ( ( $set && !$this->canAdd( $group ) ) || ( !$set && !$this->canRemove( $group ) ) ); @@ -556,27 +584,30 @@ class UserrightsPage extends SpecialPage { 'irreversible' => $irreversible ); - if( $disabled ) { + if ( $disabled ) { $columns['unchangeable'][$group] = $checkbox; } else { $columns['changeable'][$group] = $checkbox; } } - # Build the HTML table + // Build the HTML table $ret .= Xml::openElement( 'table', array( 'class' => 'mw-userrights-groups' ) ) . "
          \n"; - foreach( $columns as $name => $column ) { - if( $column === array() ) + foreach ( $columns as $name => $column ) { + if ( $column === array() ) { continue; + } + // Messages: userrights-changeable-col, userrights-unchangeable-col $ret .= Xml::element( 'th', null, $this->msg( 'userrights-' . $name . '-col', count( $column ) )->text() ); } $ret .= "\n\n"; - foreach( $columns as $column ) { - if( $column === array() ) + foreach ( $columns as $column ) { + if ( $column === array() ) { continue; + } $ret .= "\t\n"; - foreach( $software as $name => $version ) { + foreach ( $software as $name => $version ) { $out .= " @@ -220,11 +221,11 @@ class SpecialVersion extends SpecialPage { wfProfileIn( __METHOD__ ); $gitVersion = self::getVersionLinkedGit(); - if( $gitVersion ) { + if ( $gitVersion ) { $v = $gitVersion; } else { $svnVersion = self::getVersionLinkedSvn(); - if( $svnVersion ) { + if ( $svnVersion ) { $v = $svnVersion; } else { $v = $wgVersion; // fallback @@ -242,7 +243,7 @@ class SpecialVersion extends SpecialPage { global $IP; $info = self::getSvnInfo( $IP ); - if( !isset( $info['checkout-rev'] ) ) { + if ( !isset( $info['checkout-rev'] ) ) { return false; } @@ -267,7 +268,7 @@ class SpecialVersion extends SpecialPage { private static function getwgVersionLinked() { global $wgVersion; $versionUrl = ""; - if( wfRunHooks( 'SpecialVersionVersionUrl', array( $wgVersion, &$versionUrl ) ) ) { + if ( wfRunHooks( 'SpecialVersionVersionUrl', array( $wgVersion, &$versionUrl ) ) ) { $versionParts = array(); preg_match( "/^(\d+\.\d+)/", $wgVersion, $versionParts ); $versionUrl = "https://www.mediawiki.org/wiki/MediaWiki_{$versionParts[1]}"; @@ -276,22 +277,30 @@ class SpecialVersion extends SpecialPage { } /** - * @return bool|string wgVersion + HEAD sha1 stripped to the first 7 chars. False on failure + * @since 1.22 Returns the HEAD date in addition to the sha1 and link + * @return bool|string wgVersion + HEAD sha1 stripped to the first 7 chars with link and date, or false on failure */ private static function getVersionLinkedGit() { - global $IP; + global $IP, $wgLang; $gitInfo = new GitInfo( $IP ); $headSHA1 = $gitInfo->getHeadSHA1(); - if( !$headSHA1 ) { + if ( !$headSHA1 ) { return false; } $shortSHA1 = '(' . substr( $headSHA1, 0, 7 ) . ')'; - $viewerUrl = $gitInfo->getHeadViewUrl(); - if ( $viewerUrl !== false ) { - $shortSHA1 = "[$viewerUrl $shortSHA1]"; + + $gitHeadUrl = $gitInfo->getHeadViewUrl(); + if ( $gitHeadUrl !== false ) { + $shortSHA1 = "[$gitHeadUrl $shortSHA1]"; } + + $gitHeadCommitDate = $gitInfo->getHeadCommitDate(); + if ( $gitHeadCommitDate ) { + $shortSHA1 .= "
          " . $wgLang->timeanddate( $gitHeadCommitDate, true ); + } + return self::getwgVersionLinked() . " $shortSHA1"; } @@ -384,11 +393,6 @@ class SpecialVersion extends SpecialPage { // We want the 'other' type to be last in the list. $out .= $this->getExtensionCategory( 'other', $extensionTypes['other'] ); - if ( count( $wgExtensionFunctions ) ) { - $out .= $this->openExtType( $this->msg( 'version-extension-functions' )->text(), 'extension-functions' ); - $out .= '
          \n"; - } - $tags = $wgParser->getTags(); $cnt = count( $tags ); @@ -397,11 +401,11 @@ class SpecialVersion extends SpecialPage { $tags[$i] = "<{$tags[$i]}>"; } $out .= $this->openExtType( $this->msg( 'version-parser-extensiontags' )->text(), 'parser-tags' ); - $out .= '\n"; + $out .= '\n"; } $fhooks = $wgParser->getFunctionHooks(); - if( count( $fhooks ) ) { + if ( count( $fhooks ) ) { $out .= $this->openExtType( $this->msg( 'version-parser-function-hooks' )->text(), 'parser-function-hooks' ); $out .= '\n"; } @@ -446,7 +450,7 @@ class SpecialVersion extends SpecialPage { * @return int */ function compare( $a, $b ) { - if( $a['name'] === $b['name'] ) { + if ( $a['name'] === $b['name'] ) { return 0; } else { return $this->getLanguage()->lc( $a['name'] ) > $this->getLanguage()->lc( $b['name'] ) @@ -463,6 +467,8 @@ class SpecialVersion extends SpecialPage { * @return string */ function getCreditsForExtension( array $extension ) { + global $wgLang; + $name = isset( $extension['name'] ) ? $extension['name'] : '[no name]'; $vcsText = false; @@ -476,6 +482,10 @@ class SpecialVersion extends SpecialPage { if ( $gitViewerUrl !== false ) { $vcsText = "[$gitViewerUrl $vcsText]"; } + $gitHeadCommitDate = $gitInfo->getHeadCommitDate(); + if ( $gitHeadCommitDate ) { + $vcsText .= "
          " . $wgLang->timeanddate( $gitHeadCommitDate, true ); + } } else { $svnInfo = self::getSvnInfo( dirname( $extension['path'] ) ); # Make subversion text/link. @@ -503,13 +513,13 @@ class SpecialVersion extends SpecialPage { } # Make description text. - $description = isset ( $extension['description'] ) ? $extension['description'] : ''; + $description = isset( $extension['description'] ) ? $extension['description'] : ''; - if( isset ( $extension['descriptionmsg'] ) ) { + if ( isset( $extension['descriptionmsg'] ) ) { # Look for a localized description. $descriptionMsg = $extension['descriptionmsg']; - if( is_array( $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 @@ -528,7 +538,7 @@ class SpecialVersion extends SpecialPage {
          "; } - $author = isset ( $extension['author'] ) ? $extension['author'] : array(); + $author = isset( $extension['author'] ) ? $extension['author'] : array(); $extDescAuthor = "\n"; @@ -564,21 +574,22 @@ class SpecialVersion extends SpecialPage { $ret .= Xml::closeElement( 'table' ); return $ret; - } else + } else { return ''; + } } private function openExtType( $text, $name = null ) { $opt = array( 'colspan' => 4 ); $out = ''; - if( $this->firstExtOpened ) { + if ( $this->firstExtOpened ) { // Insert a spacing line $out .= '' . Html::element( 'td', $opt ) . "\n"; } $this->firstExtOpened = true; - if( $name ) { + if ( $name ) { $opt['id'] = "sv-$name"; } @@ -605,7 +616,7 @@ class SpecialVersion extends SpecialPage { */ function listAuthors( $authors ) { $list = array(); - foreach( (array)$authors as $item ) { + foreach ( (array)$authors as $item ) { if ( $item == '...' ) { $list[] = $this->msg( 'version-poweredby-others' )->text(); } elseif ( substr( $item, -5 ) == ' ...]' ) { @@ -650,16 +661,16 @@ class SpecialVersion extends SpecialPage { * @return Mixed */ public static function arrayToString( $list ) { - if( is_array( $list ) && count( $list ) == 1 ) { + if ( is_array( $list ) && count( $list ) == 1 ) { $list = $list[0]; } - if( is_object( $list ) ) { + if ( is_object( $list ) ) { $class = wfMessage( 'parentheses' )->params( get_class( $list ) )->escaped(); 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 { $class = $list[0]; @@ -688,7 +699,7 @@ class SpecialVersion extends SpecialPage { // http://svnbook.red-bean.com/nightly/en/svn.developer.insidewc.html $entries = $dir . '/.svn/entries'; - if( !file_exists( $entries ) ) { + if ( !file_exists( $entries ) ) { return false; } @@ -698,9 +709,9 @@ class SpecialVersion extends SpecialPage { } // check if file is xml (subversion release <= 1.3) or not (subversion release = 1.4) - if( preg_match( '/^<\?xml/', $lines[0] ) ) { + if ( preg_match( '/^<\?xml/', $lines[0] ) ) { // subversion is release <= 1.3 - if( !function_exists( 'simplexml_load_file' ) ) { + if ( !function_exists( 'simplexml_load_file' ) ) { // We could fall back to expat... YUCK return false; } @@ -710,11 +721,11 @@ class SpecialVersion extends SpecialPage { $xml = simplexml_load_file( $entries ); wfRestoreWarnings(); - if( $xml ) { - foreach( $xml->entry as $entry ) { - if( $xml->entry[0]['name'] == '' ) { + if ( $xml ) { + foreach ( $xml->entry as $entry ) { + if ( $xml->entry[0]['name'] == '' ) { // The directory entry should always have a revision marker. - if( $entry['revision'] ) { + if ( $entry['revision'] ) { return array( 'checkout-rev' => intval( $entry['revision'] ) ); } } @@ -831,108 +842,4 @@ class SpecialVersion extends SpecialPage { return 'wiki'; } - 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=<<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 0035bfab..d2ffdb94 100644 --- a/includes/specials/SpecialWantedcategories.php +++ b/includes/specials/SpecialWantedcategories.php @@ -35,22 +35,22 @@ class WantedCategoriesPage extends WantedQueryPage { } function getQueryInfo() { - return array ( - 'tables' => array ( 'categorylinks', 'page' ), - 'fields' => array ( 'namespace' => NS_CATEGORY, + return array( + 'tables' => array( 'categorylinks', 'page' ), + 'fields' => array( 'namespace' => NS_CATEGORY, 'title' => 'cl_to', 'value' => 'COUNT(*)' ), - 'conds' => array ( 'page_title IS NULL' ), - 'options' => array ( 'GROUP BY' => 'cl_to' ), - 'join_conds' => array ( 'page' => array ( 'LEFT JOIN', - array ( 'page_title = cl_to', + '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 + * @param Skin $skin + * @param object $result Result row * @return string */ function formatResult( $skin, $result ) { diff --git a/includes/specials/SpecialWantedfiles.php b/includes/specials/SpecialWantedfiles.php index 9a2d30a3..b5c1fdbe 100644 --- a/includes/specials/SpecialWantedfiles.php +++ b/includes/specials/SpecialWantedfiles.php @@ -73,16 +73,16 @@ class WantedFilesPage extends WantedQueryPage { } function getQueryInfo() { - return array ( - 'tables' => array ( 'imagelinks', 'image' ), - 'fields' => array ( 'namespace' => NS_FILE, + return array( + 'tables' => array( 'imagelinks', 'image' ), + 'fields' => array( 'namespace' => NS_FILE, 'title' => 'il_to', 'value' => 'COUNT(*)' ), - 'conds' => array ( 'img_name IS NULL' ), - 'options' => array ( 'GROUP BY' => 'il_to' ), - 'join_conds' => array ( 'image' => - array ( 'LEFT JOIN', - array ( 'il_to = img_name' ) + 'conds' => array( 'img_name IS NULL' ), + 'options' => array( 'GROUP BY' => 'il_to' ), + 'join_conds' => array( 'image' => + array( 'LEFT JOIN', + array( 'il_to = img_name' ) ) ) ); diff --git a/includes/specials/SpecialWantedtemplates.php b/includes/specials/SpecialWantedtemplates.php index f5539c18..d13fa031 100644 --- a/includes/specials/SpecialWantedtemplates.php +++ b/includes/specials/SpecialWantedtemplates.php @@ -38,17 +38,17 @@ class WantedTemplatesPage extends WantedQueryPage { } function getQueryInfo() { - return array ( - 'tables' => array ( 'templatelinks', 'page' ), - 'fields' => array ( 'namespace' => 'tl_namespace', + return array( + 'tables' => array( 'templatelinks', 'page' ), + 'fields' => array( 'namespace' => 'tl_namespace', 'title' => 'tl_title', 'value' => 'COUNT(*)' ), - 'conds' => array ( 'page_title IS NULL', + 'conds' => array( 'page_title IS NULL', 'tl_namespace' => NS_TEMPLATE ), - 'options' => array ( + 'options' => array( 'GROUP BY' => array( 'tl_namespace', 'tl_title' ) ), - 'join_conds' => array ( 'page' => array ( 'LEFT JOIN', - array ( 'page_namespace = tl_namespace', + 'join_conds' => array( 'page' => array( 'LEFT JOIN', + array( 'page_namespace = tl_namespace', 'page_title = tl_title' ) ) ) ); } diff --git a/includes/specials/SpecialWatchlist.php b/includes/specials/SpecialWatchlist.php index c7f122b8..4afa279e 100644 --- a/includes/specials/SpecialWatchlist.php +++ b/includes/specials/SpecialWatchlist.php @@ -26,8 +26,8 @@ class SpecialWatchlist extends SpecialPage { /** * Constructor */ - public function __construct( $page = 'Watchlist' ) { - parent::__construct( $page ); + public function __construct( $page = 'Watchlist', $restriction = 'viewmywatchlist' ) { + parent::__construct( $page, $restriction ); } /** @@ -41,7 +41,7 @@ class SpecialWatchlist extends SpecialPage { $output = $this->getOutput(); # Anons don't get a watchlist - if( $user->isAnon() ) { + if ( $user->isAnon() ) { $output->setPageTitle( $this->msg( 'watchnologin' ) ); $output->setRobotPolicy( 'noindex,nofollow' ); $llink = Linker::linkKnown( @@ -54,17 +54,16 @@ class SpecialWatchlist extends SpecialPage { return; } + // Check permissions + $this->checkPermissions(); + // Add feed links - $wlToken = $user->getOption( 'watchlisttoken' ); - if ( !$wlToken ) { - $wlToken = MWCryptRand::generateHex( 40 ); - $user->setOption( 'watchlisttoken', $wlToken ); - $user->saveSettings(); + $wlToken = $user->getTokenFromOption( 'watchlisttoken' ); + if ( $wlToken ) { + $this->addFeedLinks( array( 'action' => 'feedwatchlist', 'allrev' => 'allrev', + 'wlowner' => $user->getName(), 'wltoken' => $wlToken ) ); } - $this->addFeedLinks( array( 'action' => 'feedwatchlist', 'allrev' => 'allrev', - 'wlowner' => $user->getName(), 'wltoken' => $wlToken ) ); - $this->setHeaders(); $this->outputHeader(); @@ -74,9 +73,9 @@ class SpecialWatchlist extends SpecialPage { $request = $this->getRequest(); $mode = SpecialEditWatchlist::getMode( $request, $par ); - if( $mode !== false ) { + if ( $mode !== false ) { # TODO: localise? - switch( $mode ) { + switch ( $mode ) { case SpecialEditWatchlist::EDIT_CLEAR: $mode = 'clear'; break; @@ -87,7 +86,7 @@ class SpecialWatchlist extends SpecialPage { $mode = null; } $title = SpecialPage::getTitleFor( 'EditWatchlist', $mode ); - $output->redirect( $title->getLocalUrl() ); + $output->redirect( $title->getLocalURL() ); return; } @@ -99,30 +98,30 @@ class SpecialWatchlist extends SpecialPage { return; } - // @TODO: use FormOptions! + // @todo use FormOptions! $defaults = array( - /* float */ 'days' => floatval( $user->getOption( 'watchlistdays' ) ), /* 3.0 or 0.5, watch further below */ + /* float */ 'days' => floatval( $user->getOption( 'watchlistdays' ) ), /* bool */ 'hideMinor' => (int)$user->getBoolOption( 'watchlisthideminor' ), - /* bool */ 'hideBots' => (int)$user->getBoolOption( 'watchlisthidebots' ), + /* bool */ 'hideBots' => (int)$user->getBoolOption( 'watchlisthidebots' ), /* bool */ 'hideAnons' => (int)$user->getBoolOption( 'watchlisthideanons' ), - /* bool */ 'hideLiu' => (int)$user->getBoolOption( 'watchlisthideliu' ), + /* bool */ 'hideLiu' => (int)$user->getBoolOption( 'watchlisthideliu' ), /* bool */ 'hidePatrolled' => (int)$user->getBoolOption( 'watchlisthidepatrolled' ), - /* bool */ 'hideOwn' => (int)$user->getBoolOption( 'watchlisthideown' ), - /* bool */ 'extended' => (int)$user->getBoolOption( 'extendwatchlist' ), + /* bool */ 'hideOwn' => (int)$user->getBoolOption( 'watchlisthideown' ), + /* bool */ 'extended' => (int)$user->getBoolOption( 'extendwatchlist' ), /* ? */ 'namespace' => '', //means all - /* ? */ 'invert' => false, + /* ? */ 'invert' => false, /* bool */ 'associated' => false, ); $this->customFilters = array(); wfRunHooks( 'SpecialWatchlistFilters', array( $this, &$this->customFilters ) ); - foreach( $this->customFilters as $key => $params ) { + foreach ( $this->customFilters as $key => $params ) { $defaults[$key] = $params['default']; } # Extract variables from the request, falling back to user preferences or # other default values if these don't exist $values = array(); - $values['days'] = $request->getVal( 'days', $defaults['days'] ); + $values['days'] = floatval( $request->getVal( 'days', $defaults['days'] ) ); $values['hideMinor'] = (int)$request->getBool( 'hideMinor', $defaults['hideMinor'] ); $values['hideBots'] = (int)$request->getBool( 'hideBots', $defaults['hideBots'] ); $values['hideAnons'] = (int)$request->getBool( 'hideAnons', $defaults['hideAnons'] ); @@ -130,7 +129,7 @@ class SpecialWatchlist extends SpecialPage { $values['hideOwn'] = (int)$request->getBool( 'hideOwn', $defaults['hideOwn'] ); $values['hidePatrolled'] = (int)$request->getBool( 'hidePatrolled', $defaults['hidePatrolled'] ); $values['extended'] = (int)$request->getBool( 'extended', $defaults['extended'] ); - foreach( $this->customFilters as $key => $params ) { + foreach ( $this->customFilters as $key => $params ) { $values[$key] = (int)$request->getBool( $key, $defaults[$key] ); } @@ -159,61 +158,41 @@ class SpecialWatchlist extends SpecialPage { $values['invert'] = $invert; $values['associated'] = $associated; - 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'] ); - } - // Dump everything here $nondefaults = array(); foreach ( $defaults as $name => $defValue ) { wfAppendToArrayIfNotDefault( $name, $values[$name], $defaults, $nondefaults ); } - if( ( $wgEnotifWatchlist || $wgShowUpdatedMarker ) && $request->getVal( 'reset' ) && + if ( ( $wgEnotifWatchlist || $wgShowUpdatedMarker ) && $request->getVal( 'reset' ) && $request->wasPosted() ) { $user->clearAllNotifications(); - $output->redirect( $this->getTitle()->getFullUrl( $nondefaults ) ); + $output->redirect( $this->getTitle()->getFullURL( $nondefaults ) ); return; } # Possible where conditions $conds = array(); - if( $values['days'] > 0 ) { + if ( $values['days'] > 0 ) { $conds[] = 'rc_timestamp > ' . $dbr->addQuotes( $dbr->timestamp( time() - intval( $values['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( $values['hideOwn'] ) { + if ( $values['hideOwn'] ) { $conds[] = 'rc_user != ' . $user->getId(); } - if( $values['hideBots'] ) { + if ( $values['hideBots'] ) { $conds[] = 'rc_bot = 0'; } - if( $values['hideMinor'] ) { + if ( $values['hideMinor'] ) { $conds[] = 'rc_minor = 0'; } - if( $values['hideLiu'] ) { + if ( $values['hideLiu'] ) { $conds[] = 'rc_user = 0'; } - if( $values['hideAnons'] ) { + if ( $values['hideAnons'] ) { $conds[] = 'rc_user != 0'; } if ( $user->useRCPatrol() && $values['hidePatrolled'] ) { @@ -224,44 +203,72 @@ class SpecialWatchlist extends SpecialPage { } # Toggle watchlist content (all recent edits or just the latest) - if( $values['extended'] ) { + if ( $values['extended'] ) { $limitWatchlist = $user->getIntOption( 'wllimit' ); $usePage = false; } else { # Top log Ids for a page are not stored - $conds[] = 'rc_this_oldid=page_latest OR rc_type=' . RC_LOG; + $nonRevisionTypes = array( RC_LOG ); + wfRunHooks( 'SpecialWatchlistGetNonRevisionTypes', array( &$nonRevisionTypes ) ); + if ( $nonRevisionTypes ) { + if ( count( $nonRevisionTypes ) === 1 ) { + // if only one use an equality instead of IN condition + $nonRevisionTypes = reset( $nonRevisionTypes ); + } + $conds[] = $dbr->makeList( + array( + 'rc_this_oldid=page_latest', + 'rc_type' => $nonRevisionTypes, + ), + LIST_OR + ); + } $limitWatchlist = 0; $usePage = true; } # Show a message about slave lag, if applicable $lag = wfGetLB()->safeGetLag( $dbr ); - if( $lag > 0 ) { + if ( $lag > 0 ) { $output->showLagWarning( $lag ); } - # Create output form - $form = Xml::fieldset( $this->msg( 'watchlist-options' )->text(), false, array( 'id' => 'mw-watchlist-options' ) ); + # Create output + $form = ''; # Show watchlist header + $form .= "

          "; $form .= $this->msg( 'watchlist-details' )->numParams( $nitems )->parse() . "\n"; - - if( $user->getOption( 'enotifwatchlistpages' ) && $wgEnotifWatchlist) { - $form .= $this->msg( 'wlheader-enotif' )->parseAsBlock() . "\n"; + if ( $wgEnotifWatchlist && $user->getOption( 'enotifwatchlistpages' ) ) { + $form .= $this->msg( 'wlheader-enotif' )->parse() . "\n"; + } + if ( $wgShowUpdatedMarker ) { + $form .= $this->msg( 'wlheader-showupdated' )->parse() . "\n"; } - if( $wgShowUpdatedMarker ) { + $form .= "

          "; + + if ( $wgShowUpdatedMarker ) { $form .= Xml::openElement( 'form', array( 'method' => 'post', - 'action' => $this->getTitle()->getLocalUrl(), - 'id' => 'mw-watchlist-resetbutton' ) ) . "\n" . - $this->msg( 'wlheader-showupdated' )->parse() . - Xml::submitButton( $this->msg( 'enotif_reset' )->text(), array( 'name' => 'dummy' ) ) . "\n" . - Html::hidden( 'reset', 'all' ) . "\n"; - foreach ( $nondefaults as $key => $value ) { - $form .= Html::hidden( $key, $value ) . "\n"; - } - $form .= Xml::closeElement( 'form' ) . "\n"; - } - $form .= "
          \n"; + 'action' => $this->getTitle()->getLocalURL(), + 'id' => 'mw-watchlist-resetbutton' ) ) . "\n" . + Xml::submitButton( $this->msg( 'enotif_reset' )->text(), array( 'name' => 'dummy' ) ) . "\n" . + Html::hidden( 'reset', 'all' ) . "\n"; + foreach ( $nondefaults as $key => $value ) { + $form .= Html::hidden( $key, $value ) . "\n"; + } + $form .= Xml::closeElement( 'form' ) . "\n"; + } + + $form .= Xml::openElement( 'form', array( + 'method' => 'post', + 'action' => $this->getTitle()->getLocalURL(), + 'id' => 'mw-watchlist-form' + ) ); + $form .= Xml::fieldset( + $this->msg( 'watchlist-options' )->text(), + false, + array( 'id' => 'mw-watchlist-options' ) + ); $tables = array( 'recentchanges', 'watchlist' ); $fields = RecentChange::selectFields(); @@ -276,10 +283,10 @@ class SpecialWatchlist extends SpecialPage { ), ); $options = array( 'ORDER BY' => 'rc_timestamp DESC' ); - if( $wgShowUpdatedMarker ) { + if ( $wgShowUpdatedMarker ) { $fields[] = 'wl_notificationtimestamp'; } - if( $limitWatchlist ) { + if ( $limitWatchlist ) { $options['LIMIT'] = $limitWatchlist; } @@ -302,7 +309,7 @@ class SpecialWatchlist extends SpecialPage { $lang = $this->getLanguage(); $wlInfo = ''; - if( $values['days'] > 0 ) { + if ( $values['days'] > 0 ) { $timestamp = wfTimestampNow(); $wlInfo = $this->msg( 'wlnote' )->numParams( $numRows, round( $values['days'] * 24 ) )->params( $lang->userDate( $timestamp, $user ), $lang->userTime( $timestamp, $user ) )->parse() . "
          \n"; @@ -312,11 +319,11 @@ class SpecialWatchlist extends SpecialPage { # Spit out some control panel links $filters = array( - 'hideMinor' => 'rcshowhideminor', - 'hideBots' => 'rcshowhidebots', - 'hideAnons' => 'rcshowhideanons', - 'hideLiu' => 'rcshowhideliu', - 'hideOwn' => 'rcshowhidemine', + 'hideMinor' => 'rcshowhideminor', + 'hideBots' => 'rcshowhidebots', + 'hideAnons' => 'rcshowhideanons', + 'hideLiu' => 'rcshowhideliu', + 'hideOwn' => 'rcshowhidemine', 'hidePatrolled' => 'rcshowhidepatr' ); foreach ( $this->customFilters as $key => $params ) { @@ -328,7 +335,7 @@ class SpecialWatchlist extends SpecialPage { } $links = array(); - foreach( $filters as $name => $msg ) { + foreach ( $filters as $name => $msg ) { $links[] = $this->showHideLink( $nondefaults, $msg, $name, $values[$name] ); } @@ -341,7 +348,6 @@ class SpecialWatchlist extends SpecialPage { $form .= $wlInfo; $form .= $cutofflinks; $form .= $lang->pipeList( $links ) . "\n"; - $form .= Xml::openElement( 'form', array( 'method' => 'post', 'action' => $this->getTitle()->getLocalUrl(), 'id' => 'mw-watchlist-form-namespaceselector' ) ) . "\n"; $form .= "
          \n

          "; $form .= Html::namespaceSelector( array( @@ -349,8 +355,8 @@ class SpecialWatchlist extends SpecialPage { 'all' => '', 'label' => $this->msg( 'namespace' )->text() ), array( - 'name' => 'namespace', - 'id' => 'namespace', + 'name' => 'namespace', + 'id' => 'namespace', 'class' => 'namespaceselector', ) ) . ' '; @@ -372,13 +378,15 @@ class SpecialWatchlist extends SpecialPage { foreach ( $hiddenFields as $key => $value ) { $form .= Html::hidden( $key, $value ) . "\n"; } - $form .= Xml::closeElement( 'form' ) . "\n"; $form .= Xml::closeElement( 'fieldset' ) . "\n"; + $form .= Xml::closeElement( 'form' ) . "\n"; $output->addHTML( $form ); # If there's nothing to show, stop here - if( $numRows == 0 ) { - $output->addWikiMsg( 'watchnochange' ); + if ( $numRows == 0 ) { + $output->wrapWikiMsg( + "

          \n$1\n
          ", 'recentchanges-noresult' + ); return; } @@ -438,7 +446,7 @@ class SpecialWatchlist extends SpecialPage { protected function showHideLink( $options, $message, $name, $value ) { $label = $this->msg( $value ? 'show' : 'hide' )->escaped(); - $options[$name] = 1 - (int) $value; + $options[$name] = 1 - (int)$value; return $this->msg( $message )->rawParams( Linker::linkKnown( $this->getTitle(), $label, array(), $options ) )->escaped(); } @@ -469,17 +477,19 @@ class SpecialWatchlist extends SpecialPage { /** * Returns html * + * @param int $days This gets overwritten, so is not used + * @param array $options Query parameters for URL * @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 ) { + foreach ( $hours as $h ) { $hours[$i++] = $this->hoursLink( $h, $options ); } $i = 0; - foreach( $days as $d ) { + foreach ( $days as $d ) { $days[$i++] = $this->daysLink( $d, $options ); } return $this->msg( 'wlshowlast' )->rawParams( @@ -491,7 +501,7 @@ class SpecialWatchlist extends SpecialPage { /** * Count the number of items on a user's watchlist * - * @param $dbr A database connection + * @param DatabaseBase $dbr A database connection * @return Integer */ protected function countItems( $dbr ) { diff --git a/includes/specials/SpecialWhatlinkshere.php b/includes/specials/SpecialWhatlinkshere.php index cb3e985c..05c7dd5f 100644 --- a/includes/specials/SpecialWhatlinkshere.php +++ b/includes/specials/SpecialWhatlinkshere.php @@ -77,7 +77,7 @@ class SpecialWhatLinksHere extends SpecialPage { $this->opts = $opts; $this->target = Title::newFromURL( $opts->getValue( 'target' ) ); - if( !$this->target ) { + if ( !$this->target ) { $out->addHTML( $this->whatlinkshereForm() ); return; } @@ -94,11 +94,11 @@ class SpecialWhatLinksHere extends SpecialPage { } /** - * @param int $level Recursion level - * @param $target Title Target title - * @param int $limit Number of entries to display - * @param $from Title Display from this article ID - * @param $back Title Display from this article ID at backwards scrolling + * @param int $level Recursion level + * @param Title $target Target title + * @param int $limit Number of entries to display + * @param int $from Display from this article ID (default: 0) + * @param int $back Display from this article ID at backwards scrolling (default: 0) */ function showIndirectLinks( $level, $target, $limit, $from = 0, $back = 0 ) { global $wgMaxRedirectLinksRetrieved; @@ -111,7 +111,7 @@ class SpecialWhatLinksHere extends SpecialPage { $hidetrans = $this->opts->getValue( 'hidetrans' ); $hideimages = $target->getNamespace() != NS_FILE || $this->opts->getValue( 'hideimages' ); - $fetchlinks = (!$hidelinks || !$hideredirs); + $fetchlinks = ( !$hidelinks || !$hideredirs ); // Make the query $plConds = array( @@ -119,9 +119,9 @@ class SpecialWhatLinksHere extends SpecialPage { 'pl_namespace' => $target->getNamespace(), 'pl_title' => $target->getDBkey(), ); - if( $hideredirs ) { + if ( $hideredirs ) { $plConds['rd_from'] = null; - } elseif( $hidelinks ) { + } elseif ( $hidelinks ) { $plConds[] = 'rd_from is NOT NULL'; } @@ -166,34 +166,38 @@ class SpecialWhatLinksHere extends SpecialPage { 'rd_interwiki = ' . $dbr->addQuotes( '' ) . ' OR rd_interwiki IS NULL' ))); - if( $fetchlinks ) { + if ( $fetchlinks ) { $options['ORDER BY'] = 'pl_from'; $plRes = $dbr->select( array( 'pagelinks', 'page', 'redirect' ), $fields, $plConds, __METHOD__, $options, - $joinConds); + $joinConds + ); } - if( !$hidetrans ) { + if ( !$hidetrans ) { $options['ORDER BY'] = 'tl_from'; $tlRes = $dbr->select( array( 'templatelinks', 'page', 'redirect' ), $fields, $tlConds, __METHOD__, $options, - $joinConds); + $joinConds + ); } - if( !$hideimages ) { + if ( !$hideimages ) { $options['ORDER BY'] = 'il_from'; $ilRes = $dbr->select( array( 'imagelinks', 'page', 'redirect' ), $fields, $ilConds, __METHOD__, $options, - $joinConds); + $joinConds + ); } - if( ( !$fetchlinks || !$plRes->numRows() ) && ( $hidetrans || !$tlRes->numRows() ) && ( $hideimages || !$ilRes->numRows() ) ) { + if ( ( !$fetchlinks || !$plRes->numRows() ) && ( $hidetrans || !$tlRes->numRows() ) && ( $hideimages || !$ilRes->numRows() ) ) { if ( 0 == $level ) { $out->addHTML( $this->whatlinkshereForm() ); // Show filters only if there are links - if( $hidelinks || $hidetrans || $hideredirs || $hideimages ) + if ( $hidelinks || $hidetrans || $hideredirs || $hideimages ) { $out->addHTML( $this->getFilterPanel() ); + } $errMsg = is_int( $namespace ) ? 'nolinkshere-ns' : 'nolinkshere'; $out->addWikiMsg( $errMsg, $this->target->getPrefixedText() ); @@ -204,21 +208,21 @@ class SpecialWhatLinksHere extends SpecialPage { // Read the rows into an array and remove duplicates // templatelinks comes second so that the templatelinks row overwrites the // pagelinks row, so we get (inclusion) rather than nothing - if( $fetchlinks ) { + if ( $fetchlinks ) { foreach ( $plRes as $row ) { $row->is_template = 0; $row->is_image = 0; $rows[$row->page_id] = $row; } } - if( !$hidetrans ) { + if ( !$hidetrans ) { foreach ( $tlRes as $row ) { $row->is_template = 1; $row->is_image = 0; $rows[$row->page_id] = $row; } } - if( !$hideimages ) { + if ( !$hideimages ) { foreach ( $ilRes as $row ) { $row->is_template = 0; $row->is_image = 1; @@ -269,7 +273,7 @@ class SpecialWhatLinksHere extends SpecialPage { $out->addHTML( $this->listEnd() ); - if( $level == 0 ) { + if ( $level == 0 ) { $out->addHTML( $prevnext ); } } @@ -292,7 +296,7 @@ class SpecialWhatLinksHere extends SpecialPage { } } - if( $row->rd_from ) { + if ( $row->rd_from ) { $query = array( 'redirect' => 'no' ); } else { $query = array(); @@ -308,12 +312,15 @@ class SpecialWhatLinksHere extends SpecialPage { // Display properties (redirect or template) $propsText = ''; $props = array(); - if ( $row->rd_from ) + if ( $row->rd_from ) { $props[] = $msgcache['isredirect']; - if ( $row->is_template ) + } + if ( $row->is_template ) { $props[] = $msgcache['istemplate']; - if( $row->is_image ) + } + if ( $row->is_image ) { $props[] = $msgcache['isimage']; + } if ( count( $props ) ) { $propsText = $this->msg( 'parentheses' )->rawParams( implode( $msgcache['semicolon-separator'], $props ) )->escaped(); @@ -334,8 +341,9 @@ class SpecialWhatLinksHere extends SpecialPage { protected function wlhLink( Title $target, $text ) { static $title = null; - if ( $title === null ) + if ( $title === null ) { $title = $this->getTitle(); + } return Linker::linkKnown( $title, @@ -419,8 +427,8 @@ class SpecialWhatLinksHere extends SpecialPage { 'all' => '', 'label' => $this->msg( 'namespace' )->text() ), array( - 'name' => 'namespace', - 'id' => 'namespace', + 'name' => 'namespace', + 'id' => 'namespace', 'class' => 'namespaceselector', ) ); @@ -450,12 +458,13 @@ class SpecialWhatLinksHere extends SpecialPage { $links = array(); $types = array( 'hidetrans', 'hidelinks', 'hideredirs' ); - if( $this->target->getNamespace() == NS_FILE ) + if ( $this->target->getNamespace() == NS_FILE ) { $types[] = 'hideimages'; + } // Combined message keys: 'whatlinkshere-hideredirs', 'whatlinkshere-hidetrans', 'whatlinkshere-hidelinks', 'whatlinkshere-hideimages' // To be sure they will be found by grep - foreach( $types as $type ) { + foreach ( $types as $type ) { $chosen = $this->opts->getValue( $type ); $msg = $chosen ? $show : $hide; $overrides = array( $type => !$chosen ); diff --git a/includes/specials/SpecialWithoutinterwiki.php b/includes/specials/SpecialWithoutinterwiki.php index 37237407..9d23499f 100644 --- a/includes/specials/SpecialWithoutinterwiki.php +++ b/includes/specials/SpecialWithoutinterwiki.php @@ -44,21 +44,21 @@ class WithoutInterwikiPage extends PageQueryPage { global $wgScript; # Do not show useless input form if special page is cached - if( $this->isCached() ) { + if ( $this->isCached() ) { return ''; } $prefix = $this->prefix; $t = $this->getTitle(); - return Xml::openElement( 'form', array( 'method' => 'get', 'action' => $wgScript ) ) . - Xml::openElement( 'fieldset' ) . - Xml::element( 'legend', null, $this->msg( 'withoutinterwiki-legend' )->text() ) . - Html::hidden( 'title', $t->getPrefixedText() ) . - Xml::inputLabel( $this->msg( 'allpagesprefix' )->text(), 'prefix', 'wiprefix', 20, $prefix ) . ' ' . - Xml::submitButton( $this->msg( 'withoutinterwiki-submit' )->text() ) . - Xml::closeElement( 'fieldset' ) . - Xml::closeElement( 'form' ); + return Html::openElement( 'form', array( 'method' => 'get', 'action' => $wgScript ) ) . "\n" . + Html::openElement( 'fieldset' ) . "\n" . + Html::element( 'legend', null, $this->msg( 'withoutinterwiki-legend' )->text() ) . "\n" . + Html::hidden( 'title', $t->getPrefixedText() ) . "\n" . + Xml::inputLabel( $this->msg( 'allpagesprefix' )->text(), 'prefix', 'wiprefix', 20, $prefix ) . "\n" . + Xml::submitButton( $this->msg( 'withoutinterwiki-submit' )->text() ) . "\n" . + Html::closeElement( 'fieldset' ) . "\n" . + Html::closeElement( 'form' ); } function sortDescending() { @@ -78,15 +78,15 @@ class WithoutInterwikiPage extends PageQueryPage { } function getQueryInfo() { - $query = array ( - 'tables' => array ( 'page', 'langlinks' ), - 'fields' => array ( 'namespace' => 'page_namespace', + $query = array( + 'tables' => array( 'page', 'langlinks' ), + 'fields' => array( 'namespace' => 'page_namespace', 'title' => 'page_title', 'value' => 'page_title' ), - 'conds' => array ( 'll_title IS NULL', + 'conds' => array( 'll_title IS NULL', 'page_namespace' => MWNamespace::getContentNamespaces(), 'page_is_redirect' => 0 ), - 'join_conds' => array ( 'langlinks' => array ( + 'join_conds' => array( 'langlinks' => array( 'LEFT JOIN', 'll_from = page_id' ) ) ); if ( $this->prefix ) { -- cgit v1.2.2
          " . - $this->diffHeader( $previousRev, 'o' ) . - "" . - $this->diffHeader( $currentRev, 'n' ) . - "" . + $this->diffHeader( $previousRev, 'o' ) . + "" . + $this->diffHeader( $currentRev, 'n' ) . + "
            " . - Xml::checkLabel( $this->msg( 'revdelete-unsuppress' )->text(), - 'wpUnsuppress', 'mw-undelete-unsuppress', $this->mUnsuppress ). + Xml::checkLabel( $this->msg( 'revdelete-unsuppress' )->text(), + 'wpUnsuppress', 'mw-undelete-unsuppress', $this->mUnsuppress ) . "
          " . - $this->msg( 'undeleteextrahelp' )->parseAsBlock() . - "
          " . - Xml::label( $this->msg( 'undeletecomment' )->text(), 'wpComment' ) . - "" . - Xml::input( 'wpComment', 50, $this->mComment, array( 'id' => 'wpComment' ) ) . - "
           " . - Xml::submitButton( $this->msg( 'undeletebtn' )->text(), array( 'name' => 'restore', 'id' => 'mw-undelete-submit' ) ) . ' ' . - Xml::submitButton( $this->msg( 'undeleteinvert' )->text(), array( 'name' => 'invert', 'id' => 'mw-undelete-invert' ) ) . - "
          " . + Xml::label( $this->msg( 'undeletecomment' )->text(), 'wpComment' ) . + "" . + Xml::input( 'wpComment', 50, $this->mComment, array( 'id' => 'wpComment', 'autofocus' => true ) ) . + "
           " . + Xml::submitButton( $this->msg( 'undeletebtn' )->text(), array( 'name' => 'restore', 'id' => 'mw-undelete-submit' ) ) . ' ' . + Xml::submitButton( $this->msg( 'undeleteinvert' )->text(), array( 'name' => 'invert', 'id' => 'mw-undelete-invert' ) ) . + "
          \n"; - foreach( $column as $group => $checkbox ) { + foreach ( $column as $group => $checkbox ) { $attr = $checkbox['disabled'] ? array( 'disabled' => 'disabled' ) : array(); $member = User::getGroupMember( $group, $user->getName() ); @@ -604,8 +635,7 @@ class UserrightsPage extends SpecialPage { * @return bool Can we remove the group? */ private function canRemove( $group ) { - // $this->changeableGroups()['remove'] doesn't work, of course. Thanks, - // PHP. + // $this->changeableGroups()['remove'] doesn't work, of course. Thanks, PHP. $groups = $this->changeableGroups(); return in_array( $group, $groups['remove'] ) || ( $this->isself && in_array( $group, $groups['remove-self'] ) ); } diff --git a/includes/specials/SpecialVersion.php b/includes/specials/SpecialVersion.php index 81d17817..5ba785f5 100644 --- a/includes/specials/SpecialVersion.php +++ b/includes/specials/SpecialVersion.php @@ -55,7 +55,7 @@ class SpecialVersion extends SpecialPage { $out = $this->getOutput(); $out->allowClickjacking(); - if( $par !== 'Credits' ) { + if ( $par !== 'Credits' ) { $text = $this->getMediaWikiCredits() . $this->softwareInformation() . @@ -69,9 +69,7 @@ class SpecialVersion extends SpecialPage { $out->addHTML( $this->IPInfo() ); if ( $this->getRequest()->getVal( 'easteregg' ) ) { - if ( $this->showEasterEgg() ) { - // TODO: put something interesting here - } + // TODO: put something interesting here } } else { // Credits sub page @@ -115,11 +113,13 @@ class SpecialVersion extends SpecialPage { global $wgLang; if ( defined( 'MEDIAWIKI_INSTALL' ) ) { - $othersLink = '[http://www.mediawiki.org/wiki/Special:Version/Credits ' . wfMessage( 'version-poweredby-others' )->text() . ']'; + $othersLink = '[//www.mediawiki.org/wiki/Special:Version/Credits ' . wfMessage( 'version-poweredby-others' )->text() . ']'; } else { $othersLink = '[[Special:Version/Credits|' . wfMessage( 'version-poweredby-others' )->text() . ']]'; } + $translatorsLink = '[//translatewiki.net/wiki/Translating:MediaWiki/Credits ' . wfMessage( 'version-poweredby-translators' )->text() . ']'; + $authorList = array( 'Magnus Manske', 'Brion Vibber', 'Lee Daniel Crocker', 'Tim Starling', 'Erik Möller', 'Gabriel Wicke', 'Ævar Arnfjörð Bjarmason', @@ -128,10 +128,11 @@ class SpecialVersion extends SpecialPage { 'Alexandre Emsenhuber', 'Siebrand Mazeland', 'Chad Horohoe', 'Roan Kattouw', 'Trevor Parscal', 'Bryan Tong Minh', 'Sam Reed', 'Victor Vasiliev', 'Rotem Liss', 'Platonides', 'Antoine Musso', - 'Timo Tijhof', 'Daniel Kinzler', 'Jeroen De Dauw', $othersLink + 'Timo Tijhof', 'Daniel Kinzler', 'Jeroen De Dauw', $othersLink, + $translatorsLink ); - return wfMessage( 'version-poweredby-credits', date( 'Y' ), + return wfMessage( 'version-poweredby-credits', MWTimestamp::getLocalInstance()->format( 'Y' ), $wgLang->listToText( $authorList ) )->text(); } @@ -161,7 +162,7 @@ class SpecialVersion extends SpecialPage { " . wfMessage( 'version-software-version' )->text() . "
          " . $name . " " . $version . "
          ' . $this->listToText( $wgExtensionFunctions ) . "
          ' . $this->listToText( $tags ). "
          ' . $this->listToText( $tags ) . "
          ' . $this->listToText( $fhooks ) . "
          $mainLink $versionText$description " . $this->listAuthors( $author, false ) . "