X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2FSpecialPage.php;h=c7b03084d69655d4b420fbc6389252be88259b72;hb=9b44e8f749a9dfdaca579790f9d56aefdc936d99;hp=4767626b7e86c4a27b51be25af8b60ebee05ea26;hpb=8ecd17b7e1195199f89fc8331bbc4128eac059f0;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/SpecialPage.php b/includes/SpecialPage.php index 4767626b7e..c7b03084d6 100644 --- a/includes/SpecialPage.php +++ b/includes/SpecialPage.php @@ -2,33 +2,30 @@ /** * SpecialPage: handling special pages and lists thereof. * - * To add a special page in an extension, add to $wgSpecialPages either - * an object instance or an array containing the name and constructor - * parameters. The latter is preferred for performance reasons. + * To add a special page in an extension, add to $wgSpecialPages either + * an object instance or an array containing the name and constructor + * parameters. The latter is preferred for performance reasons. * - * The object instantiated must be either an instance of SpecialPage or a - * sub-class thereof. It must have an execute() method, which sends the HTML - * for the special page to $wgOut. The parent class has an execute() method - * which distributes the call to the historical global functions. Additionally, - * execute() also checks if the user has the necessary access privileges + * The object instantiated must be either an instance of SpecialPage or a + * sub-class thereof. It must have an execute() method, which sends the HTML + * for the special page to $wgOut. The parent class has an execute() method + * which distributes the call to the historical global functions. Additionally, + * execute() also checks if the user has the necessary access privileges * and bails out if not. * - * To add a core special page, use the similar static list in + * To add a core special page, use the similar static list in * SpecialPage::$mList. To remove a core static special page at runtime, use * a SpecialPage_initList hook. * - * @package MediaWiki - * @subpackage SpecialPage - */ - -/** - * @access private + * @file + * @ingroup SpecialPage + * @defgroup SpecialPage SpecialPage */ /** * Parent special page class, also static functions for handling the special - * page list - * @package MediaWiki + * page list. + * @ingroup SpecialPage */ class SpecialPage { @@ -73,7 +70,15 @@ class SpecialPage * Query parameters that can be passed through redirects */ var $mAllowedRedirectParams = array(); - + /** + * List of special pages, followed by parameters. + * If the only parameter is a string, that is the page name. + * Otherwise, it is an array. The format is one of: + ** array( 'SpecialPage', name, right ) + ** array( 'IncludableSpecialPage', name, right, listed? ) + ** array( 'UnlistedSpecialPage', name, right ) + ** array( 'SpecialRedirectToSpecial', name, page to redirect to, special page param, ... ) + */ static public $mList = array( 'DoubleRedirects' => array( 'SpecialPage', 'DoubleRedirects' ), 'BrokenRedirects' => array( 'SpecialPage', 'BrokenRedirects' ), @@ -81,42 +86,49 @@ class SpecialPage 'Userlogin' => array( 'SpecialPage', 'Userlogin' ), 'Userlogout' => array( 'UnlistedSpecialPage', 'Userlogout' ), + 'CreateAccount' => array( 'SpecialRedirectToSpecial', 'CreateAccount', 'Userlogin', 'signup', array( 'uselang' ) ), 'Preferences' => array( 'SpecialPage', 'Preferences' ), 'Watchlist' => array( 'SpecialPage', 'Watchlist' ), - 'Recentchanges' => array( 'IncludableSpecialPage', 'Recentchanges' ), + 'Recentchanges' => 'SpecialRecentchanges', 'Upload' => array( 'SpecialPage', 'Upload' ), 'Imagelist' => array( 'SpecialPage', 'Imagelist' ), 'Newimages' => array( 'IncludableSpecialPage', 'Newimages' ), 'Listusers' => array( 'SpecialPage', 'Listusers' ), + 'Listgrouprights' => 'SpecialListGroupRights', 'Statistics' => array( 'SpecialPage', 'Statistics' ), - 'Randompage' => array( 'SpecialPage', 'Randompage' ), + 'Randompage' => 'Randompage', 'Lonelypages' => array( 'SpecialPage', 'Lonelypages' ), 'Uncategorizedpages' => array( 'SpecialPage', 'Uncategorizedpages' ), 'Uncategorizedcategories' => array( 'SpecialPage', 'Uncategorizedcategories' ), 'Uncategorizedimages' => array( 'SpecialPage', 'Uncategorizedimages' ), + 'Uncategorizedtemplates' => array( 'SpecialPage', 'Uncategorizedtemplates' ), 'Unusedcategories' => array( 'SpecialPage', 'Unusedcategories' ), 'Unusedimages' => array( 'SpecialPage', 'Unusedimages' ), 'Wantedpages' => array( 'IncludableSpecialPage', 'Wantedpages' ), 'Wantedcategories' => array( 'SpecialPage', 'Wantedcategories' ), 'Mostlinked' => array( 'SpecialPage', 'Mostlinked' ), 'Mostlinkedcategories' => array( 'SpecialPage', 'Mostlinkedcategories' ), + 'Mostlinkedtemplates' => array( 'SpecialPage', 'Mostlinkedtemplates' ), 'Mostcategories' => array( 'SpecialPage', 'Mostcategories' ), 'Mostimages' => array( 'SpecialPage', 'Mostimages' ), 'Mostrevisions' => array( 'SpecialPage', 'Mostrevisions' ), + 'Fewestrevisions' => array( 'SpecialPage', 'Fewestrevisions' ), 'Shortpages' => array( 'SpecialPage', 'Shortpages' ), 'Longpages' => array( 'SpecialPage', 'Longpages' ), - 'Newpages' => array( 'IncludableSpecialPage', 'Newpages' ), + 'Newpages' => 'SpecialNewpages', 'Ancientpages' => array( 'SpecialPage', 'Ancientpages' ), 'Deadendpages' => array( 'SpecialPage', 'Deadendpages' ), + 'Protectedpages' => array( 'SpecialPage', 'Protectedpages' ), + 'Protectedtitles' => array( 'SpecialPage', 'Protectedtitles' ), 'Allpages' => array( 'IncludableSpecialPage', 'Allpages' ), 'Prefixindex' => array( 'IncludableSpecialPage', 'Prefixindex' ) , 'Ipblocklist' => array( 'SpecialPage', 'Ipblocklist' ), 'Specialpages' => array( 'UnlistedSpecialPage', 'Specialpages' ), - 'Contributions' => array( 'UnlistedSpecialPage', 'Contributions' ), + 'Contributions' => array( 'SpecialPage', 'Contributions' ), 'Emailuser' => array( 'UnlistedSpecialPage', 'Emailuser' ), - 'Whatlinkshere' => array( 'UnlistedSpecialPage', 'Whatlinkshere' ), - 'Recentchangeslinked' => array( 'UnlistedSpecialPage', 'Recentchangeslinked' ), + 'Whatlinkshere' => array( 'SpecialPage', 'Whatlinkshere' ), + 'Recentchangeslinked' => 'SpecialRecentchangeslinked', 'Movepage' => array( 'UnlistedSpecialPage', 'Movepage' ), 'Blockme' => array( 'UnlistedSpecialPage', 'Blockme' ), 'Resetpass' => array( 'UnlistedSpecialPage', 'Resetpass' ), @@ -124,26 +136,31 @@ class SpecialPage 'Categories' => array( 'SpecialPage', 'Categories' ), 'Export' => array( 'SpecialPage', 'Export' ), 'Version' => array( 'SpecialPage', 'Version' ), + 'Blankpage' => array( 'UnlistedSpecialPage', 'Blankpage' ), 'Allmessages' => array( 'SpecialPage', 'Allmessages' ), 'Log' => array( 'SpecialPage', 'Log' ), 'Blockip' => array( 'SpecialPage', 'Blockip', 'block' ), 'Undelete' => array( 'SpecialPage', 'Undelete', 'deletedhistory' ), - 'Import' => array( 'SpecialPage', "Import", 'import' ), + 'Import' => array( 'SpecialPage', 'Import', 'import' ), 'Lockdb' => array( 'SpecialPage', 'Lockdb', 'siteadmin' ), 'Unlockdb' => array( 'SpecialPage', 'Unlockdb', 'siteadmin' ), - 'Userrights' => array( 'SpecialPage', 'Userrights', 'userrights' ), + 'Userrights' => 'UserrightsPage', 'MIMEsearch' => array( 'SpecialPage', 'MIMEsearch' ), + 'FileDuplicateSearch' => array( 'SpecialPage', 'FileDuplicateSearch' ), 'Unwatchedpages' => array( 'SpecialPage', 'Unwatchedpages', 'unwatchedpages' ), 'Listredirects' => array( 'SpecialPage', 'Listredirects' ), - 'Listinterwikis' => array( 'SpecialPage', 'Listinterwikis' ), - 'Revisiondelete' => array( 'SpecialPage', 'Revisiondelete', 'deleterevision' ), + 'Revisiondelete' => array( 'UnlistedSpecialPage', 'Revisiondelete', 'deleterevision' ), 'Unusedtemplates' => array( 'SpecialPage', 'Unusedtemplates' ), - 'Randomredirect' => array( 'SpecialPage', 'Randomredirect' ), + 'Randomredirect' => 'SpecialRandomredirect', + 'Withoutinterwiki' => array( 'SpecialPage', 'Withoutinterwiki' ), + 'Filepath' => array( 'SpecialPage', 'Filepath' ), 'Mypage' => array( 'SpecialMypage' ), 'Mytalk' => array( 'SpecialMytalk' ), 'Mycontributions' => array( 'SpecialMycontributions' ), 'Listadmins' => array( 'SpecialRedirectToSpecial', 'Listadmins', 'Listusers', 'sysop' ), + 'MergeHistory' => array( 'SpecialPage', 'MergeHistory', 'mergehistory' ), + 'Listbots' => array( 'SpecialRedirectToSpecial', 'Listbots', 'Listusers', 'bot' ), ); static public $mAliases; @@ -163,7 +180,7 @@ class SpecialPage return; } wfProfileIn( __METHOD__ ); - + # Better to set this now, to avoid infinite recursion in carelessly written hooks self::$mListInitialised = true; @@ -176,7 +193,8 @@ class SpecialPage } if( $wgEmailAuthentication ) { - self::$mList['Confirmemail'] = array( 'UnlistedSpecialPage', 'Confirmemail' ); + self::$mList['Confirmemail'] = 'EmailConfirmation'; + self::$mList['Invalidateemail'] = 'EmailInvalidation'; } # Add extension special pages @@ -226,7 +244,7 @@ class SpecialPage } /** - * Given a special page name with a possible subpage, return an array + * Given a special page name with a possible subpage, return an array * where the first element is the special page name and the second is the * subpage. */ @@ -242,14 +260,11 @@ class SpecialPage } /** - * Add a page to the list of valid special pages. This used to be the preferred - * method for adding special pages in extensions. It's now suggested that you add + * Add a page to the list of valid special pages. This used to be the preferred + * method for adding special pages in extensions. It's now suggested that you add * an associative record to $wgSpecialPages. This avoids autoloading SpecialPage. * - * @param mixed $page Must either be an array specifying a class name and - * constructor parameters, or an object. The object, - * when constructed, must have an execute() method which - * sends HTML to $wgOut. + * @param SpecialPage $page * @static */ static function addPage( &$page ) { @@ -259,11 +274,48 @@ class SpecialPage self::$mList[$page->mName] = $page; } + /** + * Add a page to a certain display group for Special:SpecialPages + * + * @param mixed $page (SpecialPage or string) + * @param string $group + * @static + */ + static function setGroup( $page, $group ) { + global $wgSpecialPageGroups; + $name = is_object($page) ? $page->mName : $page; + $wgSpecialPageGroups[$name] = $group; + } + + /** + * Add a page to a certain display group for Special:SpecialPages + * + * @param SpecialPage $page + * @static + */ + static function getGroup( &$page ) { + global $wgSpecialPageGroups; + static $specialPageGroupsCache = array(); + if( isset($specialPageGroupsCache[$page->mName]) ) { + return $specialPageGroupsCache[$page->mName]; + } + $group = wfMsg('specialpages-specialpagegroup-'.strtolower($page->mName)); + if( $group == '' + || wfEmptyMsg('specialpages-specialpagegroup-'.strtolower($page->mName), $group ) ) { + $group = isset($wgSpecialPageGroups[$page->mName]) + ? $wgSpecialPageGroups[$page->mName] + : '-'; + } + if( $group == '-' ) $group = 'other'; + $specialPageGroupsCache[$page->mName] = $group; + return $group; + } + /** * Remove a special page from the list - * Formerly used to disable expensive or dangerous special pages. The + * Formerly used to disable expensive or dangerous special pages. The * preferred method is now to add a SpecialPage_initList hook. - * + * * @static */ static function removePage( $name ) { @@ -273,6 +325,30 @@ class SpecialPage unset( self::$mList[$name] ); } + /** + * Check if a given name exist as a special page or as a special page alias + * @param $name string: name of a special page + * @return boolean: true if a special page exists with this name + */ + static function exists( $name ) { + global $wgContLang; + if ( !self::$mListInitialised ) { + self::initList(); + } + if( !self::$mAliases ) { + self::initAliasList(); + } + + # Remove special pages inline parameters: + $bits = explode( '/', $name ); + $name = $wgContLang->caseFold($bits[0]); + + return + array_key_exists( $name, self::$mList ) + or array_key_exists( $name, self::$mAliases ) + ; + } + /** * Find the object with a given name and return it (or NULL) * @static @@ -310,6 +386,32 @@ class SpecialPage } } + /** + * Return categorised listable special pages which are available + * for the current user, and everyone. + * @static + */ + static function getUsablePages() { + global $wgUser; + if ( !self::$mListInitialised ) { + self::initList(); + } + $pages = array(); + + foreach ( self::$mList as $name => $rec ) { + $page = self::getPage( $name ); + if ( $page->isListed() + && ( + !$page->isRestricted() + || $page->userCanExecute( $wgUser ) + ) + ) { + $pages[$name] = $page; + } + } + return $pages; + } + /** * Return categorised listable special pages for all users * @static @@ -322,7 +424,7 @@ class SpecialPage foreach ( self::$mList as $name => $rec ) { $page = self::getPage( $name ); - if ( $page->isListed() && $page->getRestriction() == '' ) { + if ( $page->isListed() && !$page->isRestricted() ) { $pages[$name] = $page; } } @@ -336,18 +438,19 @@ class SpecialPage */ static function getRestrictedPages() { global $wgUser; - if ( !self::$mListInitialised ) { + if( !self::$mListInitialised ) { self::initList(); } $pages = array(); - foreach ( self::$mList as $name => $rec ) { + foreach( self::$mList as $name => $rec ) { $page = self::getPage( $name ); - if ( $page->isListed() ) { - $restriction = $page->getRestriction(); - if ( $restriction != '' && $wgUser->isAllowed( $restriction ) ) { - $pages[$name] = $page; - } + if( + $page->isListed() + && $page->isRestricted() + && $page->userCanExecute( $wgUser ) + ) { + $pages[$name] = $page; } } return $pages; @@ -377,12 +480,11 @@ class SpecialPage $par = $bits[1]; } $page = SpecialPage::getPageByAlias( $name ); - # Nonexistent? if ( !$page ) { if ( !$including ) { $wgOut->setArticleRelated( false ); - $wgOut->setRobotpolicy( 'noindex,nofollow' ); + $wgOut->setRobotPolicy( 'noindex,nofollow' ); $wgOut->setStatusCode( 404 ); $wgOut->showErrorPage( 'nosuchspecialpage', 'nospecialpagetext' ); } @@ -403,9 +505,9 @@ class SpecialPage } # Redirect to canonical alias for GET commands - # Not for POST, we'd lose the post data, so it's best to just distribute - # the request. Such POST requests are possible for old extensions that - # generate self-links without being aware that their default name has + # Not for POST, we'd lose the post data, so it's best to just distribute + # the request. Such POST requests are possible for old extensions that + # generate self-links without being aware that their default name has # changed. if ( !$including && $name != $page->getLocalName() && !$wgRequest->wasPosted() ) { $query = $_GET; @@ -459,6 +561,11 @@ class SpecialPage /** * Get the local name for a specified canonical name + * + * @param $name + * @param mixed $subpage Boolean false, or string + * + * @return string */ static function getLocalNameFor( $name, $subpage = false ) { global $wgContLang; @@ -536,7 +643,7 @@ class SpecialPage $this->mFunction = $function; } if ( $file === 'default' ) { - $this->mFile = "Special{$name}.php"; + $this->mFile = dirname(__FILE__) . "/specials/Special$name.php"; } else { $this->mFile = $file; } @@ -575,11 +682,26 @@ class SpecialPage return $this->mLocalName; } + /** + * Can be overridden by subclasses with more complicated permissions + * schemes. + * + * @return bool Should the page be displayed with the restricted-access + * pages? + */ + public function isRestricted() { + return $this->mRestriction != ''; + } + /** * Checks if the given user (identified by an object) can execute this - * special page (as defined by $mRestriction) + * special page (as defined by $mRestriction). Can be overridden by sub- + * classes with more complicated permissions schemes. + * + * @param User $user The user to check + * @return bool Does the user have permission to view the page? */ - function userCanExecute( &$user ) { + public function userCanExecute( $user ) { return $user->isAllowed( $this->mRestriction ); } @@ -605,7 +727,7 @@ class SpecialPage * Default execute method * Checks user permissions, calls the function given in mFunction * - * This may be overridden by subclasses. + * This may be overridden by subclasses. */ function execute( $par ) { global $wgUser; @@ -615,15 +737,15 @@ class SpecialPage if ( $this->userCanExecute( $wgUser ) ) { $func = $this->mFunction; // only load file if the function does not exist - if(!function_exists($func) and $this->mFile) { + if(!is_callable($func) and $this->mFile) { require_once( $this->mFile ); } - # FIXME: these hooks are broken for extensions and anything else that subclasses SpecialPage. + # FIXME: these hooks are broken for extensions and anything else that subclasses SpecialPage. if ( wfRunHooks( 'SpecialPageExecuteBeforeHeader', array( &$this, &$par, &$func ) ) ) $this->outputHeader(); if ( ! wfRunHooks( 'SpecialPageExecuteBeforePage', array( &$this, &$par, &$func ) ) ) return; - $func( $par, $this ); + call_user_func( $func, $par, $this ); if ( ! wfRunHooks( 'SpecialPageExecuteAfterPage', array( &$this, &$par, &$func ) ) ) return; } else { @@ -635,9 +757,10 @@ class SpecialPage global $wgOut, $wgContLang; $msg = $wgContLang->lc( $this->name() ) . '-summary'; - $out = wfMsg( $msg ); - if ( ! wfEmptyMsg( $msg, $out ) and $out !== '' and ! $this->including() ) - $wgOut->addWikiText( $out ); + $out = wfMsgNoTrans( $msg ); + if ( ! wfEmptyMsg( $msg, $out ) and $out !== '' and ! $this->including() ) { + $wgOut->addWikiMsg( $msg ); + } } @@ -665,7 +788,7 @@ class SpecialPage } /** - * If the special page is a redirect, then get the Title object it redirects to. + * If the special page is a redirect, then get the Title object it redirects to. * False otherwise. */ function getRedirect( $subpage ) { @@ -685,14 +808,14 @@ class SpecialPage if( $val = $wgRequest->getVal( $arg, false ) ) $params[] = $arg . '=' . $val; } - + return count( $params ) ? implode( '&', $params ) : false; } } /** * Shortcut to construct a special page which is unlisted by default - * @package MediaWiki + * @ingroup SpecialPage */ class UnlistedSpecialPage extends SpecialPage { @@ -703,7 +826,7 @@ class UnlistedSpecialPage extends SpecialPage /** * Shortcut to construct an includable special page - * @package MediaWiki + * @ingroup SpecialPage */ class IncludableSpecialPage extends SpecialPage { @@ -712,6 +835,10 @@ class IncludableSpecialPage extends SpecialPage } } +/** + * Shortcut to construct a special page alias. + * @ingroup SpecialPage + */ class SpecialRedirectToSpecial extends UnlistedSpecialPage { var $redirName, $redirSubpage; @@ -731,10 +858,21 @@ class SpecialRedirectToSpecial extends UnlistedSpecialPage { } } +/** SpecialMypage, SpecialMytalk and SpecialMycontributions special pages + * are used to get user independant links pointing to the user page, talk + * page and list of contributions. + * This can let us cache a single copy of any generated content for all + * users. + */ + +/** + * Shortcut to construct a special page pointing to current user user's page. + * @ingroup SpecialPage + */ class SpecialMypage extends UnlistedSpecialPage { function __construct() { parent::__construct( 'Mypage' ); - $this->mAllowedRedirectParams = array( 'action' ); + $this->mAllowedRedirectParams = array( 'action' , 'preload' , 'editintro', 'section' ); } function getRedirect( $subpage ) { @@ -747,10 +885,14 @@ class SpecialMypage extends UnlistedSpecialPage { } } +/** + * Shortcut to construct a special page pointing to current user talk page. + * @ingroup SpecialPage + */ class SpecialMytalk extends UnlistedSpecialPage { function __construct() { parent::__construct( 'Mytalk' ); - $this->mAllowedRedirectParams = array( 'action' ); + $this->mAllowedRedirectParams = array( 'action' , 'preload' , 'editintro', 'section' ); } function getRedirect( $subpage ) { @@ -763,6 +905,10 @@ class SpecialMytalk extends UnlistedSpecialPage { } } +/** + * Shortcut to construct a special page pointing to current user contributions. + * @ingroup SpecialPage + */ class SpecialMycontributions extends UnlistedSpecialPage { function __construct() { parent::__construct( 'Mycontributions' ); @@ -773,5 +919,3 @@ class SpecialMycontributions extends UnlistedSpecialPage { return SpecialPage::getTitleFor( 'Contributions', $wgUser->getName() ); } } - -?>