summaryrefslogtreecommitdiff
path: root/includes/specials
diff options
context:
space:
mode:
authorPierre Schmitz <pierre@archlinux.de>2009-02-22 13:37:51 +0100
committerPierre Schmitz <pierre@archlinux.de>2009-02-22 13:37:51 +0100
commitb9b85843572bf283f48285001e276ba7e61b63f6 (patch)
tree4c6f4571552ada9ccfb4030481dcf77308f8b254 /includes/specials
parentd9a20acc4e789cca747ad360d87ee3f3e7aa58c1 (diff)
updated to MediaWiki 1.14.0
Diffstat (limited to 'includes/specials')
-rw-r--r--includes/specials/SpecialAllmessages.php85
-rw-r--r--includes/specials/SpecialAllpages.php717
-rw-r--r--includes/specials/SpecialBlockip.php195
-rw-r--r--includes/specials/SpecialBooksources.php56
-rw-r--r--includes/specials/SpecialCategories.php4
-rw-r--r--includes/specials/SpecialConfirmemail.php22
-rw-r--r--includes/specials/SpecialContributions.php682
-rw-r--r--includes/specials/SpecialDeletedContributions.php369
-rw-r--r--includes/specials/SpecialDisambiguations.php8
-rw-r--r--includes/specials/SpecialEmailuser.php142
-rw-r--r--includes/specials/SpecialExport.php38
-rw-r--r--includes/specials/SpecialFileDuplicateSearch.php6
-rw-r--r--includes/specials/SpecialFilepath.php4
-rw-r--r--includes/specials/SpecialImport.php1202
-rw-r--r--includes/specials/SpecialIpblocklist.php118
-rw-r--r--includes/specials/SpecialLinkSearch.php185
-rw-r--r--includes/specials/SpecialListUserRestrictions.php161
-rw-r--r--includes/specials/SpecialListfiles.php (renamed from includes/specials/SpecialImagelist.php)51
-rw-r--r--includes/specials/SpecialListgrouprights.php25
-rw-r--r--includes/specials/SpecialListredirects.php3
-rw-r--r--includes/specials/SpecialListusers.php68
-rw-r--r--includes/specials/SpecialLockdb.php2
-rw-r--r--includes/specials/SpecialLog.php22
-rw-r--r--includes/specials/SpecialLonelypages.php7
-rw-r--r--includes/specials/SpecialMIMEsearch.php2
-rw-r--r--includes/specials/SpecialMergeHistory.php22
-rw-r--r--includes/specials/SpecialMostcategories.php4
-rw-r--r--includes/specials/SpecialMostimages.php2
-rw-r--r--includes/specials/SpecialMostlinkedtemplates.php19
-rw-r--r--includes/specials/SpecialMovepage.php136
-rw-r--r--includes/specials/SpecialNewimages.php127
-rw-r--r--includes/specials/SpecialNewpages.php57
-rw-r--r--includes/specials/SpecialPreferences.php461
-rw-r--r--includes/specials/SpecialPrefixindex.php139
-rw-r--r--includes/specials/SpecialProtectedpages.php32
-rw-r--r--includes/specials/SpecialProtectedtitles.php13
-rw-r--r--includes/specials/SpecialRandompage.php22
-rw-r--r--includes/specials/SpecialRecentchanges.php263
-rw-r--r--includes/specials/SpecialRecentchangeslinked.php30
-rw-r--r--includes/specials/SpecialRemoveRestrictions.php60
-rw-r--r--includes/specials/SpecialResetpass.php178
-rw-r--r--includes/specials/SpecialRestrictUser.php189
-rw-r--r--includes/specials/SpecialRevisiondelete.php72
-rw-r--r--includes/specials/SpecialSearch.php984
-rw-r--r--includes/specials/SpecialSpecialpages.php2
-rw-r--r--includes/specials/SpecialStatistics.php277
-rw-r--r--includes/specials/SpecialUncategorizedimages.php2
-rw-r--r--includes/specials/SpecialUndelete.php197
-rw-r--r--includes/specials/SpecialUnusedimages.php2
-rw-r--r--includes/specials/SpecialUpload.php69
-rw-r--r--includes/specials/SpecialUserlogin.php249
-rw-r--r--includes/specials/SpecialUserlogout.php2
-rw-r--r--includes/specials/SpecialUserrights.php88
-rw-r--r--includes/specials/SpecialVersion.php74
-rw-r--r--includes/specials/SpecialWantedfiles.php90
-rw-r--r--includes/specials/SpecialWantedtemplates.php110
-rw-r--r--includes/specials/SpecialWatchlist.php266
-rw-r--r--includes/specials/SpecialWhatlinkshere.php20
58 files changed, 5318 insertions, 3114 deletions
diff --git a/includes/specials/SpecialAllmessages.php b/includes/specials/SpecialAllmessages.php
index c2a8de4e..0ff94b49 100644
--- a/includes/specials/SpecialAllmessages.php
+++ b/includes/specials/SpecialAllmessages.php
@@ -29,15 +29,19 @@ function wfSpecialAllmessages() {
$wgMessageCache->loadAllMessages();
- $sortedArray = array_merge( Language::getMessagesFor( 'en' ), $wgMessageCache->getExtensionMessagesFor( 'en' ) );
+ $sortedArray = array_merge( Language::getMessagesFor( 'en' ),
+ $wgMessageCache->getExtensionMessagesFor( 'en' ) );
ksort( $sortedArray );
- $messages = array();
- foreach ( $sortedArray as $key => $value ) {
+ $messages = array();
+ foreach( $sortedArray as $key => $value ) {
$messages[$key]['enmsg'] = $value;
- $messages[$key]['statmsg'] = wfMsgReal( $key, array(), false, false, false ); // wfMsgNoDbNoTrans doesn't exist
+ $messages[$key]['statmsg'] = wfMsgReal( $key, array(), false, false, false );
$messages[$key]['msg'] = wfMsgNoTrans( $key );
+ $sortedArray[$key] = NULL; // trade bytes from $sortedArray to this
+
}
+ unset($sortedArray); // trade bytes from $sortedArray to this
wfProfileOut( __METHOD__ . '-setup' );
@@ -63,13 +67,14 @@ function wfSpecialAllmessages() {
wfProfileOut( __METHOD__ );
}
-function wfAllMessagesMakeXml( $messages ) {
+function wfAllMessagesMakeXml( &$messages ) {
global $wgLang;
$lang = $wgLang->getCode();
$txt = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n";
$txt .= "<messages lang=\"$lang\">\n";
foreach( $messages as $key => $m ) {
$txt .= "\t" . Xml::element( 'message', array( 'name' => $key ), $m['msg'] ) . "\n";
+ $messages[$key] = NULL; // trade bytes
}
$txt .= "</messages>";
return $txt;
@@ -81,7 +86,7 @@ function wfAllMessagesMakeXml( $messages ) {
* @return The PHP messages array.
* @todo Make suitable for language files.
*/
-function wfAllMessagesMakePhp( $messages ) {
+function wfAllMessagesMakePhp( &$messages ) {
global $wgLang;
$txt = "\n\n\$messages = array(\n";
foreach( $messages as $key => $m ) {
@@ -94,6 +99,7 @@ function wfAllMessagesMakePhp( $messages ) {
$comment = '';
}
$txt .= "'$key' => '" . preg_replace( '/(?<!\\\\)\'/', "\'", $m['msg']) . "',$comment\n";
+ $messages[$key] = NULL; // trade bytes
}
$txt .= ');';
return $txt;
@@ -104,7 +110,7 @@ function wfAllMessagesMakePhp( $messages ) {
* @param $messages Messages array.
* @return The HTML list of messages.
*/
-function wfAllMessagesMakeHTMLText( $messages ) {
+function wfAllMessagesMakeHTMLText( &$messages ) {
global $wgLang, $wgContLang, $wgUser;
wfProfileIn( __METHOD__ );
@@ -123,7 +129,8 @@ function wfAllMessagesMakeHTMLText( $messages ) {
'onclick' => 'allmessagesmodified()'
), '' );
- $txt = '<span id="allmessagesfilter" style="display: none;">' . wfMsgHtml( 'allmessagesfilter' ) . " {$input}{$checkbox} " . '</span>';
+ $txt = '<span id="allmessagesfilter" style="display: none;">' . wfMsgHtml( 'allmessagesfilter' ) .
+ " {$input}{$checkbox} " . '</span>';
$txt .= '
<table border="1" cellspacing="0" width="100%" id="allmessagestable">
@@ -144,11 +151,14 @@ function wfAllMessagesMakeHTMLText( $messages ) {
NS_MEDIAWIKI_TALK => array()
);
$dbr = wfGetDB( DB_SLAVE );
- $page = $dbr->tableName( 'page' );
- $sql = "SELECT page_namespace,page_title FROM $page WHERE page_namespace IN (" . NS_MEDIAWIKI . ", " . NS_MEDIAWIKI_TALK . ")";
- $res = $dbr->query( $sql );
+ $res = $dbr->select( 'page',
+ array( 'page_namespace', 'page_title' ),
+ array( 'page_namespace' => array(NS_MEDIAWIKI,NS_MEDIAWIKI_TALK) ),
+ __METHOD__,
+ array( 'USE INDEX' => 'name_title' )
+ );
while( $s = $dbr->fetchObject( $res ) ) {
- $pageExists[$s->page_namespace][$s->page_title] = true;
+ $pageExists[$s->page_namespace][$s->page_title] = 1;
}
$dbr->freeResult( $res );
wfProfileOut( __METHOD__ . "-check" );
@@ -163,19 +173,21 @@ function wfAllMessagesMakeHTMLText( $messages ) {
$title .= '/' . $wgLang->getCode();
}
- $titleObj =& Title::makeTitle( NS_MEDIAWIKI, $title );
- $talkPage =& Title::makeTitle( NS_MEDIAWIKI_TALK, $title );
+ $titleObj = Title::makeTitle( NS_MEDIAWIKI, $title );
+ $talkPage = Title::makeTitle( NS_MEDIAWIKI_TALK, $title );
$changed = ( $m['statmsg'] != $m['msg'] );
$message = htmlspecialchars( $m['statmsg'] );
$mw = htmlspecialchars( $m['msg'] );
- if( isset( $pageExists[NS_MEDIAWIKI][$title] ) ) {
- $pageLink = $sk->makeKnownLinkObj( $titleObj, "<span id=\"sp-allmessages-i-$i\">" . htmlspecialchars( $key ) . '</span>' );
+ if( array_key_exists( $title, $pageExists[NS_MEDIAWIKI] ) ) {
+ $pageLink = $sk->makeKnownLinkObj( $titleObj, "<span id=\"sp-allmessages-i-$i\">" .
+ htmlspecialchars( $key ) . '</span>' );
} else {
- $pageLink = $sk->makeBrokenLinkObj( $titleObj, "<span id=\"sp-allmessages-i-$i\">" . htmlspecialchars( $key ) . '</span>' );
+ $pageLink = $sk->makeBrokenLinkObj( $titleObj, "<span id=\"sp-allmessages-i-$i\">" .
+ htmlspecialchars( $key ) . '</span>' );
}
- if( isset( $pageExists[NS_MEDIAWIKI_TALK][$title] ) ) {
+ if( array_key_exists( $title, $pageExists[NS_MEDIAWIKI_TALK] ) ) {
$talkLink = $sk->makeKnownLinkObj( $talkPage, htmlspecialchars( $talk ) );
} else {
$talkLink = $sk->makeBrokenLinkObj( $talkPage, htmlspecialchars( $talk ) );
@@ -186,27 +198,28 @@ function wfAllMessagesMakeHTMLText( $messages ) {
if( $changed ) {
$txt .= "
- <tr class=\"orig\" id=\"sp-allmessages-r1-$i\">
- <td rowspan=\"2\">
- $anchor$pageLink<br />$talkLink
- </td><td>
-$message
- </td>
- </tr><tr class=\"new\" id=\"sp-allmessages-r2-$i\">
- <td>
-$mw
- </td>
- </tr>";
+ <tr class=\"orig\" id=\"sp-allmessages-r1-$i\">
+ <td rowspan=\"2\">
+ $anchor$pageLink<br />$talkLink
+ </td><td>
+ $message
+ </td>
+ </tr><tr class=\"new\" id=\"sp-allmessages-r2-$i\">
+ <td>
+ $mw
+ </td>
+ </tr>";
} else {
$txt .= "
- <tr class=\"def\" id=\"sp-allmessages-r1-$i\">
- <td>
- $anchor$pageLink<br />$talkLink
- </td><td>
-$mw
- </td>
- </tr>";
+ <tr class=\"def\" id=\"sp-allmessages-r1-$i\">
+ <td>
+ $anchor$pageLink<br />$talkLink
+ </td><td>
+ $mw
+ </td>
+ </tr>";
}
+ $messages[$key] = NULL; // trade bytes
$i++;
}
$txt .= '</table>';
diff --git a/includes/specials/SpecialAllpages.php b/includes/specials/SpecialAllpages.php
index 7223e317..bf68dfa6 100644
--- a/includes/specials/SpecialAllpages.php
+++ b/includes/specials/SpecialAllpages.php
@@ -1,404 +1,445 @@
<?php
-/**
- * @file
- * @ingroup SpecialPage
- */
-
-/**
- * Entry point : initialise variables and call subfunctions.
- * @param $par String: becomes "FOO" when called like Special:Allpages/FOO (default NULL)
- * @param $specialPage See the SpecialPage object.
- */
-function wfSpecialAllpages( $par=NULL, $specialPage ) {
- global $wgRequest, $wgOut, $wgContLang;
-
- # GET values
- $from = $wgRequest->getVal( 'from' );
- $namespace = $wgRequest->getInt( 'namespace' );
-
- $namespaces = $wgContLang->getNamespaces();
-
- $indexPage = new SpecialAllpages();
-
- $wgOut->setPagetitle( ( $namespace > 0 && in_array( $namespace, array_keys( $namespaces) ) ) ?
- wfMsg( 'allinnamespace', str_replace( '_', ' ', $namespaces[$namespace] ) ) :
- wfMsg( 'allarticles' )
- );
-
- if ( isset($par) ) {
- $indexPage->showChunk( $namespace, $par, $specialPage->including() );
- } elseif ( isset($from) ) {
- $indexPage->showChunk( $namespace, $from, $specialPage->including() );
- } else {
- $indexPage->showToplevel ( $namespace, $specialPage->including() );
- }
-}
/**
* Implements Special:Allpages
* @ingroup SpecialPage
*/
-class SpecialAllpages {
+class SpecialAllpages extends IncludableSpecialPage {
+
/**
* Maximum number of pages to show on single subpage.
*/
- protected $maxPerPage = 960;
+ protected $maxPerPage = 345;
/**
- * Name of this special page. Used to make title objects that reference back
- * to this page.
+ * Maximum number of pages to show on single index subpage.
*/
- protected $name = 'Allpages';
+ protected $maxLineCount = 200;
+
+ /**
+ * Maximum number of chars to show for an entry.
+ */
+ protected $maxPageLength = 70;
/**
* Determines, which message describes the input field 'nsfrom'.
*/
protected $nsfromMsg = 'allpagesfrom';
-/**
- * HTML for the top form
- * @param integer $namespace A namespace constant (default NS_MAIN).
- * @param string $from Article name we are starting listing at.
- */
-function namespaceForm ( $namespace = NS_MAIN, $from = '' ) {
- global $wgScript;
- $t = SpecialPage::getTitleFor( $this->name );
-
- $out = Xml::openElement( 'div', array( 'class' => 'namespaceoptions' ) );
- $out .= Xml::openElement( 'form', array( 'method' => 'get', 'action' => $wgScript ) );
- $out .= Xml::hidden( 'title', $t->getPrefixedText() );
- $out .= Xml::openElement( 'fieldset' );
- $out .= Xml::element( 'legend', null, wfMsg( 'allpages' ) );
- $out .= Xml::openElement( 'table', array( 'id' => 'nsselect', 'class' => 'allpages' ) );
- $out .= "<tr>
- <td class='mw-label'>" .
- Xml::label( wfMsg( $this->nsfromMsg ), 'nsfrom' ) .
- "</td>
- <td class='mw-input'>" .
- Xml::input( 'from', 20, $from, array( 'id' => 'nsfrom' ) ) .
- "</td>
- </tr>
- <tr>
- <td class='mw-label'>" .
- Xml::label( wfMsg( 'namespace' ), 'namespace' ) .
- "</td>
- <td class='mw-input'>" .
- Xml::namespaceSelector( $namespace, null ) . ' ' .
- Xml::submitButton( wfMsg( 'allpagessubmit' ) ) .
- "</td>
- </tr>";
- $out .= Xml::closeElement( 'table' );
- $out .= Xml::closeElement( 'fieldset' );
- $out .= Xml::closeElement( 'form' );
- $out .= Xml::closeElement( 'div' );
- return $out;
-}
+ function __construct( $name = 'Allpages' ){
+ parent::__construct( $name );
+ }
-/**
- * @param integer $namespace (default NS_MAIN)
- */
-function showToplevel ( $namespace = NS_MAIN, $including = false ) {
- global $wgOut, $wgContLang;
- $align = $wgContLang->isRtl() ? 'left' : 'right';
+ /**
+ * Entry point : initialise variables and call subfunctions.
+ * @param $par String: becomes "FOO" when called like Special:Allpages/FOO (default NULL)
+ * @param $specialPage See the SpecialPage object.
+ */
+ function execute( $par ) {
+ global $wgRequest, $wgOut, $wgContLang;
- # TODO: Either make this *much* faster or cache the title index points
- # in the querycache table.
+ $this->setHeaders();
+ $this->outputHeader();
- $dbr = wfGetDB( DB_SLAVE );
- $out = "";
- $where = array( 'page_namespace' => $namespace );
+ # GET values
+ $from = $wgRequest->getVal( 'from', null );
+ $to = $wgRequest->getVal( 'to', null );
+ $namespace = $wgRequest->getInt( 'namespace' );
- global $wgMemc;
- $key = wfMemcKey( 'allpages', 'ns', $namespace );
- $lines = $wgMemc->get( $key );
+ $namespaces = $wgContLang->getNamespaces();
- if( !is_array( $lines ) ) {
- $options = array( 'LIMIT' => 1 );
- if ( ! $dbr->implicitOrderby() ) {
- $options['ORDER BY'] = 'page_title';
+ $wgOut->setPagetitle( ( $namespace > 0 && in_array( $namespace, array_keys( $namespaces) ) ) ?
+ wfMsg( 'allinnamespace', str_replace( '_', ' ', $namespaces[$namespace] ) ) :
+ wfMsg( 'allarticles' )
+ );
+
+ if( isset($par) ) {
+ $this->showChunk( $namespace, $par, $to );
+ } elseif( isset($from) && !isset($to) ) {
+ $this->showChunk( $namespace, $from, $to );
+ } else {
+ $this->showToplevel( $namespace, $from, $to );
}
- $firstTitle = $dbr->selectField( 'page', 'page_title', $where, __METHOD__, $options );
- $lastTitle = $firstTitle;
-
- # This array is going to hold the page_titles in order.
- $lines = array( $firstTitle );
-
- # If we are going to show n rows, we need n+1 queries to find the relevant titles.
- $done = false;
- for( $i = 0; !$done; ++$i ) {
- // Fetch the last title of this chunk and the first of the next
- $chunk = is_null( $lastTitle )
- ? ''
- : 'page_title >= ' . $dbr->addQuotes( $lastTitle );
- $res = $dbr->select(
- 'page', /* FROM */
- 'page_title', /* WHAT */
- $where + array($chunk),
- __METHOD__,
- array ('LIMIT' => 2, 'OFFSET' => $this->maxPerPage - 1, 'ORDER BY' => 'page_title') );
+ }
- if ( $s = $dbr->fetchObject( $res ) ) {
- array_push( $lines, $s->page_title );
- } else {
- // Final chunk, but ended prematurely. Go back and find the end.
- $endTitle = $dbr->selectField( 'page', 'MAX(page_title)',
- array(
- 'page_namespace' => $namespace,
- $chunk
- ), __METHOD__ );
- array_push( $lines, $endTitle );
- $done = true;
+ /**
+ * HTML for the top form
+ * @param integer $namespace A namespace constant (default NS_MAIN).
+ * @param string $from dbKey we are starting listing at.
+ * @param string $to dbKey we are ending listing at.
+ */
+ function namespaceForm( $namespace = NS_MAIN, $from = '', $to = '' ) {
+ global $wgScript;
+ $t = $this->getTitle();
+
+ $out = Xml::openElement( 'div', array( 'class' => 'namespaceoptions' ) );
+ $out .= Xml::openElement( 'form', array( 'method' => 'get', 'action' => $wgScript ) );
+ $out .= Xml::hidden( 'title', $t->getPrefixedText() );
+ $out .= Xml::openElement( 'fieldset' );
+ $out .= Xml::element( 'legend', null, wfMsg( 'allpages' ) );
+ $out .= Xml::openElement( 'table', array( 'id' => 'nsselect', 'class' => 'allpages' ) );
+ $out .= "<tr>
+ <td class='mw-label'>" .
+ Xml::label( wfMsg( 'allpagesfrom' ), 'nsfrom' ) .
+ "</td>
+ <td class='mw-input'>" .
+ Xml::input( 'from', 30, str_replace('_',' ',$from), array( 'id' => 'nsfrom' ) ) .
+ "</td>
+ </tr>
+ <tr>
+ <td class='mw-label'>" .
+ Xml::label( wfMsg( 'allpagesto' ), 'nsto' ) .
+ "</td>
+ <td class='mw-input'>" .
+ Xml::input( 'to', 30, str_replace('_',' ',$to), array( 'id' => 'nsto' ) ) .
+ "</td>
+ </tr>
+ <tr>
+ <td class='mw-label'>" .
+ Xml::label( wfMsg( 'namespace' ), 'namespace' ) .
+ "</td>
+ <td class='mw-input'>" .
+ Xml::namespaceSelector( $namespace, null ) . ' ' .
+ Xml::submitButton( wfMsg( 'allpagessubmit' ) ) .
+ "</td>
+ </tr>";
+ $out .= Xml::closeElement( 'table' );
+ $out .= Xml::closeElement( 'fieldset' );
+ $out .= Xml::closeElement( 'form' );
+ $out .= Xml::closeElement( 'div' );
+ return $out;
+ }
+
+ /**
+ * @param integer $namespace (default NS_MAIN)
+ */
+ function showToplevel( $namespace = NS_MAIN, $from = '', $to = '' ) {
+ global $wgOut, $wgContLang;
+ $align = $wgContLang->isRtl() ? 'left' : 'right';
+
+ # TODO: Either make this *much* faster or cache the title index points
+ # in the querycache table.
+
+ $dbr = wfGetDB( DB_SLAVE );
+ $out = "";
+ $where = array( 'page_namespace' => $namespace );
+
+ $from = Title::makeTitleSafe( $namespace, $from );
+ $to = Title::makeTitleSafe( $namespace, $to );
+ $from = ( $from && $from->isLocal() ) ? $from->getDBKey() : null;
+ $to = ( $to && $to->isLocal() ) ? $to->getDBKey() : null;
+
+ if( isset($from) )
+ $where[] = 'page_title >= '.$dbr->addQuotes( $from );
+ if( isset($to) )
+ $where[] = 'page_title <= '.$dbr->addQuotes( $to );
+
+ global $wgMemc;
+ $key = wfMemcKey( 'allpages', 'ns', $namespace, $from, $to );
+ $lines = $wgMemc->get( $key );
+
+ $count = $dbr->estimateRowCount( 'page', '*', $where, __METHOD__ );
+ $maxPerSubpage = intval($count/$this->maxLineCount);
+ $maxPerSubpage = max($maxPerSubpage,$this->maxPerPage);
+
+ if( !is_array( $lines ) ) {
+ $options = array( 'LIMIT' => 1 );
+ $options['ORDER BY'] = 'page_title ASC';
+ $firstTitle = $dbr->selectField( 'page', 'page_title', $where, __METHOD__, $options );
+ $lastTitle = $firstTitle;
+ # This array is going to hold the page_titles in order.
+ $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 ) {
+ // Fetch the last title of this chunk and the first of the next
+ $chunk = ( $lastTitle === false )
+ ? array()
+ : array( 'page_title >= ' . $dbr->addQuotes( $lastTitle ) );
+ $res = $dbr->select( 'page', /* FROM */
+ 'page_title', /* WHAT */
+ array_merge($where,$chunk),
+ __METHOD__,
+ array ('LIMIT' => 2, 'OFFSET' => $maxPerSubpage - 1, 'ORDER BY' => 'page_title ASC')
+ );
+
+ if( $s = $dbr->fetchObject( $res ) ) {
+ array_push( $lines, $s->page_title );
+ } else {
+ // Final chunk, but ended prematurely. Go back and find the end.
+ $endTitle = $dbr->selectField( 'page', 'MAX(page_title)',
+ array_merge($where,$chunk),
+ __METHOD__ );
+ array_push( $lines, $endTitle );
+ $done = true;
+ }
+ if( $s = $res->fetchObject() ) {
+ array_push( $lines, $s->page_title );
+ $lastTitle = $s->page_title;
+ } else {
+ // This was a final chunk and ended exactly at the limit.
+ // Rare but convenient!
+ $done = true;
+ }
+ $res->free();
}
- if( $s = $dbr->fetchObject( $res ) ) {
- array_push( $lines, $s->page_title );
- $lastTitle = $s->page_title;
+ $wgMemc->add( $key, $lines, 3600 );
+ }
+
+ // 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) ) {
+ $this->showChunk( $namespace, $lines[0], $lines[count($lines)-1] );
} else {
- // This was a final chunk and ended exactly at the limit.
- // Rare but convenient!
- $done = true;
+ $wgOut->addHTML( $this->namespaceForm( $namespace, $from, $to ) );
}
- $dbr->freeResult( $res );
+ return;
}
- $wgMemc->add( $key, $lines, 3600 );
- }
- // If there are only two or less sections, don't even display them.
- // Instead, display the first section directly.
- if( count( $lines ) <= 2 ) {
- $this->showChunk( $namespace, '', $including );
- return;
- }
+ # At this point, $lines should contain an even number of elements.
+ $out .= "<table class='allpageslist' style='background: inherit;'>";
+ while( count ( $lines ) > 0 ) {
+ $inpoint = array_shift( $lines );
+ $outpoint = array_shift( $lines );
+ $out .= $this->showline( $inpoint, $outpoint, $namespace );
+ }
+ $out .= '</table>';
+ $nsForm = $this->namespaceForm( $namespace, $from, $to );
- # At this point, $lines should contain an even number of elements.
- $out .= "<table class='allpageslist' style='background: inherit;'>";
- while ( count ( $lines ) > 0 ) {
- $inpoint = array_shift ( $lines );
- $outpoint = array_shift ( $lines );
- $out .= $this->showline ( $inpoint, $outpoint, $namespace, false );
- }
- $out .= '</table>';
- $nsForm = $this->namespaceForm( $namespace, '', false );
-
- # Is there more?
- if ( $including ) {
- $out2 = '';
- } else {
- $morelinks = '';
- if ( $morelinks != '' ) {
- $out2 = '<table style="background: inherit;" width="100%" cellpadding="0" cellspacing="0" border="0">';
- $out2 .= '<tr valign="top"><td>' . $nsForm;
- $out2 .= '</td><td align="' . $align . '" style="font-size: smaller; margin-bottom: 1em;">';
- $out2 .= $morelinks . '</td></tr></table><hr />';
+ # Is there more?
+ if( $this->including() ) {
+ $out2 = '';
} else {
- $out2 = $nsForm . '<hr />';
+ if( isset($from) || isset($to) ) {
+ global $wgUser;
+ $out2 = '<table style="background: inherit;" width="100%" cellpadding="0" cellspacing="0" border="0">';
+ $out2 .= '<tr valign="top"><td>' . $nsForm;
+ $out2 .= '</td><td align="' . $align . '" style="font-size: smaller; margin-bottom: 1em;">' .
+ $wgUser->getSkin()->makeKnownLinkObj( $this->getTitle(), wfMsgHtml ( 'allpages' ) );
+ $out2 .= "</td></tr></table><hr />";
+ } else {
+ $out2 = $nsForm . '<hr />';
+ }
}
+ $wgOut->addHTML( $out2 . $out );
}
- $wgOut->addHtml( $out2 . $out );
-}
-
-/**
- * @todo Document
- * @param string $from
- * @param integer $namespace (Default NS_MAIN)
- */
-function showline( $inpoint, $outpoint, $namespace = NS_MAIN ) {
- global $wgContLang;
- $align = $wgContLang->isRtl() ? 'left' : 'right';
- $inpointf = htmlspecialchars( str_replace( '_', ' ', $inpoint ) );
- $outpointf = htmlspecialchars( str_replace( '_', ' ', $outpoint ) );
- $queryparams = ($namespace ? "namespace=$namespace" : '');
- $special = SpecialPage::getTitleFor( $this->name, $inpoint );
- $link = $special->escapeLocalUrl( $queryparams );
-
- $out = wfMsgHtml(
- 'alphaindexline',
- "<a href=\"$link\">$inpointf</a></td><td><a href=\"$link\">",
- "</a></td><td><a href=\"$link\">$outpointf</a>"
- );
- return '<tr><td align="' . $align . '">'.$out.'</td></tr>';
-}
+ /**
+ * Show a line of "ABC to DEF" ranges of articles
+ * @param string $inpoint Lower limit of pagenames
+ * @param string $outpout Upper limit of pagenames
+ * @param integer $namespace (Default NS_MAIN)
+ */
+ function showline( $inpoint, $outpoint, $namespace = NS_MAIN ) {
+ global $wgContLang;
+ $align = $wgContLang->isRtl() ? 'left' : 'right';
+ $inpointf = htmlspecialchars( str_replace( '_', ' ', $inpoint ) );
+ $outpointf = htmlspecialchars( 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&" : '';
+ $special = $this->getTitle();
+ $link = $special->escapeLocalUrl( $queryparams . 'from=' . urlencode($inpoint) . '&to=' . urlencode($outpoint) );
+
+ $out = wfMsgHtml( 'alphaindexline',
+ "<a href=\"$link\">$inpointf</a></td><td>",
+ "</td><td><a href=\"$link\">$outpointf</a>"
+ );
+ return '<tr><td align="' . $align . '">'.$out.'</td></tr>';
+ }
-/**
- * @param integer $namespace (Default NS_MAIN)
- * @param string $from list all pages from this name (default FALSE)
- */
-function showChunk( $namespace = NS_MAIN, $from, $including = false ) {
- global $wgOut, $wgUser, $wgContLang;
+ /**
+ * @param integer $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)
+ */
+ function showChunk( $namespace = NS_MAIN, $from = false, $to = false ) {
+ global $wgOut, $wgUser, $wgContLang;
- $sk = $wgUser->getSkin();
+ $sk = $wgUser->getSkin();
- $fromList = $this->getNamespaceKeyAndText($namespace, $from);
- $namespaces = $wgContLang->getNamespaces();
- $align = $wgContLang->isRtl() ? 'left' : 'right';
+ $fromList = $this->getNamespaceKeyAndText($namespace, $from);
+ $toList = $this->getNamespaceKeyAndText( $namespace, $to );
+ $namespaces = $wgContLang->getNamespaces();
+ $align = $wgContLang->isRtl() ? 'left' : 'right';
- $n = 0;
+ $n = 0;
- if ( !$fromList ) {
- $out = wfMsgWikiHtml( 'allpagesbadtitle' );
- } elseif ( !in_array( $namespace, array_keys( $namespaces ) ) ) {
- // Show errormessage and reset to NS_MAIN
- $out = wfMsgExt( 'allpages-bad-ns', array( 'parseinline' ), $namespace );
- $namespace = NS_MAIN;
- } else {
- list( $namespace, $fromKey, $from ) = $fromList;
+ if ( !$fromList || !$toList ) {
+ $out = wfMsgWikiHtml( 'allpagesbadtitle' );
+ } elseif ( !in_array( $namespace, array_keys( $namespaces ) ) ) {
+ // Show errormessage and reset to NS_MAIN
+ $out = wfMsgExt( 'allpages-bad-ns', array( 'parseinline' ), $namespace );
+ $namespace = NS_MAIN;
+ } else {
+ list( $namespace, $fromKey, $from ) = $fromList;
+ list( $namespace2, $toKey, $to ) = $toList;
- $dbr = wfGetDB( DB_SLAVE );
- $res = $dbr->select( 'page',
- array( 'page_namespace', 'page_title', 'page_is_redirect' ),
- array(
+ $dbr = wfGetDB( DB_SLAVE );
+ $conds = array(
'page_namespace' => $namespace,
'page_title >= ' . $dbr->addQuotes( $fromKey )
- ),
- __METHOD__,
- array(
- 'ORDER BY' => 'page_title',
- 'LIMIT' => $this->maxPerPage + 1,
- 'USE INDEX' => 'name_title',
- )
- );
+ );
+ if( $toKey !== "" ) {
+ $conds[] = 'page_title <= ' . $dbr->addQuotes( $toKey );
+ }
- if( $res->numRows() > 0 ) {
- $out = '<table style="background: inherit;" border="0" width="100%">';
-
- while( ($n < $this->maxPerPage) && ($s = $dbr->fetchObject( $res )) ) {
- $t = Title::makeTitle( $s->page_namespace, $s->page_title );
- if( $t ) {
- $link = ($s->page_is_redirect ? '<div class="allpagesredirect">' : '' ) .
- $sk->makeKnownLinkObj( $t, htmlspecialchars( $t->getText() ), false, false ) .
- ($s->page_is_redirect ? '</div>' : '' );
- } else {
- $link = '[[' . htmlspecialchars( $s->page_title ) . ']]';
- }
- if( $n % 3 == 0 ) {
- $out .= '<tr>';
+ $res = $dbr->select( 'page',
+ array( 'page_namespace', 'page_title', 'page_is_redirect' ),
+ $conds,
+ __METHOD__,
+ array(
+ 'ORDER BY' => 'page_title',
+ 'LIMIT' => $this->maxPerPage + 1,
+ 'USE INDEX' => 'name_title',
+ )
+ );
+
+ if( $res->numRows() > 0 ) {
+ $out = '<table style="background: inherit;" border="0" width="100%">';
+
+ while( ( $n < $this->maxPerPage ) && ( $s = $res->fetchObject() ) ) {
+ $t = Title::makeTitle( $s->page_namespace, $s->page_title );
+ if( $t ) {
+ $link = ( $s->page_is_redirect ? '<div class="allpagesredirect">' : '' ) .
+ $sk->makeKnownLinkObj( $t, htmlspecialchars( $t->getText() ), false, false ) .
+ ($s->page_is_redirect ? '</div>' : '' );
+ } else {
+ $link = '[[' . htmlspecialchars( $s->page_title ) . ']]';
+ }
+ if( $n % 3 == 0 ) {
+ $out .= '<tr>';
+ }
+ $out .= "<td width=\"33%\">$link</td>";
+ $n++;
+ if( $n % 3 == 0 ) {
+ $out .= '</tr>';
+ }
}
- $out .= "<td width=\"33%\">$link</td>";
- $n++;
- if( $n % 3 == 0 ) {
+ if( ($n % 3) != 0 ) {
$out .= '</tr>';
}
+ $out .= '</table>';
+ } else {
+ $out = '';
}
- if( ($n % 3) != 0 ) {
- $out .= '</tr>';
- }
- $out .= '</table>';
- } else {
- $out = '';
}
- }
- if ( $including ) {
- $out2 = '';
- } else {
- if( $from == '' ) {
- // First chunk; no previous link.
- $prevTitle = null;
+ if ( $this->including() ) {
+ $out2 = '';
} else {
- # Get the last title from previous chunk
- $dbr = wfGetDB( DB_SLAVE );
- $res_prev = $dbr->select(
- 'page',
- 'page_title',
- array( 'page_namespace' => $namespace, 'page_title < '.$dbr->addQuotes($from) ),
- __METHOD__,
- array( 'ORDER BY' => 'page_title DESC', 'LIMIT' => $this->maxPerPage, 'OFFSET' => ($this->maxPerPage - 1 ) )
- );
-
- # Get first title of previous complete chunk
- if( $dbr->numrows( $res_prev ) >= $this->maxPerPage ) {
- $pt = $dbr->fetchObject( $res_prev );
- $prevTitle = Title::makeTitle( $namespace, $pt->page_title );
+ if( $from == '' ) {
+ // First chunk; no previous link.
+ $prevTitle = null;
} 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() ) {
- $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 ) {
- $prevTitle = Title::makeTitle( $namespace, $reallyFirstPage_title );
+ # Get the last title from previous chunk
+ $dbr = wfGetDB( DB_SLAVE );
+ $res_prev = $dbr->select(
+ 'page',
+ 'page_title',
+ array( 'page_namespace' => $namespace, 'page_title < '.$dbr->addQuotes($from) ),
+ __METHOD__,
+ array( 'ORDER BY' => 'page_title DESC', 'LIMIT' => $this->maxPerPage, 'OFFSET' => ($this->maxPerPage - 1 ) )
+ );
+
+ # Get first title of previous complete chunk
+ if( $dbr->numrows( $res_prev ) >= $this->maxPerPage ) {
+ $pt = $dbr->fetchObject( $res_prev );
+ $prevTitle = Title::makeTitle( $namespace, $pt->page_title );
} else {
- $prevTitle = null;
+ # 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() ) {
+ $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 ) {
+ $prevTitle = Title::makeTitle( $namespace, $reallyFirstPage_title );
+ } else {
+ $prevTitle = null;
+ }
}
}
- }
- $nsForm = $this->namespaceForm( $namespace, $from );
- $out2 = '<table style="background: inherit;" width="100%" cellpadding="0" cellspacing="0" border="0">';
- $out2 .= '<tr valign="top"><td>' . $nsForm;
- $out2 .= '</td><td align="' . $align . '" style="font-size: smaller; margin-bottom: 1em;">' .
- $sk->makeKnownLink( $wgContLang->specialPage( "Allpages" ),
- wfMsgHtml ( 'allpages' ) );
-
- $self = SpecialPage::getTitleFor( 'Allpages' );
-
- # Do we put a previous link ?
- if( isset( $prevTitle ) && $pt = $prevTitle->getText() ) {
- $q = 'from=' . $prevTitle->getPartialUrl()
- . ( $namespace ? '&namespace=' . $namespace : '' );
- $prevLink = $sk->makeKnownLinkObj( $self,
- wfMsgHTML( 'prevpage', htmlspecialchars( $pt ) ), $q );
- $out2 .= ' | ' . $prevLink;
- }
+ $self = $this->getTitle();
- if( $n == $this->maxPerPage && $s = $dbr->fetchObject($res) ) {
- # $s is the first link of the next chunk
- $t = Title::MakeTitle($namespace, $s->page_title);
- $q = 'from=' . $t->getPartialUrl()
- . ( $namespace ? '&namespace=' . $namespace : '' );
- $nextLink = $sk->makeKnownLinkObj( $self,
- wfMsgHtml( 'nextpage', htmlspecialchars( $t->getText() ) ), $q );
- $out2 .= ' | ' . $nextLink;
- }
- $out2 .= "</td></tr></table><hr />";
- }
+ $nsForm = $this->namespaceForm( $namespace, $from, $to );
+ $out2 = '<table style="background: inherit;" width="100%" cellpadding="0" cellspacing="0" border="0">';
+ $out2 .= '<tr valign="top"><td>' . $nsForm;
+ $out2 .= '</td><td align="' . $align . '" style="font-size: smaller; margin-bottom: 1em;">' .
+ $sk->makeKnownLinkObj( $self,
+ wfMsgHtml ( 'allpages' ) );
+
+ # Do we put a previous link ?
+ if( isset( $prevTitle ) && $pt = $prevTitle->getText() ) {
+ $q = 'from=' . $prevTitle->getPartialUrl()
+ . ( $namespace ? '&namespace=' . $namespace : '' );
+ $prevLink = $sk->makeKnownLinkObj( $self,
+ wfMsgHTML( 'prevpage', htmlspecialchars( $pt ) ), $q );
+ $out2 .= ' | ' . $prevLink;
+ }
- $wgOut->addHtml( $out2 . $out );
- if( isset($prevLink) or isset($nextLink) ) {
- $wgOut->addHtml( '<hr /><p style="font-size: smaller; float: ' . $align . '">' );
- if( isset( $prevLink ) ) {
- $wgOut->addHTML( $prevLink );
- }
- if( isset( $prevLink ) && isset( $nextLink ) ) {
- $wgOut->addHTML( ' | ' );
- }
- if( isset( $nextLink ) ) {
- $wgOut->addHTML( $nextLink );
+ if( $n == $this->maxPerPage && $s = $res->fetchObject() ) {
+ # $s is the first link of the next chunk
+ $t = Title::MakeTitle($namespace, $s->page_title);
+ $q = 'from=' . $t->getPartialUrl()
+ . ( $namespace ? '&namespace=' . $namespace : '' );
+ $nextLink = $sk->makeKnownLinkObj( $self,
+ wfMsgHtml( 'nextpage', htmlspecialchars( $t->getText() ) ), $q );
+ $out2 .= ' | ' . $nextLink;
+ }
+ $out2 .= "</td></tr></table><hr />";
}
- $wgOut->addHTML( '</p>' );
- }
+ $wgOut->addHTML( $out2 . $out );
+ if( isset($prevLink) or isset($nextLink) ) {
+ $wgOut->addHTML( '<hr /><p style="font-size: smaller; float: ' . $align . '">' );
+ if( isset( $prevLink ) ) {
+ $wgOut->addHTML( $prevLink );
+ }
+ if( isset( $prevLink ) && isset( $nextLink ) ) {
+ $wgOut->addHTML( ' | ' );
+ }
+ if( isset( $nextLink ) ) {
+ $wgOut->addHTML( $nextLink );
+ }
+ $wgOut->addHTML( '</p>' );
-}
+ }
-/**
- * @param int $ns the namespace of the article
- * @param string $text the name of the article
- * @return array( int namespace, string dbkey, string pagename ) or NULL on error
- * @static (sort of)
- * @access private
- */
-function getNamespaceKeyAndText ($ns, $text) {
- if ( $text == '' )
- return array( $ns, '', '' ); # shortcut for common case
-
- $t = Title::makeTitleSafe($ns, $text);
- if ( $t && $t->isLocal() ) {
- return array( $t->getNamespace(), $t->getDBkey(), $t->getText() );
- } else if ( $t ) {
- return NULL;
}
- # try again, in case the problem was an empty pagename
- $text = preg_replace('/(#|$)/', 'X$1', $text);
- $t = Title::makeTitleSafe($ns, $text);
- if ( $t && $t->isLocal() ) {
- return array( $t->getNamespace(), '', '' );
- } else {
- return NULL;
+ /**
+ * @param int $ns the namespace of the article
+ * @param string $text the name of the article
+ * @return array( int namespace, string dbkey, string pagename ) or NULL on error
+ * @static (sort of)
+ * @access private
+ */
+ function getNamespaceKeyAndText($ns, $text) {
+ if ( $text == '' )
+ return array( $ns, '', '' ); # shortcut for common case
+
+ $t = Title::makeTitleSafe($ns, $text);
+ if ( $t && $t->isLocal() ) {
+ return array( $t->getNamespace(), $t->getDBkey(), $t->getText() );
+ } else if ( $t ) {
+ return NULL;
+ }
+
+ # try again, in case the problem was an empty pagename
+ $text = preg_replace('/(#|$)/', 'X$1', $text);
+ $t = Title::makeTitleSafe($ns, $text);
+ if ( $t && $t->isLocal() ) {
+ return array( $t->getNamespace(), '', '' );
+ } else {
+ return NULL;
+ }
}
}
-}
diff --git a/includes/specials/SpecialBlockip.php b/includes/specials/SpecialBlockip.php
index 52829d92..4d82997f 100644
--- a/includes/specials/SpecialBlockip.php
+++ b/includes/specials/SpecialBlockip.php
@@ -47,7 +47,7 @@ class IPBlockForm {
# var $BlockEmail;
function IPBlockForm( $par ) {
- global $wgRequest, $wgUser;
+ global $wgRequest, $wgUser, $wgBlockAllowsUTEdit;
$this->BlockAddress = $wgRequest->getVal( 'wpBlockAddress', $wgRequest->getVal( 'ip', $par ) );
$this->BlockAddress = strtr( $this->BlockAddress, '_', ' ' );
@@ -66,6 +66,8 @@ class IPBlockForm {
$this->BlockWatchUser = $wgRequest->getBool( 'wpWatchUser', false );
# Re-check user's rights to hide names, very serious, defaults to 0
$this->BlockHideName = ( $wgRequest->getBool( 'wpHideName', 0 ) && $wgUser->isAllowed( 'hideuser' ) ) ? 1 : 0;
+ $this->BlockAllowUsertalk = ( $wgRequest->getBool( 'wpAllowUsertalk', $byDefault ) && $wgBlockAllowsUTEdit );
+ $this->BlockReblock = $wgRequest->getBool( 'wpChangeBlock', false );
}
function showForm( $err ) {
@@ -85,10 +87,26 @@ class IPBlockForm {
$mIpbreason = Xml::label( wfMsg( 'ipbotherreason' ), 'mw-bi-reason' );
$titleObj = SpecialPage::getTitleFor( 'Blockip' );
-
- if ( "" != $err ) {
+ $user = User::newFromName( $this->BlockAddress );
+
+ $alreadyBlocked = false;
+ if ( $err && $err[0] != 'ipb_already_blocked' ) {
+ $key = array_shift($err);
+ $msg = wfMsgReal($key, $err);
$wgOut->setSubtitle( wfMsgHtml( 'formerror' ) );
- $wgOut->addHTML( Xml::tags( 'p', array( 'class' => 'error' ), $err ) );
+ $wgOut->addHTML( Xml::tags( 'p', array( 'class' => 'error' ), $msg ) );
+ } elseif ( $this->BlockAddress ) {
+ $userId = 0;
+ if ( is_object( $user ) )
+ $userId = $user->getId();
+ $currentBlock = Block::newFromDB( $this->BlockAddress, $userId );
+ if ( !is_null($currentBlock) && !$currentBlock->mAuto && # The block exists and isn't an autoblock
+ ( $currentBlock->mRangeStart == $currentBlock->mRangeEnd || # The block isn't a rangeblock
+ # or if it is, the range is what we're about to block
+ ( $currentBlock->mAddress == $this->BlockAddress ) ) ) {
+ $wgOut->addWikiMsg( 'ipb-needreblock', $this->BlockAddress );
+ $alreadyBlocked = true;
+ }
}
$scBlockExpiryOptions = wfMsgForContent( 'ipboptions' );
@@ -108,7 +126,7 @@ class IPBlockForm {
$reasonDropDown = Xml::listDropDown( 'wpBlockReasonList',
wfMsgForContent( 'ipbreason-dropdown' ),
- wfMsgForContent( 'ipbreasonotherlist' ), '', 'wpBlockDropDown', 4 );
+ wfMsgForContent( 'ipbreasonotherlist' ), $this->BlockReasonList, 'wpBlockDropDown', 4 );
global $wgStylePath, $wgStyleVersion;
$wgOut->addHTML(
@@ -201,7 +219,7 @@ class IPBlockForm {
</tr>"
);
- global $wgSysopEmailBans;
+ global $wgSysopEmailBans, $wgBlockAllowsUTEdit;
if ( $wgSysopEmailBans && $wgUser->isAllowed( 'blockemail' ) ) {
$wgOut->addHTML("
<tr id='wpEnableEmailBan'>
@@ -240,25 +258,37 @@ class IPBlockForm {
</td>
</tr>"
);
+ if( $wgBlockAllowsUTEdit ){
+ $wgOut->addHTML("
+ <tr id='wpAllowUsertalkRow'>
+ <td>&nbsp;</td>
+ <td class='mw-input'>" .
+ Xml::checkLabel( wfMsg( 'ipballowusertalk' ),
+ 'wpAllowUsertalk', 'wpAllowUsertalk', $this->BlockAllowUsertalk,
+ array( 'tabindex' => '12' ) ) . "
+ </td>
+ </tr>"
+ );
+ }
$wgOut->addHTML("
<tr>
<td style='padding-top: 1em'>&nbsp;</td>
<td class='mw-submit' style='padding-top: 1em'>" .
- Xml::submitButton( wfMsg( 'ipbsubmit' ),
- array( 'name' => 'wpBlock', 'tabindex' => '12' ) ) . "
+ Xml::submitButton( wfMsg( $alreadyBlocked ? 'ipb-change-block' : 'ipbsubmit' ),
+ array( 'name' => 'wpBlock', 'tabindex' => '13', 'accesskey' => 's' ) ) . "
</td>
</tr>" .
Xml::closeElement( 'table' ) .
Xml::hidden( 'wpEditToken', $wgUser->editToken() ) .
+ ( $alreadyBlocked ? Xml::hidden( 'wpChangeBlock', 1 ) : "" ) .
Xml::closeElement( 'fieldset' ) .
Xml::closeElement( 'form' ) .
Xml::tags( 'script', array( 'type' => 'text/javascript' ), 'updateBlockOptions()' ) . "\n"
);
- $wgOut->addHtml( $this->getConvenienceLinks() );
+ $wgOut->addHTML( $this->getConvenienceLinks() );
- $user = User::newFromName( $this->BlockAddress );
if( is_object( $user ) ) {
$this->showLogFragment( $wgOut, $user->getUserPage() );
} elseif( preg_match( '/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/', $this->BlockAddress ) ) {
@@ -273,9 +303,8 @@ class IPBlockForm {
* $userID and $expiry will be filled accordingly
* @return array(message key, arguments) on failure, empty array on success
*/
- function doBlock(&$userId = null, &$expiry = null)
- {
- global $wgUser, $wgSysopUserBans, $wgSysopRangeBans;
+ function doBlock( &$userId = null, &$expiry = null ) {
+ global $wgUser, $wgSysopUserBans, $wgSysopRangeBans, $wgBlockAllowsUTEdit;
$userId = 0;
# Expand valid IPv6 addresses, usernames are left as is
@@ -327,8 +356,12 @@ class IPBlockForm {
}
}
+ if ( $wgUser->isBlocked() && ( $wgUser->getId() !== $userId ) ) {
+ return array( 'cant-block-while-blocked' );
+ }
+
$reasonstr = $this->BlockReasonList;
- if ( $reasonstr != 'other' && $this->BlockReason != '') {
+ if ( $reasonstr != 'other' && $this->BlockReason != '' ) {
// Entry from drop down menu + additional comment
$reasonstr .= ': ' . $this->BlockReason;
} elseif ( $reasonstr == 'other' ) {
@@ -339,7 +372,7 @@ class IPBlockForm {
if( $expirestr == 'other' )
$expirestr = $this->BlockOther;
- if ((strlen($expirestr) == 0) || (strlen($expirestr) > 50)) {
+ if ( ( strlen( $expirestr ) == 0) || ( strlen( $expirestr ) > 50) ) {
return array('ipb_expiry_invalid');
}
@@ -358,14 +391,27 @@ class IPBlockForm {
$block = new Block( $this->BlockAddress, $userId, $wgUser->getId(),
$reasonstr, wfTimestampNow(), 0, $expiry, $this->BlockAnonOnly,
$this->BlockCreateAccount, $this->BlockEnableAutoblock, $this->BlockHideName,
- $this->BlockEmail );
+ $this->BlockEmail, isset( $this->BlockAllowUsertalk ) ? $this->BlockAllowUsertalk : $wgBlockAllowsUTEdit );
if ( wfRunHooks('BlockIp', array(&$block, &$wgUser)) ) {
if ( !$block->insert() ) {
- return array('ipb_already_blocked', htmlspecialchars($this->BlockAddress));
+ if ( !$this->BlockReblock ) {
+ return array( 'ipb_already_blocked' );
+ } else {
+ # This returns direct blocks before autoblocks/rangeblocks, since we should
+ # be sure the user is blocked by now it should work for our purposes
+ $currentBlock = Block::newFromDB( $this->BlockAddress, $userId );
+ if( $block->equals( $currentBlock ) ) {
+ return array( 'ipb_already_blocked' );
+ }
+ $currentBlock->delete();
+ $block->insert();
+ $log_action = 'reblock';
+ }
+ } else {
+ $log_action = 'block';
}
-
wfRunHooks('BlockIpComplete', array($block, $wgUser));
if ( $this->BlockWatchUser ) {
@@ -380,7 +426,7 @@ class IPBlockForm {
# Make log entry, if the name is hidden, put it in the oversight log
$log_type = ($this->BlockHideName) ? 'suppress' : 'block';
$log = new LogPage( $log_type );
- $log->addEntry( 'block', Title::makeTitle( NS_USER, $this->BlockAddress ),
+ $log->addEntry( $log_action, Title::makeTitle( NS_USER, $this->BlockAddress ),
$reasonstr, $logParams );
# Report to the user
@@ -404,8 +450,7 @@ class IPBlockForm {
urlencode( $this->BlockAddress ) ) );
return;
}
- $key = array_shift($retval);
- $this->showForm(wfMsgReal($key, $retval));
+ $this->showForm( $retval );
}
function showSuccess() {
@@ -414,12 +459,22 @@ class IPBlockForm {
$wgOut->setPagetitle( wfMsg( 'blockip' ) );
$wgOut->setSubtitle( wfMsg( 'blockipsuccesssub' ) );
$text = wfMsgExt( 'blockipsuccesstext', array( 'parse' ), $this->BlockAddress );
- $wgOut->addHtml( $text );
+ $wgOut->addHTML( $text );
}
function showLogFragment( $out, $title ) {
- $out->addHtml( Xml::element( 'h2', NULL, LogPage::logName( 'block' ) ) );
- LogEventsList::showLogExtract( $out, 'block', $title->getPrefixedText() );
+ global $wgUser;
+ $out->addHTML( Xml::element( 'h2', NULL, LogPage::logName( 'block' ) ) );
+ $count = LogEventsList::showLogExtract( $out, 'block', $title->getPrefixedText(), '', 10 );
+ if($count > 10){
+ $out->addHTML( $wgUser->getSkin()->link(
+ SpecialPage::getTitleFor( 'Log' ),
+ wfMsgHtml( 'blocklog-fulllog' ),
+ array(),
+ array(
+ 'type' => 'block',
+ 'page' => $title->getPrefixedText() ) ) );
+ }
}
/**
@@ -429,6 +484,7 @@ class IPBlockForm {
* @return array
*/
private function blockLogFlags() {
+ global $wgBlockAllowsUTEdit;
$flags = array();
if( $this->BlockAnonOnly && IP::isIPAddress( $this->BlockAddress ) )
// when blocking a user the option 'anononly' is not available/has no effect -> do not write this into log
@@ -439,6 +495,8 @@ class IPBlockForm {
$flags[] = 'noautoblock';
if ( $this->BlockEmail )
$flags[] = 'noemail';
+ if ( !$this->BlockAllowUsertalk && $wgBlockAllowsUTEdit )
+ $flags[] = 'nousertalk';
return implode( ',', $flags );
}
@@ -450,11 +508,25 @@ class IPBlockForm {
private function getConvenienceLinks() {
global $wgUser;
$skin = $wgUser->getSkin();
- $links[] = $skin->makeLink ( 'MediaWiki:Ipbreason-dropdown', wfMsgHtml( 'ipb-edit-dropdown' ) );
+ if( $this->BlockAddress )
+ $links[] = $this->getContribsLink( $skin );
$links[] = $this->getUnblockLink( $skin );
$links[] = $this->getBlockListLink( $skin );
+ $links[] = $skin->makeLink ( 'MediaWiki:Ipbreason-dropdown', wfMsgHtml( 'ipb-edit-dropdown' ) );
return '<p class="mw-ipb-conveniencelinks">' . implode( ' | ', $links ) . '</p>';
}
+
+ /**
+ * Build a convenient link to a user or IP's contribs
+ * form
+ *
+ * @param $skin Skin to use
+ * @return string
+ */
+ private function getContribsLink( $skin ) {
+ $contribsPage = SpecialPage::getTitleFor( 'Contributions', $this->BlockAddress );
+ return $skin->link( $contribsPage, wfMsgHtml( 'ipb-blocklist-contribs', $this->BlockAddress ) );
+ }
/**
* Build a convenient link to unblock the given username or IP
@@ -491,4 +563,77 @@ class IPBlockForm {
return $skin->makeKnownLinkObj( $list, wfMsgHtml( 'ipb-blocklist' ) );
}
}
+
+ /**
+ * Block a list of selected users
+ * @param array $users
+ * @param string $reason
+ * @param string $tag replaces user pages
+ * @param string $talkTag replaces user talk pages
+ * @returns array, list of html-safe usernames
+ */
+ public static function doMassUserBlock( $users, $reason = '', $tag = '', $talkTag = '' ) {
+ global $wgUser;
+ $counter = $blockSize = 0;
+ $safeUsers = array();
+ $log = new LogPage( 'block' );
+ foreach( $users as $name ) {
+ # Enforce limits
+ $counter++;
+ $blockSize++;
+ # Lets not go *too* fast
+ if( $blockSize >= 20 ) {
+ $blockSize = 0;
+ wfWaitForSlaves( 5 );
+ }
+ $u = User::newFromName( $name, false );
+ // If user doesn't exist, it ought to be an IP then
+ if( is_null($u) || (!$u->getId() && !IP::isIPAddress( $u->getName() )) ) {
+ continue;
+ }
+ $userTitle = $u->getUserPage();
+ $userTalkTitle = $u->getTalkPage();
+ $userpage = new Article( $userTitle );
+ $usertalk = new Article( $userTalkTitle );
+ $safeUsers[] = '[[' . $userTitle->getPrefixedText() . '|' . $userTitle->getText() . ']]';
+ $expirestr = $u->getId() ? 'indefinite' : '1 week';
+ $expiry = Block::parseExpiryInput( $expirestr );
+ $anonOnly = IP::isIPAddress( $u->getName() ) ? 1 : 0;
+ // Create the block
+ $block = new Block( $u->getName(), // victim
+ $u->getId(), // uid
+ $wgUser->getId(), // blocker
+ $reason, // comment
+ wfTimestampNow(), // block time
+ 0, // auto ?
+ $expiry, // duration
+ $anonOnly, // anononly?
+ 1, // block account creation?
+ 1, // autoblocking?
+ 0, // suppress name?
+ 0 // block from sending email?
+ );
+ $oldblock = Block::newFromDB( $u->getName(), $u->getId() );
+ if( !$oldblock ) {
+ $block->insert();
+ # Prepare log parameters
+ $logParams = array();
+ $logParams[] = $expirestr;
+ if( $anonOnly ) {
+ $logParams[] = 'anononly';
+ }
+ $logParams[] = 'nocreate';
+ # Add log entry
+ $log->addEntry( 'block', $userTitle, $reason, $logParams );
+ }
+ # Tag userpage! (check length to avoid mistakes)
+ if( strlen($tag) > 2 ) {
+ $userpage->doEdit( $tag, $reason, EDIT_MINOR );
+ }
+ if( strlen($talkTag) > 2 ) {
+ $usertalk->doEdit( $talkTag, $reason, EDIT_MINOR );
+ }
+ }
+ return $safeUsers;
+ }
}
diff --git a/includes/specials/SpecialBooksources.php b/includes/specials/SpecialBooksources.php
index 0690c5c0..12b119d8 100644
--- a/includes/specials/SpecialBooksources.php
+++ b/includes/specials/SpecialBooksources.php
@@ -30,20 +30,62 @@ class SpecialBookSources extends SpecialPage {
public function execute( $isbn ) {
global $wgOut, $wgRequest;
$this->setHeaders();
- $this->isbn = $this->cleanIsbn( $isbn ? $isbn : $wgRequest->getText( 'isbn' ) );
+ $this->isbn = self::cleanIsbn( $isbn ? $isbn : $wgRequest->getText( 'isbn' ) );
$wgOut->addWikiMsg( 'booksources-summary' );
- $wgOut->addHtml( $this->makeForm() );
- if( strlen( $this->isbn ) > 0 )
+ $wgOut->addHTML( $this->makeForm() );
+ if( strlen( $this->isbn ) > 0 ) {
+ if( !$this->isValidIsbn( $this->isbn ) ) {
+ $wgOut->wrapWikiMsg( '<div class="error">$1</div>', 'booksources-invalid-isbn' );
+ }
$this->showList();
+ }
}
/**
+ * Returns whether a given ISBN (10 or 13) is valid. True indicates validity.
+ * @param isbn ISBN passed for check
+ */
+ public static function isValidISBN( $isbn ) {
+ $isbn = self::cleanIsbn( $isbn );
+ $sum = 0;
+ $check = -1;
+ 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;
+ if ($check == $isbn{12}) {
+ return true;
+ }
+ } elseif( strlen( $isbn ) == 10 ) {
+ for($i = 0; $i < 9; $i++) {
+ $sum += $isbn{$i} * ($i + 1);
+ }
+
+ $check = $sum % 11;
+ if($check == 10) {
+ $check = "X";
+ }
+ if($check == $isbn{9}) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+
+ /**
* Trim ISBN and remove characters which aren't required
*
* @param $isbn Unclean ISBN
* @return string
*/
- private function cleanIsbn( $isbn ) {
+ private static function cleanIsbn( $isbn ) {
return trim( preg_replace( '![^0-9X]!', '', $isbn ) );
}
@@ -88,11 +130,11 @@ class SpecialBookSources extends SpecialPage {
# Fall back to the defaults given in the language file
$wgOut->addWikiMsg( 'booksources-text' );
- $wgOut->addHtml( '<ul>' );
+ $wgOut->addHTML( '<ul>' );
$items = $wgContLang->getBookstoreList();
foreach( $items as $label => $url )
- $wgOut->addHtml( $this->makeListItem( $label, $url ) );
- $wgOut->addHtml( '</ul>' );
+ $wgOut->addHTML( $this->makeListItem( $label, $url ) );
+ $wgOut->addHTML( '</ul>' );
return true;
}
diff --git a/includes/specials/SpecialCategories.php b/includes/specials/SpecialCategories.php
index 951c2228..8c2ae2b6 100644
--- a/includes/specials/SpecialCategories.php
+++ b/includes/specials/SpecialCategories.php
@@ -14,11 +14,13 @@ function wfSpecialCategories( $par=null ) {
}
$cap = new CategoryPager( $from );
$wgOut->addHTML(
+ XML::openElement( 'div', array('class' => 'mw-spcontent') ) .
wfMsgExt( 'categoriespagetext', array( 'parse' ) ) .
$cap->getStartForm( $from ) .
$cap->getNavigationBar() .
'<ul>' . $cap->getBody() . '</ul>' .
- $cap->getNavigationBar()
+ $cap->getNavigationBar() .
+ XML::closeElement( 'div' )
);
}
diff --git a/includes/specials/SpecialConfirmemail.php b/includes/specials/SpecialConfirmemail.php
index 9075fb95..e19aa99b 100644
--- a/includes/specials/SpecialConfirmemail.php
+++ b/includes/specials/SpecialConfirmemail.php
@@ -36,8 +36,9 @@ class EmailConfirmation extends UnlistedSpecialPage {
$title = SpecialPage::getTitleFor( 'Userlogin' );
$self = SpecialPage::getTitleFor( 'Confirmemail' );
$skin = $wgUser->getSkin();
- $llink = $skin->makeKnownLinkObj( $title, wfMsgHtml( 'loginreqlink' ), 'returnto=' . $self->getPrefixedUrl() );
- $wgOut->addHtml( wfMsgWikiHtml( 'confirmemail_needlogin', $llink ) );
+ $llink = $skin->makeKnownLinkObj( $title, wfMsgHtml( 'loginreqlink' ),
+ 'returnto=' . $self->getPrefixedUrl() );
+ $wgOut->addHTML( wfMsgWikiHtml( 'confirmemail_needlogin', $llink ) );
}
} else {
$this->attemptConfirm( $code );
@@ -58,19 +59,24 @@ class EmailConfirmation extends UnlistedSpecialPage {
}
} else {
if( $wgUser->isEmailConfirmed() ) {
+ // date and time are separate parameters to facilitate localisation.
+ // $time is kept for backward compat reasons.
+ // 'emailauthenticated' is also used in SpecialPreferences.php
$time = $wgLang->timeAndDate( $wgUser->mEmailAuthenticated, true );
- $wgOut->addWikiMsg( 'emailauthenticated', $time );
+ $d = $wgLang->date( $wgUser->mEmailAuthenticated, true );
+ $t = $wgLang->time( $wgUser->mEmailAuthenticated, true );
+ $wgOut->addWikiMsg( 'emailauthenticated', $time, $d, $t );
}
if( $wgUser->isEmailConfirmationPending() ) {
$wgOut->addWikiMsg( 'confirmemail_pending' );
}
$wgOut->addWikiMsg( 'confirmemail_text' );
$self = SpecialPage::getTitleFor( 'Confirmemail' );
- $form = wfOpenElement( 'form', array( 'method' => 'post', 'action' => $self->getLocalUrl() ) );
- $form .= wfHidden( 'token', $wgUser->editToken() );
- $form .= wfSubmitButton( wfMsgHtml( 'confirmemail_send' ) );
- $form .= wfCloseElement( 'form' );
- $wgOut->addHtml( $form );
+ $form = Xml::openElement( 'form', array( 'method' => 'post', 'action' => $self->getLocalUrl() ) );
+ $form .= Xml::hidden( 'token', $wgUser->editToken() );
+ $form .= Xml::submitButton( wfMsgHtml( 'confirmemail_send' ) );
+ $form .= Xml::closeElement( 'form' );
+ $wgOut->addHTML( $form );
}
}
diff --git a/includes/specials/SpecialContributions.php b/includes/specials/SpecialContributions.php
index 4a131f15..3d8c18dd 100644
--- a/includes/specials/SpecialContributions.php
+++ b/includes/specials/SpecialContributions.php
@@ -4,6 +4,363 @@
* @file
* @ingroup SpecialPage
*/
+
+class SpecialContributions extends SpecialPage {
+
+ public function __construct() {
+ parent::__construct( 'Contributions' );
+ }
+
+ public function execute( $par ) {
+ global $wgUser, $wgOut, $wgLang, $wgRequest;
+
+ $this->setHeaders();
+ $this->outputHeader();
+
+ $this->opts = array();
+
+ if( $par == 'newbies' ) {
+ $target = 'newbies';
+ $this->opts['contribs'] = 'newbie';
+ } elseif( isset( $par ) ) {
+ $target = $par;
+ } else {
+ $target = $wgRequest->getVal( 'target' );
+ }
+
+ // check for radiobox
+ if( $wgRequest->getVal( 'contribs' ) == 'newbie' ) {
+ $target = 'newbies';
+ $this->opts['contribs'] = 'newbie';
+ }
+
+ if( !strlen( $target ) ) {
+ $wgOut->addHTML( $this->getForm( '' ) );
+ return;
+ }
+
+ $this->opts['limit'] = $wgRequest->getInt( 'limit', 50 );
+ $this->opts['target'] = $target;
+
+ $nt = Title::makeTitleSafe( NS_USER, $target );
+ if( !$nt ) {
+ $wgOut->addHTML( $this->getForm( '' ) );
+ return;
+ }
+ $id = User::idFromName( $nt->getText() );
+
+ if( $target != 'newbies' ) {
+ $target = $nt->getText();
+ $wgOut->setSubtitle( $this->contributionsSub( $nt, $id ) );
+ $wgOut->setHTMLTitle( wfMsg( 'pagetitle', wfMsg( 'contributions-title', $target ) ) );
+ } else {
+ $wgOut->setSubtitle( wfMsgHtml( 'sp-contributions-newbies-sub') );
+ $wgOut->setHTMLTitle( wfMsg( 'pagetitle', wfMsg( 'sp-contributions-newbies-title' ) ) );
+ }
+
+ if( ( $ns = $wgRequest->getVal( 'namespace', null ) ) !== null && $ns !== '' ) {
+ $this->opts['namespace'] = intval( $ns );
+ } else {
+ $this->opts['namespace'] = '';
+ }
+
+ // 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
+ if( $wgUser->isAllowed( 'markbotedits' ) && $wgRequest->getBool( 'bot' ) ) {
+ $this->opts['bot'] = '1';
+ }
+
+ $skip = $wgRequest->getText( 'offset' ) || $wgRequest->getText( 'dir' ) == 'prev';
+ # Offset overrides year/month selection
+ if( ( $month = $wgRequest->getIntOrNull( 'month' ) ) !== null && $month !== -1 ) {
+ $this->opts['month'] = intval( $month );
+ } else {
+ $this->opts['month'] = '';
+ }
+ if( ( $year = $wgRequest->getIntOrNull( 'year' ) ) !== null ) {
+ $this->opts['year'] = intval( $year );
+ } else if( $this->opts['month'] ) {
+ $thisMonth = intval( gmdate( 'n' ) );
+ $thisYear = intval( gmdate( 'Y' ) );
+ if( intval( $this->opts['month'] ) > $thisMonth ) {
+ $thisYear--;
+ }
+ $this->opts['year'] = $thisYear;
+ } else {
+ $this->opts['year'] = '';
+ }
+
+ if( $skip ) {
+ $this->opts['year'] = '';
+ $this->opts['month'] = '';
+ }
+
+ // Add RSS/atom links
+ $this->setSyndicated();
+ $feedType = $wgRequest->getVal( 'feed' );
+ if( $feedType ) {
+ return $this->feed( $feedType );
+ }
+
+ wfRunHooks( 'SpecialContributionsBeforeMainOutput', $id );
+
+ $wgOut->addHTML( $this->getForm( $this->opts ) );
+
+ $pager = new ContribsPager( $target, $this->opts['namespace'], $this->opts['year'], $this->opts['month'] );
+ if( !$pager->getNumRows() ) {
+ $wgOut->addWikiMsg( 'nocontribs' );
+ return;
+ }
+
+ # Show a message about slave lag, if applicable
+ if( ( $lag = $pager->getDatabase()->getLag() ) > 0 )
+ $wgOut->showLagWarning( $lag );
+
+ $wgOut->addHTML(
+ '<p>' . $pager->getNavigationBar() . '</p>' .
+ $pager->getBody() .
+ '<p>' . $pager->getNavigationBar() . '</p>'
+ );
+
+ # 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';
+
+ $text = wfMsgNoTrans( $message, $target );
+ if( !wfEmptyMsg( $message, $text ) && $text != '-' ) {
+ $wgOut->addHTML( '<div class="mw-contributions-footer">' );
+ $wgOut->addWikiText( $text );
+ $wgOut->addHTML( '</div>' );
+ }
+ }
+ }
+
+ protected function setSyndicated() {
+ global $wgOut;
+ $queryParams = array(
+ 'namespace' => $this->opts['namespace'],
+ 'target' => $this->opts['target']
+ );
+ $wgOut->setSyndicated( true );
+ $wgOut->setFeedAppendQuery( wfArrayToCGI( $queryParams ) );
+ }
+
+ /**
+ * Generates the subheading with links
+ * @param Title $nt Title object for the target
+ * @param integer $id User ID for the target
+ * @return String: appropriately-escaped HTML to be output literally
+ */
+ protected function contributionsSub( $nt, $id ) {
+ global $wgSysopUserBans, $wgLang, $wgUser;
+
+ $sk = $wgUser->getSkin();
+
+ if( 0 == $id ) {
+ $user = $nt->getText();
+ } else {
+ $user = $sk->makeLinkObj( $nt, htmlspecialchars( $nt->getText() ) );
+ }
+ $talk = $nt->getTalkPage();
+ if( $talk ) {
+ # Talk page link
+ $tools[] = $sk->makeLinkObj( $talk, wfMsgHtml( 'talkpagelinktext' ) );
+ if( ( $id != 0 && $wgSysopUserBans ) || ( $id == 0 && IP::isIPAddress( $nt->getText() ) ) ) {
+ # Block link
+ if( $wgUser->isAllowed( 'block' ) )
+ $tools[] = $sk->makeKnownLinkObj( SpecialPage::getTitleFor( 'Blockip',
+ $nt->getDBkey() ), wfMsgHtml( 'blocklink' ) );
+ # Block log link
+ $tools[] = $sk->makeKnownLinkObj( SpecialPage::getTitleFor( 'Log' ),
+ wfMsgHtml( 'sp-contributions-blocklog' ), 'type=block&page=' . $nt->getPrefixedUrl() );
+ }
+ # Other logs link
+ $tools[] = $sk->makeKnownLinkObj( SpecialPage::getTitleFor( 'Log' ), wfMsgHtml( 'log' ),
+ 'user=' . $nt->getPartialUrl() );
+
+ # Add link to deleted user contributions for priviledged users
+ if( $wgUser->isAllowed( 'deletedhistory' ) ) {
+ $tools[] = $sk->makeKnownLinkObj( SpecialPage::getTitleFor( 'DeletedContributions',
+ $nt->getDBkey() ), wfMsgHtml( 'deletedcontributions' ) );
+ }
+
+ wfRunHooks( 'ContributionsToolLinks', array( $id, $nt, &$tools ) );
+
+ $links = implode( ' | ', $tools );
+ }
+
+ // 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'.
+ if( wfEmptyMsg( 'contribsub', wfMsg( 'contribsub' ) ) ) {
+ return wfMsgHtml( 'contribsub2', $user, $links );
+ } else {
+ return wfMsgHtml( 'contribsub', "$user ($links)" );
+ }
+ }
+
+ /**
+ * Generates the namespace selector form with hidden attributes.
+ * @param $this->opts Array: the options to be included.
+ */
+ protected function getForm() {
+ global $wgScript, $wgTitle;
+
+ $this->opts['title'] = $wgTitle->getPrefixedText();
+ if( !isset( $this->opts['target'] ) ) {
+ $this->opts['target'] = '';
+ } else {
+ $this->opts['target'] = str_replace( '_' , ' ' , $this->opts['target'] );
+ }
+
+ if( !isset( $this->opts['namespace'] ) ) {
+ $this->opts['namespace'] = '';
+ }
+
+ if( !isset( $this->opts['contribs'] ) ) {
+ $this->opts['contribs'] = 'user';
+ }
+
+ if( !isset( $this->opts['year'] ) ) {
+ $this->opts['year'] = '';
+ }
+
+ if( !isset( $this->opts['month'] ) ) {
+ $this->opts['month'] = '';
+ }
+
+ if( $this->opts['contribs'] == 'newbie' ) {
+ $this->opts['target'] = '';
+ }
+
+ $f = Xml::openElement( 'form', array( 'method' => 'get', 'action' => $wgScript ) );
+
+ foreach ( $this->opts as $name => $value ) {
+ if( in_array( $name, array( 'namespace', 'target', 'contribs', 'year', 'month' ) ) ) {
+ continue;
+ }
+ $f .= "\t" . Xml::hidden( $name, $value ) . "\n";
+ }
+
+ $f .= '<fieldset>' .
+ Xml::element( 'legend', array(), wfMsg( 'sp-contributions-search' ) ) .
+ Xml::radioLabel( wfMsgExt( 'sp-contributions-newbies', array( 'parseinline' ) ),
+ 'contribs', 'newbie' , 'newbie', $this->opts['contribs'] == 'newbie' ? true : false ) . '<br />' .
+ Xml::radioLabel( wfMsgExt( 'sp-contributions-username', array( 'parseinline' ) ),
+ 'contribs' , 'user', 'user', $this->opts['contribs'] == 'user' ? true : false ) . ' ' .
+ Xml::input( 'target', 20, $this->opts['target']) . ' '.
+ '<span style="white-space: nowrap">' .
+ Xml::label( wfMsg( 'namespace' ), 'namespace' ) . ' ' .
+ Xml::namespaceSelector( $this->opts['namespace'], '' ) .
+ '</span>' .
+ Xml::openElement( 'p' ) .
+ '<span style="white-space: nowrap">' .
+ Xml::label( wfMsg( 'year' ), 'year' ) . ' '.
+ Xml::input( 'year', 4, $this->opts['year'], array('id' => 'year', 'maxlength' => 4) ) .
+ '</span>' .
+ ' '.
+ '<span style="white-space: nowrap">' .
+ Xml::label( wfMsg( 'month' ), 'month' ) . ' '.
+ Xml::monthSelector( $this->opts['month'], -1 ) . ' '.
+ '</span>' .
+ Xml::submitButton( wfMsg( 'sp-contributions-submit' ) ) .
+ Xml::closeElement( 'p' );
+
+ $explain = wfMsgExt( 'sp-contributions-explain', 'parseinline' );
+ if( !wfEmptyMsg( 'sp-contributions-explain', $explain ) )
+ $f .= "<p>{$explain}</p>";
+
+ $f .= '</fieldset>' .
+ Xml::closeElement( 'form' );
+ return $f;
+ }
+
+ /**
+ * Output a subscription feed listing recent edits to this page.
+ * @param string $type
+ */
+ protected function feed( $type ) {
+ global $wgRequest, $wgFeed, $wgFeedClasses, $wgFeedLimit;
+
+ if( !$wgFeed ) {
+ global $wgOut;
+ $wgOut->addWikiMsg( 'feed-unavailable' );
+ return;
+ }
+
+ if( !isset( $wgFeedClasses[$type] ) ) {
+ global $wgOut;
+ $wgOut->addWikiMsg( 'feed-invalid' );
+ return;
+ }
+
+ $feed = new $wgFeedClasses[$type](
+ $this->feedTitle(),
+ wfMsgExt( 'tagline', 'parsemag' ),
+ $this->getTitle()->getFullUrl() );
+
+ // Already valid title
+ $nt = Title::makeTitleSafe( NS_USER, $this->opts['target'] );
+ $target = $this->opts['target'] == 'newbies' ? 'newbies' : $nt->getText();
+
+ $pager = new ContribsPager( $target, $this->opts['namespace'],
+ $this->opts['year'], $this->opts['month'] );
+
+ $pager->mLimit = min( $this->opts['limit'], $wgFeedLimit );
+
+ $feed->outHeader();
+ if( $pager->getNumRows() > 0 ) {
+ while( $row = $pager->mResult->fetchObject() ) {
+ $feed->outItem( $this->feedItem( $row ) );
+ }
+ }
+ $feed->outFooter();
+ }
+
+ protected function feedTitle() {
+ global $wgContLanguageCode, $wgSitename;
+ $page = SpecialPage::getPage( 'Contributions' );
+ $desc = $page->getDescription();
+ return "$wgSitename - $desc [$wgContLanguageCode]";
+ }
+
+ protected function feedItem( $row ) {
+ $title = Title::MakeTitle( intval( $row->page_namespace ), $row->page_title );
+ if( $title ) {
+ $date = $row->rev_timestamp;
+ $comments = $title->getTalkPage()->getFullURL();
+ $revision = Revision::newFromTitle( $title, $row->rev_id );
+
+ return new FeedItem(
+ $title->getPrefixedText(),
+ $this->feedItemDesc( $revision ),
+ $title->getFullURL(),
+ $date,
+ $this->feedItemAuthor( $revision ),
+ $comments
+ );
+ } else {
+ return NULL;
+ }
+ }
+
+ protected function feedItemAuthor( $revision ) {
+ return $revision->getUserText();
+ }
+
+ protected function feedItemDesc( $revision ) {
+ if( $revision ) {
+ return '<p>' . htmlspecialchars( $revision->getUserText() ) . ': ' .
+ htmlspecialchars( FeedItem::stripComment( $revision->getComment() ) ) .
+ "</p>\n<hr />\n<div>" .
+ nl2br( htmlspecialchars( $revision->getText() ) ) . "</div>";
+ }
+ return '';
+ }
+}
/**
* Pager for Special:Contributions
@@ -12,7 +369,7 @@
class ContribsPager extends ReverseChronologicalPager {
public $mDefaultDirection = true;
var $messages, $target;
- var $namespace = '', $year = '', $month = '', $mDb;
+ var $namespace = '', $mDb;
function __construct( $target, $namespace = false, $year = false, $month = false ) {
parent::__construct();
@@ -22,12 +379,7 @@ class ContribsPager extends ReverseChronologicalPager {
$this->target = $target;
$this->namespace = $namespace;
- $year = intval($year);
- $month = intval($month);
-
- $this->year = $year > 0 ? $year : false;
- $this->month = ($month > 0 && $month < 13) ? $month : false;
- $this->getDateCond();
+ $this->getDateCond( $year, $month );
$this->mDb = wfGetDB( DB_SLAVE, 'contributions' );
}
@@ -35,23 +387,22 @@ class ContribsPager extends ReverseChronologicalPager {
function getDefaultQuery() {
$query = parent::getDefaultQuery();
$query['target'] = $this->target;
- $query['month'] = $this->month;
- $query['year'] = $this->year;
return $query;
}
function getQueryInfo() {
- list( $index, $userCond ) = $this->getUserCond();
+ list( $tables, $index, $userCond, $join_cond ) = $this->getUserCond();
$conds = array_merge( array('page_id=rev_page'), $userCond, $this->getNamespaceCond() );
$queryInfo = array(
- 'tables' => array( 'page', 'revision' ),
+ 'tables' => $tables,
'fields' => array(
'page_namespace', 'page_title', 'page_is_new', 'page_latest', 'rev_id', 'rev_page',
'rev_text_id', 'rev_timestamp', 'rev_comment', 'rev_minor_edit', 'rev_user',
'rev_user_text', 'rev_parent_id', 'rev_deleted'
),
'conds' => $conds,
- 'options' => array( 'USE INDEX' => array('revision' => $index) )
+ 'options' => array( 'USE INDEX' => array('revision' => $index) ),
+ 'join_conds' => $join_cond
);
wfRunHooks( 'ContribsPager::getQueryInfo', array( &$this, &$queryInfo ) );
return $queryInfo;
@@ -59,73 +410,31 @@ class ContribsPager extends ReverseChronologicalPager {
function getUserCond() {
$condition = array();
-
- if ( $this->target == 'newbies' ) {
+ $join_conds = array();
+ if( $this->target == 'newbies' ) {
+ $tables = array( 'user_groups', 'page', 'revision' );
$max = $this->mDb->selectField( 'user', 'max(user_id)', false, __METHOD__ );
$condition[] = 'rev_user >' . (int)($max - $max / 100);
+ $condition[] = 'ug_group IS NULL';
$index = 'user_timestamp';
+ # FIXME: other groups may have 'bot' rights
+ $join_conds['user_groups'] = array( 'LEFT JOIN', "ug_user = rev_user AND ug_group = 'bot'" );
} else {
+ $tables = array( 'page', 'revision' );
$condition['rev_user_text'] = $this->target;
$index = 'usertext_timestamp';
}
- return array( $index, $condition );
+ return array( $tables, $index, $condition, $join_conds );
}
function getNamespaceCond() {
- if ( $this->namespace !== '' ) {
+ if( $this->namespace !== '' ) {
return array( 'page_namespace' => (int)$this->namespace );
} else {
return array();
}
}
- function getDateCond() {
- // Given an optional year and month, we need to generate a timestamp
- // to use as "WHERE rev_timestamp <= result"
- // Examples: year = 2006 equals < 20070101 (+000000)
- // year=2005, month=1 equals < 20050201
- // year=2005, month=12 equals < 20060101
-
- if (!$this->year && !$this->month)
- return;
-
- if ( $this->year ) {
- $year = $this->year;
- }
- else {
- // If no year given, assume the current one
- $year = gmdate( 'Y' );
- // If this month hasn't happened yet this year, go back to last year's month
- if( $this->month > gmdate( 'n' ) ) {
- $year--;
- }
- }
-
- if ( $this->month ) {
- $month = $this->month + 1;
- // For December, we want January 1 of the next year
- if ($month > 12) {
- $month = 1;
- $year++;
- }
- }
- else {
- // No month implies we want up to the end of the year in question
- $month = 1;
- $year++;
- }
-
- if ($year > 2032)
- $year = 2032;
- $ymd = (int)sprintf( "%04d%02d01", $year, $month );
-
- // Y2K38 bug
- if ($ymd > 20320101)
- $ymd = 20320101;
-
- $this->mOffset = $this->mDb->timestamp( "${ymd}000000" );
- }
-
function getIndexField() {
return 'rev_timestamp';
}
@@ -167,8 +476,7 @@ class ContribsPager extends ReverseChronologicalPager {
$difftext .= $this->messages['newarticle'];
}
- if( !$page->getUserPermissionsErrors( 'rollback', $wgUser )
- && !$page->getUserPermissionsErrors( 'edit', $wgUser ) ) {
+ if( $page->userCan( 'rollback') && $page->userCan( 'edit' ) ) {
$topmarktext .= ' '.$sk->generateRollback( $rev );
}
@@ -182,7 +490,8 @@ class ContribsPager extends ReverseChronologicalPager {
$histlink='('.$sk->makeKnownLinkObj( $page, $this->messages['hist'], 'action=history' ) . ')';
$comment = $wgContLang->getDirMark() . $sk->revComment( $rev, false, true );
- $d = $wgLang->timeanddate( wfTimestamp( TS_MW, $row->rev_timestamp ), true );
+ $date = $wgLang->timeanddate( wfTimestamp( TS_MW, $row->rev_timestamp ), true );
+ $d = $sk->makeKnownLinkObj( $page, $date, 'oldid='.intval($row->rev_id) );
if( $this->target == 'newbies' ) {
$userlink = ' . . ' . $sk->userLink( $row->rev_user, $row->rev_user_text );
@@ -207,7 +516,7 @@ class ContribsPager extends ReverseChronologicalPager {
$mflag = '';
}
- $ret = "{$d} {$histlink} {$difftext} {$nflag}{$mflag} {$link}{$userlink}{$comment} {$topmarktext}";
+ $ret = "{$d} {$histlink} {$difftext} {$nflag}{$mflag} {$link}{$userlink} {$comment} {$topmarktext}";
if( $rev->isDeleted( Revision::DELETED_TEXT ) ) {
$ret .= ' ' . wfMsgHtml( 'deletedrev' );
}
@@ -229,242 +538,3 @@ class ContribsPager extends ReverseChronologicalPager {
}
}
-
-/**
- * Special page "user contributions".
- * Shows a list of the contributions of a user.
- *
- * @return none
- * @param $par String: (optional) user name of the user for which to show the contributions
- */
-function wfSpecialContributions( $par = null ) {
- global $wgUser, $wgOut, $wgLang, $wgRequest;
-
- $options = array();
-
- if ( isset( $par ) && $par == 'newbies' ) {
- $target = 'newbies';
- $options['contribs'] = 'newbie';
- } elseif ( isset( $par ) ) {
- $target = $par;
- } else {
- $target = $wgRequest->getVal( 'target' );
- }
-
- // check for radiobox
- if ( $wgRequest->getVal( 'contribs' ) == 'newbie' ) {
- $target = 'newbies';
- $options['contribs'] = 'newbie';
- }
-
- if ( !strlen( $target ) ) {
- $wgOut->addHTML( contributionsForm( '' ) );
- return;
- }
-
- $options['limit'] = $wgRequest->getInt( 'limit', 50 );
- $options['target'] = $target;
-
- $nt = Title::makeTitleSafe( NS_USER, $target );
- if ( !$nt ) {
- $wgOut->addHTML( contributionsForm( '' ) );
- return;
- }
- $id = User::idFromName( $nt->getText() );
-
- if ( $target != 'newbies' ) {
- $target = $nt->getText();
- $wgOut->setSubtitle( contributionsSub( $nt, $id ) );
- } else {
- $wgOut->setSubtitle( wfMsgHtml( 'sp-contributions-newbies-sub') );
- }
-
- if ( ( $ns = $wgRequest->getVal( 'namespace', null ) ) !== null && $ns !== '' ) {
- $options['namespace'] = intval( $ns );
- } else {
- $options['namespace'] = '';
- }
- if ( $wgUser->isAllowed( 'markbotedit' ) && $wgRequest->getBool( 'bot' ) ) {
- $options['bot'] = '1';
- }
-
- $skip = $wgRequest->getText( 'offset' ) || $wgRequest->getText( 'dir' ) == 'prev';
- # Offset overrides year/month selection
- if ( ( $month = $wgRequest->getIntOrNull( 'month' ) ) !== null && $month !== -1 ) {
- $options['month'] = intval( $month );
- } else {
- $options['month'] = '';
- }
- if ( ( $year = $wgRequest->getIntOrNull( 'year' ) ) !== null ) {
- $options['year'] = intval( $year );
- } else if( $options['month'] ) {
- $thisMonth = intval( gmdate( 'n' ) );
- $thisYear = intval( gmdate( 'Y' ) );
- if( intval( $options['month'] ) > $thisMonth ) {
- $thisYear--;
- }
- $options['year'] = $thisYear;
- } else {
- $options['year'] = '';
- }
-
- wfRunHooks( 'SpecialContributionsBeforeMainOutput', $id );
-
- if( $skip ) {
- $options['year'] = '';
- $options['month'] = '';
- }
-
- $wgOut->addHTML( contributionsForm( $options ) );
-
- $pager = new ContribsPager( $target, $options['namespace'], $options['year'], $options['month'] );
- if ( !$pager->getNumRows() ) {
- $wgOut->addWikiMsg( 'nocontribs' );
- return;
- }
-
- # Show a message about slave lag, if applicable
- if( ( $lag = $pager->getDatabase()->getLag() ) > 0 )
- $wgOut->showLagWarning( $lag );
-
- $wgOut->addHTML(
- '<p>' . $pager->getNavigationBar() . '</p>' .
- $pager->getBody() .
- '<p>' . $pager->getNavigationBar() . '</p>' );
-
- # 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';
-
-
- $text = wfMsgNoTrans( $message, $target );
- if( !wfEmptyMsg( $message, $text ) && $text != '-' ) {
- $wgOut->addHtml( '<div class="mw-contributions-footer">' );
- $wgOut->addWikiText( $text );
- $wgOut->addHtml( '</div>' );
- }
- }
-}
-
-/**
- * Generates the subheading with links
- * @param Title $nt Title object for the target
- * @param integer $id User ID for the target
- * @return String: appropriately-escaped HTML to be output literally
- */
-function contributionsSub( $nt, $id ) {
- global $wgSysopUserBans, $wgLang, $wgUser;
-
- $sk = $wgUser->getSkin();
-
- if ( 0 == $id ) {
- $user = $nt->getText();
- } else {
- $user = $sk->makeLinkObj( $nt, htmlspecialchars( $nt->getText() ) );
- }
- $talk = $nt->getTalkPage();
- if( $talk ) {
- # Talk page link
- $tools[] = $sk->makeLinkObj( $talk, wfMsgHtml( 'talkpagelinktext' ) );
- if( ( $id != 0 && $wgSysopUserBans ) || ( $id == 0 && User::isIP( $nt->getText() ) ) ) {
- # Block link
- if( $wgUser->isAllowed( 'block' ) )
- $tools[] = $sk->makeKnownLinkObj( SpecialPage::getTitleFor( 'Blockip', $nt->getDBkey() ), wfMsgHtml( 'blocklink' ) );
- # Block log link
- $tools[] = $sk->makeKnownLinkObj( SpecialPage::getTitleFor( 'Log' ), wfMsgHtml( 'sp-contributions-blocklog' ), 'type=block&page=' . $nt->getPrefixedUrl() );
- }
- # Other logs link
- $tools[] = $sk->makeKnownLinkObj( SpecialPage::getTitleFor( 'Log' ), wfMsgHtml( 'log' ), 'user=' . $nt->getPartialUrl() );
-
- wfRunHooks( 'ContributionsToolLinks', array( $id, $nt, &$tools ) );
-
- $links = implode( ' | ', $tools );
- }
-
- // 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'.
- if( wfEmptyMsg( 'contribsub', wfMsg( 'contribsub' ) ) ) {
- return wfMsgHtml( 'contribsub2', $user, $links );
- } else {
- return wfMsgHtml( 'contribsub', "$user ($links)" );
- }
-}
-
-/**
- * Generates the namespace selector form with hidden attributes.
- * @param $options Array: the options to be included.
- */
-function contributionsForm( $options ) {
- global $wgScript, $wgTitle, $wgRequest;
-
- $options['title'] = $wgTitle->getPrefixedText();
- if ( !isset( $options['target'] ) ) {
- $options['target'] = '';
- } else {
- $options['target'] = str_replace( '_' , ' ' , $options['target'] );
- }
-
- if ( !isset( $options['namespace'] ) ) {
- $options['namespace'] = '';
- }
-
- if ( !isset( $options['contribs'] ) ) {
- $options['contribs'] = 'user';
- }
-
- if ( !isset( $options['year'] ) ) {
- $options['year'] = '';
- }
-
- if ( !isset( $options['month'] ) ) {
- $options['month'] = '';
- }
-
- if ( $options['contribs'] == 'newbie' ) {
- $options['target'] = '';
- }
-
- $f = Xml::openElement( 'form', array( 'method' => 'get', 'action' => $wgScript ) );
-
- foreach ( $options as $name => $value ) {
- if ( in_array( $name, array( 'namespace', 'target', 'contribs', 'year', 'month' ) ) ) {
- continue;
- }
- $f .= "\t" . Xml::hidden( $name, $value ) . "\n";
- }
-
- $f .= '<fieldset>' .
- Xml::element( 'legend', array(), wfMsg( 'sp-contributions-search' ) ) .
- Xml::radioLabel( wfMsgExt( 'sp-contributions-newbies', array( 'parseinline' ) ), 'contribs' , 'newbie' , 'newbie', $options['contribs'] == 'newbie' ? true : false ) . '<br />' .
- Xml::radioLabel( wfMsgExt( 'sp-contributions-username', array( 'parseinline' ) ), 'contribs' , 'user', 'user', $options['contribs'] == 'user' ? true : false ) . ' ' .
- Xml::input( 'target', 20, $options['target']) . ' '.
- '<span style="white-space: nowrap">' .
- Xml::label( wfMsg( 'namespace' ), 'namespace' ) . ' ' .
- Xml::namespaceSelector( $options['namespace'], '' ) .
- '</span>' .
- Xml::openElement( 'p' ) .
- '<span style="white-space: nowrap">' .
- Xml::label( wfMsg( 'year' ), 'year' ) . ' '.
- Xml::input( 'year', 4, $options['year'], array('id' => 'year', 'maxlength' => 4) ) .
- '</span>' .
- ' '.
- '<span style="white-space: nowrap">' .
- Xml::label( wfMsg( 'month' ), 'month' ) . ' '.
- Xml::monthSelector( $options['month'], -1 ) . ' '.
- '</span>' .
- Xml::submitButton( wfMsg( 'sp-contributions-submit' ) ) .
- Xml::closeElement( 'p' );
-
- $explain = wfMsgExt( 'sp-contributions-explain', 'parseinline' );
- if( !wfEmptyMsg( 'sp-contributions-explain', $explain ) )
- $f .= "<p>{$explain}</p>";
-
- $f .= '</fieldset>' .
- Xml::closeElement( 'form' );
- return $f;
-}
diff --git a/includes/specials/SpecialDeletedContributions.php b/includes/specials/SpecialDeletedContributions.php
new file mode 100644
index 00000000..513d25e2
--- /dev/null
+++ b/includes/specials/SpecialDeletedContributions.php
@@ -0,0 +1,369 @@
+<?php
+/**
+ * Implements Special:DeletedContributions to display archived revisions
+ * @ingroup SpecialPage
+ */
+
+class DeletedContribsPager extends IndexPager {
+ public $mDefaultDirection = true;
+ var $messages, $target;
+ var $namespace = '', $mDb;
+
+ function __construct( $target, $namespace = false ) {
+ parent::__construct();
+ foreach( explode( ' ', 'deletionlog undeletebtn minoreditletter diff' ) as $msg ) {
+ $this->messages[$msg] = wfMsgExt( $msg, array( 'escape') );
+ }
+ $this->target = $target;
+ $this->namespace = $namespace;
+ $this->mDb = wfGetDB( DB_SLAVE, 'contributions' );
+ }
+
+ function getDefaultQuery() {
+ $query = parent::getDefaultQuery();
+ $query['target'] = $this->target;
+ return $query;
+ }
+
+ function getQueryInfo() {
+ list( $index, $userCond ) = $this->getUserCond();
+ $conds = array_merge( $userCond, $this->getNamespaceCond() );
+
+ 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'
+ ),
+ 'conds' => $conds,
+ 'options' => array( 'FORCE INDEX' => $index )
+ );
+ }
+
+ function getUserCond() {
+ $condition = array();
+
+ $condition['ar_user_text'] = $this->target;
+ $index = 'usertext_timestamp';
+
+ return array( $index, $condition );
+ }
+
+ function getIndexField() {
+ return 'ar_timestamp';
+ }
+
+ function getStartBody() {
+ return "<ul>\n";
+ }
+
+ function getEndBody() {
+ return "</ul>\n";
+ }
+
+ function getNavigationBar() {
+ if ( isset( $this->mNavigationBar ) ) {
+ return $this->mNavigationBar;
+ }
+ $linkTexts = array(
+ 'prev' => wfMsgHtml( 'pager-newer-n', $this->mLimit ),
+ 'next' => wfMsgHtml( 'pager-older-n', $this->mLimit ),
+ 'first' => wfMsgHtml( 'histlast' ),
+ 'last' => wfMsgHtml( 'histfirst' )
+ );
+
+ $pagingLinks = $this->getPagingLinks( $linkTexts );
+ $limitLinks = $this->getLimitLinks();
+ $limits = implode( ' | ', $limitLinks );
+
+ $this->mNavigationBar = "({$pagingLinks['first']} | {$pagingLinks['last']}) " .
+ wfMsgExt( 'viewprevnext', array( 'parsemag' ), $pagingLinks['prev'], $pagingLinks['next'], $limits );
+ return $this->mNavigationBar;
+ }
+
+ function getNamespaceCond() {
+ if ( $this->namespace !== '' ) {
+ return array( 'ar_namespace' => (int)$this->namespace );
+ } else {
+ return array();
+ }
+ }
+
+ /**
+ * Generates each row in the contributions list.
+ *
+ * Contributions which are marked "top" are currently on top of the history.
+ * For these contributions, a [rollback] link is shown for users with sysop
+ * privileges. The rollback link restores the most recent version that was not
+ * written by the target user.
+ *
+ * @todo This would probably look a lot nicer in a table.
+ */
+ function formatRow( $row ) {
+ wfProfileIn( __METHOD__ );
+
+ global $wgLang, $wgUser;
+
+ $sk = $this->getSkin();
+
+ $rev = new Revision( array(
+ '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,
+ 'rev_deleted' => $row->ar_deleted,
+ ) );
+
+ $page = Title::makeTitle( $row->ar_namespace, $row->ar_title );
+
+ $undelete = SpecialPage::getTitleFor( 'Undelete' );
+
+ $logs = SpecialPage::getTitleFor( 'Log' );
+ $dellog = $sk->makeKnownLinkObj( $logs,
+ $this->messages['deletionlog'],
+ 'type=delete&page=' . $page->getPrefixedUrl() );
+
+ $reviewlink = $sk->makeKnownLinkObj( SpecialPage::getTitleFor( 'Undelete', $page->getPrefixedDBkey() ),
+ $this->messages['undeletebtn'] );
+
+ $link = $sk->makeKnownLinkObj( $undelete,
+ htmlspecialchars( $page->getPrefixedText() ),
+ 'target=' . $page->getPrefixedUrl() .
+ '&timestamp=' . $rev->getTimestamp() );
+
+ $last = $sk->makeKnownLinkObj( $undelete,
+ $this->messages['diff'],
+ "target=" . $page->getPrefixedUrl() .
+ "&timestamp=" . $rev->getTimestamp() .
+ "&diff=prev" );
+
+ $comment = $sk->revComment( $rev );
+ $d = $wgLang->timeanddate( $rev->getTimestamp(), true );
+
+ if( $rev->isDeleted( Revision::DELETED_TEXT ) ) {
+ $d = '<span class="history-deleted">' . $d . '</span>';
+ } else {
+ $link = $sk->makeKnownLinkObj( $undelete, $d,
+ 'target=' . $page->getPrefixedUrl() .
+ '&timestamp=' . $rev->getTimestamp() );
+ }
+
+ $pagelink = $sk->makeLinkObj( $page );
+
+ if( $rev->isMinor() ) {
+ $mflag = '<span class="minor">' . $this->messages['minoreditletter'] . '</span> ';
+ } else {
+ $mflag = '';
+ }
+
+
+ $ret = "{$link} ($last) ({$dellog}) ({$reviewlink}) . . {$mflag} {$pagelink} {$comment}";
+ if( $rev->isDeleted( Revision::DELETED_TEXT ) ) {
+ $ret .= ' ' . wfMsgHtml( 'deletedrev' );
+ }
+
+ $ret = "<li>$ret</li>\n";
+
+ wfProfileOut( __METHOD__ );
+ return $ret;
+ }
+
+ /**
+ * Get the Database object in use
+ *
+ * @return Database
+ */
+ public function getDatabase() {
+ return $this->mDb;
+ }
+}
+
+class DeletedContributionsPage extends SpecialPage {
+ function __construct() {
+ parent::__construct( 'DeletedContributions', 'deletedhistory',
+ /*listed*/ true, /*function*/ false, /*file*/ false );
+ }
+
+ /**
+ * Special page "deleted user contributions".
+ * Shows a list of the deleted contributions of a user.
+ *
+ * @return none
+ * @param $par String: (optional) user name of the user for which to show the contributions
+ */
+ function execute( $par ) {
+ global $wgUser;
+ $this->setHeaders();
+
+ if ( !$this->userCanExecute( $wgUser ) ) {
+ $this->displayRestrictionError();
+ return;
+ }
+
+ global $wgUser, $wgOut, $wgLang, $wgRequest;
+
+ $options = array();
+
+ if ( isset( $par ) ) {
+ $target = $par;
+ } else {
+ $target = $wgRequest->getVal( 'target' );
+ }
+
+ if ( !strlen( $target ) ) {
+ $wgOut->addHTML( $this->getForm( '' ) );
+ return;
+ }
+
+ $options['limit'] = $wgRequest->getInt( 'limit', 50 );
+ $options['target'] = $target;
+
+ $nt = Title::makeTitleSafe( NS_USER, $target );
+ if ( !$nt ) {
+ $wgOut->addHTML( $this->getForm( '' ) );
+ return;
+ }
+ $id = User::idFromName( $nt->getText() );
+
+ $target = $nt->getText();
+ $wgOut->setSubtitle( $this->getSubTitle( $nt, $id ) );
+
+ if ( ( $ns = $wgRequest->getVal( 'namespace', null ) ) !== null && $ns !== '' ) {
+ $options['namespace'] = intval( $ns );
+ } else {
+ $options['namespace'] = '';
+ }
+
+ $wgOut->addHTML( $this->getForm( $options ) );
+
+ $pager = new DeletedContribsPager( $target, $options['namespace'] );
+ if ( !$pager->getNumRows() ) {
+ $wgOut->addWikiText( wfMsg( 'nocontribs' ) );
+ return;
+ }
+
+ # Show a message about slave lag, if applicable
+ if( ( $lag = $pager->getDatabase()->getLag() ) > 0 )
+ $wgOut->showLagWarning( $lag );
+
+ $wgOut->addHTML(
+ '<p>' . $pager->getNavigationBar() . '</p>' .
+ $pager->getBody() .
+ '<p>' . $pager->getNavigationBar() . '</p>' );
+
+ # 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';
+
+
+ $text = wfMsgNoTrans( $message, $target );
+ if( !wfEmptyMsg( $message, $text ) && $text != '-' ) {
+ $wgOut->addHTML( '<div class="mw-contributions-footer">' );
+ $wgOut->addWikiText( $text );
+ $wgOut->addHTML( '</div>' );
+ }
+ }
+ }
+
+ /**
+ * Generates the subheading with links
+ * @param $nt @see Title object for the target
+ */
+ function getSubTitle( $nt, $id ) {
+ global $wgSysopUserBans, $wgLang, $wgUser;
+
+ $sk = $wgUser->getSkin();
+
+ if ( 0 == $id ) {
+ $user = $nt->getText();
+ } else {
+ $user = $sk->makeLinkObj( $nt, htmlspecialchars( $nt->getText() ) );
+ }
+ $talk = $nt->getTalkPage();
+ if( $talk ) {
+ # Talk page link
+ $tools[] = $sk->makeLinkObj( $talk, wfMsgHtml( 'talkpagelinktext' ) );
+ if( ( $id != 0 && $wgSysopUserBans ) || ( $id == 0 && User::isIP( $nt->getText() ) ) ) {
+ # Block link
+ if( $wgUser->isAllowed( 'block' ) )
+ $tools[] = $sk->makeKnownLinkObj( SpecialPage::getTitleFor( 'Blockip', $nt->getDBkey() ),
+ wfMsgHtml( 'blocklink' ) );
+ # Block log link
+ $tools[] = $sk->makeKnownLinkObj( SpecialPage::getTitleFor( 'Log' ),
+ wfMsgHtml( 'sp-contributions-blocklog' ), 'type=block&page=' . $nt->getPrefixedUrl() );
+ }
+ # Other logs link
+ $tools[] = $sk->makeKnownLinkObj( SpecialPage::getTitleFor( 'Log' ),
+ wfMsgHtml( 'log' ), 'user=' . $nt->getPartialUrl() );
+ # Link to undeleted contributions
+ $tools[] = $sk->makeKnownLinkObj( SpecialPage::getTitleFor( 'Contributions', $nt->getDBkey() ),
+ wfMsgHtml( 'contributions' ) );
+
+ wfRunHooks( 'ContributionsToolLinks', array( $id, $nt, &$tools ) );
+
+ $links = implode( ' | ', $tools );
+ }
+
+ // 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'.
+ if( wfEmptyMsg( 'contribsub', wfMsg( 'contribsub' ) ) ) {
+ return wfMsgHtml( 'contribsub2', $user, $links );
+ } else {
+ return wfMsgHtml( 'contribsub', "$user ($links)" );
+ }
+ }
+
+ /**
+ * Generates the namespace selector form with hidden attributes.
+ * @param $options Array: the options to be included.
+ */
+ function getForm( $options ) {
+ global $wgScript, $wgTitle, $wgRequest;
+
+ $options['title'] = $wgTitle->getPrefixedText();
+ if ( !isset( $options['target'] ) ) {
+ $options['target'] = '';
+ } else {
+ $options['target'] = str_replace( '_' , ' ' , $options['target'] );
+ }
+
+ if ( !isset( $options['namespace'] ) ) {
+ $options['namespace'] = '';
+ }
+
+ if ( !isset( $options['contribs'] ) ) {
+ $options['contribs'] = 'user';
+ }
+
+ if ( $options['contribs'] == 'newbie' ) {
+ $options['target'] = '';
+ }
+
+ $f = Xml::openElement( 'form', array( 'method' => 'get', 'action' => $wgScript ) );
+
+ foreach ( $options as $name => $value ) {
+ if ( in_array( $name, array( 'namespace', 'target', 'contribs' ) ) ) {
+ continue;
+ }
+ $f .= "\t" . Xml::hidden( $name, $value ) . "\n";
+ }
+
+ $f .= Xml::openElement( 'fieldset' ) .
+ Xml::element( 'legend', array(), wfMsg( 'sp-contributions-search' ) ) .
+ Xml::tags( 'label', array( 'for' => 'target' ), wfMsgExt( 'sp-contributions-username', 'parseinline' ) ) . ' ' .
+ Xml::input( 'target', 20, $options['target']) . ' '.
+ Xml::label( wfMsg( 'namespace' ), 'namespace' ) . ' ' .
+ Xml::namespaceSelector( $options['namespace'], '' ) . ' ' .
+ Xml::submitButton( wfMsg( 'sp-contributions-submit' ) ) .
+ Xml::closeElement( 'fieldset' ) .
+ Xml::closeElement( 'form' );
+ return $f;
+ }
+}
diff --git a/includes/specials/SpecialDisambiguations.php b/includes/specials/SpecialDisambiguations.php
index 34045660..0a728b68 100644
--- a/includes/specials/SpecialDisambiguations.php
+++ b/includes/specials/SpecialDisambiguations.php
@@ -84,13 +84,13 @@ class DisambiguationsPage extends PageQueryPage {
function formatResult( $skin, $result ) {
global $wgContLang;
- $title = Title::newFromId( $result->value );
+ $title = Title::newFromID( $result->value );
$dp = Title::makeTitle( $result->namespace, $result->title );
- $from = $skin->makeKnownLinkObj( $title, '' );
- $edit = $skin->makeKnownLinkObj( $title, "(".wfMsgHtml("qbedit").")" , 'redirect=no&action=edit' );
+ $from = $skin->link( $title );
+ $edit = $skin->link( $title, "(".wfMsgHtml("qbedit").")", array(), array( 'redirect' => 'no', 'action' => 'edit' ) );
$arr = $wgContLang->getArrow();
- $to = $skin->makeKnownLinkObj( $dp, '' );
+ $to = $skin->link( $dp );
return "$from $edit $arr $to";
}
diff --git a/includes/specials/SpecialEmailuser.php b/includes/specials/SpecialEmailuser.php
index 3874c6a1..cf90f94d 100644
--- a/includes/specials/SpecialEmailuser.php
+++ b/includes/specials/SpecialEmailuser.php
@@ -5,17 +5,22 @@
*/
/**
- * @todo document
+ * Constructor for Special:Emailuser.
*/
function wfSpecialEmailuser( $par ) {
global $wgRequest, $wgUser, $wgOut;
+ if ( !EmailUserForm::userEmailEnabled() ) {
+ $wgOut->showErrorPage( 'nosuchspecialpage', 'nospecialpagetext' );
+ return;
+ }
+
$action = $wgRequest->getVal( 'action' );
$target = isset($par) ? $par : $wgRequest->getVal( 'target' );
$targetUser = EmailUserForm::validateEmailTarget( $target );
if ( !( $targetUser instanceof User ) ) {
- $wgOut->showErrorPage( $targetUser[0], $targetUser[1] );
+ $wgOut->showErrorPage( $targetUser.'title', $targetUser.'text' );
return;
}
@@ -30,7 +35,7 @@ function wfSpecialEmailuser( $par ) {
$error = EmailUserForm::getPermissionsError( $wgUser, $wgRequest->getVal( 'wpEditToken' ) );
if ( $error ) {
- switch ( $error[0] ) {
+ switch ( $error ) {
case 'blockedemailuser':
$wgOut->blockedPage();
return;
@@ -40,12 +45,11 @@ function wfSpecialEmailuser( $par ) {
case 'sessionfailure':
$form->showForm();
return;
- default:
- $wgOut->showErrorPage( $error[0], $error[1] );
+ case 'mailnologin':
+ $wgOut->showErrorPage( 'mailnologin', 'mailnologintext' );
return;
}
}
-
if ( "submit" == $action && $wgRequest->wasPosted() ) {
$result = $form->doSubmit();
@@ -94,46 +98,64 @@ class EmailUserForm {
$this->subject = wfMsgExt( 'defemailsubject', array( 'content', 'parsemag' ) );
}
- $emf = wfMsg( "emailfrom" );
- $senderLink = $skin->makeLinkObj(
- $wgUser->getUserPage(), htmlspecialchars( $wgUser->getName() ) );
- $emt = wfMsg( "emailto" );
- $recipientLink = $skin->makeLinkObj(
- $this->target->getUserPage(), htmlspecialchars( $this->target->getName() ) );
- $emr = wfMsg( "emailsubject" );
- $emm = wfMsg( "emailmessage" );
- $ems = wfMsg( "emailsend" );
- $emc = wfMsg( "emailccme" );
- $encSubject = htmlspecialchars( $this->subject );
-
$titleObj = SpecialPage::getTitleFor( "Emailuser" );
- $action = $titleObj->escapeLocalURL( "target=" .
+ $action = $titleObj->getLocalURL( "target=" .
urlencode( $this->target->getName() ) . "&action=submit" );
- $token = htmlspecialchars( $wgUser->editToken() );
-
- $wgOut->addHTML( "
-<form id=\"emailuser\" method=\"post\" action=\"{$action}\">
-<table border='0' id='mailheader'><tr>
-<td align='right'>{$emf}:</td>
-<td align='left'><strong>{$senderLink}</strong></td>
-</tr><tr>
-<td align='right'>{$emt}:</td>
-<td align='left'><strong>{$recipientLink}</strong></td>
-</tr><tr>
-<td align='right'>{$emr}:</td>
-<td align='left'>
-<input type='text' size='60' maxlength='200' name=\"wpSubject\" value=\"{$encSubject}\" />
-</td>
-</tr>
-</table>
-<span id='wpTextLabel'><label for=\"wpText\">{$emm}:</label><br /></span>
-<textarea id=\"wpText\" name=\"wpText\" rows='20' cols='80' style=\"width: 100%;\">" . htmlspecialchars( $this->text ) .
-"</textarea>
-" . wfCheckLabel( $emc, 'wpCCMe', 'wpCCMe', $wgUser->getBoolOption( 'ccmeonemails' ) ) . "<br />
-<input type='submit' name=\"wpSend\" value=\"{$ems}\" />
-<input type='hidden' name='wpEditToken' value=\"$token\" />
-</form>\n" );
+ $wgOut->addHTML(
+ Xml::openElement( 'form', array( 'method' => 'post', 'action' => $action, 'id' => 'emailuser' ) ) .
+ Xml::openElement( 'fieldset' ) .
+ Xml::element( 'legend', null, wfMsgExt( 'email-legend', 'parsemag' ) ) .
+ Xml::openElement( 'table', array( 'class' => 'mw-emailuser-table' ) ) .
+ "<tr>
+ <td class='mw-label'>" .
+ Xml::label( wfMsg( 'emailfrom' ), 'emailfrom' ) .
+ "</td>
+ <td class='mw-input' id='mw-emailuser-sender'>" .
+ $skin->link( $wgUser->getUserPage(), htmlspecialchars( $wgUser->getName() ) ) .
+ "</td>
+ </tr>
+ <tr>
+ <td class='mw-label'>" .
+ Xml::label( wfMsg( 'emailto' ), 'emailto' ) .
+ "</td>
+ <td class='mw-input' id='mw-emailuser-recipient'>" .
+ $skin->link( $this->target->getUserPage(), htmlspecialchars( $this->target->getName() ) ) .
+ "</td>
+ </tr>
+ <tr>
+ <td class='mw-label'>" .
+ Xml::label( wfMsg( 'emailsubject' ), 'wpSubject' ) .
+ "</td>
+ <td class='mw-input'>" .
+ Xml::input( 'wpSubject', 60, $this->subject, array( 'type' => 'text', 'maxlength' => 200 ) ) .
+ "</td>
+ </tr>
+ <tr>
+ <td class='mw-label'>" .
+ Xml::label( wfMsg( 'emailmessage' ), 'wpText' ) .
+ "</td>
+ <td class='mw-input'>" .
+ Xml::textarea( 'wpText', $this->text, 80, 20, array( 'id' => 'wpText' ) ) .
+ "</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td class='mw-input'>" .
+ Xml::checkLabel( wfMsg( 'emailccme' ), 'wpCCMe', 'wpCCMe', $wgUser->getBoolOption( 'ccmeonemails' ) ) .
+ "</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td class='mw-submit'>" .
+ Xml::submitButton( wfMsg( 'emailsend' ), array( 'name' => 'wpSend', 'accesskey' => 's' ) ) .
+ "</td>
+ </tr>" .
+ Xml::hidden( 'wpEditToken', $wgUser->editToken() ) .
+ Xml::closeElement( 'table' ) .
+ Xml::closeElement( 'fieldset' ) .
+ Xml::closeElement( 'form' )
+ );
}
/*
@@ -149,7 +171,7 @@ class EmailUserForm {
$subject = $this->subject;
// Add a standard footer and trim up trailing newlines
- $this->text = rtrim($this->text) . "\n\n---\n" . wfMsgExt( 'emailuserfooter',
+ $this->text = rtrim($this->text) . "\n\n-- \n" . wfMsgExt( 'emailuserfooter',
array( 'content', 'parsemag' ), array( $from->name, $to->name ) );
if( wfRunHooks( 'EmailUser', array( &$to, &$from, &$subject, &$this->text ) ) ) {
@@ -228,27 +250,33 @@ class EmailUserForm {
return $this->target;
}
- static function validateEmailTarget ( $target ) {
+ static function userEmailEnabled() {
global $wgEnableEmail, $wgEnableUserEmail;
-
- if( !( $wgEnableEmail && $wgEnableUserEmail ) )
- return array( "nosuchspecialpage", "nospecialpagetext" );
+ return $wgEnableEmail && $wgEnableUserEmail;
+ }
+ static function validateEmailTarget ( $target ) {
if ( "" == $target ) {
wfDebug( "Target is empty.\n" );
- return array( "notargettitle", "notargettext" );
+ return "notarget";
}
$nt = Title::newFromURL( $target );
if ( is_null( $nt ) ) {
wfDebug( "Target is invalid title.\n" );
- return array( "notargettitle", "notargettext" );
+ return "notarget";
}
$nu = User::newFromName( $nt->getText() );
- if( is_null( $nu ) || !$nu->canReceiveEmail() ) {
- wfDebug( "Target is invalid user or can't receive.\n" );
- return array( "noemailtitle", "noemailtext" );
+ if( is_null( $nu ) || !$nu->getId() ) {
+ wfDebug( "Target is invalid user.\n" );
+ return "notarget";
+ } else if ( !$nu->isEmailConfirmed() ) {
+ wfDebug( "User has no valid email.\n" );
+ return "noemail";
+ } else if ( !$nu->canReceiveEmail() ) {
+ wfDebug( "User does not allow user emails.\n" );
+ return "nowikiemail";
}
return $nu;
@@ -256,22 +284,22 @@ class EmailUserForm {
static function getPermissionsError ( $user, $editToken ) {
if( !$user->canSendEmail() ) {
wfDebug( "User can't send.\n" );
- return array( "mailnologin", "mailnologintext" );
+ return "mailnologin";
}
if( $user->isBlockedFromEmailuser() ) {
wfDebug( "User is blocked from sending e-mail.\n" );
- return array( "blockedemailuser", "" );
+ return "blockedemailuser";
}
if( $user->pingLimiter( 'emailuser' ) ) {
wfDebug( "Ping limiter triggered.\n" );
- return array( 'actionthrottledtext', '' );
+ return 'actionthrottledtext';
}
if( !$user->matchEditToken( $editToken ) ) {
wfDebug( "Matching edit token failed.\n" );
- return array( 'sessionfailure', '' );
+ return 'sessionfailure';
}
return;
diff --git a/includes/specials/SpecialExport.php b/includes/specials/SpecialExport.php
index 38bfc83e..898b5a78 100644
--- a/includes/specials/SpecialExport.php
+++ b/includes/specials/SpecialExport.php
@@ -1,5 +1,5 @@
<?php
-# Copyright (C) 2003 Brion Vibber <brion@pobox.com>
+# Copyright (C) 2003-2008 Brion Vibber <brion@pobox.com>
# http://www.mediawiki.org/
#
# This program is free software; you can redistribute it and/or modify
@@ -71,7 +71,7 @@ function wfExportGetTemplates( $inputPages, $pageSet ) {
function wfExportGetImages( $inputPages, $pageSet ) {
return wfExportGetLinks( $inputPages, $pageSet,
'imagelinks',
- array( NS_IMAGE . ' AS namespace', 'il_to AS title' ),
+ array( NS_FILE . ' AS namespace', 'il_to AS title' ),
array( 'page_id=il_from' ) );
}
@@ -93,7 +93,7 @@ function wfExportGetLinks( $inputPages, $pageSet, $table, $fields, $join ) {
array_merge( $join,
array(
'page_namespace' => $title->getNamespace(),
- 'page_title' => $title->getDbKey() ) ),
+ 'page_title' => $title->getDBKey() ) ),
__METHOD__ );
foreach( $result as $row ) {
$template = Title::makeTitle( $row->namespace, $row->title );
@@ -126,7 +126,7 @@ function wfSpecialExport( $page = '' ) {
$catname = $wgRequest->getText( 'catname' );
if ( $catname !== '' && $catname !== NULL && $catname !== false ) {
- $t = Title::makeTitleSafe( NS_CATEGORY, $catname );
+ $t = Title::makeTitleSafe( NS_MAIN, $catname );
if ( $t ) {
/**
* @fixme This can lead to hitting memory limit for very large
@@ -223,8 +223,23 @@ function wfSpecialExport( $page = '' ) {
/* Ok, let's get to it... */
- $db = wfGetDB( DB_SLAVE );
- $exporter = new WikiExporter( $db, $history );
+ if( $history == WikiExporter::CURRENT ) {
+ $lb = false;
+ $db = wfGetDB( DB_SLAVE );
+ $buffer = WikiExporter::BUFFER;
+ } else {
+ // Use an unbuffered query; histories may be very long!
+ $lb = wfGetLBFactory()->newMainLB();
+ $db = $lb->getConnection( DB_SLAVE );
+ $buffer = WikiExporter::STREAM;
+
+ // This might take a while... :D
+ wfSuppressWarnings();
+ set_time_limit(0);
+ wfRestoreWarnings();
+ }
+
+ $exporter = new WikiExporter( $db, $history, $buffer );
$exporter->list_authors = $list_authors ;
$exporter->openStream();
@@ -251,11 +266,14 @@ function wfSpecialExport( $page = '' ) {
}
$exporter->closeStream();
+ if( $lb ) {
+ $lb->closeAll();
+ }
return;
}
$self = SpecialPage::getTitleFor( 'Export' );
- $wgOut->addHtml( wfMsgExt( 'exporttext', 'parse' ) );
+ $wgOut->addHTML( wfMsgExt( 'exporttext', 'parse' ) );
$form = Xml::openElement( 'form', array( 'method' => 'post',
'action' => $self->getLocalUrl( 'action=submit' ) ) );
@@ -271,14 +289,14 @@ function wfSpecialExport( $page = '' ) {
if( $wgExportAllowHistory ) {
$form .= Xml::checkLabel( wfMsg( 'exportcuronly' ), 'curonly', 'curonly', true ) . '<br />';
} else {
- $wgOut->addHtml( wfMsgExt( 'exportnohistory', 'parse' ) );
+ $wgOut->addHTML( wfMsgExt( 'exportnohistory', 'parse' ) );
}
$form .= Xml::checkLabel( wfMsg( 'export-templates' ), 'templates', 'wpExportTemplates', false ) . '<br />';
// Enable this when we can do something useful exporting/importing image information. :)
//$form .= Xml::checkLabel( wfMsg( 'export-images' ), 'images', 'wpExportImages', false ) . '<br />';
$form .= Xml::checkLabel( wfMsg( 'export-download' ), 'wpDownload', 'wpDownload', true ) . '<br />';
- $form .= Xml::submitButton( wfMsg( 'export-submit' ) );
+ $form .= Xml::submitButton( wfMsg( 'export-submit' ), array( 'accesskey' => 's' ) );
$form .= Xml::closeElement( 'form' );
- $wgOut->addHtml( $form );
+ $wgOut->addHTML( $form );
}
diff --git a/includes/specials/SpecialFileDuplicateSearch.php b/includes/specials/SpecialFileDuplicateSearch.php
index 5236ca25..49a218c8 100644
--- a/includes/specials/SpecialFileDuplicateSearch.php
+++ b/includes/specials/SpecialFileDuplicateSearch.php
@@ -49,7 +49,7 @@ class FileDuplicateSearchPage extends QueryPage {
function formatResult( $skin, $result ) {
global $wgContLang, $wgLang;
- $nt = Title::makeTitle( NS_IMAGE, $result->title );
+ $nt = Title::makeTitle( NS_FILE, $result->title );
$text = $wgContLang->convert( $nt->getText() );
$plink = $skin->makeLink( $nt->getPrefixedText(), $text );
@@ -73,7 +73,7 @@ function wfSpecialFileDuplicateSearch( $par = null ) {
if( $title && $title->getText() != '' ) {
$dbr = wfGetDB( DB_SLAVE );
$image = $dbr->tableName( 'image' );
- $encFilename = $dbr->addQuotes( htmlspecialchars( $title->getDbKey() ) );
+ $encFilename = $dbr->addQuotes( htmlspecialchars( $title->getDBKey() ) );
$sql = "SELECT img_sha1 from $image where img_name = $encFilename";
$res = $dbr->query( $sql );
$row = $dbr->fetchRow( $res );
@@ -100,7 +100,7 @@ function wfSpecialFileDuplicateSearch( $par = null ) {
# Show a thumbnail of the file
$img = wfFindFile( $title );
if ( $img ) {
- $thumb = $img->getThumbnail( 120, 120 );
+ $thumb = $img->transform( array( 'width' => 120, 'height' => 120 ) );
if( $thumb ) {
$wgOut->addHTML( '<div style="float:' . $align . '" id="mw-fileduplicatesearch-icon">' .
$thumb->toHtml( array( 'desc-link' => false ) ) . '<br />' .
diff --git a/includes/specials/SpecialFilepath.php b/includes/specials/SpecialFilepath.php
index a2ba3e57..4a724b1f 100644
--- a/includes/specials/SpecialFilepath.php
+++ b/includes/specials/SpecialFilepath.php
@@ -9,9 +9,9 @@ function wfSpecialFilepath( $par ) {
$file = isset( $par ) ? $par : $wgRequest->getText( 'file' );
- $title = Title::newFromText( $file, NS_IMAGE );
+ $title = Title::makeTitleSafe( NS_FILE, $file );
- if ( ! $title instanceof Title || $title->getNamespace() != NS_IMAGE ) {
+ if ( ! $title instanceof Title || $title->getNamespace() != NS_FILE ) {
$cform = new FilepathForm( $title );
$cform->execute();
} else {
diff --git a/includes/specials/SpecialImport.php b/includes/specials/SpecialImport.php
index 1623245d..5e1a6533 100644
--- a/includes/specials/SpecialImport.php
+++ b/includes/specials/SpecialImport.php
@@ -23,28 +23,55 @@
* @ingroup SpecialPage
*/
-/**
- * Constructor
- */
-function wfSpecialImport( $page = '' ) {
- global $wgUser, $wgOut, $wgRequest, $wgTitle, $wgImportSources;
- global $wgImportTargetNamespace;
-
- $interwiki = false;
- $namespace = $wgImportTargetNamespace;
- $frompage = '';
- $history = true;
-
- if ( wfReadOnly() ) {
- $wgOut->readOnlyPage();
- return;
+class SpecialImport extends SpecialPage {
+
+ private $interwiki = false;
+ private $namespace;
+ private $frompage = '';
+ private $logcomment= false;
+ private $history = true;
+
+ /**
+ * Constructor
+ */
+ public function __construct() {
+ parent::__construct( 'Import', 'import' );
+ global $wgImportTargetNamespace;
+ $this->namespace = $wgImportTargetNamespace;
}
-
- if( $wgRequest->wasPosted() && $wgRequest->getVal( 'action' ) == 'submit') {
+
+ /**
+ * Execute
+ */
+ function execute( $par ) {
+ global $wgRequest;
+
+ $this->setHeaders();
+ $this->outputHeader();
+
+ if ( wfReadOnly() ) {
+ global $wgOut;
+ $wgOut->readOnlyPage();
+ return;
+ }
+
+ if ( $wgRequest->wasPosted() && $wgRequest->getVal( 'action' ) == 'submit' ) {
+ $this->doImport();
+ }
+ $this->showForm();
+ }
+
+ /**
+ * Do the actual import
+ */
+ private function doImport() {
+ global $wgOut, $wgRequest, $wgUser, $wgImportSources;
$isUpload = false;
- $namespace = $wgRequest->getIntOrNull( 'namespace' );
+ $this->namespace = $wgRequest->getIntOrNull( 'namespace' );
$sourceName = $wgRequest->getVal( "source" );
+ $this->logcomment = $wgRequest->getText( 'log-comment' );
+
if ( !$wgUser->matchEditToken( $wgRequest->getVal( 'editToken' ) ) ) {
$source = new WikiErrorMsg( 'import-token-mismatch' );
} elseif ( $sourceName == 'upload' ) {
@@ -55,16 +82,16 @@ function wfSpecialImport( $page = '' ) {
return $wgOut->permissionRequired( 'importupload' );
}
} elseif ( $sourceName == "interwiki" ) {
- $interwiki = $wgRequest->getVal( 'interwiki' );
- if ( !in_array( $interwiki, $wgImportSources ) ) {
+ $this->interwiki = $wgRequest->getVal( 'interwiki' );
+ if ( !in_array( $this->interwiki, $wgImportSources ) ) {
$source = new WikiErrorMsg( "import-invalid-interwiki" );
} else {
- $history = $wgRequest->getCheck( 'interwikiHistory' );
- $frompage = $wgRequest->getText( "frompage" );
+ $this->history = $wgRequest->getCheck( 'interwikiHistory' );
+ $this->frompage = $wgRequest->getText( "frompage" );
$source = ImportStreamSource::newFromInterwiki(
- $interwiki,
- $frompage,
- $history );
+ $this->interwiki,
+ $this->frompage,
+ $this->history );
}
} else {
$source = new WikiErrorMsg( "importunknownsource" );
@@ -76,10 +103,10 @@ function wfSpecialImport( $page = '' ) {
$wgOut->addWikiMsg( "importstart" );
$importer = new WikiImporter( $source );
- if( !is_null( $namespace ) ) {
- $importer->setTargetNamespace( $namespace );
+ if( !is_null( $this->namespace ) ) {
+ $importer->setTargetNamespace( $this->namespace );
}
- $reporter = new ImportReporter( $importer, $isUpload, $interwiki );
+ $reporter = new ImportReporter( $importer, $isUpload, $this->interwiki , $this->logcomment);
$reporter->open();
$result = $importer->doImport();
@@ -99,79 +126,121 @@ function wfSpecialImport( $page = '' ) {
}
}
- $action = $wgTitle->getLocalUrl( 'action=submit' );
-
- if( $wgUser->isAllowed( 'importupload' ) ) {
- $wgOut->addWikiMsg( "importtext" );
- $wgOut->addHTML(
- Xml::openElement( 'fieldset' ).
- Xml::element( 'legend', null, wfMsg( 'import-upload' ) ) .
- Xml::openElement( 'form', array( 'enctype' => 'multipart/form-data', 'method' => 'post', 'action' => $action ) ) .
- Xml::hidden( 'action', 'submit' ) .
- Xml::hidden( 'source', 'upload' ) .
- Xml::input( 'xmlimport', 50, '', array( 'type' => 'file' ) ) . ' ' .
- Xml::hidden( 'editToken', $wgUser->editToken() ) .
- Xml::submitButton( wfMsg( 'uploadbtn' ) ) .
- Xml::closeElement( 'form' ) .
- Xml::closeElement( 'fieldset' )
- );
- } else {
- if( empty( $wgImportSources ) ) {
- $wgOut->addWikiMsg( 'importnosources' );
+ private function showForm() {
+ global $wgUser, $wgOut, $wgRequest, $wgTitle, $wgImportSources;
+ # FIXME: Quick hack to disable import for non privileged users /Raymond
+ # Regression from 43963
+ if( !$wgUser->isAllowed( 'import' ) && !$wgUser->isAllowed( 'importupload' ) )
+ return $wgOut->permissionRequired( 'import' );
+
+ $action = $wgTitle->getLocalUrl( 'action=submit' );
+
+ if( $wgUser->isAllowed( 'importupload' ) ) {
+ $wgOut->addWikiMsg( "importtext" );
+ $wgOut->addHTML(
+ Xml::openElement( 'fieldset' ).
+ Xml::element( 'legend', null, wfMsg( 'import-upload' ) ) .
+ Xml::openElement( 'form', array( 'enctype' => 'multipart/form-data', 'method' => 'post', 'action' => $action ) ) .
+ Xml::hidden( 'action', 'submit' ) .
+ Xml::hidden( 'source', 'upload' ) .
+ Xml::openElement( 'table', array( 'id' => 'mw-import-table' ) ) .
+
+ "<tr>
+ <td class='mw-label'>" .
+ Xml::label( wfMsg( 'import-upload-filename' ), 'xmlimport' ) .
+ "</td>
+ <td class='mw-input'>" .
+ Xml::input( 'xmlimport', 50, '', array( 'type' => 'file' ) ) . ' ' .
+ "</td>
+ </tr>
+ <tr>
+ <td class='mw-label'>" .
+ Xml::label( wfMsg( 'import-comment' ), 'mw-import-comment' ) .
+ "</td>
+ <td class='mw-input'>" .
+ Xml::input( 'log-comment', 50, '',
+ array( 'id' => 'mw-import-comment', 'type' => 'text' ) ) . ' ' .
+ "</td>
+ </tr>
+ <tr>
+ <td></td>
+ <td class='mw-input'>" .
+ Xml::submitButton( wfMsg( 'uploadbtn' ) ) .
+ "</td>
+ </tr>" .
+ Xml::closeElement( 'table' ).
+ Xml::hidden( 'editToken', $wgUser->editToken() ) .
+ Xml::closeElement( 'form' ) .
+ Xml::closeElement( 'fieldset' )
+ );
+ } else {
+ if( empty( $wgImportSources ) ) {
+ $wgOut->addWikiMsg( 'importnosources' );
+ }
}
- }
- if( !empty( $wgImportSources ) ) {
- $wgOut->addHTML(
- Xml::openElement( 'fieldset' ) .
- Xml::element( 'legend', null, wfMsg( 'importinterwiki' ) ) .
- Xml::openElement( 'form', array( 'method' => 'post', 'action' => $action ) ) .
- wfMsgExt( 'import-interwiki-text', array( 'parse' ) ) .
- Xml::hidden( 'action', 'submit' ) .
- Xml::hidden( 'source', 'interwiki' ) .
- Xml::hidden( 'editToken', $wgUser->editToken() ) .
- Xml::openElement( 'table', array( 'id' => 'mw-import-table' ) ) .
- "<tr>
- <td>" .
- Xml::openElement( 'select', array( 'name' => 'interwiki' ) )
- );
- foreach( $wgImportSources as $prefix ) {
- $selected = ( $interwiki === $prefix ) ? ' selected="selected"' : '';
- $wgOut->addHTML( Xml::option( $prefix, $prefix, $selected ) );
+ if( $wgUser->isAllowed( 'import' ) && !empty( $wgImportSources ) ) {
+ $wgOut->addHTML(
+ Xml::openElement( 'fieldset' ) .
+ Xml::element( 'legend', null, wfMsg( 'importinterwiki' ) ) .
+ Xml::openElement( 'form', array( 'method' => 'post', 'action' => $action ) ) .
+ wfMsgExt( 'import-interwiki-text', array( 'parse' ) ) .
+ Xml::hidden( 'action', 'submit' ) .
+ Xml::hidden( 'source', 'interwiki' ) .
+ Xml::hidden( 'editToken', $wgUser->editToken() ) .
+ Xml::openElement( 'table', array( 'id' => 'mw-import-table' ) ) .
+ "<tr>
+ <td class='mw-label'>" .
+ Xml::label( wfMsg( 'import-interwiki-source' ), 'interwiki' ) .
+ "</td>
+ <td class='mw-input'>" .
+ Xml::openElement( 'select', array( 'name' => 'interwiki' ) )
+ );
+ foreach( $wgImportSources as $prefix ) {
+ $selected = ( $this->interwiki === $prefix ) ? ' selected="selected"' : '';
+ $wgOut->addHTML( Xml::option( $prefix, $prefix, $selected ) );
+ }
+ $wgOut->addHTML(
+ Xml::closeElement( 'select' ) .
+ Xml::input( 'frompage', 50, $this->frompage ) .
+ "</td>
+ </tr>
+ <tr>
+ <td>
+ </td>
+ <td class='mw-input'>" .
+ Xml::checkLabel( wfMsg( 'import-interwiki-history' ), 'interwikiHistory', 'interwikiHistory', $this->history ) .
+ "</td>
+ </tr>
+ <tr>
+ <td>" .
+ Xml::label( wfMsg( 'import-interwiki-namespace' ), 'namespace' ) .
+ "</td>
+ <td class='mw-input'>" .
+ Xml::namespaceSelector( $this->namespace, '' ) .
+ "</td>
+ </tr>
+ <tr>
+ <td class='mw-label'>" .
+ Xml::label( wfMsg( 'import-comment' ), 'mw-interwiki-comment' ) .
+ "</td>
+ <td class='mw-input'>" .
+ Xml::input( 'log-comment', 50, '',
+ array( 'id' => 'mw-interwiki-comment', 'type' => 'text' ) ) . ' ' .
+ "</td>
+ </tr>
+ <tr>
+ <td>
+ </td>
+ <td class='mw-input'>" .
+ Xml::submitButton( wfMsg( 'import-interwiki-submit' ), array( 'accesskey' => 's' ) ) .
+ "</td>
+ </tr>" .
+ Xml::closeElement( 'table' ).
+ Xml::closeElement( 'form' ) .
+ Xml::closeElement( 'fieldset' )
+ );
}
- $wgOut->addHTML(
- Xml::closeElement( 'select' ) .
- "</td>
- <td>" .
- Xml::input( 'frompage', 50, $frompage ) .
- "</td>
- </tr>
- <tr>
- <td>
- </td>
- <td>" .
- Xml::checkLabel( wfMsg( 'import-interwiki-history' ), 'interwikiHistory', 'interwikiHistory', $history ) .
- "</td>
- </tr>
- <tr>
- <td>
- </td>
- <td>" .
- Xml::label( wfMsg( 'import-interwiki-namespace' ), 'namespace' ) .
- Xml::namespaceSelector( $namespace, '' ) .
- "</td>
- </tr>
- <tr>
- <td>
- </td>
- <td>" .
- Xml::submitButton( wfMsg( 'import-interwiki-submit' ) ) .
- "</td>
- </tr>" .
- Xml::closeElement( 'table' ).
- Xml::closeElement( 'form' ) .
- Xml::closeElement( 'fieldset' )
- );
}
}
@@ -180,16 +249,19 @@ function wfSpecialImport( $page = '' ) {
* @ingroup SpecialPage
*/
class ImportReporter {
- function __construct( $importer, $upload, $interwiki ) {
+ private $reason=false;
+
+ function __construct( $importer, $upload, $interwiki , $reason=false ) {
$importer->setPageOutCallback( array( $this, 'reportPage' ) );
$this->mPageCount = 0;
$this->mIsUpload = $upload;
$this->mInterwiki = $interwiki;
+ $this->reason = $reason;
}
function open() {
global $wgOut;
- $wgOut->addHtml( "<ul>\n" );
+ $wgOut->addHTML( "<ul>\n" );
}
function reportPage( $title, $origTitle, $revisionCount, $successCount ) {
@@ -203,7 +275,7 @@ class ImportReporter {
$contentCount = $wgContLang->formatNum( $successCount );
if( $successCount > 0 ) {
- $wgOut->addHtml( "<li>" . $skin->makeKnownLinkObj( $title ) . " " .
+ $wgOut->addHTML( "<li>" . $skin->makeKnownLinkObj( $title ) . " " .
wfMsgExt( 'import-revision-count', array( 'parsemag', 'escape' ), $localCount ) .
"</li>\n"
);
@@ -212,949 +284,43 @@ class ImportReporter {
if( $this->mIsUpload ) {
$detail = wfMsgExt( 'import-logentry-upload-detail', array( 'content', 'parsemag' ),
$contentCount );
+ if ( $this->reason ) {
+ $detail .= wfMsgForContent( 'colon-separator' ) . $this->reason;
+ }
$log->addEntry( 'upload', $title, $detail );
} else {
$interwiki = '[[:' . $this->mInterwiki . ':' .
$origTitle->getPrefixedText() . ']]';
$detail = wfMsgExt( 'import-logentry-interwiki-detail', array( 'content', 'parsemag' ),
$contentCount, $interwiki );
+ if ( $this->reason ) {
+ $detail .= wfMsgForContent( 'colon-separator' ) . $this->reason;
+ }
$log->addEntry( 'interwiki', $title, $detail );
}
$comment = $detail; // quick
$dbw = wfGetDB( DB_MASTER );
+ $latest = $title->getLatestRevID();
$nullRevision = Revision::newNullRevision( $dbw, $title->getArticleId(), $comment, true );
$nullRevision->insertOn( $dbw );
$article = new Article( $title );
# Update page record
$article->updateRevisionOn( $dbw, $nullRevision );
- wfRunHooks( 'NewRevisionFromEditComplete', array($article, $nullRevision, false) );
+ wfRunHooks( 'NewRevisionFromEditComplete', array($article, $nullRevision, $latest, $wgUser) );
} else {
- $wgOut->addHtml( '<li>' . wfMsgHtml( 'import-nonewrevisions' ) . '</li>' );
+ $wgOut->addHTML( '<li>' . wfMsgHtml( 'import-nonewrevisions' ) . '</li>' );
}
}
function close() {
global $wgOut;
if( $this->mPageCount == 0 ) {
- $wgOut->addHtml( "</ul>\n" );
+ $wgOut->addHTML( "</ul>\n" );
return new WikiErrorMsg( "importnopages" );
}
- $wgOut->addHtml( "</ul>\n" );
+ $wgOut->addHTML( "</ul>\n" );
return $this->mPageCount;
}
}
-
-/**
- *
- * @ingroup SpecialPage
- */
-class WikiRevision {
- var $title = null;
- var $id = 0;
- var $timestamp = "20010115000000";
- var $user = 0;
- var $user_text = "";
- var $text = "";
- var $comment = "";
- var $minor = false;
-
- function setTitle( $title ) {
- if( is_object( $title ) ) {
- $this->title = $title;
- } elseif( is_null( $title ) ) {
- throw new MWException( "WikiRevision given a null title in import. You may need to adjust \$wgLegalTitleChars." );
- } else {
- throw new MWException( "WikiRevision given non-object title in import." );
- }
- }
-
- function setID( $id ) {
- $this->id = $id;
- }
-
- function setTimestamp( $ts ) {
- # 2003-08-05T18:30:02Z
- $this->timestamp = wfTimestamp( TS_MW, $ts );
- }
-
- function setUsername( $user ) {
- $this->user_text = $user;
- }
-
- function setUserIP( $ip ) {
- $this->user_text = $ip;
- }
-
- function setText( $text ) {
- $this->text = $text;
- }
-
- function setComment( $text ) {
- $this->comment = $text;
- }
-
- function setMinor( $minor ) {
- $this->minor = (bool)$minor;
- }
-
- function setSrc( $src ) {
- $this->src = $src;
- }
-
- function setFilename( $filename ) {
- $this->filename = $filename;
- }
-
- function setSize( $size ) {
- $this->size = intval( $size );
- }
-
- function getTitle() {
- return $this->title;
- }
-
- function getID() {
- return $this->id;
- }
-
- function getTimestamp() {
- return $this->timestamp;
- }
-
- function getUser() {
- return $this->user_text;
- }
-
- function getText() {
- return $this->text;
- }
-
- function getComment() {
- return $this->comment;
- }
-
- function getMinor() {
- return $this->minor;
- }
-
- function getSrc() {
- return $this->src;
- }
-
- function getFilename() {
- return $this->filename;
- }
-
- function getSize() {
- return $this->size;
- }
-
- function importOldRevision() {
- $dbw = wfGetDB( DB_MASTER );
-
- # Sneak a single revision into place
- $user = User::newFromName( $this->getUser() );
- if( $user ) {
- $userId = intval( $user->getId() );
- $userText = $user->getName();
- } else {
- $userId = 0;
- $userText = $this->getUser();
- }
-
- // avoid memory leak...?
- $linkCache = LinkCache::singleton();
- $linkCache->clear();
-
- $article = new Article( $this->title );
- $pageId = $article->getId();
- if( $pageId == 0 ) {
- # must create the page...
- $pageId = $article->insertOn( $dbw );
- $created = true;
- } else {
- $created = false;
-
- $prior = Revision::loadFromTimestamp( $dbw, $this->title, $this->timestamp );
- if( !is_null( $prior ) ) {
- // FIXME: this could fail slightly for multiple matches :P
- wfDebug( __METHOD__ . ": skipping existing revision for [[" .
- $this->title->getPrefixedText() . "]], timestamp " .
- $this->timestamp . "\n" );
- return false;
- }
- }
-
- # FIXME: Use original rev_id optionally
- # FIXME: blah blah blah
-
- #if( $numrows > 0 ) {
- # return wfMsg( "importhistoryconflict" );
- #}
-
- # Insert the row
- $revision = new Revision( array(
- 'page' => $pageId,
- 'text' => $this->getText(),
- 'comment' => $this->getComment(),
- 'user' => $userId,
- 'user_text' => $userText,
- 'timestamp' => $this->timestamp,
- 'minor_edit' => $this->minor,
- ) );
- $revId = $revision->insertOn( $dbw );
- $changed = $article->updateIfNewerOn( $dbw, $revision );
-
- if( $created ) {
- wfDebug( __METHOD__ . ": running onArticleCreate\n" );
- Article::onArticleCreate( $this->title );
-
- wfDebug( __METHOD__ . ": running create updates\n" );
- $article->createUpdates( $revision );
-
- } elseif( $changed ) {
- wfDebug( __METHOD__ . ": running onArticleEdit\n" );
- Article::onArticleEdit( $this->title );
-
- wfDebug( __METHOD__ . ": running edit updates\n" );
- $article->editUpdates(
- $this->getText(),
- $this->getComment(),
- $this->minor,
- $this->timestamp,
- $revId );
- }
-
- return true;
- }
-
- function importUpload() {
- wfDebug( __METHOD__ . ": STUB\n" );
-
- /**
- // from file revert...
- $source = $this->file->getArchiveVirtualUrl( $this->oldimage );
- $comment = $wgRequest->getText( 'wpComment' );
- // TODO: Preserve file properties from database instead of reloading from file
- $status = $this->file->upload( $source, $comment, $comment );
- if( $status->isGood() ) {
- */
-
- /**
- // from file upload...
- $this->mLocalFile = wfLocalFile( $nt );
- $this->mDestName = $this->mLocalFile->getName();
- //....
- $status = $this->mLocalFile->upload( $this->mTempPath, $this->mComment, $pageText,
- File::DELETE_SOURCE, $this->mFileProps );
- if ( !$status->isGood() ) {
- $resultDetails = array( 'internal' => $status->getWikiText() );
- */
-
- // @fixme upload() uses $wgUser, which is wrong here
- // it may also create a page without our desire, also wrong potentially.
- // and, it will record a *current* upload, but we might want an archive version here
-
- $file = wfLocalFile( $this->getTitle() );
- if( !$file ) {
- var_dump( $file );
- wfDebug( "IMPORT: Bad file. :(\n" );
- return false;
- }
-
- $source = $this->downloadSource();
- if( !$source ) {
- wfDebug( "IMPORT: Could not fetch remote file. :(\n" );
- return false;
- }
-
- $status = $file->upload( $source,
- $this->getComment(),
- $this->getComment(), // Initial page, if none present...
- File::DELETE_SOURCE,
- false, // props...
- $this->getTimestamp() );
-
- if( $status->isGood() ) {
- // yay?
- wfDebug( "IMPORT: is ok?\n" );
- return true;
- }
-
- wfDebug( "IMPORT: is bad? " . $status->getXml() . "\n" );
- return false;
-
- }
-
- function downloadSource() {
- global $wgEnableUploads;
- if( !$wgEnableUploads ) {
- return false;
- }
-
- $tempo = tempnam( wfTempDir(), 'download' );
- $f = fopen( $tempo, 'wb' );
- if( !$f ) {
- wfDebug( "IMPORT: couldn't write to temp file $tempo\n" );
- return false;
- }
-
- // @fixme!
- $src = $this->getSrc();
- $data = Http::get( $src );
- if( !$data ) {
- wfDebug( "IMPORT: couldn't fetch source $src\n" );
- fclose( $f );
- unlink( $tempo );
- return false;
- }
-
- fwrite( $f, $data );
- fclose( $f );
-
- return $tempo;
- }
-
-}
-
-/**
- * implements Special:Import
- * @ingroup SpecialPage
- */
-class WikiImporter {
- var $mDebug = false;
- var $mSource = null;
- var $mPageCallback = null;
- var $mPageOutCallback = null;
- var $mRevisionCallback = null;
- var $mUploadCallback = null;
- var $mTargetNamespace = null;
- var $lastfield;
- var $tagStack = array();
-
- function __construct( $source ) {
- $this->setRevisionCallback( array( $this, "importRevision" ) );
- $this->setUploadCallback( array( $this, "importUpload" ) );
- $this->mSource = $source;
- }
-
- function throwXmlError( $err ) {
- $this->debug( "FAILURE: $err" );
- wfDebug( "WikiImporter XML error: $err\n" );
- }
-
- # --------------
-
- function doImport() {
- if( empty( $this->mSource ) ) {
- return new WikiErrorMsg( "importnotext" );
- }
-
- $parser = xml_parser_create( "UTF-8" );
-
- # case folding violates XML standard, turn it off
- xml_parser_set_option( $parser, XML_OPTION_CASE_FOLDING, false );
-
- xml_set_object( $parser, $this );
- xml_set_element_handler( $parser, "in_start", "" );
-
- $offset = 0; // for context extraction on error reporting
- do {
- $chunk = $this->mSource->readChunk();
- if( !xml_parse( $parser, $chunk, $this->mSource->atEnd() ) ) {
- wfDebug( "WikiImporter::doImport encountered XML parsing error\n" );
- return new WikiXmlError( $parser, wfMsgHtml( 'import-parse-failure' ), $chunk, $offset );
- }
- $offset += strlen( $chunk );
- } while( $chunk !== false && !$this->mSource->atEnd() );
- xml_parser_free( $parser );
-
- return true;
- }
-
- function debug( $data ) {
- if( $this->mDebug ) {
- wfDebug( "IMPORT: $data\n" );
- }
- }
-
- function notice( $data ) {
- global $wgCommandLineMode;
- if( $wgCommandLineMode ) {
- print "$data\n";
- } else {
- global $wgOut;
- $wgOut->addHTML( "<li>" . htmlspecialchars( $data ) . "</li>\n" );
- }
- }
-
- /**
- * Set debug mode...
- */
- function setDebug( $debug ) {
- $this->mDebug = $debug;
- }
-
- /**
- * Sets the action to perform as each new page in the stream is reached.
- * @param $callback callback
- * @return callback
- */
- function setPageCallback( $callback ) {
- $previous = $this->mPageCallback;
- $this->mPageCallback = $callback;
- return $previous;
- }
-
- /**
- * Sets the action to perform as each page in the stream is completed.
- * Callback accepts the page title (as a Title object), a second object
- * with the original title form (in case it's been overridden into a
- * local namespace), and a count of revisions.
- *
- * @param $callback callback
- * @return callback
- */
- function setPageOutCallback( $callback ) {
- $previous = $this->mPageOutCallback;
- $this->mPageOutCallback = $callback;
- return $previous;
- }
-
- /**
- * Sets the action to perform as each page revision is reached.
- * @param $callback callback
- * @return callback
- */
- function setRevisionCallback( $callback ) {
- $previous = $this->mRevisionCallback;
- $this->mRevisionCallback = $callback;
- return $previous;
- }
-
- /**
- * Sets the action to perform as each file upload version is reached.
- * @param $callback callback
- * @return callback
- */
- function setUploadCallback( $callback ) {
- $previous = $this->mUploadCallback;
- $this->mUploadCallback = $callback;
- return $previous;
- }
-
- /**
- * Set a target namespace to override the defaults
- */
- function setTargetNamespace( $namespace ) {
- if( is_null( $namespace ) ) {
- // Don't override namespaces
- $this->mTargetNamespace = null;
- } elseif( $namespace >= 0 ) {
- // FIXME: Check for validity
- $this->mTargetNamespace = intval( $namespace );
- } else {
- return false;
- }
- }
-
- /**
- * Default per-revision callback, performs the import.
- * @param $revision WikiRevision
- * @private
- */
- function importRevision( $revision ) {
- $dbw = wfGetDB( DB_MASTER );
- return $dbw->deadlockLoop( array( $revision, 'importOldRevision' ) );
- }
-
- /**
- * Dummy for now...
- */
- function importUpload( $revision ) {
- //$dbw = wfGetDB( DB_MASTER );
- //return $dbw->deadlockLoop( array( $revision, 'importUpload' ) );
- return false;
- }
-
- /**
- * Alternate per-revision callback, for debugging.
- * @param $revision WikiRevision
- * @private
- */
- function debugRevisionHandler( &$revision ) {
- $this->debug( "Got revision:" );
- if( is_object( $revision->title ) ) {
- $this->debug( "-- Title: " . $revision->title->getPrefixedText() );
- } else {
- $this->debug( "-- Title: <invalid>" );
- }
- $this->debug( "-- User: " . $revision->user_text );
- $this->debug( "-- Timestamp: " . $revision->timestamp );
- $this->debug( "-- Comment: " . $revision->comment );
- $this->debug( "-- Text: " . $revision->text );
- }
-
- /**
- * Notify the callback function when a new <page> is reached.
- * @param $title Title
- * @private
- */
- function pageCallback( $title ) {
- if( is_callable( $this->mPageCallback ) ) {
- call_user_func( $this->mPageCallback, $title );
- }
- }
-
- /**
- * Notify the callback function when a </page> is closed.
- * @param $title Title
- * @param $origTitle Title
- * @param $revisionCount int
- * @param $successCount Int: number of revisions for which callback returned true
- * @private
- */
- function pageOutCallback( $title, $origTitle, $revisionCount, $successCount ) {
- if( is_callable( $this->mPageOutCallback ) ) {
- call_user_func( $this->mPageOutCallback, $title, $origTitle,
- $revisionCount, $successCount );
- }
- }
-
-
- # XML parser callbacks from here out -- beware!
- function donothing( $parser, $x, $y="" ) {
- #$this->debug( "donothing" );
- }
-
- function in_start( $parser, $name, $attribs ) {
- $this->debug( "in_start $name" );
- if( $name != "mediawiki" ) {
- return $this->throwXMLerror( "Expected <mediawiki>, got <$name>" );
- }
- xml_set_element_handler( $parser, "in_mediawiki", "out_mediawiki" );
- }
-
- function in_mediawiki( $parser, $name, $attribs ) {
- $this->debug( "in_mediawiki $name" );
- if( $name == 'siteinfo' ) {
- xml_set_element_handler( $parser, "in_siteinfo", "out_siteinfo" );
- } elseif( $name == 'page' ) {
- $this->push( $name );
- $this->workRevisionCount = 0;
- $this->workSuccessCount = 0;
- $this->uploadCount = 0;
- $this->uploadSuccessCount = 0;
- xml_set_element_handler( $parser, "in_page", "out_page" );
- } else {
- return $this->throwXMLerror( "Expected <page>, got <$name>" );
- }
- }
- function out_mediawiki( $parser, $name ) {
- $this->debug( "out_mediawiki $name" );
- if( $name != "mediawiki" ) {
- return $this->throwXMLerror( "Expected </mediawiki>, got </$name>" );
- }
- xml_set_element_handler( $parser, "donothing", "donothing" );
- }
-
-
- function in_siteinfo( $parser, $name, $attribs ) {
- // no-ops for now
- $this->debug( "in_siteinfo $name" );
- switch( $name ) {
- case "sitename":
- case "base":
- case "generator":
- case "case":
- case "namespaces":
- case "namespace":
- break;
- default:
- return $this->throwXMLerror( "Element <$name> not allowed in <siteinfo>." );
- }
- }
-
- function out_siteinfo( $parser, $name ) {
- if( $name == "siteinfo" ) {
- xml_set_element_handler( $parser, "in_mediawiki", "out_mediawiki" );
- }
- }
-
-
- function in_page( $parser, $name, $attribs ) {
- $this->debug( "in_page $name" );
- switch( $name ) {
- case "id":
- case "title":
- case "restrictions":
- $this->appendfield = $name;
- $this->appenddata = "";
- xml_set_element_handler( $parser, "in_nothing", "out_append" );
- xml_set_character_data_handler( $parser, "char_append" );
- break;
- case "revision":
- $this->push( "revision" );
- if( is_object( $this->pageTitle ) ) {
- $this->workRevision = new WikiRevision;
- $this->workRevision->setTitle( $this->pageTitle );
- $this->workRevisionCount++;
- } else {
- // Skipping items due to invalid page title
- $this->workRevision = null;
- }
- xml_set_element_handler( $parser, "in_revision", "out_revision" );
- break;
- case "upload":
- $this->push( "upload" );
- if( is_object( $this->pageTitle ) ) {
- $this->workRevision = new WikiRevision;
- $this->workRevision->setTitle( $this->pageTitle );
- $this->uploadCount++;
- } else {
- // Skipping items due to invalid page title
- $this->workRevision = null;
- }
- xml_set_element_handler( $parser, "in_upload", "out_upload" );
- break;
- default:
- return $this->throwXMLerror( "Element <$name> not allowed in a <page>." );
- }
- }
-
- function out_page( $parser, $name ) {
- $this->debug( "out_page $name" );
- $this->pop();
- if( $name != "page" ) {
- return $this->throwXMLerror( "Expected </page>, got </$name>" );
- }
- xml_set_element_handler( $parser, "in_mediawiki", "out_mediawiki" );
-
- $this->pageOutCallback( $this->pageTitle, $this->origTitle,
- $this->workRevisionCount, $this->workSuccessCount );
-
- $this->workTitle = null;
- $this->workRevision = null;
- $this->workRevisionCount = 0;
- $this->workSuccessCount = 0;
- $this->pageTitle = null;
- $this->origTitle = null;
- }
-
- function in_nothing( $parser, $name, $attribs ) {
- $this->debug( "in_nothing $name" );
- return $this->throwXMLerror( "No child elements allowed here; got <$name>" );
- }
- function char_append( $parser, $data ) {
- $this->debug( "char_append '$data'" );
- $this->appenddata .= $data;
- }
- function out_append( $parser, $name ) {
- $this->debug( "out_append $name" );
- if( $name != $this->appendfield ) {
- return $this->throwXMLerror( "Expected </{$this->appendfield}>, got </$name>" );
- }
-
- switch( $this->appendfield ) {
- case "title":
- $this->workTitle = $this->appenddata;
- $this->origTitle = Title::newFromText( $this->workTitle );
- if( !is_null( $this->mTargetNamespace ) && !is_null( $this->origTitle ) ) {
- $this->pageTitle = Title::makeTitle( $this->mTargetNamespace,
- $this->origTitle->getDBkey() );
- } else {
- $this->pageTitle = Title::newFromText( $this->workTitle );
- }
- if( is_null( $this->pageTitle ) ) {
- // Invalid page title? Ignore the page
- $this->notice( "Skipping invalid page title '$this->workTitle'" );
- } else {
- $this->pageCallback( $this->workTitle );
- }
- break;
- case "id":
- if ( $this->parentTag() == 'revision' ) {
- if( $this->workRevision )
- $this->workRevision->setID( $this->appenddata );
- }
- break;
- case "text":
- if( $this->workRevision )
- $this->workRevision->setText( $this->appenddata );
- break;
- case "username":
- if( $this->workRevision )
- $this->workRevision->setUsername( $this->appenddata );
- break;
- case "ip":
- if( $this->workRevision )
- $this->workRevision->setUserIP( $this->appenddata );
- break;
- case "timestamp":
- if( $this->workRevision )
- $this->workRevision->setTimestamp( $this->appenddata );
- break;
- case "comment":
- if( $this->workRevision )
- $this->workRevision->setComment( $this->appenddata );
- break;
- case "minor":
- if( $this->workRevision )
- $this->workRevision->setMinor( true );
- break;
- case "filename":
- if( $this->workRevision )
- $this->workRevision->setFilename( $this->appenddata );
- break;
- case "src":
- if( $this->workRevision )
- $this->workRevision->setSrc( $this->appenddata );
- break;
- case "size":
- if( $this->workRevision )
- $this->workRevision->setSize( intval( $this->appenddata ) );
- break;
- default:
- $this->debug( "Bad append: {$this->appendfield}" );
- }
- $this->appendfield = "";
- $this->appenddata = "";
-
- $parent = $this->parentTag();
- xml_set_element_handler( $parser, "in_$parent", "out_$parent" );
- xml_set_character_data_handler( $parser, "donothing" );
- }
-
- function in_revision( $parser, $name, $attribs ) {
- $this->debug( "in_revision $name" );
- switch( $name ) {
- case "id":
- case "timestamp":
- case "comment":
- case "minor":
- case "text":
- $this->appendfield = $name;
- xml_set_element_handler( $parser, "in_nothing", "out_append" );
- xml_set_character_data_handler( $parser, "char_append" );
- break;
- case "contributor":
- $this->push( "contributor" );
- xml_set_element_handler( $parser, "in_contributor", "out_contributor" );
- break;
- default:
- return $this->throwXMLerror( "Element <$name> not allowed in a <revision>." );
- }
- }
-
- function out_revision( $parser, $name ) {
- $this->debug( "out_revision $name" );
- $this->pop();
- if( $name != "revision" ) {
- return $this->throwXMLerror( "Expected </revision>, got </$name>" );
- }
- xml_set_element_handler( $parser, "in_page", "out_page" );
-
- if( $this->workRevision ) {
- $ok = call_user_func_array( $this->mRevisionCallback,
- array( $this->workRevision, $this ) );
- if( $ok ) {
- $this->workSuccessCount++;
- }
- }
- }
-
- function in_upload( $parser, $name, $attribs ) {
- $this->debug( "in_upload $name" );
- switch( $name ) {
- case "timestamp":
- case "comment":
- case "text":
- case "filename":
- case "src":
- case "size":
- $this->appendfield = $name;
- xml_set_element_handler( $parser, "in_nothing", "out_append" );
- xml_set_character_data_handler( $parser, "char_append" );
- break;
- case "contributor":
- $this->push( "contributor" );
- xml_set_element_handler( $parser, "in_contributor", "out_contributor" );
- break;
- default:
- return $this->throwXMLerror( "Element <$name> not allowed in an <upload>." );
- }
- }
-
- function out_upload( $parser, $name ) {
- $this->debug( "out_revision $name" );
- $this->pop();
- if( $name != "upload" ) {
- return $this->throwXMLerror( "Expected </upload>, got </$name>" );
- }
- xml_set_element_handler( $parser, "in_page", "out_page" );
-
- if( $this->workRevision ) {
- $ok = call_user_func_array( $this->mUploadCallback,
- array( $this->workRevision, $this ) );
- if( $ok ) {
- $this->workUploadSuccessCount++;
- }
- }
- }
-
- function in_contributor( $parser, $name, $attribs ) {
- $this->debug( "in_contributor $name" );
- switch( $name ) {
- case "username":
- case "ip":
- case "id":
- $this->appendfield = $name;
- xml_set_element_handler( $parser, "in_nothing", "out_append" );
- xml_set_character_data_handler( $parser, "char_append" );
- break;
- default:
- $this->throwXMLerror( "Invalid tag <$name> in <contributor>" );
- }
- }
-
- function out_contributor( $parser, $name ) {
- $this->debug( "out_contributor $name" );
- $this->pop();
- if( $name != "contributor" ) {
- return $this->throwXMLerror( "Expected </contributor>, got </$name>" );
- }
- $parent = $this->parentTag();
- xml_set_element_handler( $parser, "in_$parent", "out_$parent" );
- }
-
- private function push( $name ) {
- array_push( $this->tagStack, $name );
- $this->debug( "PUSH $name" );
- }
-
- private function pop() {
- $name = array_pop( $this->tagStack );
- $this->debug( "POP $name" );
- return $name;
- }
-
- private function parentTag() {
- $name = $this->tagStack[count( $this->tagStack ) - 1];
- $this->debug( "PARENT $name" );
- return $name;
- }
-
-}
-
-/**
- * @todo document (e.g. one-sentence class description).
- * @ingroup SpecialPage
- */
-class ImportStringSource {
- function __construct( $string ) {
- $this->mString = $string;
- $this->mRead = false;
- }
-
- function atEnd() {
- return $this->mRead;
- }
-
- function readChunk() {
- if( $this->atEnd() ) {
- return false;
- } else {
- $this->mRead = true;
- return $this->mString;
- }
- }
-}
-
-/**
- * @todo document (e.g. one-sentence class description).
- * @ingroup SpecialPage
- */
-class ImportStreamSource {
- function __construct( $handle ) {
- $this->mHandle = $handle;
- }
-
- function atEnd() {
- return feof( $this->mHandle );
- }
-
- function readChunk() {
- return fread( $this->mHandle, 32768 );
- }
-
- static function newFromFile( $filename ) {
- $file = @fopen( $filename, 'rt' );
- if( !$file ) {
- return new WikiErrorMsg( "importcantopen" );
- }
- return new ImportStreamSource( $file );
- }
-
- static function newFromUpload( $fieldname = "xmlimport" ) {
- $upload =& $_FILES[$fieldname];
-
- if( !isset( $upload ) || !$upload['name'] ) {
- return new WikiErrorMsg( 'importnofile' );
- }
- if( !empty( $upload['error'] ) ) {
- switch($upload['error']){
- case 1: # The uploaded file exceeds the upload_max_filesize directive in php.ini.
- return new WikiErrorMsg( 'importuploaderrorsize' );
- case 2: # The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.
- return new WikiErrorMsg( 'importuploaderrorsize' );
- case 3: # The uploaded file was only partially uploaded
- return new WikiErrorMsg( 'importuploaderrorpartial' );
- case 6: #Missing a temporary folder. Introduced in PHP 4.3.10 and PHP 5.0.3.
- return new WikiErrorMsg( 'importuploaderrortemp' );
- # case else: # Currently impossible
- }
-
- }
- $fname = $upload['tmp_name'];
- if( is_uploaded_file( $fname ) ) {
- return ImportStreamSource::newFromFile( $fname );
- } else {
- return new WikiErrorMsg( 'importnofile' );
- }
- }
-
- static function newFromURL( $url, $method = 'GET' ) {
- wfDebug( __METHOD__ . ": opening $url\n" );
- # Use the standard HTTP fetch function; it times out
- # quicker and sorts out user-agent problems which might
- # otherwise prevent importing from large sites, such
- # as the Wikimedia cluster, etc.
- $data = Http::request( $method, $url );
- if( $data !== false ) {
- $file = tmpfile();
- fwrite( $file, $data );
- fflush( $file );
- fseek( $file, 0 );
- return new ImportStreamSource( $file );
- } else {
- return new WikiErrorMsg( 'importcantopen' );
- }
- }
-
- public static function newFromInterwiki( $interwiki, $page, $history=false ) {
- if( $page == '' ) {
- return new WikiErrorMsg( 'import-noarticle' );
- }
- $link = Title::newFromText( "$interwiki:Special:Export/$page" );
- if( is_null( $link ) || $link->getInterwiki() == '' ) {
- return new WikiErrorMsg( 'importbadinterwiki' );
- } else {
- $params = $history ? 'history=1' : '';
- $url = $link->getFullUrl( $params );
- # For interwikis, use POST to avoid redirects.
- return ImportStreamSource::newFromURL( $url, "POST" );
- }
- }
-}
diff --git a/includes/specials/SpecialIpblocklist.php b/includes/specials/SpecialIpblocklist.php
index 696c7efe..8d573547 100644
--- a/includes/specials/SpecialIpblocklist.php
+++ b/includes/specials/SpecialIpblocklist.php
@@ -10,7 +10,7 @@
function wfSpecialIpblocklist() {
global $wgUser, $wgOut, $wgRequest;
- $ip = $wgRequest->getVal( 'wpUnblockAddress', $wgRequest->getVal( 'ip' ) );
+ $ip = trim( $wgRequest->getVal( 'wpUnblockAddress', $wgRequest->getVal( 'ip' ) ) );
$id = $wgRequest->getVal( 'id' );
$reason = $wgRequest->getText( 'wpUnblockReason' );
$action = $wgRequest->getText( 'action' );
@@ -71,9 +71,13 @@ class IPUnblockForm {
var $ip, $reason, $id;
function IPUnblockForm( $ip, $id, $reason ) {
+ global $wgRequest;
$this->ip = strtr( $ip, '_', ' ' );
$this->id = $id;
$this->reason = $reason;
+ $this->hideuserblocks = $wgRequest->getBool( 'hideuserblocks' );
+ $this->hidetempblocks = $wgRequest->getBool( 'hidetempblocks' );
+ $this->hideaddressblocks = $wgRequest->getBool( 'hideaddressblocks' );
}
/**
@@ -158,8 +162,7 @@ class IPUnblockForm {
* @return array array(message key, parameters) on failure, empty array on success
*/
- static function doUnblock(&$id, &$ip, &$reason, &$range = null)
- {
+ static function doUnblock(&$id, &$ip, &$reason, &$range = null) {
if ( $id ) {
$block = Block::newFromID( $id );
if ( !$block ) {
@@ -241,10 +244,27 @@ class IPUnblockForm {
// No extra conditions
} elseif ( substr( $this->ip, 0, 1 ) == '#' ) {
$conds['ipb_id'] = substr( $this->ip, 1 );
- } elseif ( IP::toUnsigned( $this->ip ) !== false ) {
- $conds['ipb_address'] = $this->ip;
+ // Single IPs
+ } elseif ( IP::isIPAddress($this->ip) && strpos($this->ip,'/') === false ) {
+ if( $iaddr = IP::toHex($this->ip) ) {
+ # Only scan ranges which start in this /16, this improves search speed
+ # Blocks should not cross a /16 boundary.
+ $range = substr( $iaddr, 0, 4 );
+ // Fixme -- encapsulate this sort of query-building.
+ $dbr = wfGetDB( DB_SLAVE );
+ $encIp = $dbr->addQuotes( IP::sanitizeIP($this->ip) );
+ $encRange = $dbr->addQuotes( "$range%" );
+ $encAddr = $dbr->addQuotes( $iaddr );
+ $conds[] = "(ipb_address = $encIp) OR
+ (ipb_range_start LIKE $encRange AND
+ ipb_range_start <= $encAddr
+ AND ipb_range_end >= $encAddr)";
+ } else {
+ $conds['ipb_address'] = IP::sanitizeIP($this->ip);
+ }
$conds['ipb_auto'] = 0;
- } elseif( preg_match( '/^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\\/(\\d{1,2})$/', $this->ip, $matches ) ) {
+ // IP range
+ } elseif ( IP::isIPAddress($this->ip) ) {
$conds['ipb_address'] = Block::normaliseRange( $this->ip );
$conds['ipb_auto'] = 0;
} else {
@@ -257,6 +277,16 @@ class IPUnblockForm {
$conds['ipb_auto'] = 0;
}
}
+ // Apply filters
+ if( $this->hideuserblocks ) {
+ $conds['ipb_user'] = 0;
+ }
+ if( $this->hidetempblocks ) {
+ $conds['ipb_expiry'] = 'infinity';
+ }
+ if( $this->hideaddressblocks ) {
+ $conds[] = "ipb_user != 0 OR ipb_range_end > ipb_range_start";
+ }
$pager = new IPBlocklistPager( $this, $conds );
if ( $pager->getNumRows() ) {
@@ -270,12 +300,38 @@ class IPUnblockForm {
$wgOut->addHTML( $this->searchForm() );
$wgOut->addWikiMsg( 'ipblocklist-no-results' );
} else {
+ $wgOut->addHTML( $this->searchForm() );
$wgOut->addWikiMsg( 'ipblocklist-empty' );
}
}
function searchForm() {
global $wgTitle, $wgScript, $wgRequest;
+
+ $showhide = array( wfMsg( 'show' ), wfMsg( 'hide' ) );
+ $nondefaults = array();
+ if( $this->hideuserblocks ) {
+ $nondefaults['hideuserblocks'] = $this->hideuserblocks;
+ }
+ if( $this->hidetempblocks ) {
+ $nondefaults['hidetempblocks'] = $this->hidetempblocks;
+ }
+ if( $this->hideaddressblocks ) {
+ $nondefaults['hideaddressblocks'] = $this->hideaddressblocks;
+ }
+ $ubLink = $this->makeOptionsLink( $showhide[1-$this->hideuserblocks],
+ array( 'hideuserblocks' => 1-$this->hideuserblocks ), $nondefaults);
+ $tbLink = $this->makeOptionsLink( $showhide[1-$this->hidetempblocks],
+ array( 'hidetempblocks' => 1-$this->hidetempblocks ), $nondefaults);
+ $sipbLink = $this->makeOptionsLink( $showhide[1-$this->hideaddressblocks],
+ array( 'hideaddressblocks' => 1-$this->hideaddressblocks ), $nondefaults);
+
+ $links = array();
+ $links[] = wfMsgHtml( 'ipblocklist-sh-userblocks', $ubLink );
+ $links[] = wfMsgHtml( 'ipblocklist-sh-tempblocks', $tbLink );
+ $links[] = wfMsgHtml( 'ipblocklist-sh-addressblocks', $sipbLink );
+ $hl = implode( ' ' . wfMsg( 'pipe-separator' ) . ' ', $links );
+
return
Xml::tags( 'form', array( 'action' => $wgScript ),
Xml::hidden( 'title', $wgTitle->getPrefixedDbKey() ) .
@@ -283,16 +339,32 @@ class IPUnblockForm {
Xml::element( 'legend', null, wfMsg( 'ipblocklist-legend' ) ) .
Xml::inputLabel( wfMsg( 'ipblocklist-username' ), 'ip', 'ip', /* size */ false, $this->ip ) .
'&nbsp;' .
- Xml::submitButton( wfMsg( 'ipblocklist-submit' ) ) .
+ Xml::submitButton( wfMsg( 'ipblocklist-submit' ) ) . '<br />' .
+ $hl .
Xml::closeElement( 'fieldset' )
);
}
/**
+ * Makes change an option link which carries all the other options
+ * @param $title see Title
+ * @param $override
+ * @param $options
+ */
+ function makeOptionsLink( $title, $override, $options, $active = false ) {
+ global $wgUser;
+ $sk = $wgUser->getSkin();
+ $params = $override + $options;
+ $ipblocklist = SpecialPage::getTitleFor( 'IPBlockList' );
+ return $sk->link( $ipblocklist, htmlspecialchars( $title ),
+ ( $active ? array( 'style'=>'font-weight: bold;' ) : array() ), $params, array( 'known' ) );
+ }
+
+ /**
* Callback function to output a block
*/
function formatRow( $block ) {
- global $wgUser, $wgLang;
+ global $wgUser, $wgLang, $wgBlockAllowsUTEdit;
wfProfileIn( __METHOD__ );
@@ -302,8 +374,8 @@ class IPUnblockForm {
$sk = $wgUser->getSkin();
if( is_null( $msg ) ) {
$msg = array();
- $keys = array( 'infiniteblock', 'expiringblock', 'unblocklink',
- 'anononlyblock', 'createaccountblock', 'noautoblockblock', 'emailblock' );
+ $keys = array( 'infiniteblock', 'expiringblock', 'unblocklink', 'change-blocklink',
+ 'anononlyblock', 'createaccountblock', 'noautoblockblock', 'emailblock', 'blocklist-nousertalk' );
foreach( $keys as $key ) {
$msg[$key] = wfMsgHtml( $key );
}
@@ -341,15 +413,33 @@ class IPUnblockForm {
if ( $block->mBlockEmail && $block->mUser ) {
$properties[] = $msg['emailblock'];
}
+
+ if ( !$block->mAllowUsertalk && $wgBlockAllowsUTEdit ) {
+ $properties[] = $msg['blocklist-nousertalk'];
+ }
$properties = implode( ', ', $properties );
$line = wfMsgReplaceArgs( $msg['blocklistline'], array( $formattedTime, $blocker, $target, $properties ) );
$unblocklink = '';
- if ( $wgUser->isAllowed('block') ) {
- $titleObj = SpecialPage::getTitleFor( "Ipblocklist" );
- $unblocklink = ' (' . $sk->makeKnownLinkObj($titleObj, $msg['unblocklink'], 'action=unblock&id=' . urlencode( $block->mId ) ) . ')';
+ $changeblocklink = '';
+ $toolLinks = '';
+ if ( $wgUser->isAllowed( 'block' ) ) {
+ $unblocklink = $sk->link( SpecialPage::getTitleFor( 'Ipblocklist' ),
+ $msg['unblocklink'],
+ array(),
+ array( 'action' => 'unblock', 'id' => $block->mId ),
+ 'known' );
+
+ # Create changeblocklink for all blocks with exception of autoblocks
+ if( !$block->mAuto ) {
+ $changeblocklink = ' ' . wfMsg( 'pipe-separator' ) . ' ' .
+ $sk->link( SpecialPage::getTitleFor( 'Blockip', $block->mAddress ),
+ $msg['change-blocklink'],
+ array(), array(), 'known' );
+ }
+ $toolLinks = "($unblocklink$changeblocklink)";
}
$comment = $sk->commentBlock( $block->mReason );
@@ -359,7 +449,7 @@ class IPUnblockForm {
$s = '<span class="history-deleted">' . $s . '</span>';
wfProfileOut( __METHOD__ );
- return "<li>$s $unblocklink</li>\n";
+ return "<li>$s $toolLinks</li>\n";
}
}
diff --git a/includes/specials/SpecialLinkSearch.php b/includes/specials/SpecialLinkSearch.php
new file mode 100644
index 00000000..6b9df58f
--- /dev/null
+++ b/includes/specials/SpecialLinkSearch.php
@@ -0,0 +1,185 @@
+<?php
+/**
+ * @file
+ * @ingroup SpecialPage
+ *
+ * @author Brion Vibber
+ * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 2.0 or later
+ */
+
+/**
+ * Special:LinkSearch to search the external-links table.
+ * @ingroup SpecialPage
+ */
+
+function wfSpecialLinkSearch( $par ) {
+
+ list( $limit, $offset ) = wfCheckLimits();
+ global $wgOut, $wgRequest, $wgUrlProtocols, $wgMiserMode;
+ $target = $GLOBALS['wgRequest']->getVal( 'target', $par );
+ $namespace = $GLOBALS['wgRequest']->getIntorNull( 'namespace', null );
+
+ $protocols_list[] = '';
+ foreach( $wgUrlProtocols as $prot ) {
+ $protocols_list[] = $prot;
+ }
+
+ $target2 = $target;
+ $protocol = '';
+ $pr_sl = strpos($target2, '//' );
+ $pr_cl = strpos($target2, ':' );
+ if ( $pr_sl ) {
+ // For protocols with '//'
+ $protocol = substr( $target2, 0 , $pr_sl+2 );
+ $target2 = substr( $target2, $pr_sl+2 );
+ } elseif ( !$pr_sl && $pr_cl ) {
+ // For protocols without '//' like 'mailto:'
+ $protocol = substr( $target2, 0 , $pr_cl+1 );
+ $target2 = substr( $target2, $pr_cl+1 );
+ } elseif ( $protocol == '' && $target2 != '' ) {
+ // default
+ $protocol = 'http://';
+ }
+ if ( !in_array( $protocol, $protocols_list ) ) {
+ // unsupported protocol, show original search request
+ $target2 = $target;
+ $protocol = '';
+ }
+
+ $self = Title::makeTitle( NS_SPECIAL, 'Linksearch' );
+
+ $wgOut->addWikiText( wfMsg( 'linksearch-text', '<nowiki>' . implode( ', ', $wgUrlProtocols) . '</nowiki>' ) );
+ $s = Xml::openElement( 'form', array( 'id' => 'mw-linksearch-form', 'method' => 'get', 'action' => $GLOBALS['wgScript'] ) ) .
+ Xml::hidden( 'title', $self->getPrefixedDbKey() ) .
+ '<fieldset>' .
+ Xml::element( 'legend', array(), wfMsg( 'linksearch' ) ) .
+ Xml::inputLabel( wfMsg( 'linksearch-pat' ), 'target', 'target', 50, $target ) . ' ';
+ if ( !$wgMiserMode ) {
+ $s .= Xml::label( wfMsg( 'linksearch-ns' ), 'namespace' ) . ' ' .
+ XML::namespaceSelector( $namespace, '' );
+ }
+ $s .= Xml::submitButton( wfMsg( 'linksearch-ok' ) ) .
+ '</fieldset>' .
+ Xml::closeElement( 'form' );
+ $wgOut->addHTML( $s );
+
+ if( $target != '' ) {
+ $searcher = new LinkSearchPage;
+ $searcher->setParams( array(
+ 'query' => $target2,
+ 'namespace' => $namespace,
+ 'protocol' => $protocol ) );
+ $searcher->doQuery( $offset, $limit );
+ }
+}
+
+class LinkSearchPage extends QueryPage {
+ function setParams( $params ) {
+ $this->mQuery = $params['query'];
+ $this->mNs = $params['namespace'];
+ $this->mProt = $params['protocol'];
+ }
+
+ function getName() {
+ return 'LinkSearch';
+ }
+
+ /**
+ * Disable RSS/Atom feeds
+ */
+ function isSyndicated() {
+ return false;
+ }
+
+ /**
+ * Return an appropriately formatted LIKE query and the clause
+ */
+ static function mungeQuery( $query , $prot ) {
+ $field = 'el_index';
+ $rv = LinkFilter::makeLike( $query , $prot );
+ if ($rv === false) {
+ //makeLike 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)) {
+ $rv = $prot . rtrim($query, " \t*") . '%';
+ $field = 'el_to';
+ }
+ }
+ return array( $rv, $field );
+ }
+
+ function linkParameters() {
+ global $wgMiserMode;
+ $params = array();
+ $params['target'] = $this->mProt . $this->mQuery;
+ if( isset( $this->mNs ) && !$wgMiserMode ) {
+ $params['namespace'] = $this->mNs;
+ }
+ return $params;
+ }
+
+ function getSQL() {
+ global $wgMiserMode;
+ $dbr = wfGetDB( DB_SLAVE );
+ $page = $dbr->tableName( 'page' );
+ $externallinks = $dbr->tableName( 'externallinks' );
+
+ /* strip everything past first wildcard, so that index-based-only lookup would be done */
+ list( $munged, $clause ) = self::mungeQuery( $this->mQuery, $this->mProt );
+ $stripped = substr($munged,0,strpos($munged,'%')+1);
+ $encSearch = $dbr->addQuotes( $stripped );
+
+ $encSQL = '';
+ if ( isset ($this->mNs) && !$wgMiserMode )
+ $encSQL = 'AND page_namespace=' . $dbr->addQuotes( $this->mNs );
+
+ $use_index = $dbr->useIndexClause( $clause );
+ return
+ "SELECT
+ page_namespace AS namespace,
+ page_title AS title,
+ el_index AS value,
+ el_to AS url
+ FROM
+ $page,
+ $externallinks $use_index
+ WHERE
+ page_id=el_from
+ AND $clause LIKE $encSearch
+ $encSQL";
+ }
+
+ function formatResult( $skin, $result ) {
+ $title = Title::makeTitle( $result->namespace, $result->title );
+ $url = $result->url;
+ $pageLink = $skin->makeKnownLinkObj( $title );
+ $urlLink = $skin->makeExternalLink( $url, $url );
+
+ return wfMsgHtml( 'linksearch-line', $urlLink, $pageLink );
+ }
+
+ /**
+ * Override to check query validity.
+ */
+ function doQuery( $offset, $limit, $shownavigation=true ) {
+ global $wgOut;
+ list( $this->mMungedQuery, $clause ) = LinkSearchPage::mungeQuery( $this->mQuery, $this->mProt );
+ if( $this->mMungedQuery === false ) {
+ $wgOut->addWikiText( wfMsg( 'linksearch-error' ) );
+ } else {
+ // For debugging
+ // Generates invalid xhtml with patterns that contain --
+ //$wgOut->addHTML( "\n<!-- " . htmlspecialchars( $this->mMungedQuery ) . " -->\n" );
+ parent::doQuery( $offset, $limit, $shownavigation );
+ }
+ }
+
+ /**
+ * Override to squash the ORDER BY.
+ * We do a truncated index search, so the optimizer won't trust
+ * it as good enough for optimizing sort. The implicit ordering
+ * from the scan will usually do well enough for our needs.
+ */
+ function getOrder() {
+ return '';
+ }
+}
diff --git a/includes/specials/SpecialListUserRestrictions.php b/includes/specials/SpecialListUserRestrictions.php
new file mode 100644
index 00000000..27b24298
--- /dev/null
+++ b/includes/specials/SpecialListUserRestrictions.php
@@ -0,0 +1,161 @@
+<?php
+
+function wfSpecialListUserRestrictions() {
+ global $wgOut, $wgRequest;
+
+ $wgOut->addWikiMsg( 'listuserrestrictions-intro' );
+ $f = new SpecialListUserRestrictionsForm();
+ $wgOut->addHTML( $f->getHTML() );
+
+ if( !mt_rand( 0, 10 ) )
+ UserRestriction::purgeExpired();
+ $pager = new UserRestrictionsPager( $f->getConds() );
+ if( $pager->getNumRows() )
+ $wgOut->addHTML( $pager->getNavigationBar() .
+ Xml::tags( 'ul', null, $pager->getBody() ) .
+ $pager->getNavigationBar()
+ );
+ elseif( $f->getConds() )
+ $wgOut->addWikiMsg( 'listuserrestrictions-notfound' );
+ else
+ $wgOut->addWikiMsg( 'listuserrestrictions-empty' );
+}
+
+class SpecialListUserRestrictionsForm {
+ public function getHTML() {
+ global $wgRequest, $wgScript, $wgTitle;
+ $s = '';
+ $s .= Xml::fieldset( wfMsg( 'listuserrestrictions-legend' ) );
+ $s .= "<form action=\"{$wgScript}\">";
+ $s .= Xml::hidden( 'title', $wgTitle->getPrefixedDbKey() );
+ $s .= Xml::label( wfMsgHtml( 'listuserrestrictions-type' ), 'type' ) . '&nbsp;' .
+ self::typeSelector( 'type', $wgRequest->getVal( 'type' ), 'type' );
+ $s .= '&nbsp;';
+ $s .= Xml::inputLabel( wfMsgHtml( 'listuserrestrictions-user' ), 'user', 'user',
+ false, $wgRequest->getVal( 'user' ) );
+ $s .= '<p>';
+ $s .= Xml::label( wfMsgHtml( 'listuserrestrictions-namespace' ), 'namespace' ) . '&nbsp;' .
+ Xml::namespaceSelector( $wgRequest->getVal( 'namespace' ), '', 'namespace' );
+ $s .= '&nbsp;';
+ $s .= Xml::inputLabel( wfMsgHtml( 'listuserrestrictions-page' ), 'page', 'page',
+ false, $wgRequest->getVal( 'page' ) );
+ $s .= Xml::submitButton( wfMsg( 'listuserrestrictions-submit' ) );
+ $s .= "</p></form></fieldset>";
+ return $s;
+ }
+
+ public static function typeSelector( $name = 'type', $value = '', $id = false ) {
+ $s = new XmlSelect( $name, $id, $value );
+ $s->addOption( wfMsg( 'userrestrictiontype-none' ), '' );
+ $s->addOption( wfMsg( 'userrestrictiontype-page' ), UserRestriction::PAGE );
+ $s->addOption( wfMsg( 'userrestrictiontype-namespace' ), UserRestriction::NAMESPACE );
+ return $s->getHTML();
+ }
+
+ public function getConds() {
+ global $wgRequest;
+ $conds = array();
+
+ $type = $wgRequest->getVal( 'type' );
+ if( in_array( $type, array( UserRestriction::PAGE, UserRestriction::NAMESPACE ) ) )
+ $conds['ur_type'] = $type;
+
+ $user = $wgRequest->getVal( 'user' );
+ if( $user )
+ $conds['ur_user_text'] = $user;
+
+ $namespace = $wgRequest->getVal( 'namespace' );
+ if( $namespace || $namespace === '0' )
+ $conds['ur_namespace'] = $namespace;
+
+ $page = $wgRequest->getVal( 'page' );
+ $title = Title::newFromText( $page );
+ if( $title ) {
+ $conds['ur_page_namespace'] = $title->getNamespace();
+ $conds['ur_page_title'] = $title->getDBKey();
+ }
+
+ return $conds;
+ }
+}
+
+class UserRestrictionsPager extends ReverseChronologicalPager {
+ public $mConds;
+
+ public function __construct( $conds = array() ) {
+ $this->mConds = $conds;
+ parent::__construct();
+ }
+
+ public function getStartBody() {
+ # Copied from Special:Ipblocklist
+ wfProfileIn( __METHOD__ );
+ # Do a link batch query
+ $this->mResult->seek( 0 );
+ $lb = new LinkBatch;
+
+ # Faster way
+ # Usernames and titles are in fact related by a simple substitution of space -> underscore
+ # The last few lines of Title::secureAndSplit() tell the story.
+ foreach( $this->mResult as $row ) {
+ $name = str_replace( ' ', '_', $row->ur_by_text );
+ $lb->add( NS_USER, $name );
+ $lb->add( NS_USER_TALK, $name );
+ $name = str_replace( ' ', '_', $row->ur_user_text );
+ $lb->add( NS_USER, $name );
+ $lb->add( NS_USER_TALK, $name );
+ if( $row->ur_type == UserRestriction::PAGE )
+ $lb->add( $row->ur_page_namespace, $row->ur_page_title );
+ }
+ $lb->execute();
+ wfProfileOut( __METHOD__ );
+ return '';
+ }
+
+ public function getQueryInfo() {
+ return array(
+ 'tables' => 'user_restrictions',
+ 'fields' => '*',
+ 'conds' => $this->mConds,
+ );
+ }
+
+ public function formatRow( $row ) {
+ return self::formatRestriction( UserRestriction::newFromRow( $row ) );
+ }
+
+ // Split off for use on Special:RestrictUser
+ public static function formatRestriction( $r ) {
+ global $wgUser, $wgLang;
+ $sk = $wgUser->getSkin();
+ $timestamp = $wgLang->timeanddate( $r->getTimestamp(), true );
+ $blockerlink = $sk->userLink( $r->getBlockerId(), $r->getBlockerText() ) .
+ $sk->userToolLinks( $r->getBlockerId(), $r->getBlockerText() );
+ $subjlink = $sk->userLink( $r->getSubjectId(), $r->getSubjectText() ) .
+ $sk->userToolLinks( $r->getSubjectId(), $r->getSubjectText() );
+ $expiry = is_numeric( $r->getExpiry() ) ?
+ wfMsg( 'listuserrestrictions-row-expiry', $wgLang->timeanddate( $r->getExpiry() ) ) :
+ wfMsg( 'ipbinfinite' );
+ $msg = '';
+ if( $r->isNamespace() ) {
+ $msg = wfMsgHtml( 'listuserrestrictions-row-ns', $subjlink,
+ $wgLang->getDisplayNsText( $r->getNamespace() ), $expiry );
+ }
+ if( $r->isPage() ) {
+ $pagelink = $sk->link( $r->getPage() );
+ $msg = wfMsgHtml( 'listuserrestrictions-row-page', $subjlink,
+ $pagelink, $expiry );
+ }
+ $reason = $sk->commentBlock( $r->getReason() );
+ $removelink = '';
+ if( $wgUser->isAllowed( 'restrict' ) ) {
+ $removelink = '(' . $sk->link( SpecialPage::getTitleFor( 'RemoveRestrictions' ),
+ wfMsgHtml( 'listuserrestrictions-remove' ), array(), array( 'id' => $r->getId() ) ) . ')';
+ }
+ return "<li>{$timestamp}, {$blockerlink} {$msg} {$reason} {$removelink}</li>\n";
+ }
+
+ public function getIndexField() {
+ return 'ur_timestamp';
+ }
+}
diff --git a/includes/specials/SpecialImagelist.php b/includes/specials/SpecialListfiles.php
index 3d449b54..d2178ee0 100644
--- a/includes/specials/SpecialImagelist.php
+++ b/includes/specials/SpecialListfiles.php
@@ -7,7 +7,7 @@
/**
*
*/
-function wfSpecialImagelist() {
+function wfSpecialListfiles() {
global $wgOut;
$pager = new ImageListPager;
@@ -49,13 +49,17 @@ class ImageListPager extends TablePager {
function getFieldNames() {
if ( !$this->mFieldNames ) {
+ global $wgMiserMode;
$this->mFieldNames = array(
- 'img_timestamp' => wfMsg( 'imagelist_date' ),
- 'img_name' => wfMsg( 'imagelist_name' ),
- 'img_user_text' => wfMsg( 'imagelist_user' ),
- 'img_size' => wfMsg( 'imagelist_size' ),
- 'img_description' => wfMsg( 'imagelist_description' ),
+ 'img_timestamp' => wfMsg( 'listfiles_date' ),
+ 'img_name' => wfMsg( 'listfiles_name' ),
+ 'img_user_text' => wfMsg( 'listfiles_user' ),
+ 'img_size' => wfMsg( 'listfiles_size' ),
+ 'img_description' => wfMsg( 'listfiles_description' ),
);
+ if( !$wgMiserMode ) {
+ $this->mFieldNames['COUNT(oi_archive_name)'] = wfMsg( 'listfiles_count' );
+ }
}
return $this->mFieldNames;
}
@@ -66,13 +70,22 @@ class ImageListPager extends TablePager {
}
function getQueryInfo() {
- $fields = $this->getFieldNames();
- $fields = array_keys( $fields );
+ $tables = array( 'image' );
+ $fields = array_keys( $this->getFieldNames() );
$fields[] = 'img_user';
+ $options = $join_conds = array();
+ # Depends on $wgMiserMode
+ if( isset($this->mFieldNames['COUNT(oi_archive_name)']) ) {
+ $tables[] = 'oldimage';
+ $options = array('GROUP BY' => 'img_name');
+ $join_conds = array('oldimage' => array('LEFT JOIN','oi_name = img_name') );
+ }
return array(
- 'tables' => 'image',
- 'fields' => $fields,
- 'conds' => $this->mQueryConds
+ 'tables' => $tables,
+ 'fields' => $fields,
+ 'conds' => $this->mQueryConds,
+ 'options' => $options,
+ 'join_conds' => $join_conds
);
}
@@ -106,7 +119,7 @@ class ImageListPager extends TablePager {
if ( $imgfile === null ) $imgfile = wfMsg( 'imgfile' );
$name = $this->mCurrentRow->img_name;
- $link = $this->getSkin()->makeKnownLinkObj( Title::makeTitle( NS_IMAGE, $name ), $value );
+ $link = $this->getSkin()->makeKnownLinkObj( Title::makeTitle( NS_FILE, $name ), $value );
$image = wfLocalFile( $value );
$url = $image->getURL();
$download = Xml::element('a', array( 'href' => $url ), $imgfile );
@@ -123,6 +136,8 @@ class ImageListPager extends TablePager {
return $this->getSkin()->formatSize( $value );
case 'img_description':
return $this->getSkin()->commentBlock( $value );
+ case 'COUNT(oi_archive_name)':
+ return intval($value)+1;
}
}
@@ -130,14 +145,14 @@ class ImageListPager extends TablePager {
global $wgRequest, $wgMiserMode;
$search = $wgRequest->getText( 'ilsearch' );
- $s = Xml::openElement( 'form', array( 'method' => 'get', 'action' => $this->getTitle()->getLocalURL(), 'id' => 'mw-imagelist-form' ) ) .
+ $s = Xml::openElement( 'form', array( 'method' => 'get', 'action' => $this->getTitle()->getLocalURL(), 'id' => 'mw-listfiles-form' ) ) .
Xml::openElement( 'fieldset' ) .
- Xml::element( 'legend', null, wfMsg( 'imagelist' ) ) .
+ Xml::element( 'legend', null, wfMsg( 'listfiles' ) ) .
Xml::tags( 'label', null, wfMsgHtml( 'table_pager_limit', $this->getLimitSelect() ) );
if ( !$wgMiserMode ) {
$s .= "<br />\n" .
- Xml::inputLabel( wfMsg( 'imagelist_search_for' ), 'ilsearch', 'mw-ilsearch', 20, $search );
+ Xml::inputLabel( wfMsg( 'listfiles_search_for' ), 'ilsearch', 'mw-ilsearch', 20, $search );
}
$s .= ' ' .
Xml::submitButton( wfMsg( 'table_pager_limit_submit' ) ) ."\n" .
@@ -148,14 +163,14 @@ class ImageListPager extends TablePager {
}
function getTableClass() {
- return 'imagelist ' . parent::getTableClass();
+ return 'listfiles ' . parent::getTableClass();
}
function getNavClass() {
- return 'imagelist_nav ' . parent::getNavClass();
+ return 'listfiles_nav ' . parent::getNavClass();
}
function getSortHeaderClass() {
- return 'imagelist_sort ' . parent::getSortHeaderClass();
+ return 'listfiles_sort ' . parent::getSortHeaderClass();
}
}
diff --git a/includes/specials/SpecialListgrouprights.php b/includes/specials/SpecialListgrouprights.php
index 131c0606..5c76df8c 100644
--- a/includes/specials/SpecialListgrouprights.php
+++ b/includes/specials/SpecialListgrouprights.php
@@ -24,7 +24,8 @@ class SpecialListGroupRights extends SpecialPage {
* Show the special page
*/
public function execute( $par ) {
- global $wgOut, $wgGroupPermissions, $wgImplicitGroups, $wgMessageCache;
+ global $wgOut, $wgImplicitGroups, $wgMessageCache;
+ global $wgGroupPermissions, $wgAddGroups, $wgRemoveGroups;
$wgMessageCache->loadAllMessages();
$this->setHeaders();
@@ -69,13 +70,16 @@ class SpecialListGroupRights extends SpecialPage {
$grouplink = '';
}
+ $addgroups = isset( $wgAddGroups[$group] ) ? $wgAddGroups[$group] : array();
+ $removegroups = isset( $wgRemoveGroups[$group] ) ? $wgRemoveGroups[$group] : array();
+
$wgOut->addHTML(
'<tr>
<td>' .
$grouppage . $grouplink .
'</td>
<td>' .
- self::formatPermissions( $permissions ) .
+ self::formatPermissions( $permissions, $addgroups, $removegroups ) .
'</td>
</tr>'
);
@@ -91,18 +95,29 @@ class SpecialListGroupRights extends SpecialPage {
* @param $permissions Array of permission => bool (from $wgGroupPermissions items)
* @return string List of all granted permissions, separated by comma separator
*/
- private static function formatPermissions( $permissions ) {
+ private static function formatPermissions( $permissions, $add, $remove ) {
+ global $wgLang;
$r = array();
foreach( $permissions as $permission => $granted ) {
if ( $granted ) {
- $description = wfMsgHTML( 'listgrouprights-right-display',
- User::getRightDescription($permission),
+ $description = wfMsgExt( 'listgrouprights-right-display', array( 'parseinline' ),
+ User::getRightDescription( $permission ),
$permission
);
$r[] = $description;
}
}
sort( $r );
+ if( $add === true ){
+ $r[] = wfMsgExt( 'listgrouprights-addgroup-all', array( 'escape' ) );
+ } else if( is_array( $add ) && count( $add ) ) {
+ $r[] = wfMsgExt( 'listgrouprights-addgroup', array( 'parseinline' ), $wgLang->listToText( array_map( array( 'User', 'makeGroupLinkWiki' ), $add ) ), count( $add ) );
+ }
+ if( $remove === true ){
+ $r[] = wfMsgExt( 'listgrouprights-removegroup-all', array( 'escape' ) );
+ } else if( is_array( $remove ) && count( $remove ) ) {
+ $r[] = wfMsgExt( 'listgrouprights-removegroup', array( 'parseinline' ), $wgLang->listToText( array_map( array( 'User', 'makeGroupLinkWiki' ), $remove ) ), count( $remove ) );
+ }
if( empty( $r ) ) {
return '';
} else {
diff --git a/includes/specials/SpecialListredirects.php b/includes/specials/SpecialListredirects.php
index 808aab14..9555bd16 100644
--- a/includes/specials/SpecialListredirects.php
+++ b/includes/specials/SpecialListredirects.php
@@ -22,7 +22,8 @@ class ListredirectsPage extends QueryPage {
function getSQL() {
$dbr = wfGetDB( DB_SLAVE );
$page = $dbr->tableName( 'page' );
- $sql = "SELECT 'Listredirects' AS type, page_title AS title, page_namespace AS namespace, 0 AS value FROM $page WHERE page_is_redirect = 1";
+ $sql = "SELECT 'Listredirects' AS type, page_title AS title, page_namespace AS namespace,
+ 0 AS value FROM $page WHERE page_is_redirect = 1";
return( $sql );
}
diff --git a/includes/specials/SpecialListusers.php b/includes/specials/SpecialListusers.php
index 7dba44e2..17bec70e 100644
--- a/includes/specials/SpecialListusers.php
+++ b/includes/specials/SpecialListusers.php
@@ -35,10 +35,25 @@
*/
class UsersPager extends AlphabeticPager {
- function __construct($group=null) {
+ function __construct( $par=null ) {
global $wgRequest;
- $this->requestedGroup = $group != "" ? $group : $wgRequest->getVal( 'group' );
- $un = $wgRequest->getText( 'username' );
+ $parms = explode( '/', ($par = ( $par !== null ) ? $par : '' ) );
+ $symsForAll = array( '*', 'user' );
+ if ( $parms[0] != '' && ( in_array( $par, User::getAllGroups() ) || in_array( $par, $symsForAll ) ) ) {
+ $this->requestedGroup = $par;
+ $un = $wgRequest->getText( 'username' );
+ } else if ( count( $parms ) == 2 ) {
+ $this->requestedGroup = $parms[0];
+ $un = $parms[1];
+ } else {
+ $this->requestedGroup = $wgRequest->getVal( 'group' );
+ $un = ( $par != '' ) ? $par : $wgRequest->getText( 'username' );
+ }
+ if ( in_array( $this->requestedGroup, $symsForAll ) ) {
+ $this->requestedGroup = '';
+ }
+ $this->editsOnly = $wgRequest->getBool( 'editsOnly' );
+
$this->requestedUser = '';
if ( $un != '' ) {
$username = Title::makeTitleSafe( NS_USER, $un );
@@ -56,9 +71,9 @@ class UsersPager extends AlphabeticPager {
function getQueryInfo() {
$dbr = wfGetDB( DB_SLAVE );
- $conds=array();
- // don't show hidden names
- $conds[]='ipb_deleted IS NULL OR ipb_deleted = 0';
+ $conds = array();
+ // Don't show hidden names
+ $conds[] = 'ipb_deleted IS NULL OR ipb_deleted = 0';
if ($this->requestedGroup != "") {
$conds['ug_group'] = $this->requestedGroup;
$useIndex = '';
@@ -68,6 +83,9 @@ class UsersPager extends AlphabeticPager {
if ($this->requestedUser != "") {
$conds[] = 'user_name >= ' . $dbr->addQuotes( $this->requestedUser );
}
+ if( $this->editsOnly ) {
+ $conds[] = 'user_editcount > 0';
+ }
list ($user,$user_groups,$ipblocks) = $dbr->tableNamesN('user','user_groups','ipblocks');
@@ -76,6 +94,7 @@ class UsersPager extends AlphabeticPager {
LEFT JOIN $ipblocks ON user_id=ipb_user AND ipb_auto=0 ",
'fields' => array('user_name',
'MAX(user_id) AS user_id',
+ 'MAX(user_editcount) AS edits',
'COUNT(ug_group) AS numgroups',
'MAX(ug_group) AS singlegroup'),
'options' => array('GROUP BY' => 'user_name'),
@@ -87,6 +106,8 @@ class UsersPager extends AlphabeticPager {
}
function formatRow( $row ) {
+ global $wgLang;
+
$userPage = Title::makeTitle( NS_USER, $row->user_name );
$name = $this->getSkin()->makeLinkObj( $userPage, htmlspecialchars( $userPage->getText() ) );
@@ -102,18 +123,24 @@ class UsersPager extends AlphabeticPager {
}
$item = wfSpecialList( $name, $groups );
+
+ global $wgEdititis;
+ if ( $wgEdititis ) {
+ $editCount = $wgLang->formatNum( $row->edits );
+ $edits = ' [' . wfMsgExt( 'usereditcount', 'parsemag', $editCount ) . ']';
+ } else {
+ $edits = '';
+ }
wfRunHooks( 'SpecialListusersFormatRow', array( &$item, $row ) );
- return "<li>{$item}</li>";
+ return "<li>{$item}{$edits}</li>";
}
function getBody() {
- if (!$this->mQueryDone) {
+ if( !$this->mQueryDone ) {
$this->doQuery();
}
- $batch = new LinkBatch;
-
$this->mResult->rewind();
-
+ $batch = new LinkBatch;
while ( $row = $this->mResult->fetchObject() ) {
$batch->addObj( Title::makeTitleSafe( NS_USER, $row->user_name ) );
}
@@ -142,7 +169,9 @@ class UsersPager extends AlphabeticPager {
Xml::option( wfMsg( 'group-all' ), '' );
foreach( $this->getAllGroups() as $group => $groupText )
$out .= Xml::option( $groupText, $group, $group == $this->requestedGroup );
- $out .= Xml::closeElement( 'select' ) . ' ';
+ $out .= Xml::closeElement( 'select' ) . '<br/>';
+ $out .= Xml::checkLabel( wfMsg('listusers-editsonly'), 'editsOnly', 'editsOnly', $this->editsOnly );
+ $out .= '&nbsp;';
wfRunHooks( 'SpecialListusersHeaderForm', array( $this, &$out ) );
@@ -186,14 +215,8 @@ class UsersPager extends AlphabeticPager {
* @return array
*/
protected static function getGroups( $uid ) {
- $dbr = wfGetDB( DB_SLAVE );
- $groups = array();
- $res = $dbr->select( 'user_groups', 'ug_group', array( 'ug_user' => $uid ), __METHOD__ );
- if( $res && $dbr->numRows( $res ) > 0 ) {
- while( $row = $dbr->fetchObject( $res ) )
- $groups[] = $row->ug_group;
- $dbr->freeResult( $res );
- }
+ $user = User::newFromId( $uid );
+ $groups = array_diff( $user->getEffectiveGroups(), $user->getImplicitGroups() );
return $groups;
}
@@ -222,7 +245,8 @@ function wfSpecialListusers( $par = null ) {
# getBody() first to check, if empty
$usersbody = $up->getBody();
- $s = $up->getPageHeader();
+ $s = XML::openElement( 'div', array('class' => 'mw-spcontent') );
+ $s .= $up->getPageHeader();
if( $usersbody ) {
$s .= $up->getNavigationBar();
$s .= '<ul>' . $usersbody . '</ul>';
@@ -230,6 +254,6 @@ function wfSpecialListusers( $par = null ) {
} else {
$s .= '<p>' . wfMsgHTML('listusers-noresult') . '</p>';
};
-
+ $s .= XML::closeElement( 'div' );
$wgOut->addHTML( $s );
}
diff --git a/includes/specials/SpecialLockdb.php b/includes/specials/SpecialLockdb.php
index 04019223..5859d5b2 100644
--- a/includes/specials/SpecialLockdb.php
+++ b/includes/specials/SpecialLockdb.php
@@ -109,7 +109,7 @@ END
}
fwrite( $fp, $this->reason );
fwrite( $fp, "\n<p>(by " . $wgUser->getName() . " at " .
- $wgLang->timeanddate( wfTimestampNow() ) . ")\n" );
+ $wgLang->timeanddate( wfTimestampNow() ) . ")</p>\n" );
fclose( $fp );
$titleObj = SpecialPage::getTitleFor( 'Lockdb' );
diff --git a/includes/specials/SpecialLog.php b/includes/specials/SpecialLog.php
index 3154ed13..492c2608 100644
--- a/includes/specials/SpecialLog.php
+++ b/includes/specials/SpecialLog.php
@@ -26,10 +26,21 @@
* constructor
*/
function wfSpecialLog( $par = '' ) {
- global $wgRequest, $wgOut, $wgUser;
+ global $wgRequest, $wgOut, $wgUser, $wgLogTypes;
+
# Get parameters
- $type = $wgRequest->getVal( 'type', $par );
- $user = $wgRequest->getText( 'user' );
+ $parms = explode( '/', ($par = ( $par !== null ) ? $par : '' ) );
+ $symsForAll = array( '*', 'all' );
+ if ( $parms[0] != '' && ( in_array( $par, $wgLogTypes ) || in_array( $par, $symsForAll ) ) ) {
+ $type = $par;
+ $user = $wgRequest->getText( 'user' );
+ } else if ( count( $parms ) == 2 ) {
+ $type = $parms[0];
+ $user = $parms[1];
+ } else {
+ $type = $wgRequest->getVal( 'type' );
+ $user = ( $par != '' ) ? $par : $wgRequest->getText( 'user' );
+ }
$title = $wgRequest->getText( 'page' );
$pattern = $wgRequest->getBool( 'pattern' );
$y = $wgRequest->getIntOrNull( 'year' );
@@ -40,15 +51,14 @@ function wfSpecialLog( $par = '' ) {
$y = '';
$m = '';
}
- # Create a LogPager item to get the results and a LogEventsList
- # item to format them...
+ # Create a LogPager item to get the results and a LogEventsList item to format them...
$loglist = new LogEventsList( $wgUser->getSkin(), $wgOut, 0 );
$pager = new LogPager( $loglist, $type, $user, $title, $pattern, array(), $y, $m );
# Set title and add header
$loglist->showHeader( $pager->getType() );
# Show form options
$loglist->showOptions( $pager->getType(), $pager->getUser(), $pager->getPage(), $pager->getPattern(),
- $pager->getYear(), $pager->getMonth() );
+ $pager->getYear(), $pager->getMonth(), $pager->getFilterParams() );
# Insert list
$logBody = $pager->getBody();
if( $logBody ) {
diff --git a/includes/specials/SpecialLonelypages.php b/includes/specials/SpecialLonelypages.php
index 5aafac7d..90da25fd 100644
--- a/includes/specials/SpecialLonelypages.php
+++ b/includes/specials/SpecialLonelypages.php
@@ -29,7 +29,7 @@ class LonelyPagesPage extends PageQueryPage {
function getSQL() {
$dbr = wfGetDB( DB_SLAVE );
- list( $page, $pagelinks ) = $dbr->tableNamesN( 'page', 'pagelinks' );
+ list( $page, $pagelinks, $templatelinks ) = $dbr->tableNamesN( 'page', 'pagelinks', 'templatelinks' );
return
"SELECT 'Lonelypages' AS type,
@@ -39,9 +39,12 @@ class LonelyPagesPage extends PageQueryPage {
FROM $page
LEFT JOIN $pagelinks
ON page_namespace=pl_namespace AND page_title=pl_title
+ LEFT JOIN $templatelinks
+ ON page_namespace=tl_namespace AND page_title=tl_title
WHERE pl_namespace IS NULL
AND page_namespace=".NS_MAIN."
- AND page_is_redirect=0";
+ AND page_is_redirect=0
+ AND tl_namespace IS NULL";
}
}
diff --git a/includes/specials/SpecialMIMEsearch.php b/includes/specials/SpecialMIMEsearch.php
index 82ee4be6..cdfde24e 100644
--- a/includes/specials/SpecialMIMEsearch.php
+++ b/includes/specials/SpecialMIMEsearch.php
@@ -46,7 +46,7 @@ class MIMEsearchPage extends QueryPage {
return
"SELECT 'MIMEsearch' AS type,
- " . NS_IMAGE . " AS namespace,
+ " . NS_FILE . " AS namespace,
img_name AS title,
img_major_mime AS value,
diff --git a/includes/specials/SpecialMergeHistory.php b/includes/specials/SpecialMergeHistory.php
index 0460c207..f870406c 100644
--- a/includes/specials/SpecialMergeHistory.php
+++ b/includes/specials/SpecialMergeHistory.php
@@ -96,8 +96,10 @@ class MergehistoryForm {
wfEscapeWikiText( $this->mDestObj->getPrefixedText() )
);
}
-
- // TODO: warn about target = dest?
+
+ if ( $this->mTargetObj->equals( $this->mDestObj ) ) {
+ $errors[] = wfMsgExt( 'mergehistory-same-destination', array( 'parse' ) );
+ }
if ( count( $errors ) ) {
$this->showMergeForm();
@@ -113,7 +115,7 @@ class MergehistoryForm {
$wgOut->addWikiMsg( 'mergehistory-header' );
- $wgOut->addHtml(
+ $wgOut->addHTML(
Xml::openElement( 'form', array(
'method' => 'get',
'action' => $wgScript ) ) .
@@ -156,7 +158,7 @@ class MergehistoryForm {
$action = $titleObj->getLocalURL( "action=submit" );
# Start the form here
$top = Xml::openElement( 'form', array( 'method' => 'post', 'action' => $action, 'id' => 'merge' ) );
- $wgOut->addHtml( $top );
+ $wgOut->addHTML( $top );
if( $haveRevisions ) {
# Format the user-visible controls (comment field, submission button)
@@ -188,7 +190,7 @@ class MergehistoryForm {
Xml::closeElement( 'table' ) .
Xml::closeElement( 'fieldset' );
- $wgOut->addHtml( $table );
+ $wgOut->addHTML( $table );
}
$wgOut->addHTML( "<h2 id=\"mw-mergehistory\">" . wfMsgHtml( "mergehistory-list" ) . "</h2>\n" );
@@ -215,7 +217,7 @@ class MergehistoryForm {
$misc .= Xml::hidden( 'dest', $this->mDest );
$misc .= Xml::hidden( 'wpEditToken', $wgUser->editToken() );
$misc .= Xml::closeElement( 'form' );
- $wgOut->addHtml( $misc );
+ $wgOut->addHTML( $misc );
return true;
}
@@ -229,7 +231,7 @@ class MergehistoryForm {
$last = $this->message['last'];
$ts = wfTimestamp( TS_MW, $row->rev_timestamp );
- $checkBox = wfRadio( "mergepoint", $ts, false );
+ $checkBox = Xml::radio( "mergepoint", $ts, false );
$pageLink = $this->sk->makeKnownLinkObj( $rev->getTitle(),
htmlspecialchars( $wgLang->timeanddate( $ts ) ), 'oldid=' . $rev->getId() );
@@ -370,7 +372,7 @@ class MergehistoryForm {
$log->addEntry( 'merge', $targetTitle, $this->mComment,
array($destTitle->getPrefixedText(),$TimestampLimit) );
- $wgOut->addHtml( wfMsgExt( 'mergehistory-success', array('parseinline'),
+ $wgOut->addHTML( wfMsgExt( 'mergehistory-success', array('parseinline'),
$targetTitle->getPrefixedText(), $destTitle->getPrefixedText(), $count ) );
wfRunHooks( 'ArticleMergeComplete', array( $targetTitle, $destTitle ) );
@@ -432,10 +434,10 @@ class MergeHistoryPager extends ReverseChronologicalPager {
function getQueryInfo() {
$conds = $this->mConds;
$conds['rev_page'] = $this->articleID;
+ $conds[] = 'page_id = rev_page';
$conds[] = "rev_timestamp < {$this->maxTimestamp}";
-
return array(
- 'tables' => array('revision'),
+ 'tables' => array('revision','page'),
'fields' => array( 'rev_minor_edit', 'rev_timestamp', 'rev_user', 'rev_user_text', 'rev_comment',
'rev_id', 'rev_page', 'rev_text_id', 'rev_len', 'rev_deleted' ),
'conds' => $conds
diff --git a/includes/specials/SpecialMostcategories.php b/includes/specials/SpecialMostcategories.php
index e6810999..1ba05626 100644
--- a/includes/specials/SpecialMostcategories.php
+++ b/includes/specials/SpecialMostcategories.php
@@ -39,9 +39,9 @@ class MostcategoriesPage extends QueryPage {
function formatResult( $skin, $result ) {
global $wgLang;
$title = Title::makeTitleSafe( $result->namespace, $result->title );
- if ( !$title instanceof Title ) { throw new MWException('Invalid title in database'); }
+
$count = wfMsgExt( 'ncategories', array( 'parsemag', 'escape' ), $wgLang->formatNum( $result->value ) );
- $link = $skin->makeKnownLinkObj( $title, $title->getText() );
+ $link = $skin->link( $title );
return wfSpecialList( $link, $count );
}
}
diff --git a/includes/specials/SpecialMostimages.php b/includes/specials/SpecialMostimages.php
index 6cfeb7ad..5cc100ba 100644
--- a/includes/specials/SpecialMostimages.php
+++ b/includes/specials/SpecialMostimages.php
@@ -25,7 +25,7 @@ class MostimagesPage extends ImageQueryPage {
"
SELECT
'Mostimages' as type,
- " . NS_IMAGE . " as namespace,
+ " . NS_FILE . " as namespace,
il_to as title,
COUNT(*) as value
FROM $imagelinks
diff --git a/includes/specials/SpecialMostlinkedtemplates.php b/includes/specials/SpecialMostlinkedtemplates.php
index d597a4e0..2d398a38 100644
--- a/includes/specials/SpecialMostlinkedtemplates.php
+++ b/includes/specials/SpecialMostlinkedtemplates.php
@@ -92,15 +92,12 @@ class SpecialMostlinkedtemplates extends QueryPage {
*/
public function formatResult( $skin, $result ) {
$title = Title::makeTitleSafe( $result->namespace, $result->title );
- if( $title instanceof Title ) {
- return wfSpecialList(
- $skin->makeLinkObj( $title ),
- $this->makeWlhLink( $title, $skin, $result )
- );
- } else {
- $tsafe = htmlspecialchars( $result->title );
- return "Invalid title in result set; {$tsafe}";
- }
+
+ $skin->link( $title );
+ return wfSpecialList(
+ $skin->makeLinkObj( $title ),
+ $this->makeWlhLink( $title, $skin, $result )
+ );
}
/**
@@ -115,8 +112,8 @@ class SpecialMostlinkedtemplates extends QueryPage {
global $wgLang;
$wlh = SpecialPage::getTitleFor( 'Whatlinkshere' );
$label = wfMsgExt( 'nlinks', array( 'parsemag', 'escape' ),
- $wgLang->formatNum( $result->value ) );
- return $skin->makeKnownLinkObj( $wlh, $label, 'target=' . $title->getPrefixedUrl() );
+ $wgLang->formatNum( $result->value ) );
+ return $skin->link( $wlh, $label, array(), array( 'target' => $title->getPrefixedText() ) );
}
}
diff --git a/includes/specials/SpecialMovepage.php b/includes/specials/SpecialMovepage.php
index efd2dcfd..acc27625 100644
--- a/includes/specials/SpecialMovepage.php
+++ b/includes/specials/SpecialMovepage.php
@@ -54,12 +54,13 @@ function wfSpecialMovepage( $par = null ) {
* @ingroup SpecialPage
*/
class MovePageForm {
- var $oldTitle, $newTitle, $reason; # Text input
- var $moveTalk, $deleteAndMove, $moveSubpages, $fixRedirects;
+ var $oldTitle, $newTitle; # Objects
+ var $reason; # Text input
+ var $moveTalk, $deleteAndMove, $moveSubpages, $fixRedirects, $leaveRedirect; # Checks
private $watch = false;
- function MovePageForm( $oldTitle, $newTitle ) {
+ function __construct( $oldTitle, $newTitle ) {
global $wgRequest;
$target = isset($par) ? $par : $wgRequest->getVal( 'target' );
$this->oldTitle = $oldTitle;
@@ -68,48 +69,54 @@ class MovePageForm {
if ( $wgRequest->wasPosted() ) {
$this->moveTalk = $wgRequest->getBool( 'wpMovetalk', false );
$this->fixRedirects = $wgRequest->getBool( 'wpFixRedirects', false );
+ $this->leaveRedirect = $wgRequest->getBool( 'wpLeaveRedirect', false );
} else {
$this->moveTalk = $wgRequest->getBool( 'wpMovetalk', true );
$this->fixRedirects = $wgRequest->getBool( 'wpFixRedirects', true );
+ $this->leaveRedirect = $wgRequest->getBool( 'wpLeaveRedirect', true );
}
$this->moveSubpages = $wgRequest->getBool( 'wpMovesubpages', false );
$this->deleteAndMove = $wgRequest->getBool( 'wpDeleteAndMove' ) && $wgRequest->getBool( 'wpConfirm' );
$this->watch = $wgRequest->getCheck( 'wpWatch' );
}
- function showForm( $err, $hookErr = '' ) {
- global $wgOut, $wgUser;
+ /**
+ * Show the form
+ * @param mixed $err Error message. May either be a string message name or
+ * array message name and parameters, like the second argument to
+ * OutputPage::wrapWikiMsg().
+ */
+ function showForm( $err ) {
+ global $wgOut, $wgUser, $wgFixDoubleRedirects;
$skin = $wgUser->getSkin();
$oldTitleLink = $skin->makeLinkObj( $this->oldTitle );
- $oldTitle = $this->oldTitle->getPrefixedText();
- $wgOut->setPagetitle( wfMsg( 'move-page', $oldTitle ) );
+ $wgOut->setPagetitle( wfMsg( 'move-page', $this->oldTitle->getPrefixedText() ) );
$wgOut->setSubtitle( wfMsg( 'move-page-backlink', $oldTitleLink ) );
- if( $this->newTitle == '' ) {
+ $newTitle = $this->newTitle;
+
+ if( !$newTitle ) {
# Show the current title as a default
# when the form is first opened.
- $newTitle = $oldTitle;
- } else {
- if( $err == '' ) {
- $nt = Title::newFromURL( $this->newTitle );
- if( $nt ) {
- # If a title was supplied, probably from the move log revert
- # link, check for validity. We can then show some diagnostic
- # information and save a click.
- $newerr = $this->oldTitle->isValidMoveOperation( $nt );
- if( is_string( $newerr ) ) {
- $err = $newerr;
- }
+ $newTitle = $this->oldTitle;
+ }
+ else {
+ if( empty($err) ) {
+ # If a title was supplied, probably from the move log revert
+ # link, check for validity. We can then show some diagnostic
+ # information and save a click.
+ $newerr = $this->oldTitle->isValidMoveOperation( $newTitle );
+ if( $newerr ) {
+ $err = $newerr[0];
}
}
- $newTitle = $this->newTitle;
}
- if ( $err == 'articleexists' && $wgUser->isAllowed( 'delete' ) ) {
- $wgOut->addWikiMsg( 'delete_and_move_text', $newTitle );
+ if ( !empty($err) && $err[0] == 'articleexists' && $wgUser->isAllowed( 'delete' ) ) {
+ $wgOut->addWikiMsg( 'delete_and_move_text', $newTitle->getPrefixedText() );
$movepagebtn = wfMsg( 'delete_and_move' );
$submitVar = 'wpDeleteAndMove';
$confirm = "
@@ -131,12 +138,16 @@ class MovePageForm {
$considerTalk = ( !$this->oldTitle->isTalkPage() && $oldTalk->exists() );
$dbr = wfGetDB( DB_SLAVE );
- $hasRedirects = $dbr->selectField( 'redirect', '1',
- array(
- 'rd_namespace' => $this->oldTitle->getNamespace(),
- 'rd_title' => $this->oldTitle->getDBkey(),
- ) , __METHOD__ );
-
+ if ( $wgFixDoubleRedirects ) {
+ $hasRedirects = $dbr->selectField( 'redirect', '1',
+ array(
+ 'rd_namespace' => $this->oldTitle->getNamespace(),
+ 'rd_title' => $this->oldTitle->getDBkey(),
+ ) , __METHOD__ );
+ } else {
+ $hasRedirects = false;
+ }
+
if ( $considerTalk ) {
$wgOut->addWikiMsg( 'movepagetalktext' );
}
@@ -144,9 +155,10 @@ class MovePageForm {
$titleObj = SpecialPage::getTitleFor( 'Movepage' );
$token = htmlspecialchars( $wgUser->editToken() );
- if ( $err != '' ) {
+ if ( !empty($err) ) {
$wgOut->setSubtitle( wfMsg( 'formerror' ) );
- if( $err == 'hookaborted' ) {
+ if( $err[0] == 'hookaborted' ) {
+ $hookErr = $err[1];
$errMsg = "<p><strong class=\"error\">$hookErr</strong></p>\n";
$wgOut->addHTML( $errMsg );
} else {
@@ -172,8 +184,8 @@ class MovePageForm {
Xml::label( wfMsg( 'newtitle' ), 'wpNewTitle' ) .
"</td>
<td class='mw-input'>" .
- Xml::input( 'wpNewTitle', 40, $newTitle, array( 'type' => 'text', 'id' => 'wpNewTitle' ) ) .
- Xml::hidden( 'wpOldTitle', $oldTitle ) .
+ Xml::input( 'wpNewTitle', 40, $newTitle->getPrefixedText(), array( 'type' => 'text', 'id' => 'wpNewTitle' ) ) .
+ Xml::hidden( 'wpOldTitle', $this->oldTitle->getPrefixedText() ) .
"</td>
</tr>
<tr>
@@ -197,6 +209,18 @@ class MovePageForm {
);
}
+ if ( $wgUser->isAllowed( 'suppressredirect' ) ) {
+ $wgOut->addHTML( "
+ <tr>
+ <td></td>
+ <td class='mw-input' >" .
+ Xml::checkLabel( wfMsg( 'move-leave-redirect' ), 'wpLeaveRedirect',
+ 'wpLeaveRedirect', $this->leaveRedirect ) .
+ "</td>
+ </tr>"
+ );
+ }
+
if ( $hasRedirects ) {
$wgOut->addHTML( "
<tr>
@@ -205,7 +229,7 @@ class MovePageForm {
Xml::checkLabel( wfMsg( 'fix-double-redirects' ), 'wpFixRedirects',
'wpFixRedirects', $this->fixRedirects ) .
"</td>
- </td>"
+ </tr>"
);
}
@@ -215,7 +239,7 @@ class MovePageForm {
<tr>
<td></td>
<td class=\"mw-input\">" .
- Xml::checkLabel( wfMsgHtml(
+ Xml::checkLabel( wfMsg(
$this->oldTitle->hasSubpages()
? 'move-subpages'
: 'move-talk-subpages'
@@ -259,6 +283,7 @@ class MovePageForm {
function doSubmit() {
global $wgOut, $wgUser, $wgRequest, $wgMaximumMovedPages, $wgLang;
+ global $wgFixDoubleRedirects;
if ( $wgUser->pingLimiter( 'move' ) ) {
$wgOut->rateLimited();
@@ -280,6 +305,12 @@ class MovePageForm {
return;
}
+ // Delete an associated image if there is
+ $file = wfLocalFile( $nt );
+ if( $file->exists() ) {
+ $file->delete( wfMsgForContent( 'delete_and_move_reason' ), false );
+ }
+
// This may output an error message and exit
$article->doDelete( wfMsgForContent( 'delete_and_move_reason' ) );
}
@@ -290,14 +321,20 @@ class MovePageForm {
return;
}
- $error = $ot->moveTo( $nt, true, $this->reason );
+ if ( $wgUser->isAllowed( 'suppressredirect' ) ) {
+ $createRedirect = $this->leaveRedirect;
+ } else {
+ $createRedirect = true;
+ }
+
+ $error = $ot->moveTo( $nt, true, $this->reason, $createRedirect );
if ( $error !== true ) {
- # FIXME: showForm() should handle multiple errors
- call_user_func_array(array($this, 'showForm'), $error[0]);
+ # FIXME: show all the errors in a list, not just the first one
+ $this->showForm( reset( $error ) );
return;
}
- if ( $this->fixRedirects ) {
+ if ( $wgFixDoubleRedirects && $this->fixRedirects ) {
DoubleRedirectJob::fixRedirects( 'move', $ot, $nt );
}
@@ -312,7 +349,9 @@ class MovePageForm {
$oldLink = "<span class='plainlinks'>[$oldUrl $oldText]</span>";
$newLink = "<span class='plainlinks'>[$newUrl $newText]</span>";
+ $msgName = $createRedirect ? 'movepage-moved-redirect' : 'movepage-moved-noredirect';
$wgOut->addWikiMsg( 'movepage-moved', $oldLink, $newLink, $oldText, $newText );
+ $wgOut->addWikiMsg( $msgName );
# 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
@@ -364,25 +403,26 @@ class MovePageForm {
$conds = null;
}
- $extrapages = array();
+ $extraPages = array();
if( !is_null( $conds ) ) {
- $extrapages = $dbr->select( 'page',
- array( 'page_id', 'page_namespace', 'page_title' ),
- $conds,
- __METHOD__
+ $extraPages = TitleArray::newFromResult(
+ $dbr->select( 'page',
+ array( 'page_id', 'page_namespace', 'page_title' ),
+ $conds,
+ __METHOD__
+ )
);
}
$extraOutput = array();
$skin = $wgUser->getSkin();
$count = 1;
- foreach( $extrapages as $row ) {
- if( $row->page_id == $ot->getArticleId() ) {
+ foreach( $extraPages as $oldSubpage ) {
+ if( $oldSubpage->getArticleId() == $ot->getArticleId() ) {
# Already did this one.
continue;
}
- $oldSubpage = Title::newFromRow( $row );
$newPageName = preg_replace(
'#^'.preg_quote( $ot->getDBKey(), '#' ).'#',
$nt->getDBKey(),
@@ -408,7 +448,7 @@ class MovePageForm {
$link = $skin->makeKnownLinkObj( $newSubpage );
$extraOutput []= wfMsgHtml( 'movepage-page-exists', $link );
} else {
- $success = $oldSubpage->moveTo( $newSubpage, true, $this->reason );
+ $success = $oldSubpage->moveTo( $newSubpage, true, $this->reason, $createRedirect );
if( $success === true ) {
if ( $this->fixRedirects ) {
DoubleRedirectJob::fixRedirects( 'move', $oldSubpage, $newSubpage );
diff --git a/includes/specials/SpecialNewimages.php b/includes/specials/SpecialNewimages.php
index e57f6fc1..575e37a7 100644
--- a/includes/specials/SpecialNewimages.php
+++ b/includes/specials/SpecialNewimages.php
@@ -5,66 +5,56 @@
* FIXME: this code is crap, should use Pager and Database::select().
*/
-/**
- *
- */
function wfSpecialNewimages( $par, $specialPage ) {
- global $wgUser, $wgOut, $wgLang, $wgRequest, $wgGroupPermissions, $wgMiserMode;
+ global $wgUser, $wgOut, $wgLang, $wgRequest, $wgMiserMode;
$wpIlMatch = $wgRequest->getText( 'wpIlMatch' );
$dbr = wfGetDB( DB_SLAVE );
$sk = $wgUser->getSkin();
$shownav = !$specialPage->including();
- $hidebots = $wgRequest->getBool('hidebots',1);
+ $hidebots = $wgRequest->getBool( 'hidebots' , 1 );
$hidebotsql = '';
- if ($hidebots) {
-
- /** Make a list of group names which have the 'bot' flag
- set.
- */
- $botconds=array();
- foreach ($wgGroupPermissions as $groupname=>$perms) {
- if(array_key_exists('bot',$perms) && $perms['bot']) {
- $botconds[]="ug_group='$groupname'";
- }
+ if ( $hidebots ) {
+ # Make a list of group names which have the 'bot' flag set.
+ $botconds = array();
+ foreach ( User::getGroupsWithPermission('bot') as $groupname ) {
+ $botconds[] = 'ug_group = ' . $dbr->addQuotes( $groupname );
}
- /* If not bot groups, do not set $hidebotsql */
- if ($botconds) {
- $isbotmember=$dbr->makeList($botconds, LIST_OR);
-
- /** This join, in conjunction with WHERE ug_group
- IS NULL, returns only those rows from IMAGE
- where the uploading user is not a member of
- a group which has the 'bot' permission set.
- */
- $ug = $dbr->tableName('user_groups');
- $hidebotsql = " LEFT OUTER JOIN $ug ON img_user=ug_user AND ($isbotmember)";
+ # If not bot groups, do not set $hidebotsql
+ if ( $botconds ) {
+ $isbotmember = $dbr->makeList( $botconds, LIST_OR );
+
+ # This join, in conjunction with WHERE ug_group IS NULL, returns
+ # only those rows from IMAGE where the uploading user is not a mem-
+ # ber of a group which has the 'bot' permission set.
+ $ug = $dbr->tableName( 'user_groups' );
+ $hidebotsql = " LEFT JOIN $ug ON img_user=ug_user AND ($isbotmember)";
}
}
- $image = $dbr->tableName('image');
+ $image = $dbr->tableName( 'image' );
- $sql="SELECT img_timestamp from $image";
+ $sql = "SELECT img_timestamp from $image";
if ($hidebotsql) {
$sql .= "$hidebotsql WHERE ug_group IS NULL";
}
- $sql.=' ORDER BY img_timestamp DESC LIMIT 1';
- $res = $dbr->query($sql, 'wfSpecialNewImages');
- $row = $dbr->fetchRow($res);
- if($row!==false) {
- $ts=$row[0];
+ $sql .= ' ORDER BY img_timestamp DESC LIMIT 1';
+ $res = $dbr->query( $sql, __FUNCTION__ );
+ $row = $dbr->fetchRow( $res );
+ if( $row !== false ) {
+ $ts = $row[0];
} else {
- $ts=false;
+ $ts = false;
}
- $dbr->freeResult($res);
- $sql='';
+ $dbr->freeResult( $res );
+ $sql = '';
- /** If we were clever, we'd use this to cache. */
- $latestTimestamp = wfTimestamp( TS_MW, $ts);
+ # If we were clever, we'd use this to cache.
+ $latestTimestamp = wfTimestamp( TS_MW, $ts );
- /** Hardcode this for now. */
+ # Hardcode this for now.
$limit = 48;
if ( $parval = intval( $par ) ) {
@@ -77,10 +67,8 @@ function wfSpecialNewimages( $par, $specialPage ) {
$searchpar = '';
if ( $wpIlMatch != '' && !$wgMiserMode) {
$nt = Title::newFromUrl( $wpIlMatch );
- if($nt ) {
- $m = $dbr->strencode( strtolower( $nt->getDBkey() ) );
- $m = str_replace( '%', "\\%", $m );
- $m = str_replace( '_', "\\_", $m );
+ if( $nt ) {
+ $m = $dbr->escapeLike( strtolower( $nt->getDBkey() ) );
$where[] = "LOWER(img_name) LIKE '%{$m}%'";
$searchpar = '&wpIlMatch=' . urlencode( $wpIlMatch );
}
@@ -97,16 +85,16 @@ function wfSpecialNewimages( $par, $specialPage ) {
$sql='SELECT img_size, img_name, img_user, img_user_text,'.
"img_description,img_timestamp FROM $image";
- if($hidebotsql) {
+ if( $hidebotsql ) {
$sql .= $hidebotsql;
- $where[]='ug_group IS NULL';
+ $where[] = 'ug_group IS NULL';
}
- if(count($where)) {
- $sql.=' WHERE '.$dbr->makeList($where, LIST_AND);
+ if( count( $where ) ) {
+ $sql .= ' WHERE ' . $dbr->makeList( $where, LIST_AND );
}
$sql.=' ORDER BY img_timestamp '. ( $invertSort ? '' : ' DESC' );
- $sql.=' LIMIT '.($limit+1);
- $res = $dbr->query($sql, 'wfSpecialNewImages');
+ $sql.=' LIMIT ' . ( $limit + 1 );
+ $res = $dbr->query( $sql, __FUNCTION__ );
/**
* We have to flip things around to get the last N after a certain date
@@ -126,7 +114,8 @@ function wfSpecialNewimages( $par, $specialPage ) {
$lastTimestamp = null;
$shownImages = 0;
foreach( $images as $s ) {
- if( ++$shownImages > $limit ) {
+ $shownImages++;
+ if( $shownImages > $limit ) {
# One extra just to test for whether to show a page link;
# don't actually show it.
break;
@@ -135,7 +124,7 @@ function wfSpecialNewimages( $par, $specialPage ) {
$name = $s->img_name;
$ut = $s->img_user_text;
- $nt = Title::newFromText( $name, NS_IMAGE );
+ $nt = Title::newFromText( $name, NS_FILE );
$ul = $sk->makeLinkObj( Title::makeTitle( NS_USER, $ut ), $ut );
$gallery->add( $nt, "$ul<br />\n<i>".$wgLang->timeanddate( $s->img_timestamp, true )."</i><br />\n" );
@@ -147,33 +136,35 @@ function wfSpecialNewimages( $par, $specialPage ) {
$lastTimestamp = $timestamp;
}
+ $titleObj = SpecialPage::getTitleFor( 'Newimages' );
+ $action = $titleObj->getLocalURL( $hidebots ? '' : 'hidebots=0' );
+ if ( $shownav && !$wgMiserMode ) {
+ $wgOut->addHTML(
+ Xml::openElement( 'form', array( 'action' => $action, 'method' => 'post', 'id' => 'imagesearch' ) ) .
+ Xml::fieldset( wfMsg( 'newimages-legend' ) ) .
+ Xml::inputLabel( wfMsg( 'newimages-label' ), 'wpIlMatch', 'wpIlMatch', 20, $wpIlMatch ) . ' ' .
+ Xml::submitButton( wfMsg( 'ilsubmit' ), array( 'name' => 'wpIlSubmit' ) ) .
+ Xml::closeElement( 'fieldset' ) .
+ Xml::closeElement( 'form' )
+ );
+ }
+
$bydate = wfMsg( 'bydate' );
$lt = $wgLang->formatNum( min( $shownImages, $limit ) );
- if ($shownav) {
+ if ( $shownav ) {
$text = wfMsgExt( 'imagelisttext', array('parse'), $lt, $bydate );
$wgOut->addHTML( $text . "\n" );
}
- $sub = wfMsg( 'ilsubmit' );
- $titleObj = SpecialPage::getTitleFor( 'Newimages' );
- $action = $titleObj->escapeLocalURL( $hidebots ? '' : 'hidebots=0' );
- if ($shownav && !$wgMiserMode) {
- $wgOut->addHTML( "<form id=\"imagesearch\" method=\"post\" action=\"" .
- "{$action}\">" .
- Xml::input( 'wpIlMatch', 20, $wpIlMatch ) . ' ' .
- Xml::submitButton( $sub, array( 'name' => 'wpIlSubmit' ) ) .
- "</form>" );
- }
-
/**
* Paging controls...
*/
# If we change bot visibility, this needs to be carried along.
- if(!$hidebots) {
- $botpar='&hidebots=0';
+ if( !$hidebots ) {
+ $botpar = '&hidebots=0';
} else {
- $botpar='';
+ $botpar = '';
}
$now = wfTimestampNow();
$d = $wgLang->date( $now, true );
@@ -186,12 +177,12 @@ function wfSpecialNewimages( $par, $specialPage ) {
$opts = array( 'parsemag', 'escapenoentities' );
- $prevLink = wfMsgExt( 'prevn', $opts, $wgLang->formatNum( $limit ) );
+ $prevLink = wfMsgExt( 'pager-newer-n', $opts, $wgLang->formatNum( $limit ) );
if( $firstTimestamp && $firstTimestamp != $latestTimestamp ) {
$prevLink = $sk->makeKnownLinkObj( $titleObj, $prevLink, 'from=' . $firstTimestamp . $botpar . $searchpar );
}
- $nextLink = wfMsgExt( 'nextn', $opts, $wgLang->formatNum( $limit ) );
+ $nextLink = wfMsgExt( 'pager-older-n', $opts, $wgLang->formatNum( $limit ) );
if( $shownImages > $limit && $lastTimestamp ) {
$nextLink = $sk->makeKnownLinkObj( $titleObj, $nextLink, 'until=' . $lastTimestamp.$botpar.$searchpar );
}
diff --git a/includes/specials/SpecialNewpages.php b/includes/specials/SpecialNewpages.php
index 1a410ae0..08e776d8 100644
--- a/includes/specials/SpecialNewpages.php
+++ b/includes/specials/SpecialNewpages.php
@@ -12,7 +12,7 @@ class SpecialNewpages extends SpecialPage {
// Some internal settings
protected $showNavigation = false;
- public function __construct(){
+ public function __construct() {
parent::__construct( 'Newpages' );
$this->includable( true );
}
@@ -26,7 +26,8 @@ class SpecialNewpages extends SpecialPage {
$opts->add( 'hideliu', false );
$opts->add( 'hidepatrolled', false );
$opts->add( 'hidebots', false );
- $opts->add( 'limit', 50 );
+ $opts->add( 'hideredirs', true );
+ $opts->add( 'limit', (int)$wgUser->getOption( 'rclimit' ) );
$opts->add( 'offset', '' );
$opts->add( 'namespace', '0' );
$opts->add( 'username', '' );
@@ -58,6 +59,8 @@ class SpecialNewpages extends SpecialPage {
$this->opts->setValue( 'hidepatrolled', true );
if ( 'hidebots' == $bit )
$this->opts->setValue( 'hidebots', true );
+ if ( 'showredirs' == $bit )
+ $this->opts->setValue( 'hideredirs', false );
if ( is_numeric( $bit ) )
$this->opts->setValue( 'limit', intval( $bit ) );
@@ -67,6 +70,8 @@ class SpecialNewpages extends SpecialPage {
// PG offsets not just digits!
if ( preg_match( '/^offset=([^=]+)$/', $bit, $m ) )
$this->opts->setValue( 'offset', intval($m[1]) );
+ if ( preg_match( '/^username=(.*)$/', $bit, $m ) )
+ $this->opts->setValue( 'username', $m[1] );
if ( preg_match( '/^namespace=(.*)$/', $bit, $m ) ) {
$ns = $wgLang->getNsIndex( $m[1] );
if( $ns !== false ) {
@@ -83,7 +88,7 @@ class SpecialNewpages extends SpecialPage {
* @return string
*/
public function execute( $par ) {
- global $wgLang, $wgGroupPermissions, $wgUser, $wgOut;
+ global $wgLang, $wgUser, $wgOut;
$this->setHeaders();
$this->outputHeader();
@@ -125,7 +130,8 @@ class SpecialNewpages extends SpecialPage {
$filters = array(
'hideliu' => 'rcshowhideliu',
'hidepatrolled' => 'rcshowhidepatr',
- 'hidebots' => 'rcshowhidebots'
+ 'hidebots' => 'rcshowhidebots',
+ 'hideredirs' => 'whatlinkshere-hideredirs'
);
// Disable some if needed
@@ -142,8 +148,8 @@ class SpecialNewpages extends SpecialPage {
$self = $this->getTitle();
foreach ( $filters as $key => $msg ) {
$onoff = 1 - $this->opts->getValue($key);
- $link = $this->skin->makeKnownLinkObj( $self, $showhide[$onoff],
- wfArrayToCGI( array( $key => $onoff ), $changed )
+ $link = $this->skin->link( $self, $showhide[$onoff], array(),
+ array( $key => $onoff ) + $changed
);
$links[$key] = wfMsgHtml( $msg, $link );
}
@@ -231,7 +237,7 @@ class SpecialNewpages extends SpecialPage {
global $wgLang, $wgContLang, $wgUser;
$dm = $wgContLang->getDirMark();
- $title = Title::makeTitleSafe( $result->page_namespace, $result->page_title );
+ $title = Title::makeTitleSafe( $result->rc_namespace, $result->rc_title );
$time = $wgLang->timeAndDate( $result->rc_timestamp, true );
$plink = $this->skin->makeKnownLinkObj( $title, '', $this->patrollable( $result ) ? 'rcid=' . $result->rc_id : '' );
$hist = $this->skin->makeKnownLinkObj( $title, wfMsgHtml( 'hist' ), 'action=history' );
@@ -261,7 +267,7 @@ class SpecialNewpages extends SpecialPage {
* @param string $type
*/
protected function feed( $type ) {
- global $wgFeed, $wgFeedClasses;
+ global $wgFeed, $wgFeedClasses, $wgFeedLimit;
if ( !$wgFeed ) {
global $wgOut;
@@ -277,16 +283,12 @@ class SpecialNewpages extends SpecialPage {
$feed = new $wgFeedClasses[$type](
$this->feedTitle(),
- wfMsg( 'tagline' ),
+ wfMsgExt( 'tagline', 'parsemag' ),
$this->getTitle()->getFullUrl() );
$pager = new NewPagesPager( $this, $this->opts );
$limit = $this->opts->getValue( 'limit' );
- global $wgFeedLimit;
- if( $limit > $wgFeedLimit ) {
- $limit = $wgFeedLimit;
- }
- $pager->mLimit = $limit;
+ $pager->mLimit = min( $limit, $wgFeedLimit );
$feed->outHeader();
if( $pager->getNumRows() > 0 ) {
@@ -305,7 +307,7 @@ class SpecialNewpages extends SpecialPage {
}
protected function feedItem( $row ) {
- $title = Title::MakeTitle( intval( $row->page_namespace ), $row->page_title );
+ $title = Title::MakeTitle( intval( $row->rc_namespace ), $row->rc_title );
if( $title ) {
$date = $row->rc_timestamp;
$comments = $title->getTalkPage()->getFullURL();
@@ -322,13 +324,6 @@ class SpecialNewpages extends SpecialPage {
}
}
- /**
- * Quickie hack... strip out wikilinks to more legible form from the comment.
- */
- protected function stripComment( $text ) {
- return preg_replace( '/\[\[([^]]*\|)?([^]]+)\]\]/', '\2', $text );
- }
-
protected function feedItemAuthor( $row ) {
return isset( $row->rc_user_text ) ? $row->rc_user_text : '';
}
@@ -337,7 +332,7 @@ class SpecialNewpages extends SpecialPage {
$revision = Revision::newFromId( $row->rev_id );
if( $revision ) {
return '<p>' . htmlspecialchars( $revision->getUserText() ) . ': ' .
- htmlspecialchars( $revision->getComment() ) .
+ htmlspecialchars( FeedItem::stripComment( $revision->getComment() ) ) .
"</p>\n<hr />\n<div>" .
nl2br( htmlspecialchars( $revision->getText() ) ) . "</div>";
}
@@ -352,15 +347,13 @@ class NewPagesPager extends ReverseChronologicalPager {
// Stored opts
protected $opts, $mForm;
- private $hideliu, $hidepatrolled, $hidebots, $namespace, $user, $spTitle;
-
function __construct( $form, FormOptions $opts ) {
parent::__construct();
$this->mForm = $form;
$this->opts = $opts;
}
- function getTitle(){
+ function getTitle() {
static $title = null;
if ( $title === null )
$title = $this->mForm->getTitle();
@@ -379,13 +372,13 @@ class NewPagesPager extends ReverseChronologicalPager {
$user = Title::makeTitleSafe( NS_USER, $username );
if( $namespace !== false ) {
- $conds['page_namespace'] = $namespace;
+ $conds['rc_namespace'] = $namespace;
$rcIndexes = array( 'new_name_timestamp' );
} else {
$rcIndexes = array( 'rc_timestamp' );
}
$conds[] = 'page_id = rc_cur_id';
- $conds['page_is_redirect'] = 0;
+
# $wgEnableNewpagesUserFilter - temp WMF hack
if( $wgEnableNewpagesUserFilter && $user ) {
$conds['rc_user_text'] = $user->getText();
@@ -402,9 +395,13 @@ class NewPagesPager extends ReverseChronologicalPager {
$conds['rc_bot'] = 0;
}
+ if ( $this->opts->getValue( 'hideredirs' ) ) {
+ $conds['page_is_redirect'] = 0;
+ }
+
return array(
'tables' => array( 'recentchanges', 'page' ),
- 'fields' => 'page_namespace,page_title, rc_cur_id, rc_user,rc_user_text,rc_comment,
+ 'fields' => 'rc_namespace,rc_title, rc_cur_id, rc_user,rc_user_text,rc_comment,
rc_timestamp,rc_patrolled,rc_id,page_len as length, page_latest as rev_id',
'conds' => $conds,
'options' => array( 'USE INDEX' => array('recentchanges' => $rcIndexes) )
@@ -425,7 +422,7 @@ class NewPagesPager extends ReverseChronologicalPager {
while( $row = $this->mResult->fetchObject() ) {
$linkBatch->add( NS_USER, $row->rc_user_text );
$linkBatch->add( NS_USER_TALK, $row->rc_user_text );
- $linkBatch->add( $row->page_namespace, $row->page_title );
+ $linkBatch->add( $row->rc_namespace, $row->rc_title );
}
$linkBatch->execute();
return "<ul>";
diff --git a/includes/specials/SpecialPreferences.php b/includes/specials/SpecialPreferences.php
index b3468a3c..ca2236ee 100644
--- a/includes/specials/SpecialPreferences.php
+++ b/includes/specials/SpecialPreferences.php
@@ -21,11 +21,11 @@ function wfSpecialPreferences() {
* @ingroup SpecialPage
*/
class PreferencesForm {
- var $mQuickbar, $mOldpass, $mNewpass, $mRetypePass, $mStubs;
+ var $mQuickbar, $mStubs;
var $mRows, $mCols, $mSkin, $mMath, $mDate, $mUserEmail, $mEmailFlag, $mNick;
var $mUserLanguage, $mUserVariant;
- var $mSearch, $mRecent, $mRecentDays, $mHourDiff, $mSearchLines, $mSearchChars, $mAction;
- var $mReset, $mPosted, $mToggles, $mUseAjaxSearch, $mSearchNs, $mRealName, $mImageSize;
+ var $mSearch, $mRecent, $mRecentDays, $mTimeZone, $mHourDiff, $mSearchLines, $mSearchChars, $mAction;
+ var $mReset, $mPosted, $mToggles, $mSearchNs, $mRealName, $mImageSize;
var $mUnderline, $mWatchlistEdits;
/**
@@ -36,13 +36,10 @@ class PreferencesForm {
global $wgContLang, $wgUser, $wgAllowRealName;
$this->mQuickbar = $request->getVal( 'wpQuickbar' );
- $this->mOldpass = $request->getVal( 'wpOldpass' );
- $this->mNewpass = $request->getVal( 'wpNewpass' );
- $this->mRetypePass =$request->getVal( 'wpRetypePass' );
$this->mStubs = $request->getVal( 'wpStubs' );
$this->mRows = $request->getVal( 'wpRows' );
$this->mCols = $request->getVal( 'wpCols' );
- $this->mSkin = $request->getVal( 'wpSkin' );
+ $this->mSkin = Skin::normalizeKey( $request->getVal( 'wpSkin' ) );
$this->mMath = $request->getVal( 'wpMath' );
$this->mDate = $request->getVal( 'wpDate' );
$this->mUserEmail = $request->getVal( 'wpUserEmail' );
@@ -54,6 +51,7 @@ class PreferencesForm {
$this->mSearch = $request->getVal( 'wpSearch' );
$this->mRecent = $request->getVal( 'wpRecent' );
$this->mRecentDays = $request->getVal( 'wpRecentDays' );
+ $this->mTimeZone = $request->getVal( 'wpTimeZone' );
$this->mHourDiff = $request->getVal( 'wpHourDiff' );
$this->mSearchLines = $request->getVal( 'wpSearchLines' );
$this->mSearchChars = $request->getVal( 'wpSearchChars' );
@@ -66,7 +64,6 @@ class PreferencesForm {
$this->mSuccess = $request->getCheck( 'success' );
$this->mWatchlistDays = $request->getVal( 'wpWatchlistDays' );
$this->mWatchlistEdits = $request->getVal( 'wpWatchlistEdits' );
- $this->mUseAjaxSearch = $request->getCheck( 'wpUseAjaxSearch' );
$this->mDisableMWSuggest = $request->getCheck( 'wpDisableMWSuggest' );
$this->mSaveprefs = $request->getCheck( 'wpSaveprefs' ) &&
@@ -105,10 +102,10 @@ class PreferencesForm {
}
function execute() {
- global $wgUser, $wgOut;
+ global $wgUser, $wgOut, $wgTitle;
if ( $wgUser->isAnon() ) {
- $wgOut->showErrorPage( 'prefsnologin', 'prefsnologintext' );
+ $wgOut->showErrorPage( 'prefsnologin', 'prefsnologintext', array($wgTitle->getPrefixedDBkey()) );
return;
}
if ( wfReadOnly() ) {
@@ -174,34 +171,37 @@ class PreferencesForm {
/**
* Used to validate the user inputed timezone before saving it as
- * 'timecorrection', will return '00:00' if fed bogus data.
- * Note: It's not a 100% correct implementation timezone-wise, it will
- * accept stuff like '14:30',
+ * 'timecorrection', will return 'System' if fed bogus data.
* @access private
- * @param string $s the user input
+ * @param string $tz the user input Zoneinfo timezone
+ * @param string $s the user input offset string
* @return string
*/
- function validateTimeZone( $s ) {
- if ( $s !== '' ) {
- if ( strpos( $s, ':' ) ) {
- # HH:MM
- $array = explode( ':' , $s );
- $hour = intval( $array[0] );
- $minute = intval( $array[1] );
- } else {
- $minute = intval( $s * 60 );
- $hour = intval( $minute / 60 );
- $minute = abs( $minute ) % 60;
- }
- # Max is +14:00 and min is -12:00, see:
- # http://en.wikipedia.org/wiki/Timezone
- $hour = min( $hour, 14 );
- $hour = max( $hour, -12 );
- $minute = min( $minute, 59 );
- $minute = max( $minute, 0 );
- $s = sprintf( "%02d:%02d", $hour, $minute );
+ function validateTimeZone( $tz, $s ) {
+ $data = explode( '|', $tz, 3 );
+ switch ( $data[0] ) {
+ case 'ZoneInfo':
+ case 'System':
+ return $tz;
+ case 'Offset':
+ default:
+ $data = explode( ':', $s, 2 );
+ $minDiff = 0;
+ if( count( $data ) == 2 ) {
+ $data[0] = intval( $data[0] );
+ $data[1] = intval( $data[1] );
+ $minDiff = abs( $data[0] ) * 60 + $data[1];
+ if ( $data[0] < 0 ) $minDiff = -$minDiff;
+ } else {
+ $minDiff = intval( $data[0] ) * 60;
+ }
+
+ # Max is +14:00 and min is -12:00, see:
+ # http://en.wikipedia.org/wiki/Timezone
+ $minDiff = min( $minDiff, 840 ); # 14:00
+ $minDiff = max( $minDiff, -720 ); # -12:00
+ return 'Offset|'.$minDiff;
}
- return $s;
}
/**
@@ -213,30 +213,6 @@ class PreferencesForm {
global $wgEmailAuthentication, $wgRCMaxAge;
global $wgAuth, $wgEmailConfirmToEdit;
-
- if ( '' != $this->mNewpass && $wgAuth->allowPasswordChange() ) {
- if ( $this->mNewpass != $this->mRetypePass ) {
- wfRunHooks( 'PrefsPasswordAudit', array( $wgUser, $this->mNewpass, 'badretype' ) );
- $this->mainPrefsForm( 'error', wfMsg( 'badretype' ) );
- return;
- }
-
- if (!$wgUser->checkPassword( $this->mOldpass )) {
- wfRunHooks( 'PrefsPasswordAudit', array( $wgUser, $this->mNewpass, 'wrongpassword' ) );
- $this->mainPrefsForm( 'error', wfMsg( 'wrongpassword' ) );
- return;
- }
-
- try {
- $wgUser->setPassword( $this->mNewpass );
- wfRunHooks( 'PrefsPasswordAudit', array( $wgUser, $this->mNewpass, 'success' ) );
- $this->mNewpass = $this->mOldpass = $this->mRetypePass = '';
- } catch( PasswordError $e ) {
- wfRunHooks( 'PrefsPasswordAudit', array( $wgUser, $this->mNewpass, 'error' ) );
- $this->mainPrefsForm( 'error', $e->getMessage() );
- return;
- }
- }
$wgUser->setRealName( $this->mRealName );
$oldOptions = $wgUser->mOptions;
@@ -269,7 +245,10 @@ class PreferencesForm {
$wgUser->setOption( 'variant', $this->mUserVariant );
$wgUser->setOption( 'nickname', $this->mNick );
$wgUser->setOption( 'quickbar', $this->mQuickbar );
- $wgUser->setOption( 'skin', $this->mSkin );
+ global $wgAllowUserSkin;
+ if( $wgAllowUserSkin ) {
+ $wgUser->setOption( 'skin', $this->mSkin );
+ }
global $wgUseTeX;
if( $wgUseTeX ) {
$wgUser->setOption( 'math', $this->mMath );
@@ -284,12 +263,11 @@ class PreferencesForm {
$wgUser->setOption( 'rows', $this->validateInt( $this->mRows, 4, 1000 ) );
$wgUser->setOption( 'cols', $this->validateInt( $this->mCols, 4, 1000 ) );
$wgUser->setOption( 'stubthreshold', $this->validateIntOrNull( $this->mStubs ) );
- $wgUser->setOption( 'timecorrection', $this->validateTimeZone( $this->mHourDiff, -12, 14 ) );
+ $wgUser->setOption( 'timecorrection', $this->validateTimeZone( $this->mTimeZone, $this->mHourDiff ) );
$wgUser->setOption( 'imagesize', $this->mImageSize );
$wgUser->setOption( 'thumbsize', $this->mThumbSize );
$wgUser->setOption( 'underline', $this->validateInt($this->mUnderline, 0, 2) );
$wgUser->setOption( 'watchlistdays', $this->validateFloat( $this->mWatchlistDays, 0, 7 ) );
- $wgUser->setOption( 'ajaxsearch', $this->mUseAjaxSearch );
$wgUser->setOption( 'disablesuggest', $this->mDisableMWSuggest );
# Set search namespace options
@@ -370,9 +348,8 @@ class PreferencesForm {
* @access private
*/
function resetPrefs() {
- global $wgUser, $wgLang, $wgContLang, $wgContLanguageCode, $wgAllowRealName;
+ global $wgUser, $wgLang, $wgContLang, $wgContLanguageCode, $wgAllowRealName, $wgLocalTZoffset;
- $this->mOldpass = $this->mNewpass = $this->mRetypePass = '';
$this->mUserEmail = $wgUser->getEmail();
$this->mUserEmailAuthenticationtimestamp = $wgUser->getEmailAuthenticationtimestamp();
$this->mRealName = ($wgAllowRealName) ? $wgUser->getRealName() : '';
@@ -391,7 +368,47 @@ class PreferencesForm {
$this->mRows = $wgUser->getOption( 'rows' );
$this->mCols = $wgUser->getOption( 'cols' );
$this->mStubs = $wgUser->getOption( 'stubthreshold' );
- $this->mHourDiff = $wgUser->getOption( 'timecorrection' );
+
+ $tz = $wgUser->getOption( 'timecorrection' );
+ $data = explode( '|', $tz, 3 );
+ $minDiff = null;
+ switch ( $data[0] ) {
+ case 'ZoneInfo':
+ $this->mTimeZone = $tz;
+ # Check if the specified TZ exists, and change to 'Offset' if
+ # not.
+ if ( !function_exists('timezone_open') || @timezone_open( $data[2] ) === false ) {
+ $this->mTimeZone = 'Offset';
+ $minDiff = intval( $data[1] );
+ }
+ break;
+ case '':
+ case 'System':
+ $this->mTimeZone = 'System|'.$wgLocalTZoffset;
+ break;
+ case 'Offset':
+ $this->mTimeZone = 'Offset';
+ $minDiff = intval( $data[1] );
+ break;
+ default:
+ $this->mTimeZone = 'Offset';
+ $data = explode( ':', $tz, 2 );
+ if( count( $data ) == 2 ) {
+ $data[0] = intval( $data[0] );
+ $data[1] = intval( $data[1] );
+ $minDiff = abs( $data[0] ) * 60 + $data[1];
+ if ( $data[0] < 0 ) $minDiff = -$minDiff;
+ } else {
+ $minDiff = intval( $data[0] ) * 60;
+ }
+ break;
+ }
+ if ( is_null( $minDiff ) ) {
+ $this->mHourDiff = '';
+ } else {
+ $this->mHourDiff = sprintf( '%+03d:%02d', floor($minDiff/60), abs($minDiff)%60 );
+ }
+
$this->mSearch = $wgUser->getOption( 'searchlimit' );
$this->mSearchLines = $wgUser->getOption( 'contextlines' );
$this->mSearchChars = $wgUser->getOption( 'contextchars' );
@@ -402,7 +419,6 @@ class PreferencesForm {
$this->mWatchlistEdits = $wgUser->getOption( 'wllimit' );
$this->mUnderline = $wgUser->getOption( 'underline' );
$this->mWatchlistDays = $wgUser->getOption( 'watchlistdays' );
- $this->mUseAjaxSearch = $wgUser->getBoolOption( 'ajaxsearch' );
$this->mDisableMWSuggest = $wgUser->getBoolOption( 'disablesuggest' );
$togs = User::getToggles();
@@ -511,18 +527,18 @@ class PreferencesForm {
* @access private
*/
function mainPrefsForm( $status , $message = '' ) {
- global $wgUser, $wgOut, $wgLang, $wgContLang;
+ global $wgUser, $wgOut, $wgLang, $wgContLang, $wgAuth;
global $wgAllowRealName, $wgImageLimits, $wgThumbLimits;
- global $wgDisableLangConversion;
+ global $wgDisableLangConversion, $wgDisableTitleConversion;
global $wgEnotifWatchlist, $wgEnotifUserTalk,$wgEnotifMinorEdits;
global $wgRCShowWatchingUsers, $wgEnotifRevealEditorAddress;
global $wgEnableEmail, $wgEnableUserEmail, $wgEmailAuthentication;
- global $wgContLanguageCode, $wgDefaultSkin, $wgSkipSkins, $wgAuth;
- global $wgEmailConfirmToEdit, $wgAjaxSearch, $wgEnableMWSuggest;
+ global $wgContLanguageCode, $wgDefaultSkin, $wgCookieExpiration;
+ global $wgEmailConfirmToEdit, $wgEnableMWSuggest, $wgLocalTZoffset;
$wgOut->setPageTitle( wfMsg( 'preferences' ) );
$wgOut->setArticleRelated( false );
- $wgOut->setRobotpolicy( 'noindex,nofollow' );
+ $wgOut->setRobotPolicy( 'noindex,nofollow' );
$wgOut->addScriptFile( 'prefs.js' );
$wgOut->disallowUserJs(); # Prevent hijacked user scripts from sniffing passwords etc.
@@ -536,7 +552,6 @@ class PreferencesForm {
}
$qbs = $wgLang->getQuickbarSettings();
- $skinNames = $wgLang->getSkinNames();
$mathopts = $wgLang->getMathNames();
$dateopts = $wgLang->getDatePreferences();
$togs = User::getToggles();
@@ -552,6 +567,7 @@ class PreferencesForm {
$this->mUsedToggles[ 'enotifrevealaddr' ] = true;
$this->mUsedToggles[ 'ccmeonemails' ] = true;
$this->mUsedToggles[ 'uselivepreview' ] = true;
+ $this->mUsedToggles[ 'noconvertlink' ] = true;
if ( !$this->mEmailFlag ) { $emfc = 'checked="checked"'; }
@@ -560,7 +576,13 @@ class PreferencesForm {
if ($wgEmailAuthentication && ($this->mUserEmail != '') ) {
if( $wgUser->getEmailAuthenticationTimestamp() ) {
- $emailauthenticated = wfMsg('emailauthenticated',$wgLang->timeanddate($wgUser->getEmailAuthenticationTimestamp(), true ) ).'<br />';
+ // date and time are separate parameters to facilitate localisation.
+ // $time is kept for backward compat reasons.
+ // 'emailauthenticated' is also used in SpecialConfirmemail.php
+ $time = $wgLang->timeAndDate( $wgUser->getEmailAuthenticationTimestamp(), true );
+ $d = $wgLang->date( $wgUser->getEmailAuthenticationTimestamp(), true );
+ $t = $wgLang->time( $wgUser->getEmailAuthenticationTimestamp(), true );
+ $emailauthenticated = wfMsg('emailauthenticated', $time, $d, $t ).'<br />';
$disableEmailPrefs = false;
} else {
$disableEmailPrefs = true;
@@ -620,26 +642,26 @@ class PreferencesForm {
$toolLinks = array();
$toolLinks[] = $sk->makeKnownLinkObj( SpecialPage::getTitleFor( 'ListGroupRights' ), wfMsg( 'listgrouprights' ) );
# At the moment one tool link only but be prepared for the future...
- # FIXME: Add a link to Special:Userrights for users who are allowed to use it.
+ # FIXME: Add a link to Special:Userrights for users who are allowed to use it.
# $wgUser->isAllowed( 'userrights' ) seems to strict in some cases
$userInformationHtml =
$this->tableRow( wfMsgHtml( 'username' ), htmlspecialchars( $wgUser->getName() ) ) .
- $this->tableRow( wfMsgHtml( 'uid' ), htmlspecialchars( $wgUser->getId() ) ) .
+ $this->tableRow( wfMsgHtml( 'uid' ), $wgLang->formatNum( htmlspecialchars( $wgUser->getId() ) ) ).
$this->tableRow(
wfMsgExt( 'prefs-memberingroups', array( 'parseinline' ), count( $userEffectiveGroupsArray ) ),
- implode( wfMsg( 'comma-separator' ), $userEffectiveGroupsArray ) .
+ $wgLang->commaList( $userEffectiveGroupsArray ) .
'<br />(' . implode( ' | ', $toolLinks ) . ')'
) .
$this->tableRow(
wfMsgHtml( 'prefs-edits' ),
- $wgLang->formatNum( User::edits( $wgUser->getId() ) )
+ $wgLang->formatNum( $wgUser->getEditCount() )
);
if( wfRunHooks( 'PreferencesUserInformationPanel', array( $this, &$userInformationHtml ) ) ) {
- $wgOut->addHtml( $userInformationHtml );
+ $wgOut->addHTML( $userInformationHtml );
}
if ( $wgAllowRealName ) {
@@ -724,7 +746,7 @@ class PreferencesForm {
}
if(count($variantArray) > 1) {
- $wgOut->addHtml(
+ $wgOut->addHTML(
$this->tableRow(
Xml::label( wfMsg( 'yourvariant' ), 'wpUserVariant' ),
Xml::tags( 'select',
@@ -734,30 +756,25 @@ class PreferencesForm {
)
);
}
+
+ if(count($variantArray) > 1 && !$wgDisableLangConversion && !$wgDisableTitleConversion) {
+ $wgOut->addHTML(
+ Xml::tags( 'tr', null,
+ Xml::tags( 'td', array( 'colspan' => '2' ),
+ $this->getToggle( "noconvertlink" )
+ )
+ )
+ );
+ }
}
# Password
if( $wgAuth->allowPasswordChange() ) {
+ $link = $wgUser->getSkin()->link( SpecialPage::getTitleFor( 'ResetPass' ), wfMsgHtml( 'prefs-resetpass' ),
+ array() , array('returnto' => SpecialPage::getTitleFor( 'Preferences') ) );
$wgOut->addHTML(
$this->tableRow( Xml::element( 'h2', null, wfMsg( 'changepassword' ) ) ) .
- $this->tableRow(
- Xml::label( wfMsg( 'oldpassword' ), 'wpOldpass' ),
- Xml::password( 'wpOldpass', 25, $this->mOldpass, array( 'id' => 'wpOldpass' ) )
- ) .
- $this->tableRow(
- Xml::label( wfMsg( 'newpassword' ), 'wpNewpass' ),
- Xml::password( 'wpNewpass', 25, $this->mNewpass, array( 'id' => 'wpNewpass' ) )
- ) .
- $this->tableRow(
- Xml::label( wfMsg( 'retypenew' ), 'wpRetypePass' ),
- Xml::password( 'wpRetypePass', 25, $this->mRetypePass, array( 'id' => 'wpRetypePass' ) )
- ) .
- Xml::tags( 'tr', null,
- Xml::tags( 'td', array( 'colspan' => '2' ),
- $this->getToggle( "rememberpassword" )
- )
- )
- );
+ $this->tableRow( '<ul><li>' . $link . '</li></ul>' ) );
}
# <FIXME>
@@ -799,48 +816,49 @@ class PreferencesForm {
# Quickbar
#
if ($this->mSkin == 'cologneblue' || $this->mSkin == 'standard') {
- $wgOut->addHtml( "<fieldset>\n<legend>" . wfMsg( 'qbsettings' ) . "</legend>\n" );
+ $wgOut->addHTML( "<fieldset>\n<legend>" . wfMsg( 'qbsettings' ) . "</legend>\n" );
for ( $i = 0; $i < count( $qbs ); ++$i ) {
if ( $i == $this->mQuickbar ) { $checked = ' checked="checked"'; }
else { $checked = ""; }
$wgOut->addHTML( "<div><label><input type='radio' name='wpQuickbar' value=\"$i\"$checked />{$qbs[$i]}</label></div>\n" );
}
- $wgOut->addHtml( "</fieldset>\n\n" );
+ $wgOut->addHTML( "</fieldset>\n\n" );
} else {
# Need to output a hidden option even if the relevant skin is not in use,
# otherwise the preference will get reset to 0 on submit
- $wgOut->addHtml( wfHidden( 'wpQuickbar', $this->mQuickbar ) );
+ $wgOut->addHTML( Xml::hidden( 'wpQuickbar', $this->mQuickbar ) );
}
# Skin
#
- $wgOut->addHTML( "<fieldset>\n<legend>\n" . wfMsg('skin') . "</legend>\n" );
- $mptitle = Title::newMainPage();
- $previewtext = wfMsg('skinpreview');
- # Only show members of Skin::getSkinNames() rather than
- # $skinNames (skins is all skin names from Language.php)
- $validSkinNames = Skin::getSkinNames();
- # Sort by UI skin name. First though need to update validSkinNames as sometimes
- # the skinkey & UI skinname differ (e.g. "standard" skinkey is "Classic" in the UI).
- foreach ($validSkinNames as $skinkey => & $skinname ) {
- if ( isset( $skinNames[$skinkey] ) ) {
- $skinname = $skinNames[$skinkey];
+ global $wgAllowUserSkin;
+ if( $wgAllowUserSkin ) {
+ $wgOut->addHTML( "<fieldset>\n<legend>\n" . wfMsg( 'skin' ) . "</legend>\n" );
+ $mptitle = Title::newMainPage();
+ $previewtext = wfMsg( 'skin-preview' );
+ # Only show members of Skin::getSkinNames() rather than
+ # $skinNames (skins is all skin names from Language.php)
+ $validSkinNames = Skin::getUsableSkins();
+ # Sort by UI skin name. First though need to update validSkinNames as sometimes
+ # the skinkey & UI skinname differ (e.g. "standard" skinkey is "Classic" in the UI).
+ foreach ( $validSkinNames as $skinkey => &$skinname ) {
+ $msgName = "skinname-{$skinkey}";
+ $localisedSkinName = wfMsg( $msgName );
+ if ( !wfEmptyMsg( $msgName, $localisedSkinName ) ) {
+ $skinname = $localisedSkinName;
+ }
}
- }
- asort($validSkinNames);
- foreach ($validSkinNames as $skinkey => $sn ) {
- if ( in_array( $skinkey, $wgSkipSkins ) ) {
- continue;
+ asort($validSkinNames);
+ foreach ($validSkinNames as $skinkey => $sn ) {
+ $checked = $skinkey == $this->mSkin ? ' checked="checked"' : '';
+ $mplink = htmlspecialchars( $mptitle->getLocalURL( "useskin=$skinkey" ) );
+ $previewlink = "(<a target='_blank' href=\"$mplink\">$previewtext</a>)";
+ if( $skinkey == $wgDefaultSkin )
+ $sn .= ' (' . wfMsg( 'default' ) . ')';
+ $wgOut->addHTML( "<input type='radio' name='wpSkin' id=\"wpSkin$skinkey\" value=\"$skinkey\"$checked /> <label for=\"wpSkin$skinkey\">{$sn}</label> $previewlink<br />\n" );
}
- $checked = $skinkey == $this->mSkin ? ' checked="checked"' : '';
-
- $mplink = htmlspecialchars($mptitle->getLocalURL("useskin=$skinkey"));
- $previewlink = "<a target='_blank' href=\"$mplink\">$previewtext</a>";
- if( $skinkey == $wgDefaultSkin )
- $sn .= ' (' . wfMsg( 'default' ) . ')';
- $wgOut->addHTML( "<input type='radio' name='wpSkin' id=\"wpSkin$skinkey\" value=\"$skinkey\"$checked /> <label for=\"wpSkin$skinkey\">{$sn}</label> $previewlink<br />\n" );
+ $wgOut->addHTML( "</fieldset>\n\n" );
}
- $wgOut->addHTML( "</fieldset>\n\n" );
# Math
#
@@ -860,10 +878,6 @@ class PreferencesForm {
# Files
#
- $wgOut->addHTML(
- "<fieldset>\n" . Xml::element( 'legend', null, wfMsg( 'files' ) ) . "\n"
- );
-
$imageLimitOptions = null;
foreach ( $wgImageLimits as $index => $limits ) {
$selected = ($index == $this->mImageSize);
@@ -871,14 +885,6 @@ class PreferencesForm {
wfMsg('unit-pixel'), $index, $selected );
}
- $imageSizeId = 'wpImageSize';
- $wgOut->addHTML(
- "<div>" . Xml::label( wfMsg('imagemaxsize'), $imageSizeId ) . " " .
- Xml::openElement( 'select', array( 'name' => $imageSizeId, 'id' => $imageSizeId ) ) .
- $imageLimitOptions .
- Xml::closeElement( 'select' ) . "</div>\n"
- );
-
$imageThumbOptions = null;
foreach ( $wgThumbLimits as $index => $size ) {
$selected = ($index == $this->mThumbSize);
@@ -886,16 +892,34 @@ class PreferencesForm {
$selected);
}
+ $imageSizeId = 'wpImageSize';
$thumbSizeId = 'wpThumbSize';
$wgOut->addHTML(
- "<div>" . Xml::label( wfMsg('thumbsize'), $thumbSizeId ) . " " .
- Xml::openElement( 'select', array( 'name' => $thumbSizeId, 'id' => $thumbSizeId ) ) .
- $imageThumbOptions .
- Xml::closeElement( 'select' ) . "</div>\n"
+ Xml::fieldset( wfMsg( 'files' ) ) . "\n" .
+ Xml::openElement( 'table' ) .
+ '<tr>
+ <td class="mw-label">' .
+ Xml::label( wfMsg( 'imagemaxsize' ), $imageSizeId ) .
+ '</td>
+ <td class="mw-input">' .
+ Xml::openElement( 'select', array( 'name' => $imageSizeId, 'id' => $imageSizeId ) ) .
+ $imageLimitOptions .
+ Xml::closeElement( 'select' ) .
+ '</td>
+ </tr><tr>
+ <td class="mw-label">' .
+ Xml::label( wfMsg( 'thumbsize' ), $thumbSizeId ) .
+ '</td>
+ <td class="mw-input">' .
+ Xml::openElement( 'select', array( 'name' => $thumbSizeId, 'id' => $thumbSizeId ) ) .
+ $imageThumbOptions .
+ Xml::closeElement( 'select' ) .
+ '</td>
+ </tr>' .
+ Xml::closeElement( 'table' ) .
+ Xml::closeElement( 'fieldset' )
);
- $wgOut->addHTML( "</fieldset>\n\n" );
-
# Date format
#
# Date/Time
@@ -929,18 +953,61 @@ class PreferencesForm {
$wgOut->addHTML( Xml::closeElement( 'fieldset' ) . "\n" );
}
- $nowlocal = $wgLang->time( $now = wfTimestampNow(), true );
- $nowserver = $wgLang->time( $now, false );
+ $nowlocal = Xml::openElement( 'span', array( 'id' => 'wpLocalTime' ) ) .
+ $wgLang->time( $now = wfTimestampNow(), true ) .
+ Xml::closeElement( 'span' );
+ $nowserver = $wgLang->time( $now, false ) .
+ Xml::hidden( 'wpServerTime', substr( $now, 8, 2 ) * 60 + substr( $now, 10, 2 ) );
$wgOut->addHTML(
Xml::openElement( 'fieldset' ) .
Xml::element( 'legend', null, wfMsg( 'timezonelegend' ) ) .
Xml::openElement( 'table' ) .
$this->addRow( wfMsg( 'servertime' ), $nowserver ) .
- $this->addRow( wfMsg( 'localtime' ), $nowlocal ) .
+ $this->addRow( wfMsg( 'localtime' ), $nowlocal )
+ );
+ $opt = Xml::openElement( 'select', array(
+ 'name' => 'wpTimeZone',
+ 'id' => 'wpTimeZone',
+ 'onchange' => 'javascript:updateTimezoneSelection(false)' ) );
+ $opt .= Xml::option( wfMsg( 'timezoneuseserverdefault' ), "System|$wgLocalTZoffset", $this->mTimeZone === "System|$wgLocalTZoffset" );
+ $opt .= Xml::option( wfMsg( 'timezoneuseoffset' ), 'Offset', $this->mTimeZone === 'Offset' );
+ if ( function_exists( 'timezone_identifiers_list' ) ) {
+ $optgroup = '';
+ $tzs = timezone_identifiers_list();
+ sort( $tzs );
+ $selZone = explode( '|', $this->mTimeZone, 3);
+ $selZone = ( $selZone[0] == 'ZoneInfo' ) ? $selZone[2] : null;
+ $now = date_create( 'now' );
+ foreach ( $tzs as $tz ) {
+ $z = explode( '/', $tz, 2 );
+ # timezone_identifiers_list() returns a number of
+ # backwards-compatibility entries. This filters them out of the
+ # list presented to the user.
+ if ( count( $z ) != 2 || !in_array( $z[0], array( 'Africa', 'America', 'Antarctica', 'Arctic', 'Asia', 'Atlantic', 'Australia', 'Europe', 'Indian', 'Pacific' ) ) ) continue;
+ if ( $optgroup != $z[0] ) {
+ if ( $optgroup !== '' ) $opt .= Xml::closeElement( 'optgroup' );
+ $optgroup = $z[0];
+ $opt .= Xml::openElement( 'optgroup', array( 'label' => $z[0] ) );
+ }
+ $minDiff = floor( timezone_offset_get( timezone_open( $tz ), $now ) / 60 );
+ $opt .= Xml::option( str_replace( '_', ' ', $tz ), "ZoneInfo|$minDiff|$tz", $selZone === $tz, array( 'label' => $z[1] ) );
+ }
+ if ( $optgroup !== '' ) $opt .= Xml::closeElement( 'optgroup' );
+ }
+ $opt .= Xml::closeElement( 'select' );
+ $wgOut->addHTML(
+ $this->addRow(
+ Xml::label( wfMsg( 'timezoneselect' ), 'wpTimeZone' ),
+ $opt )
+ );
+ $wgOut->addHTML(
$this->addRow(
Xml::label( wfMsg( 'timezoneoffset' ), 'wpHourDiff' ),
- Xml::input( 'wpHourDiff', 6, $this->mHourDiff, array( 'id' => 'wpHourDiff' ) ) ) .
+ Xml::input( 'wpHourDiff', 6, $this->mHourDiff, array(
+ 'id' => 'wpHourDiff',
+ 'onfocus' => 'javascript:updateTimezoneSelection(true)',
+ 'onblur' => 'javascript:updateTimezoneSelection(false)' ) ) ) .
"<tr>
<td></td>
<td class='mw-submit'>" .
@@ -961,12 +1028,11 @@ class PreferencesForm {
# Editing
#
global $wgLivePreview;
- $wgOut->addHTML( '<fieldset><legend>' . wfMsg( 'textboxsize' ) . '</legend>
- <div>' .
- wfInputLabel( wfMsg( 'rows' ), 'wpRows', 'wpRows', 3, $this->mRows ) .
- ' ' .
- wfInputLabel( wfMsg( 'columns' ), 'wpCols', 'wpCols', 3, $this->mCols ) .
- "</div>" .
+ $wgOut->addHTML(
+ Xml::fieldset( wfMsg( 'textboxsize' ) ) .
+ wfMsgHTML( 'prefs-edit-boxsize' ) . ' ' .
+ Xml::inputLabel( wfMsg( 'rows' ), 'wpRows', 'wpRows', 3, $this->mRows ) . ' ' .
+ Xml::inputLabel( wfMsg( 'columns' ), 'wpCols', 'wpCols', 3, $this->mCols ) .
$this->getToggles( array(
'editsection',
'editsectiononrightclick',
@@ -980,62 +1046,76 @@ class PreferencesForm {
'externaldiff',
$wgLivePreview ? 'uselivepreview' : false,
'forceeditsummary',
- ) ) . '</fieldset>'
+ ) )
);
- # Recent changes
- $wgOut->addHtml( '<fieldset><legend>' . wfMsgHtml( 'prefs-rc' ) . '</legend>' );
-
- $rc = '<table><tr>';
- $rc .= '<td>' . Xml::label( wfMsg( 'recentchangesdays' ), 'wpRecentDays' ) . '</td>';
- $rc .= '<td>' . Xml::input( 'wpRecentDays', 3, $this->mRecentDays, array( 'id' => 'wpRecentDays' ) ) . '</td>';
- $rc .= '</tr><tr>';
- $rc .= '<td>' . Xml::label( wfMsg( 'recentchangescount' ), 'wpRecent' ) . '</td>';
- $rc .= '<td>' . Xml::input( 'wpRecent', 3, $this->mRecent, array( 'id' => 'wpRecent' ) ) . '</td>';
- $rc .= '</tr></table>';
- $wgOut->addHtml( $rc );
+ $wgOut->addHTML( Xml::closeElement( 'fieldset' ) );
- $wgOut->addHtml( '<br />' );
+ # Recent changes
+ global $wgRCMaxAge;
+ $wgOut->addHTML(
+ Xml::fieldset( wfMsg( 'prefs-rc' ) ) .
+ Xml::openElement( 'table' ) .
+ '<tr>
+ <td class="mw-label">' .
+ Xml::label( wfMsg( 'recentchangesdays' ), 'wpRecentDays' ) .
+ '</td>
+ <td class="mw-input">' .
+ Xml::input( 'wpRecentDays', 3, $this->mRecentDays, array( 'id' => 'wpRecentDays' ) ) . ' ' .
+ wfMsgExt( 'recentchangesdays-max', 'parsemag',
+ $wgLang->formatNum( ceil( $wgRCMaxAge / ( 3600 * 24 ) ) ) ) .
+ '</td>
+ </tr><tr>
+ <td class="mw-label">' .
+ Xml::label( wfMsg( 'recentchangescount' ), 'wpRecent' ) .
+ '</td>
+ <td class="mw-input">' .
+ Xml::input( 'wpRecent', 3, $this->mRecent, array( 'id' => 'wpRecent' ) ) .
+ '</td>
+ </tr>' .
+ Xml::closeElement( 'table' ) .
+ '<br />'
+ );
$toggles[] = 'hideminor';
if( $wgRCShowWatchingUsers )
$toggles[] = 'shownumberswatching';
$toggles[] = 'usenewrc';
- $wgOut->addHtml( $this->getToggles( $toggles ) );
- $wgOut->addHtml( '</fieldset>' );
+ $wgOut->addHTML(
+ $this->getToggles( $toggles ) .
+ Xml::closeElement( 'fieldset' )
+ );
# Watchlist
- $wgOut->addHtml( '<fieldset><legend>' . wfMsgHtml( 'prefs-watchlist' ) . '</legend>' );
-
- $wgOut->addHtml( wfInputLabel( wfMsg( 'prefs-watchlist-days' ), 'wpWatchlistDays', 'wpWatchlistDays', 3, $this->mWatchlistDays ) );
- $wgOut->addHtml( '<br /><br />' );
-
- $wgOut->addHtml( $this->getToggle( 'extendwatchlist' ) );
- $wgOut->addHtml( wfInputLabel( wfMsg( 'prefs-watchlist-edits' ), 'wpWatchlistEdits', 'wpWatchlistEdits', 3, $this->mWatchlistEdits ) );
- $wgOut->addHtml( '<br /><br />' );
+ $wgOut->addHTML(
+ Xml::fieldset( wfMsg( 'prefs-watchlist' ) ) .
+ Xml::inputLabel( wfMsg( 'prefs-watchlist-days' ), 'wpWatchlistDays', 'wpWatchlistDays', 3, $this->mWatchlistDays ) . ' ' .
+ wfMsgHTML( 'prefs-watchlist-days-max' ) .
+ '<br /><br />' .
+ $this->getToggle( 'extendwatchlist' ) .
+ Xml::inputLabel( wfMsg( 'prefs-watchlist-edits' ), 'wpWatchlistEdits', 'wpWatchlistEdits', 3, $this->mWatchlistEdits ) . ' ' .
+ wfMsgHTML( 'prefs-watchlist-edits-max' ) .
+ '<br /><br />' .
+ $this->getToggles( array( 'watchlisthideminor', 'watchlisthidebots', 'watchlisthideown', 'watchlisthideanons', 'watchlisthideliu' ) )
+ );
- $wgOut->addHtml( $this->getToggles( array( 'watchlisthideown', 'watchlisthidebots', 'watchlisthideminor' ) ) );
+ if( $wgUser->isAllowed( 'createpage' ) || $wgUser->isAllowed( 'createtalk' ) ) {
+ $wgOut->addHTML( $this->getToggle( 'watchcreations' ) );
+ }
- if( $wgUser->isAllowed( 'createpage' ) || $wgUser->isAllowed( 'createtalk' ) )
- $wgOut->addHtml( $this->getToggle( 'watchcreations' ) );
foreach( array( 'edit' => 'watchdefault', 'move' => 'watchmoves', 'delete' => 'watchdeletion' ) as $action => $toggle ) {
if( $wgUser->isAllowed( $action ) )
- $wgOut->addHtml( $this->getToggle( $toggle ) );
+ $wgOut->addHTML( $this->getToggle( $toggle ) );
}
$this->mUsedToggles['watchcreations'] = true;
$this->mUsedToggles['watchdefault'] = true;
$this->mUsedToggles['watchmoves'] = true;
$this->mUsedToggles['watchdeletion'] = true;
- $wgOut->addHtml( '</fieldset>' );
+ $wgOut->addHTML( Xml::closeElement( 'fieldset' ) );
# Search
- $ajaxsearch = $wgAjaxSearch ?
- $this->addRow(
- Xml::label( wfMsg( 'useajaxsearch' ), 'wpUseAjaxSearch' ),
- Xml::check( 'wpUseAjaxSearch', $this->mUseAjaxSearch, array( 'id' => 'wpUseAjaxSearch' ) )
- ) : '';
$mwsuggest = $wgEnableMWSuggest ?
$this->addRow(
Xml::label( wfMsg( 'mwsuggest-disable' ), 'wpDisableMWSuggest' ),
@@ -1049,7 +1129,6 @@ class PreferencesForm {
Xml::openElement( 'fieldset' ) .
Xml::element( 'legend', null, wfMsg( 'prefs-searchoptions' ) ) .
Xml::openElement( 'table' ) .
- $ajaxsearch .
$this->addRow(
Xml::label( wfMsg( 'resultsperpage' ), 'wpSearch' ),
Xml::input( 'wpSearch', 4, $this->mSearch, array( 'id' => 'wpSearch' ) )
@@ -1078,8 +1157,8 @@ class PreferencesForm {
# Misc
#
$wgOut->addHTML('<fieldset><legend>' . wfMsg('prefs-misc') . '</legend>');
- $wgOut->addHtml( '<label for="wpStubs">' . wfMsg( 'stub-threshold' ) . '</label>&nbsp;' );
- $wgOut->addHtml( Xml::input( 'wpStubs', 6, $this->mStubs, array( 'id' => 'wpStubs' ) ) );
+ $wgOut->addHTML( '<label for="wpStubs">' . wfMsg( 'stub-threshold' ) . '</label>&nbsp;' );
+ $wgOut->addHTML( Xml::input( 'wpStubs', 6, $this->mStubs, array( 'id' => 'wpStubs' ) ) );
$msgUnderline = htmlspecialchars( wfMsg ( 'tog-underline' ) );
$msgUnderlinenever = htmlspecialchars( wfMsg ( 'underline-never' ) );
$msgUnderlinealways = htmlspecialchars( wfMsg ( 'underline-always' ) );
@@ -1098,9 +1177,13 @@ class PreferencesForm {
foreach ( $togs as $tname ) {
if( !array_key_exists( $tname, $this->mUsedToggles ) ) {
- $wgOut->addHTML( $this->getToggle( $tname ) );
+ if( $tname == 'norollbackdiff' && $wgUser->isAllowed( 'rollback' ) )
+ $wgOut->addHTML( $this->getToggle( $tname ) );
+ else
+ $wgOut->addHTML( $this->getToggle( $tname ) );
}
}
+
$wgOut->addHTML( '</fieldset>' );
wfRunHooks( 'RenderPreferencesForm', array( $this, $wgOut ) );
@@ -1119,7 +1202,7 @@ class PreferencesForm {
<input type='hidden' name='wpEditToken' value=\"{$token}\" />
</div></form>\n" );
- $wgOut->addHtml( Xml::tags( 'div', array( 'class' => "prefcache" ),
+ $wgOut->addHTML( Xml::tags( 'div', array( 'class' => "prefcache" ),
wfMsgExt( 'clearyourcache', 'parseinline' ) )
);
}
diff --git a/includes/specials/SpecialPrefixindex.php b/includes/specials/SpecialPrefixindex.php
index 9c880349..ea0c1135 100644
--- a/includes/specials/SpecialPrefixindex.php
+++ b/includes/specials/SpecialPrefixindex.php
@@ -1,40 +1,4 @@
<?php
-/**
- * @file
- * @ingroup SpecialPage
- */
-
-/**
- * Entry point : initialise variables and call subfunctions.
- * @param $par String: becomes "FOO" when called like Special:Prefixindex/FOO (default NULL)
- * @param $specialPage SpecialPage object.
- */
-function wfSpecialPrefixIndex( $par=NULL, $specialPage ) {
- global $wgRequest, $wgOut, $wgContLang;
-
- # GET values
- $from = $wgRequest->getVal( 'from' );
- $prefix = $wgRequest->getVal( 'prefix' );
- $namespace = $wgRequest->getInt( 'namespace' );
- $namespaces = $wgContLang->getNamespaces();
-
- $indexPage = new SpecialPrefixIndex();
-
- $wgOut->setPagetitle( ( $namespace > 0 && in_array( $namespace, array_keys( $namespaces ) ) )
- ? wfMsg( 'allinnamespace', str_replace( '_', ' ', $namespaces[$namespace] ) )
- : wfMsg( 'allarticles' )
- );
-
- if ( isset($par) ) {
- $indexPage->showChunk( $namespace, $par, $specialPage->including(), $from );
- } elseif ( isset($prefix) ) {
- $indexPage->showChunk( $namespace, $prefix, $specialPage->including(), $from );
- } elseif ( isset($from) ) {
- $indexPage->showChunk( $namespace, $from, $specialPage->including(), $from );
- } else {
- $wgOut->addHtml($indexPage->namespaceForm ( $namespace, null ));
- }
-}
/**
* implements Special:Prefixindex
@@ -44,18 +8,90 @@ class SpecialPrefixindex extends SpecialAllpages {
// Inherit $maxPerPage
// Define other properties
- protected $name = 'Prefixindex';
protected $nsfromMsg = 'allpagesprefix';
+
+ function __construct(){
+ parent::__construct( 'Prefixindex' );
+ }
+
+ /**
+ * Entry point : initialise variables and call subfunctions.
+ * @param $par String: becomes "FOO" when called like Special:Prefixindex/FOO (default null)
+ */
+ function execute( $par ) {
+ global $wgRequest, $wgOut, $wgContLang;
+
+ $this->setHeaders();
+ $this->outputHeader();
+
+ # GET values
+ $from = $wgRequest->getVal( 'from' );
+ $prefix = $wgRequest->getVal( 'prefix' );
+ $namespace = $wgRequest->getInt( 'namespace' );
+ $namespaces = $wgContLang->getNamespaces();
+
+ $wgOut->setPagetitle( ( $namespace > 0 && in_array( $namespace, array_keys( $namespaces ) ) )
+ ? wfMsg( 'allinnamespace', str_replace( '_', ' ', $namespaces[$namespace] ) )
+ : wfMsg( 'prefixindex' )
+ );
+
+ if( isset( $par ) ){
+ $this->showPrefixChunk( $namespace, $par, $from );
+ } elseif( isset( $prefix ) ){
+ $this->showPrefixChunk( $namespace, $prefix, $from );
+ } elseif( isset( $from ) ){
+ $this->showPrefixChunk( $namespace, $from, $from );
+ } else {
+ $wgOut->addHTML( $this->namespacePrefixForm( $namespace, null ) );
+ }
+ }
+
+ /**
+ * HTML for the top form
+ * @param integer $namespace A namespace constant (default NS_MAIN).
+ * @param string $from dbKey we are starting listing at.
+ */
+ function namespacePrefixForm( $namespace = NS_MAIN, $from = '' ) {
+ global $wgScript;
+ $t = $this->getTitle();
+
+ $out = Xml::openElement( 'div', array( 'class' => 'namespaceoptions' ) );
+ $out .= Xml::openElement( 'form', array( 'method' => 'get', 'action' => $wgScript ) );
+ $out .= Xml::hidden( 'title', $t->getPrefixedText() );
+ $out .= Xml::openElement( 'fieldset' );
+ $out .= Xml::element( 'legend', null, wfMsg( 'allpages' ) );
+ $out .= Xml::openElement( 'table', array( 'id' => 'nsselect', 'class' => 'allpages' ) );
+ $out .= "<tr>
+ <td class='mw-label'>" .
+ Xml::label( wfMsg( 'allpagesfrom' ), 'nsfrom' ) .
+ "</td>
+ <td class='mw-input'>" .
+ Xml::input( 'from', 30, str_replace('_',' ',$from), array( 'id' => 'nsfrom' ) ) .
+ "</td>
+ </tr>
+ <tr>
+ <td class='mw-label'>" .
+ Xml::label( wfMsg( 'namespace' ), 'namespace' ) .
+ "</td>
+ <td class='mw-input'>" .
+ Xml::namespaceSelector( $namespace, null ) . ' ' .
+ Xml::submitButton( wfMsg( 'allpagessubmit' ) ) .
+ "</td>
+ </tr>";
+ $out .= Xml::closeElement( 'table' );
+ $out .= Xml::closeElement( 'fieldset' );
+ $out .= Xml::closeElement( 'form' );
+ $out .= Xml::closeElement( 'div' );
+ return $out;
+ }
/**
* @param integer $namespace (Default NS_MAIN)
* @param string $from list all pages from this name (default FALSE)
*/
- function showChunk( $namespace = NS_MAIN, $prefix, $including = false, $from = null ) {
+ function showPrefixChunk( $namespace = NS_MAIN, $prefix, $from = null ) {
global $wgOut, $wgUser, $wgContLang;
- $fname = 'indexShowChunk';
-
$sk = $wgUser->getSkin();
if (!isset($from)) $from = $prefix;
@@ -86,7 +122,7 @@ class SpecialPrefixindex extends SpecialAllpages {
'page_title LIKE \'' . $dbr->escapeLike( $prefixKey ) .'%\'',
'page_title >= ' . $dbr->addQuotes( $fromKey ),
),
- $fname,
+ __METHOD__,
array(
'ORDER BY' => 'page_title',
'LIMIT' => $this->maxPerPage + 1,
@@ -100,7 +136,7 @@ class SpecialPrefixindex extends SpecialAllpages {
if( $res->numRows() > 0 ) {
$out = '<table style="background: inherit;" border="0" width="100%">';
- while( ($n < $this->maxPerPage) && ($s = $dbr->fetchObject( $res )) ) {
+ while( ( $n < $this->maxPerPage ) && ( $s = $res->fetchObject() ) ) {
$t = Title::makeTitle( $s->page_namespace, $s->page_title );
if( $t ) {
$link = ($s->page_is_redirect ? '<div class="allpagesredirect">' : '' ) .
@@ -127,26 +163,27 @@ class SpecialPrefixindex extends SpecialAllpages {
}
}
- if ( $including ) {
+ if ( $this->including() ) {
$out2 = '';
} else {
- $nsForm = $this->namespaceForm ( $namespace, $prefix );
+ $nsForm = $this->namespacePrefixForm( $namespace, $prefix );
+ $self = $this->getTitle();
$out2 = '<table style="background: inherit;" width="100%" cellpadding="0" cellspacing="0" border="0">';
$out2 .= '<tr valign="top"><td>' . $nsForm;
$out2 .= '</td><td align="' . $align . '" style="font-size: smaller; margin-bottom: 1em;">' .
- $sk->makeKnownLink( $wgContLang->specialPage( $this->name ),
+ $sk->makeKnownLinkObj( $self,
wfMsg ( 'allpages' ) );
- if ( isset($dbr) && $dbr && ($n == $this->maxPerPage) && ($s = $dbr->fetchObject( $res )) ) {
+ if( isset( $res ) && $res && ( $n == $this->maxPerPage ) && ( $s = $res->fetchObject() ) ) {
$namespaceparam = $namespace ? "&namespace=$namespace" : "";
- $out2 .= " | " . $sk->makeKnownLink(
- $wgContLang->specialPage( $this->name ),
+ $out2 .= " | " . $sk->makeKnownLinkObj(
+ $self,
wfMsgHtml( 'nextpage', htmlspecialchars( $s->page_title ) ),
- "from=" . wfUrlEncode ( $s->page_title ) .
- "&prefix=" . wfUrlEncode ( $prefix ) . $namespaceparam );
+ "from=" . wfUrlEncode( $s->page_title ) .
+ "&prefix=" . wfUrlEncode( $prefix ) . $namespaceparam );
}
$out2 .= "</td></tr></table><hr />";
}
- $wgOut->addHtml( $out2 . $out );
+ $wgOut->addHTML( $out2 . $out );
}
}
diff --git a/includes/specials/SpecialProtectedpages.php b/includes/specials/SpecialProtectedpages.php
index 3025c055..4e56ca42 100644
--- a/includes/specials/SpecialProtectedpages.php
+++ b/includes/specials/SpecialProtectedpages.php
@@ -16,7 +16,6 @@ class ProtectedPagesForm {
public function showList( $msg = '' ) {
global $wgOut, $wgRequest;
- $wgOut->setPagetitle( wfMsg( "protectedpages" ) );
if ( "" != $msg ) {
$wgOut->setSubtitle( $msg );
}
@@ -32,10 +31,11 @@ class ProtectedPagesForm {
$size = $wgRequest->getIntOrNull( 'size' );
$NS = $wgRequest->getIntOrNull( 'namespace' );
$indefOnly = $wgRequest->getBool( 'indefonly' ) ? 1 : 0;
+ $cascadeOnly = $wgRequest->getBool('cascadeonly') ? 1 : 0;
- $pager = new ProtectedPagesPager( $this, array(), $type, $level, $NS, $sizetype, $size, $indefOnly );
+ $pager = new ProtectedPagesPager( $this, array(), $type, $level, $NS, $sizetype, $size, $indefOnly, $cascadeOnly );
- $wgOut->addHTML( $this->showOptions( $NS, $type, $level, $sizetype, $size, $indefOnly ) );
+ $wgOut->addHTML( $this->showOptions( $NS, $type, $level, $sizetype, $size, $indefOnly, $cascadeOnly ) );
if ( $pager->getNumRows() ) {
$s = $pager->getNavigationBar();
@@ -83,7 +83,7 @@ class ProtectedPagesForm {
if ( $row->pr_expiry != 'infinity' && strlen($row->pr_expiry) ) {
$expiry = Block::decodeExpiry( $row->pr_expiry );
- $expiry_description = wfMsgForContent( 'protect-expiring', $wgLang->timeanddate( $expiry ) );
+ $expiry_description = wfMsg( 'protect-expiring' , $wgLang->timeanddate( $expiry ) , $wgLang->date( $expiry ) , $wgLang->time( $expiry ) );
$description_items[] = $expiry_description;
}
@@ -111,21 +111,24 @@ class ProtectedPagesForm {
* @param $level string
* @param $minsize int
* @param $indefOnly bool
+ * @param $cascadeOnly bool
* @return string Input form
* @private
*/
- protected function showOptions( $namespace, $type='edit', $level, $sizetype, $size, $indefOnly ) {
+ protected function showOptions( $namespace, $type='edit', $level, $sizetype, $size, $indefOnly, $cascadeOnly ) {
global $wgScript;
$title = SpecialPage::getTitleFor( 'ProtectedPages' );
return Xml::openElement( 'form', array( 'method' => 'get', 'action' => $wgScript ) ) .
Xml::openElement( 'fieldset' ) .
Xml::element( 'legend', array(), wfMsg( 'protectedpages' ) ) .
- Xml::hidden( 'title', $title->getPrefixedDBkey() ) . "&nbsp;\n" .
+ Xml::hidden( 'title', $title->getPrefixedDBkey() ) . "\n" .
$this->getNamespaceMenu( $namespace ) . "&nbsp;\n" .
$this->getTypeMenu( $type ) . "&nbsp;\n" .
$this->getLevelMenu( $level ) . "&nbsp;\n" .
- "<br /><span style='white-space: nowrap'>&nbsp;&nbsp;" .
+ "<br/><span style='white-space: nowrap'>" .
$this->getExpiryCheck( $indefOnly ) . "&nbsp;\n" .
+ $this->getCascadeCheck( $cascadeOnly ) . "&nbsp;\n" .
+ "</span><br/><span style='white-space: nowrap'>" .
$this->getSizeLimit( $sizetype, $size ) . "&nbsp;\n" .
"</span>" .
"&nbsp;" . Xml::submitButton( wfMsg( 'allpagessubmit' ) ) . "\n" .
@@ -153,6 +156,14 @@ class ProtectedPagesForm {
return
Xml::checkLabel( wfMsg('protectedpages-indef'), 'indefonly', 'indefonly', $indefOnly ) . "\n";
}
+
+ /**
+ * @return string Formatted HTML
+ */
+ protected function getCascadeCheck( $cascadeOnly ) {
+ return
+ Xml::checkLabel( wfMsg('protectedpages-cascade'), 'cascadeonly', 'cascadeonly', $cascadeOnly ) . "\n";
+ }
/**
* @return string Formatted HTML
@@ -237,7 +248,8 @@ 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 ) {
+ 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';
@@ -246,6 +258,7 @@ class ProtectedPagesPager extends AlphabeticPager {
$this->sizetype = $sizetype;
$this->size = intval($size);
$this->indefonly = (bool)$indefonly;
+ $this->cascadeonly = (bool)$cascadeonly;
parent::__construct();
}
@@ -281,6 +294,9 @@ class ProtectedPagesPager extends AlphabeticPager {
if( $this->indefonly ) {
$conds[] = "pr_expiry = 'infinity' OR pr_expiry IS NULL";
}
+ if ( $this->cascadeonly ) {
+ $conds[] = "pr_cascade = '1'";
+ }
if( $this->level )
$conds[] = 'pr_level=' . $this->mDb->addQuotes( $this->level );
diff --git a/includes/specials/SpecialProtectedtitles.php b/includes/specials/SpecialProtectedtitles.php
index 2ec68a66..7e8126d9 100644
--- a/includes/specials/SpecialProtectedtitles.php
+++ b/includes/specials/SpecialProtectedtitles.php
@@ -16,7 +16,6 @@ class ProtectedTitlesForm {
function showList( $msg = '' ) {
global $wgOut, $wgRequest;
- $wgOut->setPagetitle( wfMsg( "protectedtitles" ) );
if ( "" != $msg ) {
$wgOut->setSubtitle( $msg );
}
@@ -75,7 +74,7 @@ class ProtectedTitlesForm {
if ( $row->pt_expiry != 'infinity' && strlen($row->pt_expiry) ) {
$expiry = Block::decodeExpiry( $row->pt_expiry );
- $expiry_description = wfMsgForContent( 'protect-expiring', $wgLang->timeanddate( $expiry ) );
+ $expiry_description = wfMsg( 'protect-expiring', $wgLang->timeanddate( $expiry ) , $wgLang->date( $expiry ) , $wgLang->time( $expiry ) );
$description_items[] = $expiry_description;
}
@@ -102,7 +101,7 @@ class ProtectedTitlesForm {
Xml::element( 'legend', array(), wfMsg( 'protectedtitles' ) ) .
Xml::hidden( 'title', $special ) . "&nbsp;\n" .
$this->getNamespaceMenu( $namespace ) . "&nbsp;\n" .
- // $this->getLevelMenu( $level ) . "<br/>\n" .
+ $this->getLevelMenu( $level ) . "&nbsp;\n" .
"&nbsp;" . Xml::submitButton( wfMsg( 'allpagessubmit' ) ) . "\n" .
"</fieldset></form>";
}
@@ -137,7 +136,10 @@ class ProtectedTitlesForm {
$m[$text] = $type;
}
}
-
+ // Is there only one level (aside from "all")?
+ if( count($m) <= 2 ) {
+ return '';
+ }
// Third pass generates sorted XHTML content
foreach( $m as $text => $type ) {
$selected = ($type == $pr_level );
@@ -190,7 +192,8 @@ class ProtectedtitlesPager extends AlphabeticPager {
function getQueryInfo() {
$conds = $this->mConds;
$conds[] = 'pt_expiry>' . $this->mDb->addQuotes( $this->mDb->timestamp() );
-
+ if( $this->level )
+ $conds['pt_create_perm'] = $this->level;
if( !is_null($this->namespace) )
$conds[] = 'pt_namespace=' . $this->mDb->addQuotes( $this->namespace );
return array(
diff --git a/includes/specials/SpecialRandompage.php b/includes/specials/SpecialRandompage.php
index 0e7ada1d..f4bff30b 100644
--- a/includes/specials/SpecialRandompage.php
+++ b/includes/specials/SpecialRandompage.php
@@ -8,19 +8,23 @@
* @license GNU General Public Licence 2.0 or later
*/
class RandomPage extends SpecialPage {
- private $namespace = NS_MAIN; // namespace to select pages from
+ private $namespaces; // namespaces to select pages from
function __construct( $name = 'Randompage' ){
+ global $wgContentNamespaces;
+
+ $this->namespaces = $wgContentNamespaces;
+
parent::__construct( $name );
}
- public function getNamespace() {
- return $this->namespace;
+ public function getNamespaces() {
+ return $this->namespaces;
}
public function setNamespace ( $ns ) {
if( $ns < NS_MAIN ) $ns = NS_MAIN;
- $this->namespace = $ns;
+ $this->namespaces = array( $ns );
}
// select redirects instead of normal pages?
@@ -39,7 +43,7 @@ class RandomPage extends SpecialPage {
if( is_null( $title ) ) {
$this->setHeaders();
- $wgOut->addWikiMsg( strtolower( $this->mName ) . '-nopages' );
+ $wgOut->addWikiMsg( strtolower( $this->mName ) . '-nopages', $wgContLang->getNsText( $this->namespace ) );
return;
}
@@ -67,7 +71,7 @@ class RandomPage extends SpecialPage {
$row = $this->selectRandomPageFromDB( "0" );
if( $row )
- return Title::makeTitleSafe( $this->namespace, $row->page_title );
+ return Title::makeTitleSafe( $row->page_namespace, $row->page_title );
else
return null;
}
@@ -81,13 +85,13 @@ class RandomPage extends SpecialPage {
$use_index = $dbr->useIndexClause( 'page_random' );
$page = $dbr->tableName( 'page' );
- $ns = (int) $this->namespace;
+ $ns = implode( ",", $this->namespaces );
$redirect = $this->isRedirect() ? 1 : 0;
$extra = $wgExtraRandompageSQL ? "AND ($wgExtraRandompageSQL)" : "";
- $sql = "SELECT page_title
+ $sql = "SELECT page_title, page_namespace
FROM $page $use_index
- WHERE page_namespace = $ns
+ WHERE page_namespace IN ( $ns )
AND page_is_redirect = $redirect
AND page_random >= $randstr
$extra
diff --git a/includes/specials/SpecialRecentchanges.php b/includes/specials/SpecialRecentchanges.php
index cb718bdc..8c14e1fc 100644
--- a/includes/specials/SpecialRecentchanges.php
+++ b/includes/specials/SpecialRecentchanges.php
@@ -6,7 +6,7 @@
*/
class SpecialRecentChanges extends SpecialPage {
public function __construct() {
- SpecialPage::SpecialPage( 'Recentchanges' );
+ parent::__construct( 'Recentchanges' );
$this->includable( true );
}
@@ -16,13 +16,14 @@ class SpecialRecentChanges extends SpecialPage {
* @return FormOptions
*/
public function getDefaultOptions() {
+ global $wgUser;
$opts = new FormOptions();
- $opts->add( 'days', (int)User::getDefaultOption( 'rcdays' ) );
- $opts->add( 'limit', (int)User::getDefaultOption( 'rclimit' ) );
+ $opts->add( 'days', (int)$wgUser->getOption( 'rcdays' ) );
+ $opts->add( 'limit', (int)$wgUser->getOption( 'rclimit' ) );
$opts->add( 'from', '' );
- $opts->add( 'hideminor', false );
+ $opts->add( 'hideminor', (bool)$wgUser->getOption( 'hideminor' ) );
$opts->add( 'hidebots', true );
$opts->add( 'hideanons', false );
$opts->add( 'hideliu', false );
@@ -34,7 +35,6 @@ class SpecialRecentChanges extends SpecialPage {
$opts->add( 'categories', '' );
$opts->add( 'categories_any', false );
-
return $opts;
}
@@ -44,16 +44,13 @@ class SpecialRecentChanges extends SpecialPage {
* @return FormOptions
*/
public function setup( $parameters ) {
- global $wgUser, $wgRequest;
+ global $wgRequest;
$opts = $this->getDefaultOptions();
- $opts['days'] = (int)$wgUser->getOption( 'rcdays', $opts['days'] );
- $opts['limit'] = (int)$wgUser->getOption( 'rclimit', $opts['limit'] );
- $opts['hideminor'] = $wgUser->getOption( 'hideminor', $opts['hideminor'] );
$opts->fetchValuesFromRequest( $wgRequest );
// Give precedence to subpage syntax
- if ( $parameters !== null ) {
+ if( $parameters !== null ) {
$this->parseParameters( $parameters, $opts );
}
@@ -85,9 +82,9 @@ class SpecialRecentChanges extends SpecialPage {
# 10 seconds server-side caching max
$wgOut->setSquidMaxage( 10 );
-
+ # Check if the client has a cached version
$lastmod = $this->checkLastModified( $feedFormat );
- if( $lastmod === false ){
+ if( $lastmod === false ) {
return;
}
@@ -97,33 +94,32 @@ class SpecialRecentChanges extends SpecialPage {
// Fetch results, prepare a batch link existence check query
$rows = array();
- $batch = new LinkBatch;
$conds = $this->buildMainQueryConds( $opts );
- $res = $this->doMainQuery( $conds, $opts );
- if( $res === false ){
- $this->doHeader( $opts );
+ $rows = $this->doMainQuery( $conds, $opts );
+ if( $rows === false ){
+ if( !$this->including() ) {
+ $this->doHeader( $opts );
+ }
return;
}
- $dbr = wfGetDB( DB_SLAVE );
- while( $row = $dbr->fetchObject( $res ) ){
- $rows[] = $row;
- if ( !$feedFormat ) {
- // User page and talk links
+
+ if( !$feedFormat ) {
+ $batch = new LinkBatch;
+ foreach( $rows as $row ) {
$batch->add( NS_USER, $row->rc_user_text );
$batch->add( NS_USER_TALK, $row->rc_user_text );
}
-
+ $batch->execute();
}
- $dbr->freeResult( $res );
- if ( $feedFormat ) {
+ if( $feedFormat ) {
list( $feed, $feedObj ) = $this->getFeedObject( $feedFormat );
$feed->execute( $feedObj, $rows, $opts['limit'], $opts['hideminor'], $lastmod );
} else {
- $batch->execute();
$this->webOutput( $rows, $opts );
}
-
+
+ $rows->free();
}
/**
@@ -149,21 +145,21 @@ class SpecialRecentChanges extends SpecialPage {
*/
public function parseParameters( $par, FormOptions $opts ) {
$bits = preg_split( '/\s*,\s*/', trim( $par ) );
- foreach ( $bits as $bit ) {
- if ( 'hidebots' === $bit ) $opts['hidebots'] = true;
- if ( 'bots' === $bit ) $opts['hidebots'] = false;
- if ( 'hideminor' === $bit ) $opts['hideminor'] = true;
- if ( 'minor' === $bit ) $opts['hideminor'] = false;
- if ( 'hideliu' === $bit ) $opts['hideliu'] = true;
- if ( 'hidepatrolled' === $bit ) $opts['hidepatrolled'] = true;
- if ( 'hideanons' === $bit ) $opts['hideanons'] = true;
- if ( 'hidemyself' === $bit ) $opts['hidemyself'] = true;
-
- if ( is_numeric( $bit ) ) $opts['limit'] = $bit;
+ foreach( $bits as $bit ) {
+ if( 'hidebots' === $bit ) $opts['hidebots'] = true;
+ if( 'bots' === $bit ) $opts['hidebots'] = false;
+ if( 'hideminor' === $bit ) $opts['hideminor'] = true;
+ if( 'minor' === $bit ) $opts['hideminor'] = false;
+ if( 'hideliu' === $bit ) $opts['hideliu'] = true;
+ if( 'hidepatrolled' === $bit ) $opts['hidepatrolled'] = true;
+ if( 'hideanons' === $bit ) $opts['hideanons'] = true;
+ if( 'hidemyself' === $bit ) $opts['hidemyself'] = true;
+
+ if( is_numeric( $bit ) ) $opts['limit'] = $bit;
$m = array();
- if ( preg_match( '/^limit=(\d+)$/', $bit, $m ) ) $opts['limit'] = $m[1];
- if ( preg_match( '/^days=(\d+)$/', $bit, $m ) ) $opts['days'] = $m[1];
+ if( preg_match( '/^limit=(\d+)$/', $bit, $m ) ) $opts['limit'] = $m[1];
+ if( preg_match( '/^days=(\d+)$/', $bit, $m ) ) $opts['days'] = $m[1];
}
}
@@ -173,14 +169,14 @@ class SpecialRecentChanges extends SpecialPage {
* update the timestamp
*
* @param $feedFormat String
- * @return int or false
+ * @return string or false
*/
public function checkLastModified( $feedFormat ) {
global $wgUseRCPatrol, $wgOut;
$dbr = wfGetDB( DB_SLAVE );
$lastmod = $dbr->selectField( 'recentchanges', 'MAX(rc_timestamp)', false, __FUNCTION__ );
- if ( $feedFormat || !$wgUseRCPatrol ) {
- if( $lastmod && $wgOut->checkLastModified( $lastmod ) ){
+ if( $feedFormat || !$wgUseRCPatrol ) {
+ if( $lastmod && $wgOut->checkLastModified( $lastmod ) ) {
# Client cache fresh and headers sent, nothing more to do.
return false;
}
@@ -232,12 +228,12 @@ class SpecialRecentChanges extends SpecialPage {
$hideLoggedInUsers = $opts['hideliu'] && !$forcebot;
$hideAnonymousUsers = $opts['hideanons'] && !$forcebot;
- if ( $opts['hideminor'] ) $conds['rc_minor'] = 0;
- if ( $opts['hidebots'] ) $conds['rc_bot'] = 0;
- if ( $hidePatrol ) $conds['rc_patrolled'] = 0;
- if ( $forcebot ) $conds['rc_bot'] = 1;
- if ( $hideLoggedInUsers ) $conds[] = 'rc_user = 0';
- if ( $hideAnonymousUsers ) $conds[] = 'rc_user != 0';
+ if( $opts['hideminor'] ) $conds['rc_minor'] = 0;
+ if( $opts['hidebots'] ) $conds['rc_bot'] = 0;
+ if( $hidePatrol ) $conds['rc_patrolled'] = 0;
+ if( $forcebot ) $conds['rc_bot'] = 1;
+ if( $hideLoggedInUsers ) $conds[] = 'rc_user = 0';
+ if( $hideAnonymousUsers ) $conds[] = 'rc_user != 0';
if( $opts['hidemyself'] ) {
if( $wgUser->getId() ) {
@@ -248,8 +244,8 @@ class SpecialRecentChanges extends SpecialPage {
}
# Namespace filtering
- if ( $opts['namespace'] !== '' ) {
- if ( !$opts['invert'] ) {
+ if( $opts['namespace'] !== '' ) {
+ if( !$opts['invert'] ) {
$conds[] = 'rc_namespace = ' . $dbr->addQuotes( $opts['namespace'] );
} else {
$conds[] = 'rc_namespace != ' . $dbr->addQuotes( $opts['namespace'] );
@@ -281,7 +277,8 @@ class SpecialRecentChanges extends SpecialPage {
// JOIN on watchlist for users
if( $uid ) {
$tables[] = 'watchlist';
- $join_conds = array( 'watchlist' => array('LEFT JOIN',"wl_user={$uid} AND wl_title=rc_title AND wl_namespace=rc_namespace") );
+ $join_conds = array( 'watchlist' => array('LEFT JOIN',
+ "wl_user={$uid} AND wl_title=rc_title AND wl_namespace=rc_namespace") );
}
wfRunHooks('SpecialRecentChangesQuery', array( &$conds, &$tables, &$join_conds, $opts ) );
@@ -329,7 +326,7 @@ class SpecialRecentChanges extends SpecialPage {
$limit = $opts['limit'];
- if ( !$this->including() ) {
+ if( !$this->including() ) {
// Output options box
$this->doHeader( $opts );
}
@@ -337,55 +334,46 @@ class SpecialRecentChanges extends SpecialPage {
// And now for the content
$wgOut->setSyndicated( true );
- $list = ChangesList::newFromUser( $wgUser );
-
- if ( $wgAllowCategorizedRecentChanges ) {
+ if( $wgAllowCategorizedRecentChanges ) {
$this->filterByCategories( $rows, $opts );
}
- $s = $list->beginRecentChangesList();
- $counter = 1;
-
$showWatcherCount = $wgRCShowWatchingUsers && $wgUser->getOption( 'shownumberswatching' );
$watcherCache = array();
$dbr = wfGetDB( DB_SLAVE );
- foreach( $rows as $obj ){
- if( $limit == 0) {
- break;
- }
-
- if ( ! ( $opts['hideminor'] && $obj->rc_minor ) &&
- ! ( $opts['hidepatrolled'] && $obj->rc_patrolled ) ) {
- $rc = RecentChange::newFromRow( $obj );
- $rc->counter = $counter++;
-
- if ($wgShowUpdatedMarker
- && !empty( $obj->wl_notificationtimestamp )
- && ($obj->rc_timestamp >= $obj->wl_notificationtimestamp)) {
- $rc->notificationtimestamp = true;
- } else {
- $rc->notificationtimestamp = false;
- }
+ $counter = 1;
+ $list = ChangesList::newFromUser( $wgUser );
- $rc->numberofWatchingusers = 0; // Default
- 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',
- 'COUNT(*)',
- array(
- 'wl_namespace' => $obj->rc_namespace,
- 'wl_title' => $obj->rc_title,
- ),
- __METHOD__ . '-watchers' );
- }
- $rc->numberofWatchingusers = $watcherCache[$obj->rc_namespace][$obj->rc_title];
+ $s = $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) ) {
+ $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]) ) {
+ $watcherCache[$obj->rc_namespace][$obj->rc_title] =
+ $dbr->selectField( 'watchlist',
+ 'COUNT(*)',
+ array(
+ 'wl_namespace' => $obj->rc_namespace,
+ 'wl_title' => $obj->rc_title,
+ ),
+ __METHOD__ . '-watchers' );
}
- $s .= $list->recentChangesLine( $rc, !empty( $obj->wl_user ) );
- --$limit;
+ $rc->numberofWatchingusers = $watcherCache[$obj->rc_namespace][$obj->rc_title];
}
+ $s .= $list->recentChangesLine( $rc, !empty( $obj->wl_user ) );
+ --$limit;
}
$s .= $list->endRecentChangesList();
$wgOut->addHTML( $s );
@@ -411,22 +399,29 @@ class SpecialRecentChanges extends SpecialPage {
$panel[] = '<hr />';
$extraOpts = $this->getExtraOptions( $opts );
+ $extraOptsCount = count( $extraOpts );
+ $count = 0;
+ $submit = ' ' . Xml::submitbutton( wfMsg( 'allpagessubmit' ) );
+
+ $out = Xml::openElement( 'table', array( 'class' => 'mw-recentchanges-table' ) );
+ foreach( $extraOpts as $optionRow ) {
+ # Add submit button to the last row only
+ ++$count;
+ $addSubmit = $count === $extraOptsCount ? $submit : '';
- $out = Xml::openElement( 'table' );
- foreach ( $extraOpts as $optionRow ) {
$out .= Xml::openElement( 'tr' );
- if ( is_array($optionRow) ) {
- $out .= Xml::tags( 'td', null, $optionRow[0] );
- $out .= Xml::tags( 'td', null, $optionRow[1] );
+ if( is_array( $optionRow ) ) {
+ $out .= Xml::tags( 'td', array( 'class' => 'mw-label' ), $optionRow[0] );
+ $out .= Xml::tags( 'td', array( 'class' => 'mw-input' ), $optionRow[1] . $addSubmit );
} else {
- $out .= Xml::tags( 'td', array( 'colspan' => 2 ), $optionRow );
+ $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 .= Xml::hidden( $key, $value );
}
@@ -437,7 +432,7 @@ class SpecialRecentChanges extends SpecialPage {
$panelString = implode( "\n", $panel );
$wgOut->addHTML(
- Xml::fieldset( wfMsg( strtolower( $this->mName ) ), $panelString, array( 'class' => 'rcoptions' ) )
+ Xml::fieldset( wfMsg( 'recentchanges-legend' ), $panelString, array( 'class' => 'rcoptions' ) )
);
$this->setBottomText( $wgOut, $opts );
@@ -454,12 +449,11 @@ class SpecialRecentChanges extends SpecialPage {
$extraOpts['namespace'] = $this->namespaceFilterForm( $opts );
global $wgAllowCategorizedRecentChanges;
- if ( $wgAllowCategorizedRecentChanges ) {
+ if( $wgAllowCategorizedRecentChanges ) {
$extraOpts['category'] = $this->categoryFilterForm( $opts );
}
wfRunHooks( 'SpecialRecentChangesPanel', array( &$extraOpts, $opts ) );
- $extraOpts['submit'] = Xml::submitbutton( wfMsg('allpagessubmit') );
return $extraOpts;
}
@@ -469,7 +463,7 @@ class SpecialRecentChanges extends SpecialPage {
* @param $out OutputPage
* @param $opts FormOptions
*/
- function setTopText( &$out, $opts ){
+ function setTopText( OutputPage $out, FormOptions $opts ){
$out->addWikiText( wfMsgForContentNoTrans( 'recentchangestext' ) );
}
@@ -480,7 +474,7 @@ class SpecialRecentChanges extends SpecialPage {
* @param $out OutputPage
* @param $opts FormOptions
*/
- function setBottomText( &$out, $opts ){}
+ function setBottomText( OutputPage $out, FormOptions $opts ){}
/**
* Creates the choose namespace selection
@@ -489,7 +483,7 @@ class SpecialRecentChanges extends SpecialPage {
* @return string
*/
protected function namespaceFilterForm( FormOptions $opts ) {
- $nsSelect = HTMLnamespaceselector( $opts['namespace'], '' );
+ $nsSelect = Xml::namespaceSelector( $opts['namespace'], '' );
$nsLabel = Xml::label( wfMsg('namespace'), 'namespace' );
$invert = Xml::checkLabel( wfMsg('invert'), 'invert', 'nsinvert', $opts['invert'] );
return array( $nsLabel, "$nsSelect $invert" );
@@ -526,30 +520,30 @@ class SpecialRecentChanges extends SpecialPage {
# Filter categories
$cats = array();
- foreach ( $categories as $cat ) {
+ foreach( $categories as $cat ) {
$cat = trim( $cat );
- if ( $cat == "" ) continue;
+ if( $cat == "" ) continue;
$cats[] = $cat;
}
# Filter articles
$articles = array();
$a2r = array();
- foreach ( $rows AS $k => $r ) {
+ foreach( $rows AS $k => $r ) {
$nt = Title::makeTitle( $r->rc_namespace, $r->rc_title );
$id = $nt->getArticleID();
- if ( $id == 0 ) continue; # Page might have been deleted...
- if ( !in_array($id, $articles) ) {
+ if( $id == 0 ) continue; # Page might have been deleted...
+ if( !in_array($id, $articles) ) {
$articles[] = $id;
}
- if ( !isset($a2r[$id]) ) {
+ if( !isset($a2r[$id]) ) {
$a2r[$id] = array();
}
$a2r[$id][] = $k;
}
# Shortcut?
- if ( !count($articles) || !count($cats) )
+ if( !count($articles) || !count($cats) )
return ;
# Look up
@@ -559,8 +553,8 @@ class SpecialRecentChanges extends SpecialPage {
# 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] = $rows[$k];
}
@@ -577,8 +571,9 @@ class SpecialRecentChanges extends SpecialPage {
function makeOptionsLink( $title, $override, $options, $active = false ) {
global $wgUser;
$sk = $wgUser->getSkin();
- return $sk->makeKnownLinkObj( $this->getTitle(), htmlspecialchars( $title ),
- wfArrayToCGI( $override, $options ), '', '', $active ? 'style="font-weight: bold;"' : '' );
+ $params = $override + $options;
+ return $sk->link( $this->getTitle(), htmlspecialchars( $title ),
+ ( $active ? array( 'style'=>'font-weight: bold;' ) : array() ), $params, array( 'known' ) );
}
/**
@@ -591,43 +586,41 @@ class SpecialRecentChanges extends SpecialPage {
$options = $nondefaults + $defaults;
- if( $options['from'] )
- $note = wfMsgExt( 'rcnotefrom', array( 'parseinline' ),
+ $note = '';
+ if( $options['from'] ) {
+ $note .= wfMsgExt( 'rcnotefrom', array( 'parseinline' ),
$wgLang->formatNum( $options['limit'] ),
- $wgLang->timeanddate( $options['from'], true ) );
- else
- $note = wfMsgExt( 'rcnote', array( 'parseinline' ),
- $wgLang->formatNum( $options['limit'] ),
- $wgLang->formatNum( $options['days'] ),
- $wgLang->timeAndDate( wfTimestampNow(), true ),
- $wgLang->date( wfTimestampNow(), true ),
- $wgLang->time( wfTimestampNow(), true ) );
+ $wgLang->timeanddate( $options['from'], true ) ) . '<br />';
+ }
+ if( !wfEmptyMsg( 'rclegend', wfMsg('rclegend') ) ) {
+ $note .= wfMsgExt( 'rclegend', array('parseinline') ) . '<br />';
+ }
# 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);
+ sort( $wgRCLinkLimits );
+ sort( $wgRCLinkDays );
+ $wgRCLinkLimits = array_unique( $wgRCLinkLimits );
+ $wgRCLinkDays = array_unique( $wgRCLinkDays );
// limit links
foreach( $wgRCLinkLimits as $value ) {
$cl[] = $this->makeOptionsLink( $wgLang->formatNum( $value ),
array( 'limit' => $value ), $nondefaults, $value == $options['limit'] ) ;
}
- $cl = implode( ' | ', $cl);
+ $cl = implode( ' | ', $cl );
// day links, reset 'from' to none
foreach( $wgRCLinkDays as $value ) {
$dl[] = $this->makeOptionsLink( $wgLang->formatNum( $value ),
array( 'days' => $value, 'from' => '' ), $nondefaults, $value == $options['days'] ) ;
}
- $dl = implode( ' | ', $dl);
+ $dl = implode( ' | ', $dl );
// show/hide links
- $showhide = array( wfMsg( 'show' ), wfMsg( 'hide' ));
+ $showhide = array( wfMsg( 'show' ), wfMsg( 'hide' ) );
$minorLink = $this->makeOptionsLink( $showhide[1-$options['hideminor']],
array( 'hideminor' => 1-$options['hideminor'] ), $nondefaults);
$botLink = $this->makeOptionsLink( $showhide[1-$options['hidebots']],
@@ -652,11 +645,11 @@ class SpecialRecentChanges extends SpecialPage {
// show from this onward link
$now = $wgLang->timeanddate( wfTimestampNow(), true );
- $tl = $this->makeOptionsLink( $now, array( 'from' => wfTimestampNow()), $nondefaults );
+ $tl = $this->makeOptionsLink( $now, array( 'from' => wfTimestampNow() ), $nondefaults );
- $rclinks = wfMsgExt( 'rclinks', array( 'parseinline', 'replaceafter'),
+ $rclinks = wfMsgExt( 'rclinks', array( 'parseinline', 'replaceafter' ),
$cl, $dl, $hl );
- $rclistfrom = wfMsgExt( 'rclistfrom', array( 'parseinline', 'replaceafter'), $tl );
- return "$note<br />$rclinks<br />$rclistfrom";
+ $rclistfrom = wfMsgExt( 'rclistfrom', array( 'parseinline', 'replaceafter' ), $tl );
+ return "{$note}$rclinks<br />$rclistfrom";
}
}
diff --git a/includes/specials/SpecialRecentchangeslinked.php b/includes/specials/SpecialRecentchangeslinked.php
index d773fb77..c0734354 100644
--- a/includes/specials/SpecialRecentchangeslinked.php
+++ b/includes/specials/SpecialRecentchangeslinked.php
@@ -7,7 +7,8 @@
class SpecialRecentchangeslinked extends SpecialRecentchanges {
function __construct(){
- SpecialPage::SpecialPage( 'Recentchangeslinked' );
+ SpecialPage::SpecialPage( 'Recentchangeslinked' );
+ $this->includable( true );
}
public function getDefaultOptions() {
@@ -92,10 +93,13 @@ class SpecialRecentchangeslinked extends SpecialRecentchanges {
} else {
// 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_IMAGE
- if( $ns == NS_IMAGE || !$showlinkedto ) $link_tables[] = 'imagelinks';
+ // imagelinks only contains links to pages in NS_FILE
+ if( $ns == NS_FILE || !$showlinkedto ) $link_tables[] = 'imagelinks';
}
+ if( $id == 0 && !$showlinkedto )
+ return false; // nonexistent pages can't link to any pages
+
// field name prefixes for all the various tables we might want to join with
$prefix = array( 'pagelinks' => 'pl', 'templatelinks' => 'tl', 'categorylinks' => 'cl', 'imagelinks' => 'il' );
@@ -105,7 +109,7 @@ class SpecialRecentchangeslinked extends SpecialRecentchanges {
$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' ) $link_ns = NS_IMAGE;
+ if( $link_table == 'imagelinks' ) $link_ns = NS_FILE;
else if( $link_table == 'categorylinks' ) $link_ns = NS_CATEGORY;
else $link_ns = 0;
@@ -145,7 +149,7 @@ class SpecialRecentchangeslinked extends SpecialRecentchanges {
$res = $dbr->query( $sql, __METHOD__ );
- if( $dbr->numRows( $res ) == 0 )
+ if( $res->numRows() == 0 )
$this->mResultEmpty = true;
return $res;
@@ -159,17 +163,21 @@ class SpecialRecentchangeslinked extends SpecialRecentchanges {
Xml::input( 'target', 40, str_replace('_',' ',$opts['target']) ) .
Xml::check( 'showlinkedto', $opts['showlinkedto'], array('id' => 'showlinkedto') ) . ' ' .
Xml::label( wfMsg("recentchangeslinked-to"), 'showlinkedto' ) );
- $extraOpts['submit'] = Xml::submitbutton( wfMsg('allpagessubmit') );
return $extraOpts;
}
-
- function setTopText( &$out, $opts ){}
-
- function setBottomText( &$out, $opts ){
+
+ function setTopText( OutputPage $out, FormOptions $opts ) {
+ global $wgUser;
+ $skin = $wgUser->getSkin();
+ if( isset( $this->mTargetTitle ) && is_object( $this->mTargetTitle ) )
+ $out->setSubtitle( wfMsg( 'recentchangeslinked-backlink', $skin->link( $this->mTargetTitle,
+ $this->mTargetTitle->getPrefixedText(), array(), array( 'redirect' => 'no' ) ) ) );
+ }
+
+ function setBottomText( OutputPage $out, FormOptions $opts ){
if( isset( $this->mTargetTitle ) && is_object( $this->mTargetTitle ) ){
global $wgUser;
$out->setFeedAppendQuery( "target=" . urlencode( $this->mTargetTitle->getPrefixedDBkey() ) );
- $out->addHTML("&lt; ".$wgUser->getSkin()->makeLinkObj( $this->mTargetTitle, "", "redirect=no" )."<hr />\n");
}
if( isset( $this->mResultEmpty ) && $this->mResultEmpty ){
$out->addWikiMsg( 'recentchangeslinked-noresult' );
diff --git a/includes/specials/SpecialRemoveRestrictions.php b/includes/specials/SpecialRemoveRestrictions.php
new file mode 100644
index 00000000..ded6cbe3
--- /dev/null
+++ b/includes/specials/SpecialRemoveRestrictions.php
@@ -0,0 +1,60 @@
+<?php
+
+function wfSpecialRemoveRestrictions() {
+ global $wgOut, $wgRequest, $wgUser, $wgLang, $wgTitle;
+ $sk = $wgUser->getSkin();
+
+ $id = $wgRequest->getVal( 'id' );
+ if( !is_numeric( $id ) ) {
+ $wgOut->addWikiMsg( 'removerestrictions-noid' );
+ return;
+ }
+
+ UserRestriction::purgeExpired();
+ $r = UserRestriction::newFromId( $id, true );
+ if( !$r ) {
+ $wgOut->addWikiMsg( 'removerestrictions-wrongid' );
+ return;
+ }
+
+ $form = array();
+ $form['removerestrictions-user'] = $sk->userLink( $r->getSubjectId(), $r->getSubjectText() ) .
+ $sk->userToolLinks( $r->getSubjectId(), $r->getSubjectText() );
+ $form['removerestrictions-type'] = UserRestriction::formatType( $r->getType() );
+ if( $r->isPage() )
+ $form['removerestrictions-page'] = $sk->link( $r->getPage() );
+ if( $r->isNamespace() )
+ $form['removerestrictions-namespace'] = $wgLang->getDisplayNsText( $r->getNamespace() );
+ $form['removerestrictions-reason'] = Xml::input( 'reason' );
+
+ $result = null;
+ if( $wgRequest->wasPosted() && $wgUser->matchEditToken( $wgRequest->getVal( 'edittoken' ) ) )
+ $result = wfSpecialRemoveRestrictionsProcess( $r );
+
+ $wgOut->addWikiMsg( 'removerestrictions-intro' );
+ $wgOut->addHTML( Xml::fieldset( wfMsgHtml( 'removerestrictions-legend' ) ) );
+ if( $result )
+ $wgOut->addHTML( '<strong class="success">' . wfMsgExt( 'removerestrictions-success',
+ 'parseinline', $r->getSubjectText() ) . '</strong>' );
+ $wgOut->addHTML( Xml::openElement( 'form', array( 'action' => $wgTitle->getLocalUrl( array( 'id' => $id ) ),
+ 'method' => 'post' ) ) );
+ $wgOut->addHTML( Xml::buildForm( $form, 'removerestrictions-submit' ) );
+ $wgOut->addHTML( Xml::hidden( 'id', $r->getId() ) );
+ $wgOut->addHTML( Xml::hidden( 'title', $wgTitle->getPrefixedDbKey() ) );
+ $wgOut->addHTML( Xml::hidden( 'edittoken', $wgUser->editToken() ) );
+ $wgOut->addHTML( "</form></fieldset>" );
+}
+
+function wfSpecialRemoveRestrictionsProcess( $r ) {
+ global $wgUser, $wgRequest;
+ $reason = $wgRequest->getVal( 'reason' );
+ $result = $r->delete();
+ $log = new LogPage( 'restrict' );
+ $params = array( $r->getType() );
+ if( $r->isPage() )
+ $params[] = $r->getPage()->getPrefixedDbKey();
+ if( $r->isNamespace() )
+ $params[] = $r->getNamespace();
+ $log->addEntry( 'remove', Title::makeTitle( NS_USER, $r->getSubjectText() ), $reason, $params );
+ return $result;
+}
diff --git a/includes/specials/SpecialResetpass.php b/includes/specials/SpecialResetpass.php
index 707b941d..059f8dbd 100644
--- a/includes/specials/SpecialResetpass.php
+++ b/includes/specials/SpecialResetpass.php
@@ -4,26 +4,13 @@
* @ingroup SpecialPage
*/
-/** Constructor */
-function wfSpecialResetpass( $par ) {
- $form = new PasswordResetForm();
- $form->execute( $par );
-}
-
/**
* Let users recover their password.
* @ingroup SpecialPage
*/
-class PasswordResetForm extends SpecialPage {
- function __construct( $name=null, $reset=null ) {
- if( $name !== null ) {
- $this->mName = $name;
- $this->mTemporaryPassword = $reset;
- } else {
- global $wgRequest;
- $this->mName = $wgRequest->getVal( 'wpName' );
- $this->mTemporaryPassword = $wgRequest->getVal( 'wpPassword' );
- }
+class SpecialResetpass extends SpecialPage {
+ public function __construct() {
+ parent::__construct( 'Resetpass' );
}
/**
@@ -32,36 +19,46 @@ class PasswordResetForm extends SpecialPage {
function execute( $par ) {
global $wgUser, $wgAuth, $wgOut, $wgRequest;
+ $this->mUserName = $wgRequest->getVal( 'wpName' );
+ $this->mOldpass = $wgRequest->getVal( 'wpPassword' );
+ $this->mNewpass = $wgRequest->getVal( 'wpNewPassword' );
+ $this->mRetype = $wgRequest->getVal( 'wpRetype' );
+
+ $this->setHeaders();
+ $this->outputHeader();
+
if( !$wgAuth->allowPasswordChange() ) {
$this->error( wfMsg( 'resetpass_forbidden' ) );
return;
}
- if( $this->mName === null && !$wgRequest->wasPosted() ) {
- $this->error( wfMsg( 'resetpass_missing' ) );
+ if( !$wgRequest->wasPosted() && !$wgUser->isLoggedIn() ) {
+ $this->error( wfMsg( 'resetpass-no-info' ) );
return;
}
- if( $wgRequest->wasPosted() && $wgUser->matchEditToken( $wgRequest->getVal( 'token' ) ) ) {
- $newpass = $wgRequest->getVal( 'wpNewPassword' );
- $retype = $wgRequest->getVal( 'wpRetype' );
+ if( $wgRequest->wasPosted() && $wgUser->matchEditToken( $wgRequest->getVal('token') ) ) {
try {
- $this->attemptReset( $newpass, $retype );
+ $this->attemptReset( $this->mNewpass, $this->mRetype );
$wgOut->addWikiMsg( 'resetpass_success' );
-
- $data = array(
- 'action' => 'submitlogin',
- 'wpName' => $this->mName,
- 'wpPassword' => $newpass,
- 'returnto' => $wgRequest->getVal( 'returnto' ),
- );
- if( $wgRequest->getCheck( 'wpRemember' ) ) {
- $data['wpRemember'] = 1;
+ if( !$wgUser->isLoggedIn() ) {
+ $data = array(
+ 'action' => 'submitlogin',
+ 'wpName' => $this->mUserName,
+ 'wpPassword' => $this->mNewpass,
+ 'returnto' => $wgRequest->getVal( 'returnto' ),
+ );
+ if( $wgRequest->getCheck( 'wpRemember' ) ) {
+ $data['wpRemember'] = 1;
+ }
+ $login = new LoginForm( new FauxRequest( $data, true ) );
+ $login->execute();
}
- $login = new LoginForm( new FauxRequest( $data, true ) );
- $login->execute();
-
- return;
+ $titleObj = Title::newFromText( $wgRequest->getVal( 'returnto' ) );
+ if ( !$titleObj instanceof Title ) {
+ $titleObj = Title::newMainPage();
+ }
+ $wgOut->redirect( $titleObj->getFullURL() );
} catch( PasswordError $e ) {
$this->error( $e->getMessage() );
}
@@ -71,9 +68,7 @@ class PasswordResetForm extends SpecialPage {
function error( $msg ) {
global $wgOut;
- $wgOut->addHtml( '<div class="errorbox">' .
- htmlspecialchars( $msg ) .
- '</div>' );
+ $wgOut->addHTML( Xml::element('p', array( 'class' => 'error' ), $msg ) );
}
function showForm() {
@@ -82,44 +77,54 @@ class PasswordResetForm extends SpecialPage {
$wgOut->disallowUserJs();
$self = SpecialPage::getTitleFor( 'Resetpass' );
- $form =
- '<div id="userloginForm">' .
- wfOpenElement( 'form',
+ if ( !$this->mUserName ) {
+ $this->mUserName = $wgUser->getName();
+ }
+ $rememberMe = '';
+ if ( !$wgUser->isLoggedIn() ) {
+ $rememberMe = '<tr>' .
+ '<td></td>' .
+ '<td class="mw-input">' .
+ Xml::checkLabel( wfMsg( 'remembermypassword' ),
+ 'wpRemember', 'wpRemember',
+ $wgRequest->getCheck( 'wpRemember' ) ) .
+ '</td>' .
+ '</tr>';
+ $submitMsg = 'resetpass_submit';
+ $oldpassMsg = 'resetpass-temp-password';
+ } else {
+ $oldpassMsg = 'oldpassword';
+ $submitMsg = 'resetpass-submit-loggedin';
+ }
+ $wgOut->addHTML(
+ Xml::fieldset( wfMsg( 'resetpass_header' ) ) .
+ Xml::openElement( 'form',
array(
'method' => 'post',
- 'action' => $self->getLocalUrl() ) ) .
- '<h2>' . wfMsgHtml( 'resetpass_header' ) . '</h2>' .
- '<div id="userloginprompt">' .
+ 'action' => $self->getLocalUrl(),
+ 'id' => 'mw-resetpass-form' ) ) .
+ Xml::hidden( 'token', $wgUser->editToken() ) .
+ Xml::hidden( 'wpName', $this->mUserName ) .
+ Xml::hidden( 'returnto', $wgRequest->getVal( 'returnto' ) ) .
wfMsgExt( 'resetpass_text', array( 'parse' ) ) .
- '</div>' .
- '<table>' .
- wfHidden( 'token', $wgUser->editToken() ) .
- wfHidden( 'wpName', $this->mName ) .
- wfHidden( 'wpPassword', $this->mTemporaryPassword ) .
- wfHidden( 'returnto', $wgRequest->getVal( 'returnto' ) ) .
+ Xml::openElement( 'table', array( 'id' => 'mw-resetpass-table' ) ) .
$this->pretty( array(
- array( 'wpName', 'username', 'text', $this->mName ),
+ array( 'wpName', 'username', 'text', $this->mUserName ),
+ array( 'wpPassword', $oldpassMsg, 'password', $this->mOldpass ),
array( 'wpNewPassword', 'newpassword', 'password', '' ),
- array( 'wpRetype', 'yourpasswordagain', 'password', '' ),
+ array( 'wpRetype', 'retypenew', 'password', '' ),
) ) .
+ $rememberMe .
'<tr>' .
'<td></td>' .
- '<td>' .
- Xml::checkLabel( wfMsg( 'remembermypassword' ),
- 'wpRemember', 'wpRemember',
- $wgRequest->getCheck( 'wpRemember' ) ) .
- '</td>' .
- '</tr>' .
- '<tr>' .
- '<td></td>' .
- '<td>' .
- wfSubmitButton( wfMsgHtml( 'resetpass_submit' ) ) .
+ '<td class="mw-input">' .
+ Xml::submitButton( wfMsg( $submitMsg ) ) .
'</td>' .
'</tr>' .
- '</table>' .
- wfCloseElement( 'form' ) .
- '</div>';
- $wgOut->addHtml( $form );
+ Xml::closeElement( 'table' ) .
+ Xml::closeElement( 'form' ) .
+ Xml::closeElement( 'fieldset' )
+ );
}
function pretty( $fields ) {
@@ -127,16 +132,19 @@ class PasswordResetForm extends SpecialPage {
foreach( $fields as $list ) {
list( $name, $label, $type, $value ) = $list;
if( $type == 'text' ) {
- $field = '<tt>' . htmlspecialchars( $value ) . '</tt>';
+ $field = htmlspecialchars( $value );
} else {
$field = Xml::input( $name, 20, $value,
array( 'id' => $name, 'type' => $type ) );
}
$out .= '<tr>';
- $out .= '<td align="right">';
- $out .= Xml::label( wfMsg( $label ), $name );
+ $out .= "<td class='mw-label'>";
+ if ( $type != 'text' )
+ $out .= Xml::label( wfMsg( $label ), $name );
+ else
+ $out .= wfMsg( $label );
$out .= '</td>';
- $out .= '<td>';
+ $out .= "<td class='mw-input'>";
$out .= $field;
$out .= '</td>';
$out .= '</tr>';
@@ -147,21 +155,33 @@ class PasswordResetForm extends SpecialPage {
/**
* @throws PasswordError when cannot set the new password because requirements not met.
*/
- function attemptReset( $newpass, $retype ) {
- $user = User::newFromName( $this->mName );
- if( $user->isAnon() ) {
+ protected function attemptReset( $newpass, $retype ) {
+ $user = User::newFromName( $this->mUserName );
+ if( !$user || $user->isAnon() ) {
throw new PasswordError( 'no such user' );
}
-
- if( !$user->checkTemporaryPassword( $this->mTemporaryPassword ) ) {
- throw new PasswordError( wfMsg( 'resetpass_bad_temporary' ) );
- }
-
+
if( $newpass !== $retype ) {
+ wfRunHooks( 'PrefsPasswordAudit', array( $user, $newpass, 'badretype' ) );
throw new PasswordError( wfMsg( 'badretype' ) );
}
- $user->setPassword( $newpass );
+ if( !$user->checkTemporaryPassword($this->mOldpass) && !$user->checkPassword($this->mOldpass) ) {
+ wfRunHooks( 'PrefsPasswordAudit', array( $user, $newpass, 'wrongpassword' ) );
+ throw new PasswordError( wfMsg( 'resetpass-wrong-oldpass' ) );
+ }
+
+ try {
+ $user->setPassword( $this->mNewpass );
+ wfRunHooks( 'PrefsPasswordAudit', array( $user, $newpass, 'success' ) );
+ $this->mNewpass = $this->mOldpass = $this->mRetypePass = '';
+ } catch( PasswordError $e ) {
+ wfRunHooks( 'PrefsPasswordAudit', array( $user, $newpass, 'error' ) );
+ throw new PasswordError( $e->getMessage() );
+ return;
+ }
+
+ $user->setCookies();
$user->saveSettings();
}
}
diff --git a/includes/specials/SpecialRestrictUser.php b/includes/specials/SpecialRestrictUser.php
new file mode 100644
index 00000000..761e0cd6
--- /dev/null
+++ b/includes/specials/SpecialRestrictUser.php
@@ -0,0 +1,189 @@
+<?php
+
+function wfSpecialRestrictUser( $par = null ) {
+ global $wgOut, $wgRequest;
+ $user = $userOrig = null;
+ if( $par ) {
+ $userOrig = $par;
+ } elseif( $wgRequest->getVal( 'user' ) ) {
+ $userOrig = $wgRequest->getVal( 'user' );
+ } else {
+ $wgOut->addHTML( RestrictUserForm::selectUserForm() );
+ return;
+ }
+ $isIP = User::isIP( $userOrig );
+ $user = $isIP ? $userOrig : User::getCanonicalName( $userOrig );
+ $uid = User::idFromName( $user );
+ if( !$uid && !$isIP ) {
+ $err = '<strong class="error">' . wfMsgHtml( 'restrictuser-notfound' ) . '</strong>';
+ $wgOut->addHTML( RestrictUserForm::selectUserForm( $userOrig, $err ) );
+ return;
+ }
+ $wgOut->addHTML( RestrictUserForm::selectUserForm( $user ) );
+
+ UserRestriction::purgeExpired();
+ $old = UserRestriction::fetchForUser( $user, true );
+
+ RestrictUserForm::pageRestrictionForm( $uid, $user, $old );
+ RestrictUserForm::namespaceRestrictionForm( $uid, $user, $old );
+
+ // Renew it after possible changes in previous two functions
+ $old = UserRestriction::fetchForUser( $user, true );
+ if( $old ) {
+ $wgOut->addHTML( RestrictUserForm::existingRestrictions( $old ) );
+ }
+}
+
+class RestrictUserForm {
+ public static function selectUserForm( $val = null, $error = null ) {
+ global $wgScript, $wgTitle;
+ $s = Xml::fieldset( wfMsg( 'restrictuser-userselect' ) ) . "<form action=\"{$wgScript}\">";
+ if( $error )
+ $s .= '<p>' . $error . '</p>';
+ $s .= Xml::hidden( 'title', $wgTitle->getPrefixedDbKey() );
+ $form = array( 'restrictuser-user' => Xml::input( 'user', false, $val ) );
+ $s .= Xml::buildForm( $form, 'restrictuser-go' );
+ $s .= "</form></fieldset>";
+ return $s;
+ }
+
+ public static function existingRestrictions( $restrictions ) {
+ //TODO: autoload?
+ require_once( dirname( __FILE__ ) . '/SpecialListUserRestrictions.php' );
+ $s = Xml::fieldset( wfMsg( 'restrictuser-existing' ) ) . '<ul>';
+ foreach( $restrictions as $r )
+ $s .= UserRestrictionsPager::formatRestriction( $r );
+ $s .= "</ul></fieldset>";
+ return $s;
+ }
+
+ public static function pageRestrictionForm( $uid, $user, $oldRestrictions ) {
+ global $wgOut, $wgTitle, $wgRequest, $wgUser;
+ $error = '';
+ $success = false;
+ if( $wgRequest->wasPosted() && $wgRequest->getVal( 'type' ) == UserRestriction::PAGE &&
+ $wgUser->matchEditToken( $wgRequest->getVal( 'edittoken' ) ) ) {
+
+ $title = Title::newFromText( $wgRequest->getVal( 'page' ) );
+ if( !$title ) {
+ $error = array( 'restrictuser-badtitle', $wgRequest->getVal( 'page' ) );
+ } elseif( UserRestriction::convertExpiry( $wgRequest->getVal( 'expiry' ) ) === false ) {
+ $error = array( 'restrictuser-badexpiry', $wgRequest->getVal( 'expiry' ) );
+ } else {
+ foreach( $oldRestrictions as $r ) {
+ if( $r->isPage() && $r->getPage()->equals( $title ) )
+ $error = array( 'restrictuser-duptitle' );
+ }
+ }
+ if( !$error ) {
+ self::doPageRestriction( $uid, $user );
+ $success = array('restrictuser-success', $user);
+ }
+ }
+ $useRequestValues = $wgRequest->getVal( 'type' ) == UserRestriction::PAGE;
+ $wgOut->addHTML( Xml::fieldset( wfMsg( 'restrictuser-legend-page' ) ) );
+
+ self::printSuccessError( $success, $error );
+
+ $wgOut->addHTML( Xml::openElement( 'form', array( 'action' => $wgTitle->getLocalUrl(),
+ 'method' => 'post' ) ) );
+ $wgOut->addHTML( Xml::hidden( 'type', UserRestriction::PAGE ) );
+ $wgOut->addHTML( Xml::hidden( 'edittoken', $wgUser->editToken() ) );
+ $wgOut->addHTML( Xml::hidden( 'user', $user ) );
+ $form = array();
+ $form['restrictuser-title'] = Xml::input( 'page', false,
+ $useRequestValues ? $wgRequest->getVal( 'page' ) : false );
+ $form['restrictuser-expiry'] = Xml::input( 'expiry', false,
+ $useRequestValues ? $wgRequest->getVal( 'expiry' ) : false );
+ $form['restrictuser-reason'] = Xml::input( 'reason', false,
+ $useRequestValues ? $wgRequest->getVal( 'reason' ) : false );
+ $wgOut->addHTML( Xml::buildForm( $form, 'restrictuser-submit' ) );
+ $wgOut->addHTML( "</form></fieldset>" );
+ }
+
+ public static function printSuccessError( $success, $error ) {
+ global $wgOut;
+ if ( $error )
+ $wgOut->wrapWikiMsg( '<strong class="error">$1</strong>', $error );
+ if ( $success )
+ $wgOut->wrapWikiMsg( '<strong class="success">$1</strong>', $success );
+ }
+
+ public static function doPageRestriction( $uid, $user ) {
+ global $wgUser, $wgRequest;
+ $r = new UserRestriction();
+ $r->setType( UserRestriction::PAGE );
+ $r->setPage( Title::newFromText( $wgRequest->getVal( 'page' ) ) );
+ $r->setSubjectId( $uid );
+ $r->setSubjectText( $user );
+ $r->setBlockerId( $wgUser->getId() );
+ $r->setBlockerText( $wgUser->getName() );
+ $r->setReason( $wgRequest->getVal( 'reason' ) );
+ $r->setExpiry( UserRestriction::convertExpiry( $wgRequest->getVal( 'expiry' ) ) );
+ $r->setTimestamp( wfTimestampNow( TS_MW ) );
+ $r->commit();
+ $logExpiry = $wgRequest->getVal( 'expiry' ) ? $wgRequest->getVal( 'expiry' ) : Block::infinity();
+ $l = new LogPage( 'restrict' );
+ $l->addEntry( 'restrict', Title::makeTitle( NS_USER, $user ), $r->getReason(),
+ array( $r->getType(), $r->getPage()->getFullText(), $logExpiry) );
+ }
+
+ public static function namespaceRestrictionForm( $uid, $user, $oldRestrictions ) {
+ global $wgOut, $wgTitle, $wgRequest, $wgUser, $wgContLang;
+ $error = '';
+ $success = false;
+ if( $wgRequest->wasPosted() && $wgRequest->getVal( 'type' ) == UserRestriction::NAMESPACE &&
+ $wgUser->matchEditToken( $wgRequest->getVal( 'edittoken' ) ) ) {
+ $ns = $wgRequest->getVal( 'namespace' );
+ if( $wgContLang->getNsText( $ns ) === false )
+ $error = wfMsgExt( 'restrictuser-badnamespace', 'parseinline' );
+ elseif( UserRestriction::convertExpiry( $wgRequest->getVal( 'expiry' ) ) === false )
+ $error = wfMsgExt( 'restrictuser-badexpiry', 'parseinline', $wgRequest->getVal( 'expiry' ) );
+ else
+ foreach( $oldRestrictions as $r )
+ if( $r->isNamespace() && $r->getNamespace() == $ns )
+ $error = wfMsgExt( 'restrictuser-dupnamespace', 'parse' );
+ if( !$error ) {
+ self::doNamespaceRestriction( $uid, $user );
+ $success = array('restrictuser-success', $user);
+ }
+ }
+ $useRequestValues = $wgRequest->getVal( 'type' ) == UserRestriction::NAMESPACE;
+ $wgOut->addHTML( Xml::fieldset( wfMsg( 'restrictuser-legend-namespace' ) ) );
+
+ self::printSuccessError( $success, $error );
+
+ $wgOut->addHTML( Xml::openElement( 'form', array( 'action' => $wgTitle->getLocalUrl(),
+ 'method' => 'post' ) ) );
+ $wgOut->addHTML( Xml::hidden( 'type', UserRestriction::NAMESPACE ) );
+ $wgOut->addHTML( Xml::hidden( 'edittoken', $wgUser->editToken() ) );
+ $wgOut->addHTML( Xml::hidden( 'user', $user ) );
+ $form = array();
+ $form['restrictuser-namespace'] = Xml::namespaceSelector( $wgRequest->getVal( 'namespace' ) );
+ $form['restrictuser-expiry'] = Xml::input( 'expiry', false,
+ $useRequestValues ? $wgRequest->getVal( 'expiry' ) : false );
+ $form['restrictuser-reason'] = Xml::input( 'reason', false,
+ $useRequestValues ? $wgRequest->getVal( 'reason' ) : false );
+ $wgOut->addHTML( Xml::buildForm( $form, 'restrictuser-submit' ) );
+ $wgOut->addHTML( "</form></fieldset>" );
+ }
+
+ public static function doNamespaceRestriction( $uid, $user ) {
+ global $wgUser, $wgRequest;
+ $r = new UserRestriction();
+ $r->setType( UserRestriction::NAMESPACE );
+ $r->setNamespace( $wgRequest->getVal( 'namespace' ) );
+ $r->setSubjectId( $uid );
+ $r->setSubjectText( $user );
+ $r->setBlockerId( $wgUser->getId() );
+ $r->setBlockerText( $wgUser->getName() );
+ $r->setReason( $wgRequest->getVal( 'reason' ) );
+ $r->setExpiry( UserRestriction::convertExpiry( $wgRequest->getVal( 'expiry' ) ) );
+ $r->setTimestamp( wfTimestampNow( TS_MW ) );
+ $r->commit();
+ $logExpiry = $wgRequest->getVal( 'expiry' ) ? $wgRequest->getVal( 'expiry' ) : Block::infinity();
+ $l = new LogPage( 'restrict' );
+ $l->addEntry( 'restrict', Title::makeTitle( NS_USER, $user ), $r->getReason(),
+ array( $r->getType(), $r->getNamespace(), $logExpiry ) );
+ }
+}
diff --git a/includes/specials/SpecialRevisiondelete.php b/includes/specials/SpecialRevisiondelete.php
index e94fc222..74b118e2 100644
--- a/includes/specials/SpecialRevisiondelete.php
+++ b/includes/specials/SpecialRevisiondelete.php
@@ -171,7 +171,7 @@ class RevisionDeleteForm {
$wgOut->addWikiMsg( 'revdelete-selected', $this->page->getPrefixedText(), $count );
$bitfields = 0;
- $wgOut->addHtml( "<ul>" );
+ $wgOut->addHTML( "<ul>" );
$where = $revObjs = array();
$dbr = wfGetDB( DB_SLAVE );
@@ -204,7 +204,7 @@ class RevisionDeleteForm {
$UserAllowed = false;
}
$revisions++;
- $wgOut->addHtml( $this->historyLine( $revObjs[$revid] ) );
+ $wgOut->addHTML( $this->historyLine( $revObjs[$revid] ) );
$bitfields |= $revObjs[$revid]->mDeleted;
}
// The archives...
@@ -245,7 +245,7 @@ class RevisionDeleteForm {
$UserAllowed = false;
}
$revisions++;
- $wgOut->addHtml( $this->historyLine( $revObjs[$timestamp] ) );
+ $wgOut->addHTML( $this->historyLine( $revObjs[$timestamp] ) );
$bitfields |= $revObjs[$timestamp]->mDeleted;
}
}
@@ -254,7 +254,7 @@ class RevisionDeleteForm {
return;
}
- $wgOut->addHtml( "</ul>" );
+ $wgOut->addHTML( "</ul>" );
$wgOut->addWikiMsg( 'revdelete-text' );
@@ -278,7 +278,7 @@ class RevisionDeleteForm {
$hidden[] = Xml::hidden( 'artimestamp[]', $rev->getTimestamp() );
}
$special = SpecialPage::getTitleFor( 'Revisiondelete' );
- $wgOut->addHtml(
+ $wgOut->addHTML(
Xml::openElement( 'form', array( 'method' => 'post', 'action' => $special->getLocalUrl( 'action=submit' ),
'id' => 'mw-revdel-form-revisions' ) ) .
Xml::openElement( 'fieldset' ) .
@@ -287,15 +287,15 @@ class RevisionDeleteForm {
// FIXME: all items checked for just one rev are checked, even if not set for the others
foreach( $this->checks as $item ) {
list( $message, $name, $field ) = $item;
- $wgOut->addHtml( Xml::tags( 'div', null, Xml::checkLabel( wfMsg( $message ), $name, $name, $bitfields & $field ) ) );
+ $wgOut->addHTML( Xml::tags( 'div', null, Xml::checkLabel( wfMsg( $message ), $name, $name, $bitfields & $field ) ) );
}
foreach( $items as $item ) {
- $wgOut->addHtml( Xml::tags( 'p', null, $item ) );
+ $wgOut->addHTML( Xml::tags( 'p', null, $item ) );
}
foreach( $hidden as $item ) {
- $wgOut->addHtml( $item );
+ $wgOut->addHTML( $item );
}
- $wgOut->addHtml(
+ $wgOut->addHTML(
Xml::closeElement( 'fieldset' ) .
Xml::closeElement( 'form' ) . "\n"
);
@@ -317,7 +317,7 @@ class RevisionDeleteForm {
$wgLang->formatNum($count) );
$bitfields = 0;
- $wgOut->addHtml( "<ul>" );
+ $wgOut->addHTML( "<ul>" );
$where = $filesObjs = array();
$dbr = wfGetDB( DB_SLAVE );
@@ -326,11 +326,11 @@ class RevisionDeleteForm {
if( $this->deleteKey=='oldimage' ) {
// Run through and pull all our data in one query
foreach( $this->ofiles as $timestamp ) {
- $where[] = $dbr->addQuotes( $timestamp.'!'.$this->page->getDbKey() );
+ $where[] = $dbr->addQuotes( $timestamp.'!'.$this->page->getDBKey() );
}
$whereClause = 'oi_archive_name IN(' . implode(',',$where) . ')';
$result = $dbr->select( 'oldimage', '*',
- array( 'oi_name' => $this->page->getDbKey(),
+ array( 'oi_name' => $this->page->getDBKey(),
$whereClause ),
__METHOD__ );
while( $row = $dbr->fetchObject( $result ) ) {
@@ -340,7 +340,7 @@ class RevisionDeleteForm {
}
// Check through our images
foreach( $this->ofiles as $timestamp ) {
- $archivename = $timestamp.'!'.$this->page->getDbKey();
+ $archivename = $timestamp.'!'.$this->page->getDBKey();
if( !isset($filesObjs[$archivename]) ) {
continue;
} else if( !$filesObjs[$archivename]->userCan(File::DELETED_RESTRICTED) ) {
@@ -353,7 +353,7 @@ class RevisionDeleteForm {
}
$revisions++;
// Inject history info
- $wgOut->addHtml( $this->fileLine( $filesObjs[$archivename] ) );
+ $wgOut->addHTML( $this->fileLine( $filesObjs[$archivename] ) );
$bitfields |= $filesObjs[$archivename]->deleted;
}
// Archived files...
@@ -364,7 +364,7 @@ class RevisionDeleteForm {
}
$whereClause = 'fa_id IN(' . implode(',',$where) . ')';
$result = $dbr->select( 'filearchive', '*',
- array( 'fa_name' => $this->page->getDbKey(),
+ array( 'fa_name' => $this->page->getDBKey(),
$whereClause ),
__METHOD__ );
while( $row = $dbr->fetchObject( $result ) ) {
@@ -384,7 +384,7 @@ class RevisionDeleteForm {
}
$revisions++;
// Inject history info
- $wgOut->addHtml( $this->archivedfileLine( $filesObjs[$fileid] ) );
+ $wgOut->addHTML( $this->archivedfileLine( $filesObjs[$fileid] ) );
$bitfields |= $filesObjs[$fileid]->deleted;
}
}
@@ -393,7 +393,7 @@ class RevisionDeleteForm {
return;
}
- $wgOut->addHtml( "</ul>" );
+ $wgOut->addHTML( "</ul>" );
$wgOut->addWikiMsg('revdelete-text' );
//Normal sysops can always see what they did, but can't always change it
@@ -416,7 +416,7 @@ class RevisionDeleteForm {
$hidden[] = Xml::hidden( 'fileid[]', $fileid );
}
$special = SpecialPage::getTitleFor( 'Revisiondelete' );
- $wgOut->addHtml(
+ $wgOut->addHTML(
Xml::openElement( 'form', array( 'method' => 'post', 'action' => $special->getLocalUrl( 'action=submit' ),
'id' => 'mw-revdel-form-filerevisions' ) ) .
Xml::fieldset( wfMsg( 'revdelete-legend' ) )
@@ -424,16 +424,16 @@ class RevisionDeleteForm {
// FIXME: all items checked for just one file are checked, even if not set for the others
foreach( $this->checks as $item ) {
list( $message, $name, $field ) = $item;
- $wgOut->addHtml( Xml::tags( 'div', null, Xml::checkLabel( wfMsg( $message ), $name, $name, $bitfields & $field ) ) );
+ $wgOut->addHTML( Xml::tags( 'div', null, Xml::checkLabel( wfMsg( $message ), $name, $name, $bitfields & $field ) ) );
}
foreach( $items as $item ) {
- $wgOut->addHtml( "<p>$item</p>" );
+ $wgOut->addHTML( "<p>$item</p>" );
}
foreach( $hidden as $item ) {
- $wgOut->addHtml( $item );
+ $wgOut->addHTML( $item );
}
- $wgOut->addHtml(
+ $wgOut->addHTML(
Xml::closeElement( 'fieldset' ) .
Xml::closeElement( 'form' ) . "\n"
);
@@ -449,7 +449,7 @@ class RevisionDeleteForm {
$wgOut->addWikiMsg( 'logdelete-selected', $wgLang->formatNum( count($this->events) ) );
$bitfields = 0;
- $wgOut->addHtml( "<ul>" );
+ $wgOut->addHTML( "<ul>" );
$where = $logRows = array();
$dbr = wfGetDB( DB_SLAVE );
@@ -480,7 +480,7 @@ class RevisionDeleteForm {
$UserAllowed = false;
}
$logItems++;
- $wgOut->addHtml( $this->logLine( $logRows[$logid] ) );
+ $wgOut->addHTML( $this->logLine( $logRows[$logid] ) );
$bitfields |= $logRows[$logid]->log_deleted;
}
if( !$logItems ) {
@@ -488,7 +488,7 @@ class RevisionDeleteForm {
return;
}
- $wgOut->addHtml( "</ul>" );
+ $wgOut->addHTML( "</ul>" );
$wgOut->addWikiMsg( 'revdelete-text' );
// Normal sysops can always see what they did, but can't always change it
@@ -506,7 +506,7 @@ class RevisionDeleteForm {
}
$special = SpecialPage::getTitleFor( 'Revisiondelete' );
- $wgOut->addHtml(
+ $wgOut->addHTML(
Xml::openElement( 'form', array( 'method' => 'post', 'action' => $special->getLocalUrl( 'action=submit' ),
'id' => 'mw-revdel-form-logs' ) ) .
Xml::fieldset( wfMsg( 'revdelete-legend' ) )
@@ -514,16 +514,16 @@ class RevisionDeleteForm {
// FIXME: all items checked for just on event are checked, even if not set for the others
foreach( $this->checks as $item ) {
list( $message, $name, $field ) = $item;
- $wgOut->addHtml( Xml::tags( 'div', null, Xml::checkLabel( wfMsg( $message ), $name, $name, $bitfields & $field ) ) );
+ $wgOut->addHTML( Xml::tags( 'div', null, Xml::checkLabel( wfMsg( $message ), $name, $name, $bitfields & $field ) ) );
}
foreach( $items as $item ) {
- $wgOut->addHtml( "<p>$item</p>" );
+ $wgOut->addHTML( "<p>$item</p>" );
}
foreach( $hidden as $item ) {
- $wgOut->addHtml( $item );
+ $wgOut->addHTML( $item );
}
- $wgOut->addHtml(
+ $wgOut->addHTML(
Xml::closeElement( 'fieldset' ) .
Xml::closeElement( 'form' ) . "\n"
);
@@ -606,7 +606,7 @@ class RevisionDeleteForm {
* @returns string
*/
private function archivedfileLine( $file ) {
- global $wgLang, $wgTitle;
+ global $wgLang;
$target = $this->page->getPrefixedText();
$date = $wgLang->timeanddate( $file->getTimestamp(), true );
@@ -939,11 +939,11 @@ class RevisionDeleter {
$set = array();
// Run through and pull all our data in one query
foreach( $items as $timestamp ) {
- $where[] = $this->dbw->addQuotes( $timestamp.'!'.$title->getDbKey() );
+ $where[] = $this->dbw->addQuotes( $timestamp.'!'.$title->getDBKey() );
}
$whereClause = 'oi_archive_name IN(' . implode(',',$where) . ')';
$result = $this->dbw->select( 'oldimage', '*',
- array( 'oi_name' => $title->getDbKey(),
+ array( 'oi_name' => $title->getDBKey(),
$whereClause ),
__METHOD__ );
while( $row = $this->dbw->fetchObject( $result ) ) {
@@ -953,7 +953,7 @@ class RevisionDeleter {
}
// To work!
foreach( $items as $timestamp ) {
- $archivename = $timestamp.'!'.$title->getDbKey();
+ $archivename = $timestamp.'!'.$title->getDBKey();
if( !isset($filesObjs[$archivename]) ) {
$success = false;
continue; // Must exist
@@ -1036,7 +1036,7 @@ class RevisionDeleter {
}
$whereClause = 'fa_id IN(' . implode(',',$where) . ')';
$result = $this->dbw->select( 'filearchive', '*',
- array( 'fa_name' => $title->getDbKey(),
+ array( 'fa_name' => $title->getDBKey(),
$whereClause ),
__METHOD__ );
while( $row = $this->dbw->fetchObject( $result ) ) {
@@ -1344,7 +1344,7 @@ class RevisionDeleter {
function updatePage( $title ) {
$title->invalidateCache();
$title->purgeSquid();
-
+ $title->touchLinks();
// Extensions that require referencing previous revisions may need this
wfRunHooks( 'ArticleRevisionVisiblitySet', array( &$title ) );
}
diff --git a/includes/specials/SpecialSearch.php b/includes/specials/SpecialSearch.php
index f13c1676..f3117242 100644
--- a/includes/specials/SpecialSearch.php
+++ b/includes/specials/SpecialSearch.php
@@ -29,13 +29,18 @@
* @param $par String: (default '')
*/
function wfSpecialSearch( $par = '' ) {
- global $wgRequest, $wgUser;
-
- $search = str_replace( "\n", " ", $wgRequest->getText( 'search', $par ) );
- $searchPage = new SpecialSearch( $wgRequest, $wgUser );
+ global $wgRequest, $wgUser, $wgUseOldSearchUI;
+ // Strip underscores from title parameter; most of the time we'll want
+ // text form here. But don't strip underscores from actual text params!
+ $titleParam = str_replace( '_', ' ', $par );
+ // Fetch the search term
+ $search = str_replace( "\n", " ", $wgRequest->getText( 'search', $titleParam ) );
+ $class = $wgUseOldSearchUI ? 'SpecialSearchOld' : 'SpecialSearch';
+ $searchPage = new $class( $wgRequest, $wgUser );
if( $wgRequest->getVal( 'fulltext' )
|| !is_null( $wgRequest->getVal( 'offset' ))
- || !is_null( $wgRequest->getVal( 'searchx' ))) {
+ || !is_null( $wgRequest->getVal( 'searchx' )) )
+ {
$searchPage->showResults( $search, 'search' );
} else {
$searchPage->goResult( $search );
@@ -56,9 +61,806 @@ class SpecialSearch {
* @param User $user
* @public
*/
- function SpecialSearch( &$request, &$user ) {
+ function __construct( &$request, &$user ) {
list( $this->limit, $this->offset ) = $request->getLimitOffset( 20, 'searchlimit' );
+ $this->mPrefix = $request->getVal('prefix', '');
+ # Extract requested namespaces
+ $this->namespaces = $this->powerSearch( $request );
+ if( empty( $this->namespaces ) ) {
+ $this->namespaces = SearchEngine::userNamespaces( $user );
+ }
+ $this->searchRedirects = $request->getcheck( 'redirs' ) ? true : false;
+ $this->searchAdvanced = $request->getVal( 'advanced' );
+ $this->active = 'advanced';
+ $this->sk = $user->getSkin();
+ $this->didYouMeanHtml = ''; # html of did you mean... link
+ }
+
+ /**
+ * If an exact title match can be found, jump straight ahead to it.
+ * @param string $term
+ */
+ public function goResult( $term ) {
+ global $wgOut;
+ $this->setupPage( $term );
+ # 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 ) ) {
+ return $this->showResults( $term );
+ }
+ # If there's an exact or very near match, jump right there.
+ $t = SearchEngine::getNearMatch( $term );
+ if( !is_null( $t ) ) {
+ $wgOut->redirect( $t->getFullURL() );
+ return;
+ }
+ # No match, generate an edit URL
+ $t = Title::newFromText( $term );
+ if( !is_null( $t ) ) {
+ global $wgGoToEdit;
+ wfRunHooks( 'SpecialSearchNogomatch', array( &$t ) );
+ # If the feature is enabled, go straight to the edit page
+ if( $wgGoToEdit ) {
+ $wgOut->redirect( $t->getFullURL( 'action=edit' ) );
+ return;
+ }
+ }
+ return $this->showResults( $term );
+ }
+
+ /**
+ * @param string $term
+ */
+ public function showResults( $term ) {
+ global $wgOut, $wgUser, $wgDisableTextSearch, $wgContLang;
+ wfProfileIn( __METHOD__ );
+
+ $sk = $wgUser->getSkin();
+
+ $this->searchEngine = SearchEngine::create();
+ $search =& $this->searchEngine;
+ $search->setLimitOffset( $this->limit, $this->offset );
+ $search->setNamespaces( $this->namespaces );
+ $search->showRedirects = $this->searchRedirects;
+ $search->prefix = $this->mPrefix;
+ $term = $search->transformSearchTerm($term);
+
+ $this->setupPage( $term );
+
+ if( $wgDisableTextSearch ) {
+ global $wgSearchForwardUrl;
+ if( $wgSearchForwardUrl ) {
+ $url = str_replace( '$1', urlencode( $term ), $wgSearchForwardUrl );
+ $wgOut->redirect( $url );
+ wfProfileOut( __METHOD__ );
+ return;
+ }
+ global $wgInputEncoding;
+ $wgOut->addHTML(
+ Xml::openElement( 'fieldset' ) .
+ Xml::element( 'legend', null, wfMsg( 'search-external' ) ) .
+ Xml::element( 'p', array( 'class' => 'mw-searchdisabled' ), wfMsg( 'searchdisabled' ) ) .
+ wfMsg( 'googlesearch',
+ htmlspecialchars( $term ),
+ htmlspecialchars( $wgInputEncoding ),
+ htmlspecialchars( wfMsg( 'searchbutton' ) )
+ ) .
+ Xml::closeElement( 'fieldset' )
+ );
+ wfProfileOut( __METHOD__ );
+ return;
+ }
+
+ $t = Title::newFromText( $term );
+
+ // fetch search results
+ $rewritten = $search->replacePrefixes($term);
+
+ $titleMatches = $search->searchTitle( $rewritten );
+ if( !($titleMatches instanceof SearchResultTooMany))
+ $textMatches = $search->searchText( $rewritten );
+
+ // did you mean... suggestions
+ if( $textMatches && $textMatches->hasSuggestion() ) {
+ $st = SpecialPage::getTitleFor( 'Search' );
+ $stParams = wfArrayToCGI(
+ array( 'search' => $textMatches->getSuggestionQuery(), 'fulltext' => wfMsg('search') ),
+ $this->powerSearchOptions()
+ );
+ $suggestLink = $sk->makeKnownLinkObj( $st,
+ $textMatches->getSuggestionSnippet(),
+ $stParams );
+
+ $this->didYouMeanHtml = '<div class="searchdidyoumean">'.wfMsg('search-suggest',$suggestLink).'</div>';
+ }
+
+ // start rendering the page
+ $wgOut->addHtml(
+ Xml::openElement( 'table', array( 'border'=>0, 'cellpadding'=>0, 'cellspacing'=>0 ) ) .
+ Xml::openElement( 'tr' ) .
+ Xml::openElement( 'td' ) . "\n" .
+ ( $this->searchAdvanced ? $this->powerSearchBox( $term ) : $this->shortDialog( $term ) ) .
+ Xml::closeElement('td') .
+ Xml::closeElement('tr') .
+ Xml::closeElement('table')
+ );
+
+ // Sometimes the search engine knows there are too many hits
+ if( $titleMatches instanceof SearchResultTooMany ) {
+ $wgOut->addWikiText( '==' . wfMsg( 'toomanymatches' ) . "==\n" );
+ wfProfileOut( __METHOD__ );
+ return;
+ }
+
+ $filePrefix = $wgContLang->getFormattedNsText(NS_FILE).':';
+ if( '' === trim( $term ) || $filePrefix === trim( $term ) ) {
+ $wgOut->addHTML( $this->searchAdvanced ? $this->powerSearchFocus() : $this->searchFocus() );
+ // Empty query -- straight view of search form
+ wfProfileOut( __METHOD__ );
+ return;
+ }
+
+ // show direct page/create link
+ if( !is_null($t) ) {
+ if( !$t->exists() ) {
+ $wgOut->addWikiMsg( 'searchmenu-new', wfEscapeWikiText( $t->getPrefixedText() ) );
+ } else {
+ $wgOut->addWikiMsg( 'searchmenu-exists', wfEscapeWikiText( $t->getPrefixedText() ) );
+ }
+ }
+
+ // Get number of results
+ $titleMatchesSQL = $titleMatches ? $titleMatches->numRows() : 0;
+ $textMatchesSQL = $textMatches ? $textMatches->numRows() : 0;
+ // Total initial query matches (possible false positives)
+ $numSQL = $titleMatchesSQL + $textMatchesSQL;
+ // Get total actual results (after second filtering, if any)
+ $numTitleMatches = $titleMatches && !is_null( $titleMatches->getTotalHits() ) ?
+ $titleMatches->getTotalHits() : $titleMatchesSQL;
+ $numTextMatches = $textMatches && !is_null( $textMatches->getTotalHits() ) ?
+ $textMatches->getTotalHits() : $textMatchesSQL;
+ $totalRes = $numTitleMatches + $numTextMatches;
+
+ // show number of results and current offset
+ if( $numSQL > 0 ) {
+ if( $numSQL > 0 ) {
+ $top = wfMsgExt('showingresultstotal', array( 'parseinline' ),
+ $this->offset+1, $this->offset+$numSQL, $totalRes, $numSQL );
+ } elseif( $numSQL >= $this->limit ) {
+ $top = wfShowingResults( $this->offset, $this->limit );
+ } else {
+ $top = wfShowingResultsNum( $this->offset, $this->limit, $numSQL );
+ }
+ $wgOut->addHTML( "<p class='mw-search-numberresults'>{$top}</p>\n" );
+ }
+
+ // prev/next links
+ if( $numSQL || $this->offset ) {
+ $prevnext = wfViewPrevNext( $this->offset, $this->limit,
+ SpecialPage::getTitleFor( 'Search' ),
+ wfArrayToCGI( $this->powerSearchOptions(), array( 'search' => $term ) ),
+ max( $titleMatchesSQL, $textMatchesSQL ) < $this->limit
+ );
+ $wgOut->addHTML( "<p class='mw-search-pager-top'>{$prevnext}</p>\n" );
+ wfRunHooks( 'SpecialSearchResults', array( $term, &$titleMatches, &$textMatches ) );
+ } else {
+ wfRunHooks( 'SpecialSearchNoResults', array( $term ) );
+ }
+
+ $wgOut->addHtml( "<div class='searchresults'>" );
+ if( $titleMatches ) {
+ if( $numTitleMatches > 0 ) {
+ $wgOut->wrapWikiMsg( "==$1==\n", 'titlematches' );
+ $wgOut->addHTML( $this->showMatches( $titleMatches ) );
+ }
+ $titleMatches->free();
+ }
+ if( $textMatches ) {
+ // output appropriate heading
+ if( $numTextMatches > 0 && $numTitleMatches > 0 ) {
+ // if no title matches the heading is redundant
+ $wgOut->wrapWikiMsg( "==$1==\n", 'textmatches' );
+ } elseif( $totalRes == 0 ) {
+ # Don't show the 'no text matches' if we received title matches
+ $wgOut->wrapWikiMsg( "==$1==\n", 'notextmatches' );
+ }
+ // show interwiki results if any
+ if( $textMatches->hasInterwikiResults() ) {
+ $wgOut->addHTML( $this->showInterwiki( $textMatches->getInterwikiResults(), $term ) );
+ }
+ // show results
+ if( $numTextMatches > 0 ) {
+ $wgOut->addHTML( $this->showMatches( $textMatches ) );
+ }
+
+ $textMatches->free();
+ }
+ if( $totalRes === 0 ) {
+ $wgOut->addWikiMsg( 'search-nonefound' );
+ }
+ $wgOut->addHtml( "</div>" );
+ if( $totalRes === 0 ) {
+ $wgOut->addHTML( $this->searchAdvanced ? $this->powerSearchFocus() : $this->searchFocus() );
+ }
+
+ if( $numSQL || $this->offset ) {
+ $wgOut->addHTML( "<p class='mw-search-pager-bottom'>{$prevnext}</p>\n" );
+ }
+ wfProfileOut( __METHOD__ );
+ }
+
+ /**
+ *
+ */
+ protected function setupPage( $term ) {
+ global $wgOut;
+ // Figure out the active search profile header
+ $nsAllSet = array_keys( SearchEngine::searchableNamespaces() );
+ if( $this->searchAdvanced )
+ $this->active = 'advanced';
+ else if( $this->namespaces === NS_FILE || $this->startsWithImage( $term ) )
+ $this->active = 'images';
+ elseif( $this->namespaces === $nsAllSet )
+ $this->active = 'all';
+ elseif( $this->namespaces === SearchEngine::defaultNamespaces() )
+ $this->active = 'default';
+ elseif( $this->namespaces === SearchEngine::projectNamespaces() )
+ $this->active = 'project';
+ else
+ $this->active = 'advanced';
+ # Should advanced UI be used?
+ $this->searchAdvanced = ($this->active === 'advanced');
+ if( !empty( $term ) ) {
+ $wgOut->setPageTitle( wfMsg( 'searchresults') );
+ $wgOut->setHTMLTitle( wfMsg( 'pagetitle', wfMsg( 'searchresults-title', $term ) ) );
+ }
+ $wgOut->setArticleRelated( false );
+ $wgOut->setRobotPolicy( 'noindex,nofollow' );
+ }
+
+ /**
+ * Extract "power search" namespace settings from the request object,
+ * returning a list of index numbers to search.
+ *
+ * @param WebRequest $request
+ * @return array
+ */
+ protected function powerSearch( &$request ) {
+ $arr = array();
+ foreach( SearchEngine::searchableNamespaces() as $ns => $name ) {
+ if( $request->getCheck( 'ns' . $ns ) ) {
+ $arr[] = $ns;
+ }
+ }
+ return $arr;
+ }
+ /**
+ * Reconstruct the 'power search' options for links
+ * @return array
+ */
+ protected function powerSearchOptions() {
+ $opt = array();
+ foreach( $this->namespaces as $n ) {
+ $opt['ns' . $n] = 1;
+ }
+ $opt['redirs'] = $this->searchRedirects ? 1 : 0;
+ if( $this->searchAdvanced ) {
+ $opt['advanced'] = $this->searchAdvanced;
+ }
+ return $opt;
+ }
+
+ /**
+ * Show whole set of results
+ *
+ * @param SearchResultSet $matches
+ */
+ protected function showMatches( &$matches ) {
+ global $wgContLang;
+ wfProfileIn( __METHOD__ );
+
+ $terms = $wgContLang->convertForSearchResult( $matches->termMatches() );
+
+ $out = "";
+ $infoLine = $matches->getInfo();
+ if( !is_null($infoLine) ) {
+ $out .= "\n<!-- {$infoLine} -->\n";
+ }
+ $off = $this->offset + 1;
+ $out .= "<ul class='mw-search-results'>\n";
+ while( $result = $matches->next() ) {
+ $out .= $this->showHit( $result, $terms );
+ }
+ $out .= "</ul>\n";
+
+ // convert the whole thing to desired language variant
+ $out = $wgContLang->convert( $out );
+ wfProfileOut( __METHOD__ );
+ return $out;
+ }
+
+ /**
+ * Format a single hit result
+ * @param SearchResult $result
+ * @param array $terms terms to highlight
+ */
+ protected function showHit( $result, $terms ) {
+ global $wgContLang, $wgLang, $wgUser;
+ wfProfileIn( __METHOD__ );
+
+ if( $result->isBrokenTitle() ) {
+ wfProfileOut( __METHOD__ );
+ return "<!-- Broken link in search result -->\n";
+ }
+
+ $sk = $wgUser->getSkin();
+ $t = $result->getTitle();
+
+ $link = $this->sk->makeKnownLinkObj( $t, $result->getTitleSnippet($terms));
+
+ //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->userCanRead() ) {
+ wfProfileOut( __METHOD__ );
+ return "<li>{$link}</li>\n";
+ }
+
+ // 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() ) {
+ wfProfileOut( __METHOD__ );
+ return "<!-- missing page " . htmlspecialchars( $t->getPrefixedText() ) . "-->\n";
+ }
+
+ // format redirects / relevant sections
+ $redirectTitle = $result->getRedirectTitle();
+ $redirectText = $result->getRedirectSnippet($terms);
+ $sectionTitle = $result->getSectionTitle();
+ $sectionText = $result->getSectionSnippet($terms);
+ $redirect = '';
+ if( !is_null($redirectTitle) )
+ $redirect = "<span class='searchalttitle'>"
+ .wfMsg('search-redirect',$this->sk->makeKnownLinkObj( $redirectTitle, $redirectText))
+ ."</span>";
+ $section = '';
+ if( !is_null($sectionTitle) )
+ $section = "<span class='searchalttitle'>"
+ .wfMsg('search-section', $this->sk->makeKnownLinkObj( $sectionTitle, $sectionText))
+ ."</span>";
+
+ // format text extract
+ $extract = "<div class='searchresult'>".$result->getTextSnippet($terms)."</div>";
+
+ // format score
+ if( is_null( $result->getScore() ) ) {
+ // Search engine doesn't report scoring info
+ $score = '';
+ } else {
+ $percent = sprintf( '%2.1f', $result->getScore() * 100 );
+ $score = wfMsg( 'search-result-score', $wgLang->formatNum( $percent ) )
+ . ' - ';
+ }
+
+ // format description
+ $byteSize = $result->getByteSize();
+ $wordCount = $result->getWordCount();
+ $timestamp = $result->getTimestamp();
+ $size = wfMsgExt( 'search-result-size', array( 'parsemag', 'escape' ),
+ $this->sk->formatSize( $byteSize ), $wordCount );
+ $date = $wgLang->timeanddate( $timestamp );
+
+ // link to related articles if supported
+ $related = '';
+ if( $result->hasRelated() ) {
+ $st = SpecialPage::getTitleFor( 'Search' );
+ $stParams = wfArrayToCGI( $this->powerSearchOptions(),
+ array('search' => wfMsgForContent('searchrelated').':'.$t->getPrefixedText(),
+ 'fulltext' => wfMsg('search') ));
+
+ $related = ' -- ' . $sk->makeKnownLinkObj( $st,
+ wfMsg('search-relatedarticle'), $stParams );
+ }
+
+ // Include a thumbnail for media files...
+ if( $t->getNamespace() == NS_FILE ) {
+ $img = wfFindFile( $t );
+ if( $img ) {
+ $thumb = $img->transform( array( 'width' => 120, 'height' => 120 ) );
+ if( $thumb ) {
+ $desc = $img->getShortDesc();
+ wfProfileOut( __METHOD__ );
+ // Float doesn't seem to interact well with the bullets.
+ // Table messes up vertical alignment of the bullets.
+ // Bullets are therefore disabled (didn't look great anyway).
+ return "<li>" .
+ '<table class="searchResultImage">' .
+ '<tr>' .
+ '<td width="120" align="center" valign="top">' .
+ $thumb->toHtml( array( 'desc-link' => true ) ) .
+ '</td>' .
+ '<td valign="top">' .
+ $link .
+ $extract .
+ "<div class='mw-search-result-data'>{$score}{$desc} - {$date}{$related}</div>" .
+ '</td>' .
+ '</tr>' .
+ '</table>' .
+ "</li>\n";
+ }
+ }
+ }
+
+ wfProfileOut( __METHOD__ );
+ return "<li>{$link} {$redirect} {$section} {$extract}\n" .
+ "<div class='mw-search-result-data'>{$score}{$size} - {$date}{$related}</div>" .
+ "</li>\n";
+
+ }
+
+ /**
+ * Show results from other wikis
+ *
+ * @param SearchResultSet $matches
+ */
+ protected function showInterwiki( &$matches, $query ) {
+ global $wgContLang;
+ wfProfileIn( __METHOD__ );
+ $terms = $wgContLang->convertForSearchResult( $matches->termMatches() );
+
+ $out = "<div id='mw-search-interwiki'><div id='mw-search-interwiki-caption'>".
+ wfMsg('search-interwiki-caption')."</div>\n";
+ $off = $this->offset + 1;
+ $out .= "<ul class='mw-search-iwresults'>\n";
+
+ // work out custom project captions
+ $customCaptions = array();
+ $customLines = explode("\n",wfMsg('search-interwiki-custom')); // format per line <iwprefix>:<caption>
+ foreach($customLines as $line) {
+ $parts = explode(":",$line,2);
+ if(count($parts) == 2) // validate line
+ $customCaptions[$parts[0]] = $parts[1];
+ }
+
+ $prev = null;
+ while( $result = $matches->next() ) {
+ $out .= $this->showInterwikiHit( $result, $prev, $terms, $query, $customCaptions );
+ $prev = $result->getInterwikiPrefix();
+ }
+ // FIXME: should support paging in a non-confusing way (not sure how though, maybe via ajax)..
+ $out .= "</ul></div>\n";
+
+ // convert the whole thing to desired language variant
+ $out = $wgContLang->convert( $out );
+ wfProfileOut( __METHOD__ );
+ return $out;
+ }
+
+ /**
+ * Show single interwiki link
+ *
+ * @param SearchResult $result
+ * @param string $lastInterwiki
+ * @param array $terms
+ * @param string $query
+ * @param array $customCaptions iw prefix -> caption
+ */
+ protected function showInterwikiHit( $result, $lastInterwiki, $terms, $query, $customCaptions) {
+ wfProfileIn( __METHOD__ );
+ global $wgContLang, $wgLang;
+
+ if( $result->isBrokenTitle() ) {
+ wfProfileOut( __METHOD__ );
+ return "<!-- Broken link in search result -->\n";
+ }
+
+ $t = $result->getTitle();
+
+ $link = $this->sk->makeKnownLinkObj( $t, $result->getTitleSnippet($terms));
+
+ // format redirect if any
+ $redirectTitle = $result->getRedirectTitle();
+ $redirectText = $result->getRedirectSnippet($terms);
+ $redirect = '';
+ if( !is_null($redirectTitle) )
+ $redirect = "<span class='searchalttitle'>"
+ .wfMsg('search-redirect',$this->sk->makeKnownLinkObj( $redirectTitle, $redirectText))
+ ."</span>";
+
+ $out = "";
+ // display project name
+ if(is_null($lastInterwiki) || $lastInterwiki != $t->getInterwiki()) {
+ if( key_exists($t->getInterwiki(),$customCaptions) )
+ // captions from 'search-interwiki-custom'
+ $caption = $customCaptions[$t->getInterwiki()];
+ else{
+ // default is to show the hostname of the other wiki which might suck
+ // if there are many wikis on one hostname
+ $parsed = parse_url($t->getFullURL());
+ $caption = wfMsg('search-interwiki-default', $parsed['host']);
+ }
+ // "more results" link (special page stuff could be localized, but we might not know target lang)
+ $searchTitle = Title::newFromText($t->getInterwiki().":Special:Search");
+ $searchLink = $this->sk->makeKnownLinkObj( $searchTitle, wfMsg('search-interwiki-more'),
+ wfArrayToCGI(array('search' => $query, 'fulltext' => 'Search')));
+ $out .= "</ul><div class='mw-search-interwiki-project'><span class='mw-search-interwiki-more'>
+ {$searchLink}</span>{$caption}</div>\n<ul>";
+ }
+
+ $out .= "<li>{$link} {$redirect}</li>\n";
+ wfProfileOut( __METHOD__ );
+ return $out;
+ }
+
+
+ /**
+ * Generates the power search box at bottom of [[Special:Search]]
+ * @param $term string: search term
+ * @return $out string: HTML form
+ */
+ protected function powerSearchBox( $term ) {
+ global $wgScript;
+
+ $namespaces = SearchEngine::searchableNamespaces();
+
+ $tables = $this->namespaceTables( $namespaces );
+
+ $redirect = Xml::check( 'redirs', $this->searchRedirects, array( 'value' => '1', 'id' => 'redirs' ) );
+ $redirectLabel = Xml::label( wfMsg( 'powersearch-redir' ), 'redirs' );
+ $searchField = Xml::input( 'search', 50, $term, array( 'type' => 'text', 'id' => 'powerSearchText' ) );
+ $searchButton = Xml::submitButton( wfMsg( 'powersearch' ), array( 'name' => 'fulltext' )) . "\n";
+ $searchTitle = SpecialPage::getTitleFor( 'Search' );
+
+ $redirectText = '';
+ // show redirects check only if backend supports it
+ if( $this->searchEngine->acceptListRedirects() ) {
+ $redirectText = "<p>". $redirect . " " . $redirectLabel ."</p>";
+ }
+
+ $out = Xml::openElement( 'form', array( 'id' => 'powersearch', 'method' => 'get', 'action' => $wgScript ) ) .
+ Xml::hidden( 'title', $searchTitle->getPrefixedText() ) . "\n" .
+ "<p>" .
+ wfMsgExt( 'powersearch-ns', array( 'parseinline' ) ) .
+ "</p>\n" .
+ '<input type="hidden" name="advanced" value="'.$this->searchAdvanced."\"/>\n".
+ $tables .
+ "<hr style=\"clear: both;\" />\n".
+ $redirectText ."\n".
+ "<div style=\"padding-top:2px;padding-bottom:2px;\">".
+ wfMsgExt( 'powersearch-field', array( 'parseinline' ) ) .
+ "&nbsp;" .
+ $searchField .
+ "&nbsp;" .
+ $searchButton .
+ "</div>".
+ "</form>";
+ $t = Title::newFromText( $term );
+ /* if( $t != null && count($this->namespaces) === 1 ) {
+ $out .= wfMsgExt( 'searchmenu-prefix', array('parseinline'), $term );
+ } */
+ return Xml::openElement( 'fieldset', array('id' => 'mw-searchoptions','style' => 'margin:0em;') ) .
+ Xml::element( 'legend', null, wfMsg('powersearch-legend') ) .
+ $this->formHeader($term) . $out . $this->didYouMeanHtml .
+ Xml::closeElement( 'fieldset' );
+ }
+
+ protected function searchFocus() {
+ global $wgJsMimeType;
+ return "<script type=\"$wgJsMimeType\">" .
+ "hookEvent(\"load\", function() {" .
+ "document.getElementById('searchText').focus();" .
+ "});" .
+ "</script>";
+ }
+
+ protected function powerSearchFocus() {
+ global $wgJsMimeType;
+ return "<script type=\"$wgJsMimeType\">" .
+ "hookEvent(\"load\", function() {" .
+ "document.getElementById('powerSearchText').focus();" .
+ "});" .
+ "</script>";
+ }
+
+ protected function formHeader( $term ) {
+ global $wgContLang, $wgCanonicalNamespaceNames;
+
+ $sep = '&nbsp;&nbsp;&nbsp;';
+ $out = Xml::openElement('div', array( 'style' => 'padding-bottom:0.5em;' ) );
+
+ $bareterm = $term;
+ if( $this->startsWithImage( $term ) )
+ $bareterm = substr( $term, strpos( $term, ':' ) + 1 ); // delete all/image prefix
+
+ $nsAllSet = array_keys( SearchEngine::searchableNamespaces() );
+
+ // search profiles headers
+ $m = wfMsg( 'searchprofile-articles' );
+ $tt = wfMsg( 'searchprofile-articles-tooltip',
+ implode( ', ', SearchEngine::namespacesAsText( SearchEngine::defaultNamespaces() ) ) );
+ if( $this->active == 'default' ) {
+ $out .= Xml::element( 'strong', array( 'title'=>$tt ), $m );
+ } else {
+ $out .= $this->makeSearchLink( $bareterm, SearchEngine::defaultNamespaces(), $m, $tt );
+ }
+ $out .= $sep;
+
+ $m = wfMsg( 'searchprofile-images' );
+ $tt = wfMsg( 'searchprofile-images-tooltip' );
+ if( $this->active == 'images' ) {
+ $out .= Xml::element( 'strong', array( 'title'=>$tt ), $m );
+ } else {
+ $imageTextForm = $wgContLang->getFormattedNsText(NS_FILE).':'.$bareterm;
+ $out .= $this->makeSearchLink( $imageTextForm, array( NS_FILE ) , $m, $tt );
+ }
+ $out .= $sep;
+
+ /*
+ $m = wfMsg( 'searchprofile-articles-and-proj' );
+ $tt = wfMsg( 'searchprofile-project-tooltip',
+ implode( ', ', SearchEngine::namespacesAsText( SearchEngine::defaultAndProjectNamespaces() ) ) );
+ if( $this->active == 'withproject' ) {
+ $out .= Xml::element( 'strong', array( 'title'=>$tt ), $m );
+ } else {
+ $out .= $this->makeSearchLink( $bareterm, SearchEngine::defaultAndProjectNamespaces(), $m, $tt );
+ }
+ $out .= $sep;
+ */
+
+ $m = wfMsg( 'searchprofile-project' );
+ $tt = wfMsg( 'searchprofile-project-tooltip',
+ implode( ', ', SearchEngine::namespacesAsText( SearchEngine::projectNamespaces() ) ) );
+ if( $this->active == 'project' ) {
+ $out .= Xml::element( 'strong', array( 'title'=>$tt ), $m );
+ } else {
+ $out .= $this->makeSearchLink( $bareterm, SearchEngine::projectNamespaces(), $m, $tt );
+ }
+ $out .= $sep;
+
+ $m = wfMsg( 'searchprofile-everything' );
+ $tt = wfMsg( 'searchprofile-everything-tooltip' );
+ if( $this->active == 'all' ) {
+ $out .= Xml::element( 'strong', array( 'title'=>$tt ), $m );
+ } else {
+ $out .= $this->makeSearchLink( $bareterm, $nsAllSet, $m, $tt );
+ }
+ $out .= $sep;
+
+ $m = wfMsg( 'searchprofile-advanced' );
+ $tt = wfMsg( 'searchprofile-advanced-tooltip' );
+ if( $this->active == 'advanced' ) {
+ $out .= Xml::element( 'strong', array( 'title'=>$tt ), $m );
+ } else {
+ $out .= $this->makeSearchLink( $bareterm, $this->namespaces, $m, $tt, array( 'advanced' => '1' ) );
+ }
+ $out .= Xml::closeElement('div') ;
+
+ return $out;
+ }
+
+ protected function shortDialog( $term ) {
+ global $wgScript;
+ $searchTitle = SpecialPage::getTitleFor( 'Search' );
+ $searchable = SearchEngine::searchableNamespaces();
+ $out = Xml::openElement( 'form', array( 'id' => 'search', 'method' => 'get', 'action' => $wgScript ) );
+ $out .= Xml::hidden( 'title', $searchTitle->getPrefixedText() ) . "\n";
+ // show namespaces only for advanced search
+ if( $this->active == 'advanced' ) {
+ $active = array();
+ foreach( $this->namespaces as $ns ) {
+ $active[$ns] = $searchable[$ns];
+ }
+ $out .= wfMsgExt( 'powersearch-ns', array( 'parseinline' ) ) . "<br/>\n";
+ $out .= $this->namespaceTables( $active, 1 )."<br/>\n";
+ // Still keep namespace settings otherwise, but don't show them
+ } else {
+ foreach( $this->namespaces as $ns ) {
+ $out .= Xml::hidden( "ns{$ns}", '1' );
+ }
+ }
+ // Keep redirect setting
+ $out .= Xml::hidden( "redirs", (int)$this->searchRedirects );
+ // Term box
+ $out .= Xml::input( 'search', 50, $term, array( 'type' => 'text', 'id' => 'searchText' ) ) . "\n";
+ $out .= Xml::submitButton( wfMsg( 'searchbutton' ), array( 'name' => 'fulltext' ) );
+ $out .= ' (' . wfMsgExt('searchmenu-help',array('parseinline') ) . ')';
+ $out .= Xml::closeElement( 'form' );
+ // Add prefix link for single-namespace searches
+ $t = Title::newFromText( $term );
+ /*if( $t != null && count($this->namespaces) === 1 ) {
+ $out .= wfMsgExt( 'searchmenu-prefix', array('parseinline'), $term );
+ }*/
+ return Xml::openElement( 'fieldset', array('id' => 'mw-searchoptions','style' => 'margin:0em;') ) .
+ Xml::element( 'legend', null, wfMsg('searchmenu-legend') ) .
+ $this->formHeader($term) . $out . $this->didYouMeanHtml .
+ Xml::closeElement( 'fieldset' );
+ }
+
+ /** Make a search link with some target namespaces */
+ protected function makeSearchLink( $term, $namespaces, $label, $tooltip, $params=array() ) {
+ $opt = $params;
+ foreach( $namespaces as $n ) {
+ $opt['ns' . $n] = 1;
+ }
+ $opt['redirs'] = $this->searchRedirects ? 1 : 0;
+
+ $st = SpecialPage::getTitleFor( 'Search' );
+ $stParams = wfArrayToCGI( array( 'search' => $term, 'fulltext' => wfMsg( 'search' ) ), $opt );
+
+ return Xml::element( 'a',
+ array( 'href'=> $st->getLocalURL( $stParams ), 'title' => $tooltip ),
+ $label );
+ }
+
+ /** Check if query starts with image: prefix */
+ protected function startsWithImage( $term ) {
+ global $wgContLang;
+
+ $p = explode( ':', $term );
+ if( count( $p ) > 1 ) {
+ return $wgContLang->getNsIndex( $p[0] ) == NS_FILE;
+ }
+ return false;
+ }
+
+ protected function namespaceTables( $namespaces, $rowsPerTable = 3 ) {
+ global $wgContLang;
+ // Group namespaces into rows according to subject.
+ // Try not to make too many assumptions about namespace numbering.
+ $rows = array();
+ $tables = "";
+ foreach( $namespaces as $ns => $name ) {
+ $subj = MWNamespace::getSubject( $ns );
+ if( !array_key_exists( $subj, $rows ) ) {
+ $rows[$subj] = "";
+ }
+ $name = str_replace( '_', ' ', $name );
+ if( '' == $name ) {
+ $name = wfMsg( 'blanknamespace' );
+ }
+ $rows[$subj] .= Xml::openElement( 'td', array( 'style' => 'white-space: nowrap' ) ) .
+ Xml::checkLabel( $name, "ns{$ns}", "mw-search-ns{$ns}", in_array( $ns, $this->namespaces ) ) .
+ Xml::closeElement( 'td' ) . "\n";
+ }
+ $rows = array_values( $rows );
+ $numRows = count( $rows );
+ // Lay out namespaces in multiple floating two-column tables so they'll
+ // be arranged nicely while still accommodating different screen widths
+ // Float to the right on RTL wikis
+ $tableStyle = $wgContLang->isRTL() ?
+ 'float: right; margin: 0 0 0em 1em' : 'float: left; margin: 0 1em 0em 0';
+ // Build the final HTML table...
+ for( $i = 0; $i < $numRows; $i += $rowsPerTable ) {
+ $tables .= Xml::openElement( 'table', array( 'style' => $tableStyle ) );
+ for( $j = $i; $j < $i + $rowsPerTable && $j < $numRows; $j++ ) {
+ $tables .= "<tr>\n" . $rows[$j] . "</tr>";
+ }
+ $tables .= Xml::closeElement( 'table' ) . "\n";
+ }
+ return $tables;
+ }
+}
+
+/**
+ * implements Special:Search - Run text & title search and display the output
+ * @ingroup SpecialPage
+ */
+class SpecialSearchOld {
+
+ /**
+ * Set up basic search parameters from the request and user settings.
+ * Typically you'll pass $wgRequest and $wgUser.
+ *
+ * @param WebRequest $request
+ * @param User $user
+ * @public
+ */
+ function __construct( &$request, &$user ) {
+ list( $this->limit, $this->offset ) = $request->getLimitOffset( 20, 'searchlimit' );
+ $this->mPrefix = $request->getVal('prefix', '');
$this->namespaces = $this->powerSearch( $request );
if( empty( $this->namespaces ) ) {
$this->namespaces = SearchEngine::userNamespaces( $user );
@@ -119,13 +921,38 @@ class SpecialSearch {
* @public
*/
function showResults( $term ) {
- $fname = 'SpecialSearch::showResults';
- wfProfileIn( $fname );
+ wfProfileIn( __METHOD__ );
global $wgOut, $wgUser;
$sk = $wgUser->getSkin();
+ $search = SearchEngine::create();
+ $search->setLimitOffset( $this->limit, $this->offset );
+ $search->setNamespaces( $this->namespaces );
+ $search->showRedirects = $this->searchRedirects;
+ $search->prefix = $this->mPrefix;
+ $term = $search->transformSearchTerm($term);
+
$this->setupPage( $term );
+ $rewritten = $search->replacePrefixes($term);
+ $titleMatches = $search->searchTitle( $rewritten );
+ $textMatches = $search->searchText( $rewritten );
+
+ // did you mean... suggestions
+ if($textMatches && $textMatches->hasSuggestion()){
+ $st = SpecialPage::getTitleFor( 'Search' );
+ $stParams = wfArrayToCGI( array(
+ 'search' => $textMatches->getSuggestionQuery(),
+ 'fulltext' => wfMsg('search')),
+ $this->powerSearchOptions());
+
+ $suggestLink = $sk->makeKnownLinkObj( $st,
+ $textMatches->getSuggestionSnippet(),
+ $stParams );
+
+ $wgOut->addHTML('<div class="searchdidyoumean">'.wfMsg('search-suggest',$suggestLink).'</div>');
+ }
+
$wgOut->addWikiMsg( 'searchresulttext' );
if( '' === trim( $term ) ) {
@@ -133,7 +960,7 @@ class SpecialSearch {
$wgOut->setSubtitle( '' );
$wgOut->addHTML( $this->powerSearchBox( $term ) );
$wgOut->addHTML( $this->powerSearchFocus() );
- wfProfileOut( $fname );
+ wfProfileOut( __METHOD__ );
return;
}
@@ -143,6 +970,7 @@ class SpecialSearch {
if( $wgSearchForwardUrl ) {
$url = str_replace( '$1', urlencode( $term ), $wgSearchForwardUrl );
$wgOut->redirect( $url );
+ wfProfileOut( __METHOD__ );
return;
}
global $wgInputEncoding;
@@ -157,45 +985,21 @@ class SpecialSearch {
) .
Xml::closeElement( 'fieldset' )
);
- wfProfileOut( $fname );
+ wfProfileOut( __METHOD__ );
return;
}
- $wgOut->addHTML( $this->shortDialog( $term ) );
-
- $search = SearchEngine::create();
- $search->setLimitOffset( $this->limit, $this->offset );
- $search->setNamespaces( $this->namespaces );
- $search->showRedirects = $this->searchRedirects;
- $rewritten = $search->replacePrefixes($term);
-
- $titleMatches = $search->searchTitle( $rewritten );
+ $wgOut->addHTML( $this->shortDialog( $term ) );
// Sometimes the search engine knows there are too many hits
if ($titleMatches instanceof SearchResultTooMany) {
$wgOut->addWikiText( '==' . wfMsg( 'toomanymatches' ) . "==\n" );
$wgOut->addHTML( $this->powerSearchBox( $term ) );
$wgOut->addHTML( $this->powerSearchFocus() );
- wfProfileOut( $fname );
+ wfProfileOut( __METHOD__ );
return;
}
- $textMatches = $search->searchText( $rewritten );
-
- // did you mean... suggestions
- if($textMatches && $textMatches->hasSuggestion()){
- $st = SpecialPage::getTitleFor( 'Search' );
- $stParams = wfArrayToCGI( array(
- 'search' => $textMatches->getSuggestionQuery(),
- 'fulltext' => wfMsg('search')),
- $this->powerSearchOptions());
-
- $suggestLink = '<a href="'.$st->escapeLocalURL($stParams).'">'.
- $textMatches->getSuggestionSnippet().'</a>';
-
- $wgOut->addHTML('<div class="searchdidyoumean">'.wfMsg('search-suggest',$suggestLink).'</div>');
- }
-
// show number of results
$num = ( $titleMatches ? $titleMatches->numRows() : 0 )
+ ( $textMatches ? $textMatches->numRows() : 0);
@@ -207,7 +1011,7 @@ class SpecialSearch {
if ( $num > 0 ) {
if ( $totalNum > 0 ){
$top = wfMsgExt('showingresultstotal', array( 'parseinline' ),
- $this->offset+1, $this->offset+$num, $totalNum );
+ $this->offset+1, $this->offset+$num, $totalNum, $num );
} elseif ( $num >= $this->limit ) {
$top = wfShowingResults( $this->offset, $this->limit );
} else {
@@ -251,7 +1055,7 @@ class SpecialSearch {
}
// show interwiki results if any
if( $textMatches->hasInterwikiResults() )
- $wgOut->addHtml( $this->showInterwiki( $textMatches->getInterwikiResults(), $term ));
+ $wgOut->addHTML( $this->showInterwiki( $textMatches->getInterwikiResults(), $term ));
// show results
if( $textMatches->numRows() )
$wgOut->addHTML( $this->showMatches( $textMatches ) );
@@ -266,7 +1070,7 @@ class SpecialSearch {
$wgOut->addHTML( "<p class='mw-search-pager-bottom'>{$prevnext}</p>\n" );
}
$wgOut->addHTML( $this->powerSearchBox( $term ) );
- wfProfileOut( $fname );
+ wfProfileOut( __METHOD__ );
}
#------------------------------------------------------------------
@@ -277,12 +1081,14 @@ class SpecialSearch {
*/
function setupPage( $term ) {
global $wgOut;
- if( !empty( $term ) )
- $wgOut->setPageTitle( wfMsg( 'searchresults' ) );
+ if( !empty( $term ) ){
+ $wgOut->setPageTitle( wfMsg( 'searchresults') );
+ $wgOut->setHTMLTitle( wfMsg( 'pagetitle', wfMsg( 'searchresults-title', $term) ) );
+ }
$subtitlemsg = ( Title::newFromText( $term ) ? 'searchsubtitle' : 'searchsubtitleinvalid' );
$wgOut->setSubtitle( $wgOut->parse( wfMsg( $subtitlemsg, wfEscapeWikiText($term) ) ) );
$wgOut->setArticleRelated( false );
- $wgOut->setRobotpolicy( 'noindex,nofollow' );
+ $wgOut->setRobotPolicy( 'noindex,nofollow' );
}
/**
@@ -323,8 +1129,7 @@ class SpecialSearch {
* @param SearchResultSet $matches
*/
function showMatches( &$matches ) {
- $fname = 'SpecialSearch::showMatches';
- wfProfileIn( $fname );
+ wfProfileIn( __METHOD__ );
global $wgContLang;
$terms = $wgContLang->convertForSearchResult( $matches->termMatches() );
@@ -347,7 +1152,7 @@ class SpecialSearch {
// convert the whole thing to desired language variant
global $wgContLang;
$out = $wgContLang->convert( $out );
- wfProfileOut( $fname );
+ wfProfileOut( __METHOD__ );
return $out;
}
@@ -357,12 +1162,11 @@ class SpecialSearch {
* @param array $terms terms to highlight
*/
function showHit( $result, $terms ) {
- $fname = 'SpecialSearch::showHit';
- wfProfileIn( $fname );
+ wfProfileIn( __METHOD__ );
global $wgUser, $wgContLang, $wgLang;
if( $result->isBrokenTitle() ) {
- wfProfileOut( $fname );
+ wfProfileOut( __METHOD__ );
return "<!-- Broken link in search result -->\n";
}
@@ -375,7 +1179,7 @@ class SpecialSearch {
//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->userCanRead()) {
- wfProfileOut( $fname );
+ wfProfileOut( __METHOD__ );
return "<li>{$link}</li>\n";
}
@@ -383,7 +1187,7 @@ class SpecialSearch {
// The least confusing at this point is to drop the result.
// You may get less results, but... oh well. :P
if( $result->isMissingRevision() ) {
- wfProfileOut( $fname );
+ wfProfileOut( __METHOD__ );
return "<!-- missing page " .
htmlspecialchars( $t->getPrefixedText() ) . "-->\n";
}
@@ -434,18 +1238,18 @@ class SpecialSearch {
array('search' => wfMsgForContent('searchrelated').':'.$t->getPrefixedText(),
'fulltext' => wfMsg('search') ));
- $related = ' -- <a href="'.$st->escapeLocalURL($stParams).'">'.
- wfMsg('search-relatedarticle').'</a>';
+ $related = ' -- ' . $sk->makeKnownLinkObj( $st,
+ wfMsg('search-relatedarticle'), $stParams );
}
// Include a thumbnail for media files...
- if( $t->getNamespace() == NS_IMAGE ) {
+ if( $t->getNamespace() == NS_FILE ) {
$img = wfFindFile( $t );
if( $img ) {
- $thumb = $img->getThumbnail( 120, 120 );
+ $thumb = $img->transform( array( 'width' => 120, 'height' => 120 ) );
if( $thumb ) {
$desc = $img->getShortDesc();
- wfProfileOut( $fname );
+ wfProfileOut( __METHOD__ );
// Ugly table. :D
// Float doesn't seem to interact well with the bullets.
// Table messes up vertical alignment of the bullet, but I'm
@@ -468,7 +1272,7 @@ class SpecialSearch {
}
}
- wfProfileOut( $fname );
+ wfProfileOut( __METHOD__ );
return "<li>{$link} {$redirect} {$section} {$extract}\n" .
"<div class='mw-search-result-data'>{$score}{$size} - {$date}{$related}</div>" .
"</li>\n";
@@ -481,8 +1285,7 @@ class SpecialSearch {
* @param SearchResultSet $matches
*/
function showInterwiki( &$matches, $query ) {
- $fname = 'SpecialSearch::showInterwiki';
- wfProfileIn( $fname );
+ wfProfileIn( __METHOD__ );
global $wgContLang;
$terms = $wgContLang->convertForSearchResult( $matches->termMatches() );
@@ -512,7 +1315,7 @@ class SpecialSearch {
// convert the whole thing to desired language variant
global $wgContLang;
$out = $wgContLang->convert( $out );
- wfProfileOut( $fname );
+ wfProfileOut( __METHOD__ );
return $out;
}
@@ -525,13 +1328,12 @@ class SpecialSearch {
* @param string $query
* @param array $customCaptions iw prefix -> caption
*/
- function showInterwikiHit( $result, $lastInterwiki, $terms, $query, $customCaptions){
- $fname = 'SpecialSearch::showInterwikiHit';
- wfProfileIn( $fname );
+ function showInterwikiHit( $result, $lastInterwiki, $terms, $query, $customCaptions) {
+ wfProfileIn( __METHOD__ );
global $wgUser, $wgContLang, $wgLang;
if( $result->isBrokenTitle() ) {
- wfProfileOut( $fname );
+ wfProfileOut( __METHOD__ );
return "<!-- Broken link in search result -->\n";
}
@@ -569,7 +1371,7 @@ class SpecialSearch {
}
$out .= "<li>{$link} {$redirect}</li>\n";
- wfProfileOut( $fname );
+ wfProfileOut( __METHOD__ );
return $out;
}
@@ -580,35 +1382,64 @@ class SpecialSearch {
* @return $out string: HTML form
*/
function powerSearchBox( $term ) {
- global $wgScript;
+ global $wgScript, $wgContLang;
- $namespaces = '';
- foreach( SearchEngine::searchableNamespaces() as $ns => $name ) {
+ $namespaces = SearchEngine::searchableNamespaces();
+
+ // group namespaces into rows according to subject; try not to make too
+ // many assumptions about namespace numbering
+ $rows = array();
+ foreach( $namespaces as $ns => $name ) {
+ $subj = MWNamespace::getSubject( $ns );
+ if( !array_key_exists( $subj, $rows ) ) {
+ $rows[$subj] = "";
+ }
$name = str_replace( '_', ' ', $name );
if( '' == $name ) {
$name = wfMsg( 'blanknamespace' );
}
- $namespaces .= Xml::openElement( 'span', array( 'style' => 'white-space: nowrap' ) ) .
+ $rows[$subj] .= Xml::openElement( 'td', array( 'style' => 'white-space: nowrap' ) ) .
Xml::checkLabel( $name, "ns{$ns}", "mw-search-ns{$ns}", in_array( $ns, $this->namespaces ) ) .
- Xml::closeElement( 'span' ) . "\n";
+ Xml::closeElement( 'td' ) . "\n";
+ }
+ $rows = array_values( $rows );
+ $numRows = count( $rows );
+
+ // lay out namespaces in multiple floating two-column tables so they'll
+ // be arranged nicely while still accommodating different screen widths
+ $rowsPerTable = 3; // seems to look nice
+
+ // float to the right on RTL wikis
+ $tableStyle = ( $wgContLang->isRTL() ?
+ 'float: right; margin: 0 0 1em 1em' :
+ 'float: left; margin: 0 1em 1em 0' );
+
+ $tables = "";
+ for( $i = 0; $i < $numRows; $i += $rowsPerTable ) {
+ $tables .= Xml::openElement( 'table', array( 'style' => $tableStyle ) );
+ for( $j = $i; $j < $i + $rowsPerTable && $j < $numRows; $j++ ) {
+ $tables .= "<tr>\n" . $rows[$j] . "</tr>";
+ }
+ $tables .= Xml::closeElement( 'table' ) . "\n";
}
$redirect = Xml::check( 'redirs', $this->searchRedirects, array( 'value' => '1', 'id' => 'redirs' ) );
$redirectLabel = Xml::label( wfMsg( 'powersearch-redir' ), 'redirs' );
$searchField = Xml::input( 'search', 50, $term, array( 'type' => 'text', 'id' => 'powerSearchText' ) );
$searchButton = Xml::submitButton( wfMsg( 'powersearch' ), array( 'name' => 'fulltext' ) ) . "\n";
-
+ $searchTitle = SpecialPage::getTitleFor( 'Search' );
+
$out = Xml::openElement( 'form', array( 'id' => 'powersearch', 'method' => 'get', 'action' => $wgScript ) ) .
Xml::fieldset( wfMsg( 'powersearch-legend' ),
- Xml::hidden( 'title', 'Special:Search' ) .
+ Xml::hidden( 'title', $searchTitle->getPrefixedText() ) . "\n" .
"<p>" .
wfMsgExt( 'powersearch-ns', array( 'parseinline' ) ) .
- "<br />" .
- $namespaces .
- "</p>" .
+ "</p>\n" .
+ $tables .
+ "<hr style=\"clear: both\" />\n" .
"<p>" .
$redirect . " " . $redirectLabel .
- "</p>" .
+ "</p>\n" .
wfMsgExt( 'powersearch-field', array( 'parseinline' ) ) .
"&nbsp;" .
$searchField .
@@ -636,7 +1467,8 @@ class SpecialSearch {
'method' => 'get',
'action' => $wgScript
));
- $out .= Xml::hidden( 'title', 'Special:Search' );
+ $searchTitle = SpecialPage::getTitleFor( 'Search' );
+ $out .= Xml::hidden( 'title', $searchTitle->getPrefixedText() );
$out .= Xml::input( 'search', 50, $term, array( 'type' => 'text', 'id' => 'searchText' ) ) . ' ';
foreach( SearchEngine::searchableNamespaces() as $ns => $name ) {
if( in_array( $ns, $this->namespaces ) ) {
diff --git a/includes/specials/SpecialSpecialpages.php b/includes/specials/SpecialSpecialpages.php
index ca91ad51..560ba445 100644
--- a/includes/specials/SpecialSpecialpages.php
+++ b/includes/specials/SpecialSpecialpages.php
@@ -12,7 +12,7 @@ function wfSpecialSpecialpages() {
$wgMessageCache->loadAllMessages();
- $wgOut->setRobotpolicy( 'noindex,nofollow' ); # Is this really needed?
+ $wgOut->setRobotPolicy( 'noindex,nofollow' ); # Is this really needed?
$sk = $wgUser->getSkin();
$pages = SpecialPage::getUsablePages();
diff --git a/includes/specials/SpecialStatistics.php b/includes/specials/SpecialStatistics.php
index 570a21c6..109c5c30 100644
--- a/includes/specials/SpecialStatistics.php
+++ b/includes/specials/SpecialStatistics.php
@@ -13,50 +13,214 @@
*
* @param mixed $par (not used)
*/
-function wfSpecialStatistics( $par = '' ) {
- global $wgOut, $wgLang, $wgRequest;
- $dbr = wfGetDB( DB_SLAVE );
+class SpecialStatistics extends SpecialPage {
+
+ private $views, $edits, $good, $images, $total, $users,
+ $activeUsers, $admins, $numJobs = 0;
+
+ public function __construct() {
+ parent::__construct( 'Statistics' );
+ }
+
+ public function execute( $par ) {
+ global $wgOut, $wgRequest, $wgMessageCache;
+ global $wgDisableCounters, $wgMiserMode;
+ $wgMessageCache->loadAllMessages();
+
+ $this->setHeaders();
+
+ $this->views = SiteStats::views();
+ $this->edits = SiteStats::edits();
+ $this->good = SiteStats::articles();
+ $this->images = SiteStats::images();
+ $this->total = SiteStats::pages();
+ $this->users = SiteStats::users();
+ $this->activeUsers = SiteStats::activeUsers();
+ $this->admins = SiteStats::numberingroup('sysop');
+ $this->numJobs = SiteStats::jobs();
+
+ # Staticic - views
+ $viewsStats = '';
+ if( !$wgDisableCounters ) {
+ $viewsStats = $this->getViewsStats();
+ }
+
+ # Set active user count
+ if( !$wgMiserMode ) {
+ $dbw = wfGetDB( DB_MASTER );
+ SiteStatsUpdate::cacheUpdate( $dbw );
+ }
+
+ # Do raw output
+ if( $wgRequest->getVal( 'action' ) == 'raw' ) {
+ $this->doRawOutput();
+ }
- $views = SiteStats::views();
- $edits = SiteStats::edits();
- $good = SiteStats::articles();
- $images = SiteStats::images();
- $total = SiteStats::pages();
- $users = SiteStats::users();
- $admins = SiteStats::admins();
- $numJobs = SiteStats::jobs();
+ $text = Xml::openElement( 'table', array( 'class' => 'mw-statistics-table' ) );
- if( $wgRequest->getVal( 'action' ) == 'raw' ) {
- $wgOut->disable();
- header( 'Pragma: nocache' );
- echo "total=$total;good=$good;views=$views;edits=$edits;users=$users;admins=$admins;images=$images;jobs=$numJobs\n";
- return;
- } else {
- $text = "__NOTOC__\n";
- $text .= '==' . wfMsgNoTrans( 'sitestats' ) . "==\n";
- $text .= wfMsgExt( 'sitestatstext', array( 'parsemag' ),
- $wgLang->formatNum( $total ),
- $wgLang->formatNum( $good ),
- $wgLang->formatNum( $views ),
- $wgLang->formatNum( $edits ),
- $wgLang->formatNum( sprintf( '%.2f', $total ? $edits / $total : 0 ) ),
- $wgLang->formatNum( sprintf( '%.2f', $edits ? $views / $edits : 0 ) ),
- $wgLang->formatNum( $numJobs ),
- $wgLang->formatNum( $images )
- )."\n";
+ # Statistic - pages
+ $text .= $this->getPageStats();
+
+ # Statistic - edits
+ $text .= $this->getEditStats();
- $text .= "==" . wfMsgNoTrans( 'userstats' ) . "==\n";
- $text .= wfMsgExt( 'userstatstext', array ( 'parsemag' ),
- $wgLang->formatNum( $users ),
- $wgLang->formatNum( $admins ),
- '[[' . wfMsgForContent( 'grouppage-sysop' ) . ']]', # TODO somehow remove, kept for backwards compatibility
- $wgLang->formatNum( @sprintf( '%.2f', $admins / $users * 100 ) ),
- User::makeGroupLinkWiki( 'sysop' )
- )."\n";
+ # Statistic - users
+ $text .= $this->getUserStats();
- global $wgDisableCounters, $wgMiserMode, $wgUser, $wgLang, $wgContLang;
+ # Statistic - usergroups
+ $text .= $this->getGroupStats();
+ $text .= $viewsStats;
+
+ # Statistic - popular pages
if( !$wgDisableCounters && !$wgMiserMode ) {
- $res = $dbr->select(
+ $text .= $this->getMostViewedPages();
+ }
+
+ $text .= Xml::closeElement( 'table' );
+
+ # Customizable footer
+ $footer = wfMsgExt( 'statistics-footer', array('parseinline') );
+ if( !wfEmptyMsg( 'statistics-footer', $footer ) && $footer != '' ) {
+ $text .= "\n" . $footer;
+ }
+
+ $wgOut->addHTML( $text );
+ }
+
+ /**
+ * Format a row
+ * @param string $text description of the row
+ * @param float $number a number
+ * @param array $trExtraParams
+ * @param string $descMsg
+ * @param string $descMsgParam
+ * @return string table row in HTML format
+ */
+ private function formatRow( $text, $number, $trExtraParams = array(), $descMsg = '', $descMsgParam = '' ) {
+ global $wgStylePath;
+ if( $descMsg ) {
+ $descriptionText = wfMsgExt( $descMsg, array( 'parseinline' ), $descMsgParam );
+ if ( !wfEmptyMsg( $descMsg, $descriptionText ) ) {
+ $descriptionText = " ($descriptionText)";
+ $text .= "<br />" . Xml::element( 'small', array( 'class' => 'mw-statistic-desc'),
+ $descriptionText );
+ }
+ }
+ return Xml::openElement( 'tr', $trExtraParams ) .
+ Xml::openElement( 'td' ) . $text . Xml::closeElement( 'td' ) .
+ Xml::openElement( 'td', array( 'class' => 'mw-statistics-numbers' ) ) . $number . Xml::closeElement( 'td' ) .
+ Xml::closeElement( 'tr' );
+ }
+
+ /**
+ * Each of these methods is pretty self-explanatory, get a particular
+ * row for the table of statistics
+ * @return string
+ */
+ private function getPageStats() {
+ global $wgLang;
+ return Xml::openElement( 'tr' ) .
+ Xml::tags( 'th', array( 'colspan' => '2' ), wfMsgExt( 'statistics-header-pages', array( 'parseinline' ) ) ) .
+ Xml::closeElement( 'tr' ) .
+ $this->formatRow( wfMsgExt( 'statistics-articles', array( 'parseinline' ) ),
+ $wgLang->formatNum( $this->good ),
+ array( 'class' => 'mw-statistics-articles' ) ) .
+ $this->formatRow( wfMsgExt( 'statistics-pages', array( 'parseinline' ) ),
+ $wgLang->formatNum( $this->total ),
+ array( 'class' => 'mw-statistics-pages' ),
+ 'statistics-pages-desc' ) .
+ $this->formatRow( wfMsgExt( 'statistics-files', array( 'parseinline' ) ),
+ $wgLang->formatNum( $this->images ),
+ array( 'class' => 'mw-statistics-files' ) );
+ }
+ private function getEditStats() {
+ global $wgLang;
+ return Xml::openElement( 'tr' ) .
+ Xml::tags( 'th', array( 'colspan' => '2' ), wfMsgExt( 'statistics-header-edits', array( 'parseinline' ) ) ) .
+ Xml::closeElement( 'tr' ) .
+ $this->formatRow( wfMsgExt( 'statistics-edits', array( 'parseinline' ) ),
+ $wgLang->formatNum( $this->edits ),
+ array( 'class' => 'mw-statistics-edits' ) ) .
+ $this->formatRow( wfMsgExt( 'statistics-edits-average', array( 'parseinline' ) ),
+ $wgLang->formatNum( sprintf( '%.2f', $this->total ? $this->edits / $this->total : 0 ) ),
+ array( 'class' => 'mw-statistics-edits-average' ) ) .
+ $this->formatRow( wfMsgExt( 'statistics-jobqueue', array( 'parseinline' ) ),
+ $wgLang->formatNum( $this->numJobs ),
+ array( 'class' => 'mw-statistics-jobqueue' ) );
+ }
+ private function getUserStats() {
+ global $wgLang, $wgRCMaxAge;
+ return Xml::openElement( 'tr' ) .
+ Xml::tags( 'th', array( 'colspan' => '2' ), wfMsgExt( 'statistics-header-users', array( 'parseinline' ) ) ) .
+ Xml::closeElement( 'tr' ) .
+ $this->formatRow( wfMsgExt( 'statistics-users', array( 'parseinline' ) ),
+ $wgLang->formatNum( $this->users ),
+ array( 'class' => 'mw-statistics-users' ) ) .
+ $this->formatRow( wfMsgExt( 'statistics-users-active', array( 'parseinline' ) ),
+ $wgLang->formatNum( $this->activeUsers ),
+ array( 'class' => 'mw-statistics-users-active' ),
+ 'statistics-users-active-desc',
+ $wgLang->formatNum( ceil( $wgRCMaxAge / ( 3600 * 24 ) ) ) );
+ }
+ private function getGroupStats() {
+ global $wgGroupPermissions, $wgImplicitGroups, $wgLang, $wgUser;
+ $sk = $wgUser->getSkin();
+ $text = '';
+ foreach( $wgGroupPermissions as $group => $permissions ) {
+ # Skip generic * and implicit groups
+ if ( in_array( $group, $wgImplicitGroups ) || $group == '*' ) {
+ continue;
+ }
+ $groupname = htmlspecialchars( $group );
+ $msg = wfMsg( 'group-' . $groupname );
+ if ( wfEmptyMsg( 'group-' . $groupname, $msg ) || $msg == '' ) {
+ $groupnameLocalized = $groupname;
+ } else {
+ $groupnameLocalized = $msg;
+ }
+ $msg = wfMsgForContent( 'grouppage-' . $groupname );
+ if ( wfEmptyMsg( 'grouppage-' . $groupname, $msg ) || $msg == '' ) {
+ $grouppageLocalized = MWNamespace::getCanonicalName( NS_PROJECT ) . ':' . $groupname;
+ } else {
+ $grouppageLocalized = $msg;
+ }
+ $grouppage = $sk->makeLink( $grouppageLocalized, htmlspecialchars( $groupnameLocalized ) );
+ $grouplink = $sk->link( SpecialPage::getTitleFor( 'Listusers' ),
+ wfMsgHtml( 'listgrouprights-members' ),
+ array(),
+ array( 'group' => $group ),
+ 'known' );
+ # Add a class when a usergroup contains no members to allow hiding these rows
+ $classZero = '';
+ $countUsers = SiteStats::numberingroup( $groupname );
+ if( $countUsers == 0 ) {
+ $classZero = ' statistics-group-zero';
+ }
+ $text .= $this->formatRow( $grouppage . ' ' . $grouplink,
+ $wgLang->formatNum( $countUsers ),
+ array( 'class' => 'statistics-group-' . Sanitizer::escapeClass( $group ) . $classZero ) );
+ }
+ return $text;
+ }
+ private function getViewsStats() {
+ global $wgLang;
+ return Xml::openElement( 'tr' ) .
+ Xml::tags( 'th', array( 'colspan' => '2' ), wfMsgExt( 'statistics-header-views', array( 'parseinline' ) ) ) .
+ Xml::closeElement( 'tr' ) .
+ $this->formatRow( wfMsgExt( 'statistics-views-total', array( 'parseinline' ) ),
+ $wgLang->formatNum( $this->views ),
+ array ( 'class' => 'mw-statistics-views-total' ) ) .
+ $this->formatRow( wfMsgExt( 'statistics-views-peredit', array( 'parseinline' ) ),
+ $wgLang->formatNum( sprintf( '%.2f', $this->edits ?
+ $this->views / $this->edits : 0 ) ),
+ array ( 'class' => 'mw-statistics-views-peredit' ) );
+ }
+ private function getMostViewedPages() {
+ global $wgLang, $wgUser;
+ $text = '';
+ $dbr = wfGetDB( DB_SLAVE );
+ $sk = $wgUser->getSkin();
+ $res = $dbr->select(
'page',
array(
'page_namespace',
@@ -74,20 +238,33 @@ function wfSpecialStatistics( $par = '' ) {
)
);
if( $res->numRows() > 0 ) {
- $text .= "==" . wfMsgNoTrans( 'statistics-mostpopular' ) . "==\n";
+ $text .= Xml::tags( 'th', array( 'colspan' => '2' ), wfMsgExt( 'statistics-mostpopular', array( 'parseinline' ) ) );
while( $row = $res->fetchObject() ) {
$title = Title::makeTitleSafe( $row->page_namespace, $row->page_title );
- if( $title instanceof Title )
- $text .= '* [[:' . $title->getPrefixedText() . ']] (' . $wgLang->formatNum( $row->page_counter ) . ")\n";
+ if( $title instanceof Title ) {
+ $text .= $this->formatRow( $sk->link( $title ),
+ $wgLang->formatNum( $row->page_counter ) );
+
+ }
}
$res->free();
}
- }
-
- $footer = wfMsgNoTrans( 'statistics-footer' );
- if( !wfEmptyMsg( 'statistics-footer', $footer ) && $footer != '' )
- $text .= "\n" . $footer;
-
- $wgOut->addWikiText( $text );
+ return $text;
+ }
+
+ /**
+ * Do the action=raw output for this page. Legacy, but we support
+ * it for backwards compatibility
+ * http://lists.wikimedia.org/pipermail/wikitech-l/2008-August/039202.html
+ */
+ private function doRawOutput() {
+ global $wgOut;
+ $wgOut->disable();
+ header( 'Pragma: nocache' );
+ echo "total=" . $this->total . ";good=" . $this->good . ";views=" .
+ $this->views . ";edits=" . $this->edits . ";users=" . $this->users . ";";
+ echo "activeusers=" . $this->activeUsers . ";admins=" . $this->admins .
+ ";images=" . $this->images . ";jobs=" . $this->numJobs . "\n";
+ return;
}
-}
+} \ No newline at end of file
diff --git a/includes/specials/SpecialUncategorizedimages.php b/includes/specials/SpecialUncategorizedimages.php
index 986ec967..25310081 100644
--- a/includes/specials/SpecialUncategorizedimages.php
+++ b/includes/specials/SpecialUncategorizedimages.php
@@ -31,7 +31,7 @@ class UncategorizedImagesPage extends ImageQueryPage {
function getSQL() {
$dbr = wfGetDB( DB_SLAVE );
list( $page, $categorylinks ) = $dbr->tableNamesN( 'page', 'categorylinks' );
- $ns = NS_IMAGE;
+ $ns = NS_FILE;
return "SELECT 'Uncategorizedimages' AS type, page_namespace AS namespace,
page_title AS title, page_title AS value
diff --git a/includes/specials/SpecialUndelete.php b/includes/specials/SpecialUndelete.php
index d862ebb3..a9fb4ef1 100644
--- a/includes/specials/SpecialUndelete.php
+++ b/includes/specials/SpecialUndelete.php
@@ -119,7 +119,7 @@ class PageArchive {
* @todo Does this belong in Image for fuller encapsulation?
*/
function listFiles() {
- if( $this->title->getNamespace() == NS_IMAGE ) {
+ if( $this->title->getNamespace() == NS_FILE ) {
$dbr = wfGetDB( DB_SLAVE );
$res = $dbr->select( 'filearchive',
array(
@@ -336,7 +336,7 @@ class PageArchive {
$restoreText = $restoreAll || !empty( $timestamps );
$restoreFiles = $restoreAll || !empty( $fileVersions );
- if( $restoreFiles && $this->title->getNamespace() == NS_IMAGE ) {
+ if( $restoreFiles && $this->title->getNamespace() == NS_FILE ) {
$img = wfLocalFile( $this->title );
$this->fileStatus = $img->restore( $fileVersions, $unsuppress );
$filesRestored = $this->fileStatus->successCount;
@@ -412,7 +412,7 @@ class PageArchive {
# we'll update the latest revision field in the record.
$newid = 0;
$pageId = $page->page_id;
- $previousRevId = $page->page_latest;
+ $previousRevId = $page->page_latest;
# Get the time span of this page
$previousTimestamp = $dbw->selectField( 'revision', 'rev_timestamp',
array( 'rev_id' => $previousRevId ),
@@ -461,25 +461,10 @@ class PageArchive {
'ar_title' => $this->title->getDBkey(),
$oldones ),
__METHOD__,
- /* options */ array(
- 'ORDER BY' => 'ar_timestamp' )
+ /* options */ array( 'ORDER BY' => 'ar_timestamp' )
);
$ret = $dbw->resultObject( $result );
-
$rev_count = $dbw->numRows( $result );
- if( $rev_count ) {
- # We need to seek around as just using DESC in the ORDER BY
- # would leave the revisions inserted in the wrong order
- $first = $ret->fetchObject();
- $ret->seek( $rev_count - 1 );
- $last = $ret->fetchObject();
- // We don't handle well changing the top revision's settings
- if( !$unsuppress && $last->ar_deleted && $last->ar_timestamp > $previousTimestamp ) {
- wfDebug( __METHOD__.": restoration would result in a deleted top revision\n" );
- return false;
- }
- $ret->seek( 0 );
- }
if( $makepage ) {
$newid = $article->insertOn( $dbw );
@@ -502,6 +487,12 @@ class PageArchive {
// a new text table entry will be created for it.
$revText = Revision::getRevisionText( $row, 'ar_' );
}
+ // Check for key dupes due to shitty archive integrity.
+ if( $row->ar_rev_id ) {
+ $exists = $dbw->selectField( 'revision', '1', array('rev_id' => $row->ar_rev_id), __METHOD__ );
+ if( $exists ) continue; // don't throw DB errors
+ }
+
$revision = new Revision( array(
'page' => $pageId,
'id' => $row->ar_rev_id,
@@ -520,17 +511,32 @@ class PageArchive {
wfRunHooks( 'ArticleRevisionUndeleted', array( &$this->title, $revision, $row->ar_page_id ) );
}
+ # Now that it's safely stored, take it out of the archive
+ $dbw->delete( 'archive',
+ /* WHERE */ array(
+ 'ar_namespace' => $this->title->getNamespace(),
+ 'ar_title' => $this->title->getDBkey(),
+ $oldones ),
+ __METHOD__ );
+
// Was anything restored at all?
- if($restored == 0)
+ if( $restored == 0 )
return 0;
if( $revision ) {
// Attach the latest revision to the page...
$wasnew = $article->updateIfNewerOn( $dbw, $revision, $previousRevId );
-
if( $newid || $wasnew ) {
// Update site stats, link tables, etc
$article->createUpdates( $revision );
+ // We don't handle well with top revision deleted
+ if( $revision->getVisibility() ) {
+ $dbw->update( 'revision',
+ array( 'rev_deleted' => 0 ),
+ array( 'rev_id' => $revision->getId() ),
+ __METHOD__
+ );
+ }
}
if( $newid ) {
@@ -541,7 +547,7 @@ class PageArchive {
Article::onArticleEdit( $this->title );
}
- if( $this->title->getNamespace() == NS_IMAGE ) {
+ if( $this->title->getNamespace() == NS_FILE ) {
$update = new HTMLCacheUpdate( $this->title, 'imagelinks' );
$update->doUpdate();
}
@@ -550,14 +556,6 @@ class PageArchive {
return self::UNDELETE_UNKNOWNERR;
}
- # Now that it's safely stored, take it out of the archive
- $dbw->delete( 'archive',
- /* WHERE */ array(
- 'ar_namespace' => $this->title->getNamespace(),
- 'ar_title' => $this->title->getDBkey(),
- $oldones ),
- __METHOD__ );
-
return $restored;
}
@@ -570,7 +568,7 @@ class PageArchive {
* @ingroup SpecialPage
*/
class UndeleteForm {
- var $mAction, $mTarget, $mTimestamp, $mRestore, $mTargetObj;
+ var $mAction, $mTarget, $mTimestamp, $mRestore, $mInvert, $mTargetObj;
var $mTargetTimestamp, $mAllowed, $mComment, $mToken;
function UndeleteForm( $request, $par = "" ) {
@@ -585,6 +583,7 @@ class UndeleteForm {
$posted = $request->wasPosted() &&
$wgUser->matchEditToken( $request->getVal( 'wpEditToken' ) );
$this->mRestore = $request->getCheck( 'restore' ) && $posted;
+ $this->mInvert = $request->getCheck( 'invert' ) && $posted;
$this->mPreview = $request->getCheck( 'preview' ) && $posted;
$this->mDiff = $request->getCheck( 'diff' );
$this->mComment = $request->getText( 'wpComment' );
@@ -606,7 +605,7 @@ class UndeleteForm {
} else {
$this->mTargetObj = NULL;
}
- if( $this->mRestore ) {
+ if( $this->mRestore || $this->mInvert ) {
$timestamps = array();
$this->mFileVersions = array();
foreach( $_REQUEST as $key => $val ) {
@@ -666,6 +665,9 @@ class UndeleteForm {
if( $this->mRestore && $this->mAction == "submit" ) {
return $this->undelete();
}
+ if( $this->mInvert && $this->mAction == "submit" ) {
+ return $this->showHistory( );
+ }
return $this->showHistory();
}
@@ -673,21 +675,20 @@ class UndeleteForm {
global $wgOut, $wgScript;
$wgOut->addWikiMsg( 'undelete-header' );
- $wgOut->addHtml(
+ $wgOut->addHTML(
Xml::openElement( 'form', array(
'method' => 'get',
'action' => $wgScript ) ) .
- '<fieldset>' .
- Xml::element( 'legend', array(),
- wfMsg( 'undelete-search-box' ) ) .
+ Xml::fieldset( wfMsg( 'undelete-search-box' ) ) .
Xml::hidden( 'title',
SpecialPage::getTitleFor( 'Undelete' )->getPrefixedDbKey() ) .
Xml::inputLabel( wfMsg( 'undelete-search-prefix' ),
'prefix', 'prefix', 20,
- $this->mSearchPrefix ) .
+ $this->mSearchPrefix ) . ' ' .
Xml::submitButton( wfMsg( 'undelete-search-submit' ) ) .
- '</fieldset>' .
- '</form>' );
+ Xml::closeElement( 'fieldset' ) .
+ Xml::closeElement( 'form' )
+ );
}
// Generic list of deleted pages
@@ -699,7 +700,7 @@ class UndeleteForm {
return;
}
- $wgOut->addWikiMsg( "undeletepagetext" );
+ $wgOut->addWikiMsg( 'undeletepagetext', $wgLang->formatNum( $result->numRows() ) );
$sk = $wgUser->getSkin();
$undelete = SpecialPage::getTitleFor( 'Undelete' );
@@ -708,11 +709,10 @@ class UndeleteForm {
$title = Title::makeTitleSafe( $row->ar_namespace, $row->ar_title );
$link = $sk->makeKnownLinkObj( $undelete, htmlspecialchars( $title->getPrefixedText() ),
'target=' . $title->getPrefixedUrl() );
- #$revs = wfMsgHtml( 'undeleterevisions', $wgLang->formatNum( $row->count ) );
$revs = wfMsgExt( 'undeleterevisions',
array( 'parseinline' ),
$wgLang->formatNum( $row->count ) );
- $wgOut->addHtml( "<li>{$link} ({$revs})</li>\n" );
+ $wgOut->addHTML( "<li>{$link} ({$revs})</li>\n" );
}
$result->free();
$wgOut->addHTML( "</ul>\n" );
@@ -752,8 +752,6 @@ class UndeleteForm {
SpecialPage::getTitleFor( 'Undelete', $this->mTargetObj->getPrefixedDBkey() ),
htmlspecialchars( $this->mTargetObj->getPrefixedText() )
);
- $time = htmlspecialchars( $wgLang->timeAndDate( $timestamp, true ) );
- $user = $skin->revUserTools( $rev );
if( $this->mDiff ) {
$previousRev = $archive->getPreviousRevision( $timestamp );
@@ -762,59 +760,66 @@ class UndeleteForm {
if( $wgUser->getOption( 'diffonly' ) ) {
return;
} else {
- $wgOut->addHtml( '<hr />' );
+ $wgOut->addHTML( '<hr />' );
}
} else {
- $wgOut->addHtml( wfMsgHtml( 'undelete-nodiff' ) );
+ $wgOut->addHTML( wfMsgHtml( 'undelete-nodiff' ) );
}
}
- $wgOut->addHtml( '<p>' . wfMsgHtml( 'undelete-revision', $link, $time, $user ) . '</p>' );
+ // date and time are separate parameters to facilitate localisation.
+ // $time is kept for backward compat reasons.
+ $time = htmlspecialchars( $wgLang->timeAndDate( $timestamp, true ) );
+ $d = htmlspecialchars( $wgLang->date( $timestamp, true ) );
+ $t = htmlspecialchars( $wgLang->time( $timestamp, true ) );
+ $user = $skin->revUserTools( $rev );
+
+ $wgOut->addHTML( '<p>' . wfMsgHtml( 'undelete-revision', $link, $time, $user, $d, $t ) . '</p>' );
wfRunHooks( 'UndeleteShowRevision', array( $this->mTargetObj, $rev ) );
if( $this->mPreview ) {
- $wgOut->addHtml( "<hr />\n" );
+ $wgOut->addHTML( "<hr />\n" );
//Hide [edit]s
$popts = $wgOut->parserOptions();
$popts->setEditSection( false );
$wgOut->parserOptions( $popts );
- $wgOut->addWikiTextTitleTidy( $rev->revText(), $this->mTargetObj, true );
+ $wgOut->addWikiTextTitleTidy( $rev->getText( Revision::FOR_THIS_USER ), $this->mTargetObj, true );
}
- $wgOut->addHtml(
- wfElement( 'textarea', array(
+ $wgOut->addHTML(
+ Xml::element( 'textarea', array(
'readonly' => 'readonly',
'cols' => intval( $wgUser->getOption( 'cols' ) ),
'rows' => intval( $wgUser->getOption( 'rows' ) ) ),
- $rev->revText() . "\n" ) .
- wfOpenElement( 'div' ) .
- wfOpenElement( 'form', array(
+ $rev->getText( Revision::FOR_THIS_USER ) . "\n" ) .
+ Xml::openElement( 'div' ) .
+ Xml::openElement( 'form', array(
'method' => 'post',
'action' => $self->getLocalURL( "action=submit" ) ) ) .
- wfElement( 'input', array(
+ Xml::element( 'input', array(
'type' => 'hidden',
'name' => 'target',
'value' => $this->mTargetObj->getPrefixedDbKey() ) ) .
- wfElement( 'input', array(
+ Xml::element( 'input', array(
'type' => 'hidden',
'name' => 'timestamp',
'value' => $timestamp ) ) .
- wfElement( 'input', array(
+ Xml::element( 'input', array(
'type' => 'hidden',
'name' => 'wpEditToken',
'value' => $wgUser->editToken() ) ) .
- wfElement( 'input', array(
+ Xml::element( 'input', array(
'type' => 'submit',
'name' => 'preview',
'value' => wfMsg( 'showpreview' ) ) ) .
- wfElement( 'input', array(
+ Xml::element( 'input', array(
'name' => 'diff',
'type' => 'submit',
'value' => wfMsg( 'showdiff' ) ) ) .
- wfCloseElement( 'form' ) .
- wfCloseElement( 'div' ) );
+ Xml::closeElement( 'form' ) .
+ Xml::closeElement( 'div' ) );
}
/**
@@ -829,7 +834,7 @@ class UndeleteForm {
$diffEngine = new DifferenceEngine();
$diffEngine->showDiffStyle();
- $wgOut->addHtml(
+ $wgOut->addHTML(
"<div>" .
"<table border='0' width='98%' cellpadding='0' cellspacing='4' class='diff'>" .
"<col class='diff-marker' />" .
@@ -838,11 +843,11 @@ class UndeleteForm {
"<col class='diff-content' />" .
"<tr>" .
"<td colspan='2' width='50%' align='center' class='diff-otitle'>" .
- $this->diffHeader( $previousRev ) .
- "</td>" .
+ $this->diffHeader( $previousRev, 'o' ) .
+ "</td>\n" .
"<td colspan='2' width='50%' align='center' class='diff-ntitle'>" .
- $this->diffHeader( $currentRev ) .
- "</td>" .
+ $this->diffHeader( $currentRev, 'n' ) .
+ "</td>\n" .
"</tr>" .
$diffEngine->generateDiffBody(
$previousRev->getText(), $currentRev->getText() ) .
@@ -851,7 +856,7 @@ class UndeleteForm {
}
- private function diffHeader( $rev ) {
+ private function diffHeader( $rev, $prefix ) {
global $wgUser, $wgLang, $wgLang;
$sk = $wgUser->getSkin();
$isDeleted = !( $rev->getId() && $rev->getTitle() );
@@ -868,17 +873,17 @@ class UndeleteForm {
$targetQuery = 'oldid=' . $rev->getId();
}
return
- '<div id="mw-diff-otitle1"><strong>' .
+ '<div id="mw-diff-'.$prefix.'title1"><strong>' .
$sk->makeLinkObj( $targetPage,
wfMsgHtml( 'revisionasof',
$wgLang->timeanddate( $rev->getTimestamp(), true ) ),
$targetQuery ) .
( $isDeleted ? ' ' . wfMsgHtml( 'deletedrev' ) : '' ) .
'</strong></div>' .
- '<div id="mw-diff-otitle2">' .
+ '<div id="mw-diff-'.$prefix.'title2">' .
$sk->revUserTools( $rev ) . '<br/>' .
'</div>' .
- '<div id="mw-diff-otitle3">' .
+ '<div id="mw-diff-'.$prefix.'title3">' .
$sk->revComment( $rev ) . '<br/>' .
'</div>';
}
@@ -891,7 +896,8 @@ class UndeleteForm {
$file = new ArchivedFile( $this->mTargetObj, '', $this->mFile );
$wgOut->addWikiMsg( 'undelete-show-file-confirm',
$this->mTargetObj->getText(),
- $wgLang->timeanddate( $file->getTimestamp() ) );
+ $wgLang->date( $file->getTimestamp() ),
+ $wgLang->time( $file->getTimestamp() ) );
$wgOut->addHTML(
Xml::openElement( 'form', array(
'method' => 'POST',
@@ -925,7 +931,7 @@ class UndeleteForm {
$store->stream( $key );
}
- private function showHistory() {
+ private function showHistory( ) {
global $wgLang, $wgUser, $wgOut;
$sk = $wgUser->getSkin();
@@ -984,7 +990,7 @@ class UndeleteForm {
$action = $titleObj->getLocalURL( "action=submit" );
# Start the form here
$top = Xml::openElement( 'form', array( 'method' => 'post', 'action' => $action, 'id' => 'undelete' ) );
- $wgOut->addHtml( $top );
+ $wgOut->addHTML( $top );
}
# Show relevant lines from the deletion log:
@@ -1007,8 +1013,7 @@ class UndeleteForm {
$unsuppressBox = "";
}
$table =
- Xml::openElement( 'fieldset' ) .
- Xml::element( 'legend', null, wfMsg( 'undelete-fieldset-title' ) ).
+ Xml::fieldset( wfMsg( 'undelete-fieldset-title' ) ) .
Xml::openElement( 'table', array( 'id' => 'mw-undelete-table' ) ) .
"<tr>
<td colspan='2'>" .
@@ -1026,15 +1031,16 @@ class UndeleteForm {
<tr>
<td>&nbsp;</td>
<td class='mw-submit'>" .
- Xml::submitButton( wfMsg( 'undeletebtn' ), array( 'name' => 'restore', 'id' => 'mw-undelete-submit' ) ) .
- Xml::element( 'input', array( 'type' => 'reset', 'value' => wfMsg( 'undeletereset' ), 'id' => 'mw-undelete-reset' ) ) .
+ Xml::submitButton( wfMsg( 'undeletebtn' ), array( 'name' => 'restore', 'id' => 'mw-undelete-submit' ) ) . ' ' .
+ Xml::element( 'input', array( 'type' => 'reset', 'value' => wfMsg( 'undeletereset' ), 'id' => 'mw-undelete-reset' ) ) . ' ' .
+ Xml::submitButton( wfMsg( 'undeleteinvert' ), array( 'name' => 'invert', 'id' => 'mw-undelete-invert' ) ) .
"</td>
</tr>" .
$unsuppressBox .
Xml::closeElement( 'table' ) .
Xml::closeElement( 'fieldset' );
- $wgOut->addHtml( $table );
+ $wgOut->addHTML( $table );
}
$wgOut->addHTML( Xml::element( 'h2', null, wfMsg( 'history' ) ) . "\n" );
@@ -1044,7 +1050,7 @@ class UndeleteForm {
$wgOut->addHTML("<ul>");
$target = urlencode( $this->mTarget );
$remaining = $revisions->numRows();
- $earliestLiveTime = $this->getEarliestTime( $this->mTargetObj );
+ $earliestLiveTime = $this->mTargetObj->getEarliestRevTime();
while( $row = $revisions->fetchObject() ) {
$remaining--;
@@ -1057,8 +1063,8 @@ class UndeleteForm {
}
if( $haveFiles ) {
- $wgOut->addHtml( Xml::element( 'h2', null, wfMsg( 'filehist' ) ) . "\n" );
- $wgOut->addHtml( "<ul>" );
+ $wgOut->addHTML( Xml::element( 'h2', null, wfMsg( 'filehist' ) ) . "\n" );
+ $wgOut->addHTML( "<ul>" );
while( $row = $files->fetchObject() ) {
$wgOut->addHTML( $this->formatFileRow( $row, $sk ) );
}
@@ -1071,7 +1077,7 @@ class UndeleteForm {
$misc = Xml::hidden( 'target', $this->mTarget );
$misc .= Xml::hidden( 'wpEditToken', $wgUser->editToken() );
$misc .= Xml::closeElement( 'form' );
- $wgOut->addHtml( $misc );
+ $wgOut->addHTML( $misc );
}
return true;
@@ -1093,7 +1099,15 @@ class UndeleteForm {
$stxt = '';
$ts = wfTimestamp( TS_MW, $row->ar_timestamp );
if( $this->mAllowed ) {
- $checkBox = Xml::check( "ts$ts" );
+ if( $this->mInvert){
+ if( in_array( $ts, $this->mTargetTimestamp ) ) {
+ $checkBox = Xml::check( "ts$ts");
+ } else {
+ $checkBox = Xml::check( "ts$ts", true );
+ }
+ } else {
+ $checkBox = Xml::check( "ts$ts" );
+ }
$titleObj = SpecialPage::getTitleFor( "Undelete" );
$pageLink = $this->getPageLink( $rev, $titleObj, $ts, $sk );
# Last link
@@ -1123,7 +1137,6 @@ class UndeleteForm {
// If revision was hidden from sysops
$del = wfMsgHtml('rev-delundel');
} else {
- $ts = wfTimestamp( TS_MW, $row->ar_timestamp );
$del = $sk->makeKnownLinkObj( $revdel,
wfMsgHtml('rev-delundel'),
'target=' . $this->mTargetObj->getPrefixedUrl() . "&artimestamp=$ts" );
@@ -1183,18 +1196,6 @@ class UndeleteForm {
return "<li>$checkBox $revdlink $pageLink . . $userLink $data $comment</li>\n";
}
- private function getEarliestTime( $title ) {
- $dbr = wfGetDB( DB_SLAVE );
- if( $title->exists() ) {
- $min = $dbr->selectField( 'revision',
- 'MIN(rev_timestamp)',
- array( 'rev_page' => $title->getArticleId() ),
- __METHOD__ );
- return wfTimestampOrNull( TS_MW, $min );
- }
- return null;
- }
-
/**
* Fetch revision text link if it's available to all users
* @return string
@@ -1286,10 +1287,10 @@ class UndeleteForm {
$skin = $wgUser->getSkin();
$link = $skin->makeKnownLinkObj( $this->mTargetObj );
- $wgOut->addHtml( wfMsgWikiHtml( 'undeletedpage', $link ) );
+ $wgOut->addHTML( wfMsgWikiHtml( 'undeletedpage', $link ) );
} else {
$wgOut->showFatalError( wfMsg( "cannotundelete" ) );
- $wgOut->addHtml( '<p>' . wfMsgHtml( "undeleterevdel" ) . '</p>' );
+ $wgOut->addHTML( '<p>' . wfMsgHtml( "undeleterevdel" ) . '</p>' );
}
// Show file deletion warnings and errors
diff --git a/includes/specials/SpecialUnusedimages.php b/includes/specials/SpecialUnusedimages.php
index d71b638f..4adf405d 100644
--- a/includes/specials/SpecialUnusedimages.php
+++ b/includes/specials/SpecialUnusedimages.php
@@ -33,7 +33,7 @@ class UnusedimagesPage extends ImageQueryPage {
FROM ((($page AS I LEFT JOIN $categorylinks AS L ON I.page_id = L.cl_from)
LEFT JOIN $imagelinks AS P ON I.page_title = P.il_to)
INNER JOIN $image AS G ON I.page_title = G.img_name)
- WHERE I.page_namespace = ".NS_IMAGE." AND L.cl_from IS NULL AND P.il_to IS NULL";
+ WHERE I.page_namespace = ".NS_FILE." AND L.cl_from IS NULL AND P.il_to IS NULL";
} else {
list( $image, $imagelinks ) = $dbr->tableNamesN( 'image','imagelinks' );
diff --git a/includes/specials/SpecialUpload.php b/includes/specials/SpecialUpload.php
index 3a79e052..450c8728 100644
--- a/includes/specials/SpecialUpload.php
+++ b/includes/specials/SpecialUpload.php
@@ -23,7 +23,7 @@ class UploadForm {
const BEFORE_PROCESSING = 1;
const LARGE_FILE_SERVER = 2;
const EMPTY_FILE = 3;
- const MIN_LENGHT_PARTNAME = 4;
+ const MIN_LENGTH_PARTNAME = 4;
const ILLEGAL_FILENAME = 5;
const PROTECTED_PAGE = 6;
const OVERWRITE_EXISTING_FILE = 7;
@@ -300,7 +300,7 @@ class UploadForm {
$this->mainUploadForm( wfMsgHtml( 'emptyfile' ) );
break;
- case self::MIN_LENGHT_PARTNAME:
+ case self::MIN_LENGTH_PARTNAME:
$this->mainUploadForm( wfMsgHtml( 'minlength1' ) );
break;
@@ -328,10 +328,7 @@ class UploadForm {
wfMsgExt( 'filetype-banned-type',
array( 'parseinline' ),
htmlspecialchars( $finalExt ),
- implode(
- wfMsgExt( 'comma-separator', array( 'escapenoentities' ) ),
- $wgFileExtensions
- ),
+ $wgLang->commaList( $wgFileExtensions ),
$wgLang->formatNum( count($wgFileExtensions) )
)
);
@@ -402,7 +399,15 @@ class UploadForm {
$basename = $this->mSrcName;
}
$filtered = wfStripIllegalFilenameChars( $basename );
-
+
+ /* Normalize to title form before we do any further processing */
+ $nt = Title::makeTitleSafe( NS_FILE, $filtered );
+ if( is_null( $nt ) ) {
+ $resultDetails = array( 'filtered' => $filtered );
+ return self::ILLEGAL_FILENAME;
+ }
+ $filtered = $nt->getDBkey();
+
/**
* We'll want to blacklist against *any* 'extension', and use
* only the final one for the whitelist.
@@ -423,14 +428,9 @@ class UploadForm {
}
if( strlen( $partname ) < 1 ) {
- return self::MIN_LENGHT_PARTNAME;
+ return self::MIN_LENGTH_PARTNAME;
}
- $nt = Title::makeTitleSafe( NS_IMAGE, $filtered );
- if( is_null( $nt ) ) {
- $resultDetails = array( 'filtered' => $filtered );
- return self::ILLEGAL_FILENAME;
- }
$this->mLocalFile = wfLocalFile( $nt );
$this->mDestName = $this->mLocalFile->getName();
@@ -520,10 +520,7 @@ class UploadForm {
wfMsgExt( 'filetype-unwanted-type',
array( 'parseinline' ),
htmlspecialchars( $finalExt ),
- implode(
- wfMsgExt( 'comma-separator', array( 'escapenoentities' ) ),
- $wgFileExtensions
- ),
+ $wgLang->commaList( $wgFileExtensions ),
$wgLang->formatNum( count($wgFileExtensions) )
) . '</li>';
}
@@ -544,7 +541,7 @@ class UploadForm {
$warning .= self::getExistsWarning( $this->mLocalFile );
}
- $warning .= $this->getDupeWarning( $this->mTempPath );
+ $warning .= $this->getDupeWarning( $this->mTempPath, $finalExt );
if( $warning != '' ) {
/**
@@ -610,7 +607,7 @@ class UploadForm {
// extensions (eg 'jpg' rather than 'JPEG').
//
// Check for another file using the normalized form...
- $nt_lc = Title::makeTitle( NS_IMAGE, $partname . '.' . $file->getExtension() );
+ $nt_lc = Title::makeTitle( NS_FILE, $partname . '.' . $file->getExtension() );
$file_lc = wfLocalFile( $nt_lc );
} else {
$file_lc = false;
@@ -737,7 +734,7 @@ class UploadForm {
public static function ajaxGetLicensePreview( $license ) {
global $wgParser, $wgUser;
$text = '{{' . $license . '}}';
- $title = Title::makeTitle( NS_IMAGE, 'Sample.jpg' );
+ $title = Title::makeTitle( NS_FILE, 'Sample.jpg' );
$options = ParserOptions::newFromUser( $wgUser );
// Expand subst: first, then live templates...
@@ -751,9 +748,10 @@ class UploadForm {
* Check for duplicate files and throw up a warning before the upload
* completes.
*/
- function getDupeWarning( $tempfile ) {
+ function getDupeWarning( $tempfile, $extension ) {
$hash = File::sha1Base36( $tempfile );
$dupes = RepoGroup::singleton()->findBySha1( $hash );
+ $archivedImage = new ArchivedFile( null, 0, $hash.".$extension" );
if( $dupes ) {
global $wgOut;
$msg = "<gallery>";
@@ -767,6 +765,10 @@ class UploadForm {
wfMsgExt( "file-exists-duplicate", array( "parse" ), count( $dupes ) ) .
$wgOut->parse( $msg ) .
"</li>\n";
+ } elseif ( $archivedImage->getID() > 0 ) {
+ global $wgOut;
+ $name = Title::makeTitle( NS_FILE, $archivedImage->getName() )->getPrefixedText();
+ return Xml::tags( 'li', null, wfMsgExt( 'file-deleted-duplicate', array( 'parseinline' ), array( $name ) ) );
} else {
return '';
}
@@ -961,7 +963,7 @@ wgUploadAutoFill = {$autofill};
}
if( $this->mDesiredDestName ) {
- $title = Title::makeTitleSafe( NS_IMAGE, $this->mDesiredDestName );
+ $title = Title::makeTitleSafe( NS_FILE, $this->mDesiredDestName );
// Show a subtitle link to deleted revisions (to sysops et al only)
if( $title instanceof Title && ( $count = $title->isDeleted() ) > 0 && $wgUser->isAllowed( 'deletedhistory' ) ) {
$link = wfMsgExt(
@@ -972,7 +974,7 @@ wgUploadAutoFill = {$autofill};
wfMsgExt( 'restorelink', array( 'parsemag', 'escape' ), $count )
)
);
- $wgOut->addHtml( "<div id=\"contentSub2\">{$link}</div>" );
+ $wgOut->addHTML( "<div id=\"contentSub2\">{$link}</div>" );
}
// Show the relevant lines from deletion log (for still deleted files only)
@@ -1005,21 +1007,20 @@ wgUploadAutoFill = {$autofill};
$allowedExtensions = '';
if( $wgCheckFileExtensions ) {
- $delim = wfMsgExt( 'comma-separator', array( 'escapenoentities' ) );
if( $wgStrictFileExtensions ) {
# Everything not permitted is banned
$extensionsList =
'<div id="mw-upload-permitted">' .
- wfMsgWikiHtml( 'upload-permitted', implode( $wgFileExtensions, $delim ) ) .
+ wfMsgWikiHtml( 'upload-permitted', $wgLang->commaList( $wgFileExtensions ) ) .
"</div>\n";
} else {
# We have to list both preferred and prohibited
$extensionsList =
'<div id="mw-upload-preferred">' .
- wfMsgWikiHtml( 'upload-preferred', implode( $wgFileExtensions, $delim ) ) .
+ wfMsgWikiHtml( 'upload-preferred', $wgLang->commaList( $wgFileExtensions ) ) .
"</div>\n" .
'<div id="mw-upload-prohibited">' .
- wfMsgWikiHtml( 'upload-prohibited', implode( $wgFileBlacklist, $delim ) ) .
+ wfMsgWikiHtml( 'upload-prohibited', $wgLang->commaList( $wgFileBlacklist ) ) .
"</div>\n";
}
} else {
@@ -1169,7 +1170,7 @@ wgUploadAutoFill = {$autofill};
<tr>"
);
if( $useAjaxLicensePreview ) {
- $wgOut->addHtml( "
+ $wgOut->addHTML( "
<td></td>
<td id=\"mw-license-preview\"></td>
</tr>
@@ -1205,7 +1206,7 @@ wgUploadAutoFill = {$autofill};
);
}
- $wgOut->addHtml( "
+ $wgOut->addHTML( "
<td></td>
<td>
<input tabindex='7' type='checkbox' name='wpWatchthis' id='wpWatchthis' $watchChecked value='true' />
@@ -1279,7 +1280,7 @@ wgUploadAutoFill = {$autofill};
*
* @return array
*/
- function splitExtensions( $filename ) {
+ public function splitExtensions( $filename ) {
$bits = explode( '.', $filename );
$basename = array_shift( $bits );
return array( $basename, $bits );
@@ -1305,7 +1306,7 @@ wgUploadAutoFill = {$autofill};
* @param array $list
* @return bool
*/
- function checkFileExtensionList( $ext, $list ) {
+ public function checkFileExtensionList( $ext, $list ) {
foreach( $ext as $e ) {
if( in_array( strtolower( $e ), $list ) ) {
return true;
@@ -1754,7 +1755,7 @@ wgUploadAutoFill = {$autofill};
function showError( $description ) {
global $wgOut;
$wgOut->setPageTitle( wfMsg( "internalerror" ) );
- $wgOut->setRobotpolicy( "noindex,nofollow" );
+ $wgOut->setRobotPolicy( "noindex,nofollow" );
$wgOut->setArticleRelated( false );
$wgOut->enableClientCache( false );
$wgOut->addWikiText( $description );
@@ -1797,14 +1798,14 @@ wgUploadAutoFill = {$autofill};
$loglist = new LogEventsList( $wgUser->getSkin(), $out );
$pager = new LogPager( $loglist, 'delete', false, $filename );
if( $pager->getNumRows() > 0 ) {
- $out->addHtml( '<div id="mw-upload-deleted-warn">' );
+ $out->addHTML( '<div class="mw-warning-with-logexcerpt">' );
$out->addWikiMsg( 'upload-wasdeleted' );
$out->addHTML(
$loglist->beginLogEventsList() .
$pager->getBody() .
$loglist->endLogEventsList()
);
- $out->addHtml( '</div>' );
+ $out->addHTML( '</div>' );
}
}
}
diff --git a/includes/specials/SpecialUserlogin.php b/includes/specials/SpecialUserlogin.php
index 27009eed..6a4da7a4 100644
--- a/includes/specials/SpecialUserlogin.php
+++ b/includes/specials/SpecialUserlogin.php
@@ -33,6 +33,7 @@ class LoginForm {
const RESET_PASS = 7;
const ABORTED = 8;
const CREATE_BLOCKED = 9;
+ const THROTTLED = 10;
var $mName, $mPassword, $mRetype, $mReturnTo, $mCookieCheck, $mPosted;
var $mAction, $mCreateaccount, $mCreateaccountMail, $mMailmypassword;
@@ -128,9 +129,10 @@ class LoginForm {
$result = $this->mailPasswordInternal( $u, false, 'createaccount-title', 'createaccount-text' );
wfRunHooks( 'AddNewAccount', array( $u, true ) );
+ $u->addNewUserLogEntry();
$wgOut->setPageTitle( wfMsg( 'accmailtitle' ) );
- $wgOut->setRobotpolicy( 'noindex,nofollow' );
+ $wgOut->setRobotPolicy( 'noindex,nofollow' );
$wgOut->setArticleRelated( false );
if( WikiError::isError( $result ) ) {
@@ -174,14 +176,16 @@ class LoginForm {
# Save settings (including confirmation token)
$u->saveSettings();
- # 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 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( $wgUser->isAnon() ) {
$wgUser = $u;
$wgUser->setCookies();
wfRunHooks( 'AddNewAccount', array( $wgUser ) );
+ $wgUser->addNewUserLogEntry();
if( $this->hasSessionCookie() ) {
- return $this->successfulLogin( 'welcomecreation', $wgUser->getName(), false );
+ return $this->successfulCreation();
} else {
return $this->cookieRedirectCheck( 'new' );
}
@@ -192,9 +196,10 @@ class LoginForm {
$wgOut->setPageTitle( wfMsgHtml( 'accountcreated' ) );
$wgOut->setArticleRelated( false );
$wgOut->setRobotPolicy( 'noindex,nofollow' );
- $wgOut->addHtml( wfMsgWikiHtml( 'accountcreatedtext', $u->getName() ) );
+ $wgOut->addHTML( wfMsgWikiHtml( 'accountcreatedtext', $u->getName() ) );
$wgOut->returnToMain( false, $self );
wfRunHooks( 'AddNewAccount', array( $u ) );
+ $u->addNewUserLogEntry();
return true;
}
}
@@ -215,12 +220,11 @@ class LoginForm {
return false;
}
- // If we are not allowing users to login locally, we should
- // be checking to see if the user is actually able to
- // authenticate to the authentication 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 we are not allowing users to login locally, we should be checking
+ // to see if the user is actually able to authenticate to the authenti-
+ // 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( !$wgAuth->canCreateAccounts() && ( !$wgAuth->userExists( $this->mName ) || !$wgAuth->authenticate( $this->mName, $this->mPassword ) ) ) {
$this->mainLoginForm( wfMsg( 'wrongpassword' ) );
@@ -280,7 +284,8 @@ class LoginForm {
}
}
- # if you need a confirmed email address to edit, then obviously you need an email address.
+ # if you need a confirmed email address to edit, then obviously you
+ # need an email address.
if ( $wgEmailConfirmToEdit && empty( $this->mEmail ) ) {
$this->mainLoginForm( wfMsg( 'noemailtitle' ) );
return false;
@@ -291,8 +296,8 @@ class LoginForm {
return false;
}
- # Set some additional data so the AbortNewAccount hook can be
- # used for more than just username validation
+ # Set some additional data so the AbortNewAccount hook can be used for
+ # more than just username validation
$u->setEmail( $this->mEmail );
$u->setRealName( $this->mRealName );
@@ -306,14 +311,15 @@ class LoginForm {
if ( $wgAccountCreationThrottle && $wgUser->isPingLimitable() ) {
$key = wfMemcKey( 'acctcreate', 'ip', $ip );
- $value = $wgMemc->incr( $key );
+ $value = $wgMemc->get( $key );
if ( !$value ) {
- $wgMemc->set( $key, 1, 86400 );
+ $wgMemc->set( $key, 0, 86400 );
}
- if ( $value > $wgAccountCreationThrottle ) {
+ if ( $value >= $wgAccountCreationThrottle ) {
$this->throttleHit( $wgAccountCreationThrottle );
return false;
}
+ $wgMemc->incr( $key );
}
if( !$wgAuth->addUser( $u, $this->mPassword, $this->mEmail, $this->mRealName ) ) {
@@ -372,12 +378,32 @@ class LoginForm {
if ( '' == $this->mName ) {
return self::NO_NAME;
}
+
+ global $wgPasswordAttemptThrottle;
+
+ $throttleCount=0;
+ if ( is_array($wgPasswordAttemptThrottle) ) {
+ $throttleKey = wfMemcKey( 'password-throttle', wfGetIP(), md5( $this->mName ) );
+ $count = $wgPasswordAttemptThrottle['count'];
+ $period = $wgPasswordAttemptThrottle['seconds'];
+
+ global $wgMemc;
+ $throttleCount = $wgMemc->get($throttleKey);
+ if ( !$throttleCount ) {
+ $wgMemc->add( $throttleKey, 1, $period ); // start counter
+ } else if ( $throttleCount < $count ) {
+ $wgMemc->incr($throttleKey);
+ } else if ( $throttleCount >= $count ) {
+ return self::THROTTLED;
+ }
+ }
- // Load $wgUser now, and check to see if we're logging in as the same name.
- // This is necessary because loading $wgUser (say by calling getName()) calls
- // the UserLoadFromSession hook, which potentially creates the user in the
- // database. Until we load $wgUser, checking for user existence using
- // User::newFromName($name)->getId() below will effectively be using stale data.
+ // Load $wgUser now, and check to see if we're logging in as the same
+ // name. This is necessary because loading $wgUser (say by calling
+ // getName()) calls the UserLoadFromSession hook, which potentially
+ // creates the user in the database. Until we load $wgUser, checking
+ // for user existence using User::newFromName($name)->getId() below
+ // will effectively be using stale data.
if ( $wgUser->getName() === $this->mName ) {
wfDebug( __METHOD__.": already logged in as {$this->mName}\n" );
return self::SUCCESS;
@@ -407,34 +433,30 @@ class LoginForm {
if (!$u->checkPassword( $this->mPassword )) {
if( $u->checkTemporaryPassword( $this->mPassword ) ) {
- // The e-mailed temporary password should not be used
- // for actual logins; that's a very sloppy habit,
- // and insecure if an attacker has a few seconds to
- // click "search" on someone's open mail reader.
+ // 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-
+ // pen mail reader.
//
- // Allow it to be used only to reset the password
- // a single time to a new value, which won't be in
- // the user's e-mail archives.
+ // Allow it to be used only to reset the password a single time
+ // to a new value, which won't be in the user's e-mail ar-
+ // chives.
//
- // For backwards compatibility, we'll still recognize
- // it at the login form to minimize surprises for
- // people who have been logging in with a temporary
- // password for some time.
- //
- // As a side-effect, we can authenticate the user's
- // e-mail address if it's not already done, since
- // the temporary password was sent via e-mail.
+ // For backwards compatibility, we'll still recognize it at the
+ // login form to minimize surprises for people who have been
+ // logging in with a temporary password for some time.
//
+ // 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() ) {
$u->confirmEmail();
$u->saveSettings();
}
- // At this point we just return an appropriate code
- // indicating that the UI should show a password
- // reset form; bot interfaces etc will probably just
- // fail cleanly here.
- //
+ // At this point we just return an appropriate code/ indicating
+ // that the UI should show a password reset form; bot inter-
+ // faces etc will probably just fail cleanly here.
$retval = self::RESET_PASS;
} else {
$retval = '' == $this->mPassword ? self::EMPTY_PASS : self::WRONG_PASS;
@@ -443,6 +465,11 @@ class LoginForm {
$wgAuth->updateUser( $u );
$wgUser = $u;
+ // Please reset throttle for successful logins, thanks!
+ if($throttleCount) {
+ $wgMemc->delete($throttleKey);
+ }
+
if ( $isAutoCreated ) {
// Must be run after $wgUser is set, for correct new user log
wfRunHooks( 'AuthPluginAutoCreate', array( $wgUser ) );
@@ -455,16 +482,16 @@ class LoginForm {
}
/**
- * Attempt to automatically create a user on login.
- * Only succeeds if there is an external authentication method which allows it.
+ * Attempt to automatically create a user on login. Only succeeds if there
+ * is an external authentication method which allows it.
* @return integer Status code
*/
function attemptAutoCreate( $user ) {
global $wgAuth, $wgUser;
/**
- * If the external authentication plugin allows it,
- * automatically create a new account for users that
- * are externally defined but have not yet logged in.
+ * 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 ( !$wgAuth->autoCreate() ) {
return self::NOT_EXISTS;
@@ -502,14 +529,19 @@ class LoginForm {
}
$wgUser->setCookies();
+ // Reset the throttle
+ $key = wfMemcKey( 'password-throttle', wfGetIP(), md5( $this->mName ) );
+ global $wgMemc;
+ $wgMemc->delete( $key );
+
if( $this->hasSessionCookie() || $this->mSkipCookieCheck ) {
- /* Replace the language object to provide user interface in correct
- * language immediately on this first page load.
+ /* Replace the language object to provide user interface in
+ * correct language immediately on this first page load.
*/
global $wgLang, $wgRequest;
$code = $wgRequest->getVal( 'uselang', $wgUser->getOption( 'language' ) );
$wgLang = Language::factory( $code );
- return $this->successfulLogin( 'loginsuccess', $wgUser->getName() );
+ return $this->successfulLogin();
} else {
return $this->cookieRedirectCheck( 'login' );
}
@@ -524,7 +556,7 @@ class LoginForm {
break;
case self::NOT_EXISTS:
if( $wgUser->isAllowed( 'createaccount' ) ){
- $this->mainLoginForm( wfMsg( 'nosuchuser', htmlspecialchars( $this->mName ) ) );
+ $this->mainLoginForm( wfMsgWikiHtml( 'nosuchuser', htmlspecialchars( $this->mName ) ) );
} else {
$this->mainLoginForm( wfMsg( 'nosuchusershort', htmlspecialchars( $this->mName ) ) );
}
@@ -541,6 +573,9 @@ class LoginForm {
case self::CREATE_BLOCKED:
$this->userBlockedMessage();
break;
+ case self::THROTTLED:
+ $this->mainLoginForm( wfMsg( 'login-throttled' ) );
+ break;
default:
throw new MWException( "Unhandled case value" );
}
@@ -548,8 +583,8 @@ class LoginForm {
function resetLoginForm( $error ) {
global $wgOut;
- $wgOut->addWikiText( "<div class=\"errorbox\">$error</div>" );
- $reset = new PasswordResetForm( $this->mName, $this->mPassword );
+ $wgOut->addHTML( Xml::element('p', array( 'class' => 'error' ), $error ) );
+ $reset = new SpecialResetpass();
$reset->execute( null );
}
@@ -587,14 +622,15 @@ class LoginForm {
return;
}
if ( 0 == $u->getID() ) {
- $this->mainLoginForm( wfMsg( 'nosuchuser', $u->getName() ) );
+ $this->mainLoginForm( wfMsgWikiHtml( 'nosuchuser', htmlspecialchars( $u->getName() ) ) );
return;
}
# Check against password throttle
if ( $u->isPasswordReminderThrottled() ) {
global $wgPasswordReminderResendTime;
- # Round the time in hours to 3 d.p., in case someone is specifying minutes or seconds.
+ # Round the time in hours to 3 d.p., in case someone is specifying
+ # minutes or seconds.
$this->mainLoginForm( wfMsgExt( 'throttled-mailpassword', array( 'parsemag' ),
round( $wgPasswordReminderResendTime, 3 ) ) );
return;
@@ -618,20 +654,22 @@ class LoginForm {
* @private
*/
function mailPasswordInternal( $u, $throttle = true, $emailTitle = 'passwordremindertitle', $emailText = 'passwordremindertext' ) {
- global $wgCookiePath, $wgCookieDomain, $wgCookiePrefix, $wgCookieSecure;
- global $wgServer, $wgScript;
+ global $wgServer, $wgScript, $wgUser;
if ( '' == $u->getEmail() ) {
return new WikiError( wfMsg( 'noemail', $u->getName() ) );
}
+ $ip = wfGetIP();
+ if( !$ip ) {
+ return new WikiError( wfMsg( 'badipaddress' ) );
+ }
+
+ wfRunHooks( 'User::mailPasswordInternal', array(&$wgUser, &$ip, &$u) );
$np = $u->randomPassword();
$u->setNewpassword( $np, $throttle );
$u->saveSettings();
- $ip = wfGetIP();
- if ( '' == $ip ) { $ip = '(Unknown)'; }
-
$m = wfMsg( $emailText, $ip, $u->getName(), $np, $wgServer . $wgScript );
$result = $u->sendMail( wfMsg( $emailTitle ), $m );
@@ -640,29 +678,66 @@ class LoginForm {
/**
- * @param string $msg Message key that will be shown on success
- * @param $params String: parameters for the above message
- * @param bool $auto Toggle auto-redirect to main page; default true
+ * Run any hooks registered for logins, then HTTP redirect to
+ * $this->mReturnTo (or Main Page if that's undefined). Formerly we had a
+ * nice message here, but that's really not as useful as just being sent to
+ * wherever you logged in from. It should be clear that the action was
+ * successful, given the lack of error messages plus the appearance of your
+ * name in the upper right.
+ *
* @private
*/
- function successfulLogin( $msg, $params, $auto = true ) {
- global $wgUser;
- global $wgOut;
+ function successfulLogin() {
+ global $wgUser, $wgOut;
- # Run any hooks; ignore results
+ # Run any hooks; display injected HTML if any, else redirect
+ $injected_html = '';
+ wfRunHooks('UserLoginComplete', array(&$wgUser, &$injected_html));
+ if( $injected_html !== '' ) {
+ $this->displaySuccessfulLogin( 'loginsuccess', $injected_html );
+ } else {
+ $titleObj = Title::newFromText( $this->mReturnTo );
+ if ( !$titleObj instanceof Title ) {
+ $titleObj = Title::newMainPage();
+ }
+
+ $wgOut->redirect( $titleObj->getFullURL() );
+ }
+ }
+
+ /**
+ * Run any hooks registered for logins, then display a message welcoming
+ * the user.
+ *
+ * @private
+ */
+ function successfulCreation() {
+ global $wgUser, $wgOut;
+
+ # Run any hooks; display injected HTML
$injected_html = '';
wfRunHooks('UserLoginComplete', array(&$wgUser, &$injected_html));
+ $this->displaySuccessfulLogin( 'welcomecreation', $injected_html );
+ }
+
+ /**
+ * Display a "login successful" page.
+ */
+ private function displaySuccessfulLogin( $msgname, $injected_html ) {
+ global $wgOut, $wgUser;
+
$wgOut->setPageTitle( wfMsg( 'loginsuccesstitle' ) );
- $wgOut->setRobotpolicy( 'noindex,nofollow' );
+ $wgOut->setRobotPolicy( 'noindex,nofollow' );
$wgOut->setArticleRelated( false );
- $wgOut->addWikiMsgArray( $msg, $params );
- $wgOut->addHtml( $injected_html );
+ $wgOut->addWikiMsg( $msgname, $wgUser->getName() );
+ $wgOut->addHTML( $injected_html );
+
if ( !empty( $this->mReturnTo ) ) {
- $wgOut->returnToMain( $auto, $this->mReturnTo );
+ $wgOut->returnToMain( null, $this->mReturnTo );
} else {
- $wgOut->returnToMain( $auto );
+ $wgOut->returnToMain( null );
}
}
@@ -671,11 +746,12 @@ class LoginForm {
global $wgOut;
$wgOut->setPageTitle( wfMsg( 'permissionserrors' ) );
- $wgOut->setRobotpolicy( 'noindex,nofollow' );
+ $wgOut->setRobotPolicy( 'noindex,nofollow' );
$wgOut->setArticleRelated( false );
$wgOut->addWikitext( $wgOut->formatPermissionsErrorMessage( $errors, 'createaccount' ) );
- // Stuff that might want to be added at the end. For example, instructions if blocked.
+ // Stuff that might want to be added at the end. For example, instruc-
+ // tions if blocked.
$wgOut->addWikiMsg( 'cantcreateaccount-nonblock-text' );
$wgOut->returnToMain( false );
@@ -694,7 +770,7 @@ class LoginForm {
# out.
$wgOut->setPageTitle( wfMsg( 'cantcreateaccounttitle' ) );
- $wgOut->setRobotpolicy( 'noindex,nofollow' );
+ $wgOut->setRobotPolicy( 'noindex,nofollow' );
$wgOut->setArticleRelated( false );
$ip = wfGetIP();
@@ -713,8 +789,8 @@ class LoginForm {
*/
function mainLoginForm( $msg, $msgtype = 'error' ) {
global $wgUser, $wgOut, $wgAllowRealName, $wgEnableEmail;
- global $wgCookiePrefix, $wgAuth, $wgLoginLanguageSelector;
- global $wgAuth, $wgEmailConfirmToEdit;
+ global $wgCookiePrefix, $wgLoginLanguageSelector;
+ global $wgAuth, $wgEmailConfirmToEdit, $wgCookieExpiration;
$titleObj = SpecialPage::getTitleFor( 'Userlogin' );
@@ -792,6 +868,7 @@ class LoginForm {
$template->set( 'useemail', $wgEnableEmail );
$template->set( 'emailrequired', $wgEmailConfirmToEdit );
$template->set( 'canreset', $wgAuth->allowPasswordChange() );
+ $template->set( 'canremember', ( $wgCookieExpiration > 0 ) );
$template->set( 'remember', $wgUser->getOption( 'rememberpassword' ) or $this->mRemember );
# Prepare language selection links as needed
@@ -810,7 +887,7 @@ class LoginForm {
}
$wgOut->setPageTitle( wfMsg( 'userlogin' ) );
- $wgOut->setRobotpolicy( 'noindex,nofollow' );
+ $wgOut->setRobotPolicy( 'noindex,nofollow' );
$wgOut->setArticleRelated( false );
$wgOut->disallowUserJs(); // just in case...
$wgOut->addTemplate( $template );
@@ -832,9 +909,9 @@ class LoginForm {
/**
* Check if a session cookie is present.
*
- * This will not pick up a cookie set during _this_ request, but is
- * meant to ensure that the client is returning the cookie which was
- * set on a previous pass through the system.
+ * This will not pick up a cookie set during _this_ request, but is meant
+ * to ensure that the client is returning the cookie which was set on a
+ * previous pass through the system.
*
* @private
*/
@@ -850,7 +927,9 @@ class LoginForm {
global $wgOut;
$titleObj = SpecialPage::getTitleFor( 'Userlogin' );
- $check = $titleObj->getFullURL( 'wpCookieCheck='.$type );
+ $query = array( 'wpCookieCheck' => $type );
+ if ( $this->mReturnTo ) $query['returnto'] = $this->mReturnTo;
+ $check = $titleObj->getFullURL( $query );
return $wgOut->redirect( $check );
}
@@ -871,7 +950,7 @@ class LoginForm {
return $this->mainLoginForm( wfMsg( 'error' ) );
}
} else {
- return $this->successfulLogin( 'loginsuccess', $wgUser->getName() );
+ return $this->successfulLogin();
}
}
@@ -879,9 +958,7 @@ class LoginForm {
* @private
*/
function throttleHit( $limit ) {
- global $wgOut;
-
- $wgOut->addWikiMsg( 'acct_creation_throttle_hit', $limit );
+ $this->mainLoginForm( wfMsgExt( 'acct_creation_throttle_hit', array( 'parseinline' ), $limit ) );
}
/**
diff --git a/includes/specials/SpecialUserlogout.php b/includes/specials/SpecialUserlogout.php
index 137eadb4..3d497bd7 100644
--- a/includes/specials/SpecialUserlogout.php
+++ b/includes/specials/SpecialUserlogout.php
@@ -12,7 +12,7 @@ function wfSpecialUserlogout() {
$oldName = $wgUser->getName();
$wgUser->logout();
- $wgOut->setRobotpolicy( 'noindex,nofollow' );
+ $wgOut->setRobotPolicy( 'noindex,nofollow' );
// Hook.
$injected_html = '';
diff --git a/includes/specials/SpecialUserrights.php b/includes/specials/SpecialUserrights.php
index fd3c690b..ce0097b2 100644
--- a/includes/specials/SpecialUserrights.php
+++ b/includes/specials/SpecialUserrights.php
@@ -26,10 +26,14 @@ class UserrightsPage extends SpecialPage {
}
public function userCanExecute( $user ) {
+ return $this->userCanChangeRights( $user, false );
+ }
+
+ public function userCanChangeRights( $user, $checkIfSelf = true ) {
$available = $this->changeableGroups();
return !empty( $available['add'] )
or !empty( $available['remove'] )
- or ($this->isself and
+ or ( ( $this->isself || !$checkIfSelf ) and
(!empty( $available['add-self'] )
or !empty( $available['remove-self'] )));
}
@@ -65,7 +69,7 @@ class UserrightsPage extends SpecialPage {
if ($this->mTarget == $wgUser->getName())
$this->isself = true;
- if( !$this->userCanExecute( $wgUser ) ) {
+ if( !$this->userCanChangeRights( $wgUser, true ) ) {
// fixme... there may be intermediate groups we can mention.
global $wgOut;
$wgOut->showPermissionsErrorPage( array(
@@ -141,13 +145,8 @@ class UserrightsPage extends SpecialPage {
// Validate input set...
$changeable = $this->changeableGroups();
- if ($wgUser->getId() != 0 && $wgUser->getId() == $user->getId()) {
- $addable = array_merge($changeable['add'], $wgGroupsAddToSelf);
- $removable = array_merge($changeable['remove'], $wgGroupsRemoveFromSelf);
- } else {
- $addable = $changeable['add'];
- $removable = $changeable['remove'];
- }
+ $addable = array_merge( $changeable['add'], $this->isself ? $changeable['add-self'] : array() );
+ $removable = array_merge( $changeable['remove'], $this->isself ? $changeable['remove-self'] : array() );
$removegroup = array_unique(
array_intersect( (array)$removegroup, $removable ) );
@@ -289,7 +288,7 @@ class UserrightsPage extends SpecialPage {
function makeGroupNameList( $ids ) {
if( empty( $ids ) ) {
- return wfMsg( 'rightsnone' );
+ return wfMsgForContent( 'rightsnone' );
} else {
return implode( ', ', $ids );
}
@@ -329,14 +328,13 @@ class UserrightsPage extends SpecialPage {
* @return Array: Tuple of addable, then removable groups
*/
protected function splitGroups( $groups ) {
- global $wgGroupsAddToSelf, $wgGroupsRemoveFromSelf;
- list($addable, $removable) = array_values( $this->changeableGroups() );
+ list($addable, $removable, $addself, $removeself) = array_values( $this->changeableGroups() );
$removable = array_intersect(
- array_merge($this->isself ? $wgGroupsRemoveFromSelf : array(), $removable),
+ array_merge( $this->isself ? $removeself : array(), $removable ),
$groups ); // Can't remove groups the user doesn't have
$addable = array_diff(
- array_merge($this->isself ? $wgGroupsAddToSelf : array(), $addable),
+ array_merge( $this->isself ? $addself : array(), $addable ),
$groups ); // Can't add groups the user does have
return array( $addable, $removable );
@@ -351,10 +349,8 @@ class UserrightsPage extends SpecialPage {
protected function showEditUserGroupsForm( $user, $groups ) {
global $wgOut, $wgUser, $wgLang;
- list( $addable, $removable ) = $this->splitGroups( $groups );
-
$list = array();
- foreach( $user->getGroups() as $group )
+ foreach( $groups as $group )
$list[] = self::buildGroupLink( $group );
$grouplist = '';
@@ -384,7 +380,7 @@ class UserrightsPage extends SpecialPage {
<tr>
<td></td>
<td class='mw-submit'>" .
- Xml::submitButton( wfMsg( 'saveusergroups' ), array( 'name' => 'saveusergroups' ) ) .
+ Xml::submitButton( wfMsg( 'saveusergroups' ), array( 'name' => 'saveusergroups', 'accesskey' => 's' ) ) .
"</td>
</tr>" .
Xml::closeElement( 'table' ) . "\n" .
@@ -510,10 +506,10 @@ class UserrightsPage extends SpecialPage {
/**
* Returns an array of the groups that the user can add/remove.
*
- * @return Array array( 'add' => array( addablegroups ), 'remove' => array( removablegroups ) )
+ * @return Array array( 'add' => array( addablegroups ), 'remove' => array( removablegroups ) , 'add-self' => array( addablegroups to self), 'remove-self' => array( removable groups from self) )
*/
function changeableGroups() {
- global $wgUser, $wgGroupsAddToSelf, $wgGroupsRemoveFromSelf;
+ global $wgUser;
if( $wgUser->isAllowed( 'userrights' ) ) {
// This group gives the right to modify everything (reverse-
@@ -533,8 +529,8 @@ class UserrightsPage extends SpecialPage {
$groups = array(
'add' => array(),
'remove' => array(),
- 'add-self' => $wgGroupsAddToSelf,
- 'remove-self' => $wgGroupsRemoveFromSelf);
+ 'add-self' => array(),
+ 'remove-self' => array() );
$addergroups = $wgUser->getEffectiveGroups();
foreach ($addergroups as $addergroup) {
@@ -543,7 +539,13 @@ class UserrightsPage extends SpecialPage {
);
$groups['add'] = array_unique( $groups['add'] );
$groups['remove'] = array_unique( $groups['remove'] );
+ $groups['add-self'] = array_unique( $groups['add-self'] );
+ $groups['remove-self'] = array_unique( $groups['remove-self'] );
}
+
+ // Run a hook because we can
+ wfRunHooks( 'UserrightsChangeableGroups', array( $this, $wgUser, $addergroups, &$groups ) );
+
return $groups;
}
@@ -551,12 +553,12 @@ class UserrightsPage extends SpecialPage {
* Returns an array of the groups that a particular group can add/remove.
*
* @param $group String: the group to check for whether it can add/remove
- * @return Array array( 'add' => array( addablegroups ), 'remove' => array( removablegroups ) )
+ * @return Array array( 'add' => array( addablegroups ), 'remove' => array( removablegroups ) , 'add-self' => array( addablegroups to self), 'remove-self' => array( removable groups from self) )
*/
private function changeableByGroup( $group ) {
- global $wgAddGroups, $wgRemoveGroups;
+ global $wgAddGroups, $wgRemoveGroups, $wgGroupsAddToSelf, $wgGroupsRemoveFromSelf;
- $groups = array( 'add' => array(), 'remove' => array() );
+ $groups = array( 'add' => array(), 'remove' => array(), 'add-self' => array(), 'remove-self' => array() );
if( empty($wgAddGroups[$group]) ) {
// Don't add anything to $groups
} elseif( $wgAddGroups[$group] === true ) {
@@ -573,6 +575,40 @@ class UserrightsPage extends SpecialPage {
} elseif( is_array($wgRemoveGroups[$group]) ) {
$groups['remove'] = $wgRemoveGroups[$group];
}
+
+ // Re-map numeric keys of AddToSelf/RemoveFromSelf to the 'user' key for backwards compatibility
+ if( empty($wgGroupsAddToSelf['user']) || $wgGroupsAddToSelf['user'] !== true ) {
+ foreach($wgGroupsAddToSelf as $key => $value) {
+ if( is_int($key) ) {
+ $wgGroupsAddToSelf['user'][] = $value;
+ }
+ }
+ }
+
+ if( empty($wgGroupsRemoveFromSelf['user']) || $wgGroupsRemoveFromSelf['user'] !== true ) {
+ foreach($wgGroupsRemoveFromSelf as $key => $value) {
+ if( is_int($key) ) {
+ $wgGroupsRemoveFromSelf['user'][] = $value;
+ }
+ }
+ }
+
+ // Now figure out what groups the user can add to him/herself
+ if( empty($wgGroupsAddToSelf[$group]) ) {
+ } elseif( $wgGroupsAddToSelf[$group] === true ) {
+ // No idea WHY this would be used, but it's there
+ $groups['add-self'] = User::getAllGroups();
+ } elseif( is_array($wgGroupsAddToSelf[$group]) ) {
+ $groups['add-self'] = $wgGroupsAddToSelf[$group];
+ }
+
+ if( empty($wgGroupsRemoveFromSelf[$group]) ) {
+ } elseif( $wgGroupsRemoveFromSelf[$group] === true ) {
+ $groups['remove-self'] = User::getAllGroups();
+ } elseif( is_array($wgGroupsRemoveFromSelf[$group]) ) {
+ $groups['remove-self'] = $wgGroupsRemoveFromSelf[$group];
+ }
+
return $groups;
}
@@ -583,7 +619,7 @@ class UserrightsPage extends SpecialPage {
* @param $output OutputPage to use
*/
protected function showLogFragment( $user, $output ) {
- $output->addHtml( Xml::element( 'h2', null, LogPage::logName( 'rights' ) . "\n" ) );
+ $output->addHTML( Xml::element( 'h2', null, LogPage::logName( 'rights' ) . "\n" ) );
LogEventsList::showLogExtract( $output, 'rights', $user->getUserPage()->getPrefixedText() );
}
}
diff --git a/includes/specials/SpecialVersion.php b/includes/specials/SpecialVersion.php
index 8c8e386d..29f527f2 100644
--- a/includes/specials/SpecialVersion.php
+++ b/includes/specials/SpecialVersion.php
@@ -1,42 +1,37 @@
<?php
-/**#@+
+
+/**
* Give information about the version of MediaWiki, PHP, the DB and extensions
*
- * @file
* @ingroup SpecialPage
*
* @author Ævar Arnfjörð Bjarmason <avarab@gmail.com>
* @copyright Copyright © 2005, Ævar Arnfjörð Bjarmason
* @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 2.0 or later
*/
-
-/**
- * constructor
- */
-function wfSpecialVersion() {
- $version = new SpecialVersion;
- $version->execute();
-}
-
-/**
- * @ingroup SpecialPage
- */
-class SpecialVersion {
+class SpecialVersion extends SpecialPage {
private $firstExtOpened = true;
+ function __construct(){
+ parent::__construct( 'Version' );
+ }
+
/**
* main()
*/
- function execute() {
+ function execute( $par ) {
global $wgOut, $wgMessageCache, $wgSpecialVersionShowHooks;
$wgMessageCache->loadAllMessages();
+ $this->setHeaders();
+ $this->outputHeader();
+
$wgOut->addHTML( '<div dir="ltr">' );
$text =
$this->MediaWikiCredits() .
$this->softwareInformation() .
$this->extensionCredits();
- if ( $wgSpecialVersionShowHooks ) {
+ if ( $wgSpecialVersionShowHooks ) {
$text .= $this->wgHooks();
}
$wgOut->addWikiText( $text );
@@ -162,15 +157,21 @@ class SpecialVersion {
usort( $wgExtensionCredits[$type], array( $this, 'compare' ) );
foreach ( $wgExtensionCredits[$type] as $extension ) {
+ $version = null;
+ $subVersion = '';
if ( isset( $extension['version'] ) ) {
$version = $extension['version'];
- } elseif ( isset( $extension['svn-revision'] ) &&
+ }
+ if ( isset( $extension['svn-revision'] ) &&
preg_match( '/\$(?:Rev|LastChangedRevision|Revision): *(\d+)/',
- $extension['svn-revision'], $m ) )
- {
- $version = 'r' . $m[1];
- } else {
- $version = null;
+ $extension['svn-revision'], $m ) ) {
+ $subVersion = 'r' . $m[1];
+ }
+
+ if( $version && $subVersion ) {
+ $version = $version . ' [' . $subVersion . ']';
+ } elseif ( !$version && $subVersion ) {
+ $version = $subVersion;
}
$out .= $this->formatCredits(
@@ -287,8 +288,6 @@ class SpecialVersion {
}
/**
- * @static
- *
* @return string
*/
function IPInfo() {
@@ -306,35 +305,34 @@ class SpecialVersion {
if ( $cnt == 1 ) {
// Enforce always returning a string
- return (string)$this->arrayToString( $list[0] );
+ return (string)self::arrayToString( $list[0] );
} elseif ( $cnt == 0 ) {
return '';
} else {
+ global $wgLang;
sort( $list );
- $t = array_slice( $list, 0, $cnt - 1 );
- $one = array_map( array( &$this, 'arrayToString' ), $t );
- $two = $this->arrayToString( $list[$cnt - 1] );
- $and = wfMsg( 'and' );
-
- return implode( ', ', $one ) . " $and $two";
+ return $wgLang->listToText( array_map( array( __CLASS__, 'arrayToString' ), $list ) );
}
}
/**
- * @static
- *
* @param mixed $list Will convert an array to string if given and return
* the paramater unaltered otherwise
* @return mixed
*/
- function arrayToString( $list ) {
+ static function arrayToString( $list ) {
+ if( is_array( $list ) && count( $list ) == 1 )
+ $list = $list[0];
if( is_object( $list ) ) {
$class = get_class( $list );
return "($class)";
- } elseif ( ! is_array( $list ) ) {
+ } elseif ( !is_array( $list ) ) {
return $list;
} else {
- $class = get_class( $list[0] );
+ if( is_object( $list[0] ) )
+ $class = get_class( $list[0] );
+ else
+ $class = $list[0];
return "($class, {$list[1]})";
}
}
@@ -387,5 +385,3 @@ class SpecialVersion {
/**#@-*/
}
-
-/**#@-*/
diff --git a/includes/specials/SpecialWantedfiles.php b/includes/specials/SpecialWantedfiles.php
new file mode 100644
index 00000000..c2731fa9
--- /dev/null
+++ b/includes/specials/SpecialWantedfiles.php
@@ -0,0 +1,90 @@
+<?php
+/*
+ * @file
+ * @ingroup SpecialPage
+ */
+
+/**
+ * Querypage that lists the most wanted files - implements Special:Wantedfiles
+ *
+ * @ingroup SpecialPage
+ *
+ * @author Soxred93 <soxred93@gmail.com>
+ * @copyright Copyright © 2008, Soxred93
+ * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 2.0 or later
+ */
+class WantedFilesPage extends QueryPage {
+
+ function getName() {
+ return 'Wantedfiles';
+ }
+
+ function isExpensive() {
+ return true;
+ }
+
+ function isSyndicated() {
+ return false;
+ }
+
+ function getSQL() {
+ $dbr = wfGetDB( DB_SLAVE );
+ list( $imagelinks, $page ) = $dbr->tableNamesN( 'imagelinks', 'page' );
+ $name = $dbr->addQuotes( $this->getName() );
+ return
+ "
+ SELECT
+ $name as type,
+ " . NS_FILE . " as namespace,
+ il_to as title,
+ COUNT(*) as value
+ FROM $imagelinks
+ LEFT JOIN $page ON il_to = page_title AND page_namespace = ". NS_FILE ."
+ WHERE page_title IS NULL
+ GROUP BY il_to
+ ";
+ }
+
+ function sortDescending() { return true; }
+
+ /**
+ * Fetch user page links and cache their existence
+ */
+ function preprocessResults( $db, $res ) {
+ $batch = new LinkBatch;
+ while ( $row = $db->fetchObject( $res ) )
+ $batch->add( $row->namespace, $row->title );
+ $batch->execute();
+
+ // Back to start for display
+ if ( $db->numRows( $res ) > 0 )
+ // If there are no rows we get an error seeking.
+ $db->dataSeek( $res, 0 );
+ }
+
+ function formatResult( $skin, $result ) {
+ global $wgLang, $wgContLang;
+
+ $nt = Title::makeTitle( $result->namespace, $result->title );
+ $text = $wgContLang->convert( $nt->getText() );
+
+ $plink = $this->isCached() ?
+ $skin->makeLinkObj( $nt, htmlspecialchars( $text ) ) :
+ $skin->makeBrokenLinkObj( $nt, htmlspecialchars( $text ) );
+
+ $nlinks = wfMsgExt( 'nmembers', array( 'parsemag', 'escape'),
+ $wgLang->formatNum( $result->value ) );
+ return wfSpecialList($plink, $nlinks);
+ }
+}
+
+/**
+ * constructor
+ */
+function wfSpecialWantedFiles() {
+ list( $limit, $offset ) = wfCheckLimits();
+
+ $wpp = new WantedFilesPage();
+
+ $wpp->doQuery( $offset, $limit );
+}
diff --git a/includes/specials/SpecialWantedtemplates.php b/includes/specials/SpecialWantedtemplates.php
new file mode 100644
index 00000000..43b5cf8f
--- /dev/null
+++ b/includes/specials/SpecialWantedtemplates.php
@@ -0,0 +1,110 @@
+<?php
+/**
+ * @file
+ * @ingroup SpecialPage
+ */
+
+/**
+ * A querypage to list the most wanted templates - implements Special:Wantedtemplates
+ * based on SpecialWantedcategories.php by Ævar Arnfjörð Bjarmason <avarab@gmail.com>
+ * makeWlhLink() taken from SpecialMostlinkedtemplates by Rob Church <robchur@gmail.com>
+ *
+ * @ingroup SpecialPage
+ *
+ * @author Danny B.
+ * @copyright Copyright © 2008, Danny B.
+ * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 2.0 or later
+ */
+class WantedTemplatesPage extends QueryPage {
+
+ function getName() {
+ return 'Wantedtemplates';
+ }
+
+ function isExpensive() {
+ return true;
+ }
+
+ function isSyndicated() {
+ return false;
+ }
+
+ function getSQL() {
+ $dbr = wfGetDB( DB_SLAVE );
+ list( $templatelinks, $page ) = $dbr->tableNamesN( 'templatelinks', 'page' );
+ $name = $dbr->addQuotes( $this->getName() );
+ return
+ "
+ SELECT $name as type,
+ tl_namespace as namespace,
+ tl_title as title,
+ COUNT(*) as value
+ FROM $templatelinks LEFT JOIN
+ $page ON tl_title = page_title AND tl_namespace = page_namespace
+ WHERE page_title IS NULL AND tl_namespace = ". NS_TEMPLATE ."
+ GROUP BY tl_title
+ ";
+ }
+
+ function sortDescending() { return true; }
+
+ /**
+ * Fetch user page links and cache their existence
+ */
+ function preprocessResults( $db, $res ) {
+ $batch = new LinkBatch;
+ while ( $row = $db->fetchObject( $res ) )
+ $batch->add( $row->namespace, $row->title );
+ $batch->execute();
+
+ // Back to start for display
+ if ( $db->numRows( $res ) > 0 )
+ // If there are no rows we get an error seeking.
+ $db->dataSeek( $res, 0 );
+ }
+
+ function formatResult( $skin, $result ) {
+ global $wgLang, $wgContLang;
+
+ $nt = Title::makeTitle( $result->namespace, $result->title );
+ $text = $wgContLang->convert( $nt->getText() );
+
+ $plink = $this->isCached() ?
+ $skin->makeLinkObj( $nt, htmlspecialchars( $text ) ) :
+ $skin->makeBrokenLinkObj( $nt, htmlspecialchars( $text ) );
+
+ $nlinks = wfMsgExt( 'nmembers', array( 'parsemag', 'escape'),
+ $wgLang->formatNum( $result->value ) );
+ return wfSpecialList(
+ $plink,
+ $this->makeWlhLink( $nt, $skin, $result )
+ );
+ }
+
+ /**
+ * Make a "what links here" link for a given title
+ *
+ * @param Title $title Title to make the link for
+ * @param Skin $skin Skin to use
+ * @param object $result Result row
+ * @return string
+ */
+ private function makeWlhLink( $title, $skin, $result ) {
+ global $wgLang;
+ $wlh = SpecialPage::getTitleFor( 'Whatlinkshere' );
+ $label = wfMsgExt( 'nlinks', array( 'parsemag', 'escape' ),
+ $wgLang->formatNum( $result->value ) );
+ return $skin->link( $wlh, $label, array(), array( 'target' => $title->getPrefixedText() ) );
+ }
+}
+
+/**
+ * constructor
+ */
+function wfSpecialWantedTemplates() {
+ list( $limit, $offset ) = wfCheckLimits();
+
+ $wpp = new WantedTemplatesPage();
+
+ $wpp->doQuery( $offset, $limit );
+}
diff --git a/includes/specials/SpecialWatchlist.php b/includes/specials/SpecialWatchlist.php
index db7cd423..61dd6b3e 100644
--- a/includes/specials/SpecialWatchlist.php
+++ b/includes/specials/SpecialWatchlist.php
@@ -13,7 +13,6 @@ function wfSpecialWatchlist( $par ) {
global $wgUser, $wgOut, $wgLang, $wgRequest;
global $wgRCShowWatchingUsers, $wgEnotifWatchlist, $wgShowUpdatedMarker;
global $wgEnotifWatchlist;
- $fname = 'wfSpecialWatchlist';
$skin = $wgUser->getSkin();
$specialTitle = SpecialPage::getTitleFor( 'Watchlist' );
@@ -22,8 +21,9 @@ function wfSpecialWatchlist( $par ) {
# Anons don't get a watchlist
if( $wgUser->isAnon() ) {
$wgOut->setPageTitle( wfMsg( 'watchnologin' ) );
- $llink = $skin->makeKnownLinkObj( SpecialPage::getTitleFor( 'Userlogin' ), wfMsgHtml( 'loginreqlink' ), 'returnto=' . $specialTitle->getPrefixedUrl() );
- $wgOut->addHtml( wfMsgWikiHtml( 'watchlistanontext', $llink ) );
+ $llink = $skin->makeKnownLinkObj( SpecialPage::getTitleFor( 'Userlogin' ),
+ wfMsgHtml( 'loginreqlink' ), 'returnto=' . $specialTitle->getPrefixedUrl() );
+ $wgOut->addHTML( wfMsgWikiHtml( 'watchlistanontext', $llink ) );
return;
}
@@ -40,40 +40,56 @@ function wfSpecialWatchlist( $par ) {
}
$uid = $wgUser->getId();
- if( ($wgEnotifWatchlist || $wgShowUpdatedMarker) && $wgRequest->getVal( 'reset' ) && $wgRequest->wasPosted() ) {
+ if( ($wgEnotifWatchlist || $wgShowUpdatedMarker) && $wgRequest->getVal( 'reset' ) &&
+ $wgRequest->wasPosted() )
+ {
$wgUser->clearAllNotifications( $uid );
$wgOut->redirect( $specialTitle->getFullUrl() );
return;
}
$defaults = array(
- /* float */ 'days' => floatval( $wgUser->getOption( 'watchlistdays' ) ), /* 3.0 or 0.5, watch further below */
- /* bool */ 'hideOwn' => (int)$wgUser->getBoolOption( 'watchlisthideown' ),
- /* bool */ 'hideBots' => (int)$wgUser->getBoolOption( 'watchlisthidebots' ),
- /* bool */ 'hideMinor' => (int)$wgUser->getBoolOption( 'watchlisthideminor' ),
+ /* float */ 'days' => floatval( $wgUser->getOption( 'watchlistdays' ) ), /* 3.0 or 0.5, watch further below */
+ /* bool */ 'hideMinor' => (int)$wgUser->getBoolOption( 'watchlisthideminor' ),
+ /* bool */ 'hideBots' => (int)$wgUser->getBoolOption( 'watchlisthidebots' ),
+ /* bool */ 'hideAnons' => (int)$wgUser->getBoolOption( 'watchlisthideanons' ),
+ /* bool */ 'hideLiu' => (int)$wgUser->getBoolOption( 'watchlisthideliu' ),
+ /* bool */ 'hidePatrolled' => (int)$wgUser->getBoolOption( 'watchlisthidepatrolled' ), // TODO
+ /* bool */ 'hideOwn' => (int)$wgUser->getBoolOption( 'watchlisthideown' ),
/* ? */ 'namespace' => 'all',
+ /* ? */ 'invert' => false,
);
extract($defaults);
# Extract variables from the request, falling back to user preferences or
# other default values if these don't exist
- $prefs['days' ] = floatval( $wgUser->getOption( 'watchlistdays' ) );
- $prefs['hideown' ] = $wgUser->getBoolOption( 'watchlisthideown' );
- $prefs['hidebots'] = $wgUser->getBoolOption( 'watchlisthidebots' );
+ $prefs['days'] = floatval( $wgUser->getOption( 'watchlistdays' ) );
$prefs['hideminor'] = $wgUser->getBoolOption( 'watchlisthideminor' );
+ $prefs['hidebots'] = $wgUser->getBoolOption( 'watchlisthidebots' );
+ $prefs['hideanons'] = $wgUser->getBoolOption( 'watchlisthideanon' );
+ $prefs['hideliu'] = $wgUser->getBoolOption( 'watchlisthideliu' );
+ $prefs['hideown' ] = $wgUser->getBoolOption( 'watchlisthideown' );
+ $prefs['hidepatrolled' ] = $wgUser->getBoolOption( 'watchlisthidepatrolled' );
# Get query variables
- $days = $wgRequest->getVal( 'days', $prefs['days'] );
- $hideOwn = $wgRequest->getBool( 'hideOwn', $prefs['hideown'] );
- $hideBots = $wgRequest->getBool( 'hideBots', $prefs['hidebots'] );
+ $days = $wgRequest->getVal( 'days' , $prefs['days'] );
$hideMinor = $wgRequest->getBool( 'hideMinor', $prefs['hideminor'] );
+ $hideBots = $wgRequest->getBool( 'hideBots' , $prefs['hidebots'] );
+ $hideAnons = $wgRequest->getBool( 'hideAnons', $prefs['hideanons'] );
+ $hideLiu = $wgRequest->getBool( 'hideLiu' , $prefs['hideliu'] );
+ $hideOwn = $wgRequest->getBool( 'hideOwn' , $prefs['hideown'] );
+ $hidePatrolled = $wgRequest->getBool( 'hidePatrolled' , $prefs['hidepatrolled'] );
# Get namespace value, if supplied, and prepare a WHERE fragment
$nameSpace = $wgRequest->getIntOrNull( 'namespace' );
+ $invert = $wgRequest->getIntOrNull( 'invert' );
if( !is_null( $nameSpace ) ) {
$nameSpace = intval( $nameSpace );
- $nameSpaceClause = " AND rc_namespace = $nameSpace";
+ if( $invert && $nameSpace !== 'all' )
+ $nameSpaceClause = "rc_namespace != $nameSpace";
+ else
+ $nameSpaceClause = "rc_namespace = $nameSpace";
} else {
$nameSpace = '';
$nameSpaceClause = '';
@@ -103,32 +119,24 @@ function wfSpecialWatchlist( $par ) {
// Dump everything here
$nondefaults = array();
- wfAppendToArrayIfNotDefault('days' , $days , $defaults, $nondefaults);
- wfAppendToArrayIfNotDefault('hideOwn' , (int)$hideOwn , $defaults, $nondefaults);
- wfAppendToArrayIfNotDefault('hideBots' , (int)$hideBots, $defaults, $nondefaults);
+ wfAppendToArrayIfNotDefault( 'days' , $days , $defaults, $nondefaults);
wfAppendToArrayIfNotDefault( 'hideMinor', (int)$hideMinor, $defaults, $nondefaults );
- wfAppendToArrayIfNotDefault('namespace', $nameSpace , $defaults, $nondefaults);
-
- $hookSql = "";
- if( ! wfRunHooks('BeforeWatchlist', array($nondefaults, $wgUser, &$hookSql)) ) {
- return;
- }
-
- if($nitems == 0) {
+ wfAppendToArrayIfNotDefault( 'hideBots' , (int)$hideBots , $defaults, $nondefaults);
+ wfAppendToArrayIfNotDefault( 'hideAnons', (int)$hideAnons, $defaults, $nondefaults );
+ wfAppendToArrayIfNotDefault( 'hideLiu' , (int)$hideLiu , $defaults, $nondefaults );
+ wfAppendToArrayIfNotDefault( 'hideOwn' , (int)$hideOwn , $defaults, $nondefaults);
+ wfAppendToArrayIfNotDefault( 'namespace', $nameSpace , $defaults, $nondefaults);
+ wfAppendToArrayIfNotDefault( 'hidePatrolled', (int)$hidePatrolled, $defaults, $nondefaults );
+
+ if( $nitems == 0 ) {
$wgOut->addWikiMsg( 'nowatchlist' );
return;
}
- if ( $days <= 0 ) {
+ if( $days <= 0 ) {
$andcutoff = '';
} else {
- $andcutoff = "AND rc_timestamp > '".$dbr->timestamp( time() - intval( $days * 86400 ) )."'";
- /*
- $sql = "SELECT COUNT(*) AS n FROM $page, $revision WHERE rev_timestamp>'$cutoff' AND page_id=rev_page";
- $res = $dbr->query( $sql, $fname );
- $s = $dbr->fetchObject( $res );
- $npages = $s->n;
- */
+ $andcutoff = "rc_timestamp > '".$dbr->timestamp( time() - intval( $days * 86400 ) )."'";
}
# If the watchlist is relatively short, it's simplest to zip
@@ -140,128 +148,158 @@ function wfSpecialWatchlist( $par ) {
# Up estimate of watched items by 15% to compensate for talk pages...
# Toggles
- $andHideOwn = $hideOwn ? "AND (rc_user <> $uid)" : '';
- $andHideBots = $hideBots ? "AND (rc_bot = 0)" : '';
- $andHideMinor = $hideMinor ? 'AND rc_minor = 0' : '';
-
- # Show watchlist header
- $header = '';
- if( $wgUser->getOption( 'enotifwatchlistpages' ) && $wgEnotifWatchlist) {
- $header .= wfMsg( 'wlheader-enotif' ) . "\n";
- }
- if ( $wgShowUpdatedMarker ) {
- $header .= wfMsg( 'wlheader-showupdated' ) . "\n";
- }
-
- # Toggle watchlist content (all recent edits or just the latest)
+ $andHideOwn = $hideOwn ? "rc_user != $uid" : '';
+ $andHideBots = $hideBots ? "rc_bot = 0" : '';
+ $andHideMinor = $hideMinor ? "rc_minor = 0" : '';
+ $andHideLiu = $hideLiu ? "rc_user = 0" : '';
+ $andHideAnons = $hideAnons ? "rc_user != 0" : '';
+ $andHidePatrolled = $wgUser->useRCPatrol() && $hidePatrolled ? "rc_patrolled != 1" : '';
+
+ # Toggle watchlist content (all recent edits or just the latest)
if( $wgUser->getOption( 'extendwatchlist' )) {
$andLatest='';
- $limitWatchlist = 'LIMIT ' . intval( $wgUser->getOption( 'wllimit' ) );
+ $limitWatchlist = intval( $wgUser->getOption( 'wllimit' ) );
} else {
# Top log Ids for a page are not stored
- $andLatest = 'AND (rc_this_oldid=page_latest OR rc_type=' . RC_LOG . ') ';
- $limitWatchlist = '';
+ $andLatest = 'rc_this_oldid=page_latest OR rc_type=' . RC_LOG;
+ $limitWatchlist = 0;
}
- $header .= wfMsgExt( 'watchlist-details', array( 'parsemag' ), $wgLang->formatNum( $nitems ) );
- $wgOut->addWikiText( $header );
-
# Show a message about slave lag, if applicable
if( ( $lag = $dbr->getLag() ) > 0 )
$wgOut->showLagWarning( $lag );
- if ( $wgShowUpdatedMarker ) {
- $wgOut->addHTML( '<form action="' .
- $specialTitle->escapeLocalUrl() .
- '" method="post"><input type="submit" name="dummy" value="' .
- htmlspecialchars( wfMsg( 'enotif_reset' ) ) .
- '" /><input type="hidden" name="reset" value="all" /></form>' .
- "\n\n" );
+ # Create output form
+ $form = Xml::fieldset( wfMsg( 'watchlist-options' ), false, array( 'id' => 'mw-watchlist-options' ) );
+
+ # Show watchlist header
+ $form .= wfMsgExt( 'watchlist-details', array( 'parseinline' ), $wgLang->formatNum( $nitems ) );
+
+ if( $wgUser->getOption( 'enotifwatchlistpages' ) && $wgEnotifWatchlist) {
+ $form .= wfMsgExt( 'wlheader-enotif', 'parse' ) . "\n";
}
- if ( $wgShowUpdatedMarker ) {
- $wltsfield = ", ${watchlist}.wl_notificationtimestamp ";
- } else {
- $wltsfield = '';
+ if( $wgShowUpdatedMarker ) {
+ $form .= Xml::openElement( 'form', array( 'method' => 'post',
+ 'action' => $specialTitle->getLocalUrl(),
+ 'id' => 'mw-watchlist-resetbutton' ) ) .
+ wfMsgExt( 'wlheader-showupdated', array( 'parseinline' ) ) . ' ' .
+ Xml::submitButton( wfMsg( 'enotif_reset' ), array( 'name' => 'dummy' ) ) .
+ Xml::hidden( 'reset', 'all' ) .
+ Xml::closeElement( 'form' );
+ }
+ $form .= '<hr />';
+
+ $tables = array( 'recentchanges', 'watchlist', 'page' );
+ $fields = array( "{$recentchanges}.*" );
+ $conds = array();
+ $join_conds = array(
+ 'watchlist' => array('INNER JOIN',"wl_user='{$uid}' AND wl_namespace=rc_namespace AND wl_title=rc_title"),
+ 'page' => array('LEFT JOIN','rc_cur_id=page_id')
+ );
+ $options = array( 'ORDER BY' => 'rc_timestamp DESC' );
+ if( $wgShowUpdatedMarker ) {
+ $fields[] = 'wl_notificationtimestamp';
+ }
+ if( $limitWatchlist ) {
+ $options['LIMIT'] = $limitWatchlist;
}
- $sql = "SELECT ${recentchanges}.* ${wltsfield}
- FROM $watchlist,$recentchanges
- LEFT JOIN $page ON rc_cur_id=page_id
- WHERE wl_user=$uid
- AND wl_namespace=rc_namespace
- AND wl_title=rc_title
- $andcutoff
- $andLatest
- $andHideOwn
- $andHideBots
- $andHideMinor
- $nameSpaceClause
- $hookSql
- ORDER BY rc_timestamp DESC
- $limitWatchlist";
-
- $res = $dbr->query( $sql, $fname );
+ if( $andcutoff ) $conds[] = $andcutoff;
+ if( $andLatest ) $conds[] = $andLatest;
+ if( $andHideOwn ) $conds[] = $andHideOwn;
+ if( $andHideBots ) $conds[] = $andHideBots;
+ if( $andHideMinor ) $conds[] = $andHideMinor;
+ if( $andHideLiu ) $conds[] = $andHideLiu;
+ if( $andHideAnons ) $conds[] = $andHideAnons;
+ if( $andHidePatrolled ) $conds[] = $andHidePatrolled;
+ if( $nameSpaceClause ) $conds[] = $nameSpaceClause;
+
+ wfRunHooks('SpecialWatchlistQuery', array(&$conds,&$tables,&$join_conds,&$fields) );
+
+ $res = $dbr->select( $tables, $fields, $conds, __METHOD__, $options, $join_conds );
$numRows = $dbr->numRows( $res );
/* Start bottom header */
- $wgOut->addHTML( "<hr />\n" );
- if($days >= 1) {
- $wgOut->addHTML(
- wfMsgExt( 'rcnote', 'parseinline',
+ $wlInfo = '';
+ if( $days >= 1 ) {
+ $wlInfo = wfMsgExt( 'rcnote', 'parseinline',
$wgLang->formatNum( $numRows ),
$wgLang->formatNum( $days ),
$wgLang->timeAndDate( wfTimestampNow(), true ),
$wgLang->date( wfTimestampNow(), true ),
$wgLang->time( wfTimestampNow(), true )
- ) . '<br />'
- );
- } elseif($days > 0) {
- $wgOut->addHtml(
- wfMsgExt( 'wlnote', 'parseinline',
+ ) . '<br />';
+ } elseif( $days > 0 ) {
+ $wlInfo = wfMsgExt( 'wlnote', 'parseinline',
$wgLang->formatNum( $numRows ),
$wgLang->formatNum( round($days*24) )
- ) . '<br />'
- );
+ ) . '<br />';
}
- $wgOut->addHTML( "\n" . wlCutoffLinks( $days, 'Watchlist', $nondefaults ) . "<br />\n" );
+ $cutofflinks = "\n" . wlCutoffLinks( $days, 'Watchlist', $nondefaults ) . "<br />\n";
# Spit out some control panel links
$thisTitle = SpecialPage::getTitleFor( 'Watchlist' );
$skin = $wgUser->getSkin();
+ $showLinktext = wfMsgHtml( 'show' );
+ $hideLinktext = wfMsgHtml( 'hide' );
+ # Hide/show minor edits
+ $label = $hideMinor ? $showLinktext : $hideLinktext;
+ $linkBits = wfArrayToCGI( array( 'hideMinor' => 1 - (int)$hideMinor ), $nondefaults );
+ $links[] = wfMsgHtml( 'rcshowhideminor', $skin->makeKnownLinkObj( $thisTitle, $label, $linkBits ) );
+
# Hide/show bot edits
- $label = $hideBots ? wfMsgHtml( 'watchlist-show-bots' ) : wfMsgHtml( 'watchlist-hide-bots' );
+ $label = $hideBots ? $showLinktext : $hideLinktext;
$linkBits = wfArrayToCGI( array( 'hideBots' => 1 - (int)$hideBots ), $nondefaults );
- $links[] = $skin->makeKnownLinkObj( $thisTitle, $label, $linkBits );
+ $links[] = wfMsgHtml( 'rcshowhidebots', $skin->makeKnownLinkObj( $thisTitle, $label, $linkBits ) );
+
+ # Hide/show anonymous edits
+ $label = $hideAnons ? $showLinktext : $hideLinktext;
+ $linkBits = wfArrayToCGI( array( 'hideAnons' => 1 - (int)$hideAnons ), $nondefaults );
+ $links[] = wfMsgHtml( 'rcshowhideanons', $skin->makeKnownLinkObj( $thisTitle, $label, $linkBits ) );
+
+ # Hide/show logged in edits
+ $label = $hideLiu ? $showLinktext : $hideLinktext;
+ $linkBits = wfArrayToCGI( array( 'hideLiu' => 1 - (int)$hideLiu ), $nondefaults );
+ $links[] = wfMsgHtml( 'rcshowhideliu', $skin->makeKnownLinkObj( $thisTitle, $label, $linkBits ) );
# Hide/show own edits
- $label = $hideOwn ? wfMsgHtml( 'watchlist-show-own' ) : wfMsgHtml( 'watchlist-hide-own' );
+ $label = $hideOwn ? $showLinktext : $hideLinktext;
$linkBits = wfArrayToCGI( array( 'hideOwn' => 1 - (int)$hideOwn ), $nondefaults );
- $links[] = $skin->makeKnownLinkObj( $thisTitle, $label, $linkBits );
+ $links[] = wfMsgHtml( 'rcshowhidemine', $skin->makeKnownLinkObj( $thisTitle, $label, $linkBits ) );
- # Hide/show minor edits
- $label = $hideMinor ? wfMsgHtml( 'watchlist-show-minor' ) : wfMsgHtml( 'watchlist-hide-minor' );
- $linkBits = wfArrayToCGI( array( 'hideMinor' => 1 - (int)$hideMinor ), $nondefaults );
- $links[] = $skin->makeKnownLinkObj( $thisTitle, $label, $linkBits );
-
- $wgOut->addHTML( implode( ' | ', $links ) );
+ # Hide/show patrolled edits
+ if( $wgUser->useRCPatrol() ) {
+ $label = $hidePatrolled ? $showLinktext : $hideLinktext;
+ $linkBits = wfArrayToCGI( array( 'hidePatrolled' => 1 - (int)$hidePatrolled ), $nondefaults );
+ $links[] = wfMsgHtml( 'rcshowhidepatr', $skin->makeKnownLinkObj( $thisTitle, $label, $linkBits ) );
+ }
- # Form for namespace filtering
- $form = Xml::openElement( 'form', array( 'method' => 'post', 'action' => $thisTitle->getLocalUrl() ) );
- $form .= '<p>';
+ # Namespace filter and put the whole form together.
+ $form .= $wlInfo;
+ $form .= $cutofflinks;
+ $form .= implode( ' | ', $links );
+ $form .= Xml::openElement( 'form', array( 'method' => 'post', 'action' => $thisTitle->getLocalUrl() ) );
+ $form .= '<hr /><p>';
$form .= Xml::label( wfMsg( 'namespace' ), 'namespace' ) . '&nbsp;';
$form .= Xml::namespaceSelector( $nameSpace, '' ) . '&nbsp;';
+ $form .= Xml::checkLabel( wfMsg('invert'), 'invert', 'nsinvert', $invert ) . '&nbsp;';
$form .= Xml::submitButton( wfMsg( 'allpagessubmit' ) ) . '</p>';
$form .= Xml::hidden( 'days', $days );
- if( $hideOwn )
- $form .= Xml::hidden( 'hideOwn', 1 );
- if( $hideBots )
- $form .= Xml::hidden( 'hideBots', 1 );
if( $hideMinor )
$form .= Xml::hidden( 'hideMinor', 1 );
+ if( $hideBots )
+ $form .= Xml::hidden( 'hideBots', 1 );
+ if( $hideAnons )
+ $form .= Xml::hidden( 'hideAnons', 1 );
+ if( $hideLiu )
+ $form .= Xml::hidden( 'hideLiu', 1 );
+ if( $hideOwn )
+ $form .= Xml::hidden( 'hideOwn', 1 );
$form .= Xml::closeElement( 'form' );
- $wgOut->addHtml( $form );
+ $form .= Xml::closeElement( 'fieldset' );
+ $wgOut->addHTML( $form );
# If there's nothing to show, stop here
if( $numRows == 0 ) {
@@ -316,7 +354,6 @@ function wfSpecialWatchlist( $par ) {
$dbr->freeResult( $res );
$wgOut->addHTML( $s );
-
}
function wlHoursLink( $h, $page, $options = array() ) {
@@ -370,7 +407,8 @@ function wlCountItems( &$user, $talk = true ) {
$dbr = wfGetDB( DB_SLAVE, 'watchlist' );
# Fetch the raw count
- $res = $dbr->select( 'watchlist', 'COUNT(*) AS count', array( 'wl_user' => $user->mId ), 'wlCountItems' );
+ $res = $dbr->select( 'watchlist', 'COUNT(*) AS count',
+ array( 'wl_user' => $user->mId ), 'wlCountItems' );
$row = $dbr->fetchObject( $res );
$count = $row->count;
$dbr->freeResult( $res );
diff --git a/includes/specials/SpecialWhatlinkshere.php b/includes/specials/SpecialWhatlinkshere.php
index 3502e33c..d91b4960 100644
--- a/includes/specials/SpecialWhatlinkshere.php
+++ b/includes/specials/SpecialWhatlinkshere.php
@@ -74,9 +74,7 @@ class WhatLinksHerePage {
$this->selfTitle = SpecialPage::getTitleFor( 'Whatlinkshere', $this->target->getPrefixedDBkey() );
$wgOut->setPageTitle( wfMsg( 'whatlinkshere-title', $this->target->getPrefixedText() ) );
- $wgOut->setSubtitle( wfMsgHtml( 'linklistsub' ) );
-
- $wgOut->addHTML( wfMsgExt( 'whatlinkshere-barrow', array( 'escapenoentities') ) . ' ' .$this->skin->makeLinkObj($this->target, '', 'redirect=no' )."<br />\n");
+ $wgOut->setSubtitle( wfMsg( 'whatlinkshere-backlink', $this->skin->link( $this->target, $this->target->getPrefixedText(), array(), array( 'redirect' => 'no' ) ) ) );
$this->showIndirectLinks( 0, $this->target, $opts->getValue( 'limit' ),
$opts->getValue( 'from' ), $opts->getValue( 'back' ) );
@@ -98,7 +96,7 @@ class WhatLinksHerePage {
$hidelinks = $this->opts->getValue( 'hidelinks' );
$hideredirs = $this->opts->getValue( 'hideredirs' );
$hidetrans = $this->opts->getValue( 'hidetrans' );
- $hideimages = $target->getNamespace() != NS_IMAGE || $this->opts->getValue( 'hideimages' );
+ $hideimages = $target->getNamespace() != NS_FILE || $this->opts->getValue( 'hideimages' );
$fetchlinks = (!$hidelinks || !$hideredirs);
@@ -169,11 +167,13 @@ class WhatLinksHerePage {
if( ( !$fetchlinks || !$dbr->numRows($plRes) ) && ( $hidetrans || !$dbr->numRows($tlRes) ) && ( $hideimages || !$dbr->numRows($ilRes) ) ) {
if ( 0 == $level ) {
$wgOut->addHTML( $this->whatlinkshereForm() );
- $errMsg = is_int($namespace) ? 'nolinkshere-ns' : 'nolinkshere';
- $wgOut->addWikiMsg( $errMsg, $this->target->getPrefixedText() );
+
// Show filters only if there are links
if( $hidelinks || $hidetrans || $hideredirs || $hideimages )
$wgOut->addHTML( $this->getFilterPanel() );
+
+ $errMsg = is_int($namespace) ? 'nolinkshere-ns' : 'nolinkshere';
+ $wgOut->addWikiMsg( $errMsg, $this->target->getPrefixedText() );
}
return;
}
@@ -256,7 +256,7 @@ class WhatLinksHerePage {
}
protected function listStart() {
- return Xml::openElement( 'ul' );
+ return Xml::openElement( 'ul', array ( 'id' => 'mw-whatlinkshere-list' ) );
}
protected function listItem( $row, $nt, $notClose = false ) {
@@ -267,7 +267,7 @@ class WhatLinksHerePage {
'whatlinkshere-links', 'isimage' );
$msgcache = array();
foreach ( $msgs as $msg ) {
- $msgcache[$msg] = wfMsgHtml( $msg );
+ $msgcache[$msg] = wfMsgExt( $msg, array( 'escapenoentities' ) );
}
}
@@ -377,6 +377,8 @@ class WhatLinksHerePage {
$f .= Xml::label( wfMsg( 'namespace' ), 'namespace' ) . '&nbsp;' .
Xml::namespaceSelector( $namespace, '' );
+ $f .= ' ';
+
# Submit
$f .= Xml::submitButton( wfMsg( 'allpagessubmit' ) );
@@ -395,7 +397,7 @@ class WhatLinksHerePage {
$links = array();
$types = array( 'hidetrans', 'hidelinks', 'hideredirs' );
- if( $this->target->getNamespace() == NS_IMAGE )
+ if( $this->target->getNamespace() == NS_FILE )
$types[] = 'hideimages';
foreach( $types as $type ) {
$chosen = $this->opts->getValue( $type );