* and does not rely on global state or the database.
*/
class Title implements LinkTarget {
- /** @var HashBagOStuff */
+ /** @var MapCacheLRU */
static private $titleCache = null;
/**
public static function newFromTextThrow( $text, $defaultNamespace = NS_MAIN ) {
if ( is_object( $text ) ) {
throw new MWException( '$text must be a string, given an object' );
+ } elseif ( $text === null ) {
+ // Legacy code relies on MalformedTitleException being thrown in this case
+ // (happens when URL with no title in it is parsed). TODO fix
+ throw new MalformedTitleException( 'title-invalid-empty' );
}
$titleCache = self::getTitleCache();
}
/**
- * @return HashBagOStuff
+ * @return MapCacheLRU
*/
private static function getTitleCache() {
if ( self::$titleCache == null ) {
- self::$titleCache = new HashBagOStuff( [ 'maxKeys' => self::CACHE_MAX ] );
+ self::$titleCache = new MapCacheLRU( self::CACHE_MAX );
}
return self::$titleCache;
}
*/
public function isSiteConfigPage() {
return (
- NS_MEDIAWIKI == $this->mNamespace
- && (
- $this->hasContentModel( CONTENT_MODEL_CSS )
- || $this->hasContentModel( CONTENT_MODEL_JSON )
- || $this->hasContentModel( CONTENT_MODEL_JAVASCRIPT )
- )
+ $this->isSiteCssConfigPage()
+ || $this->isSiteJsonConfigPage()
+ || $this->isSiteJsConfigPage()
);
}
*/
public function isUserConfigPage() {
return (
- NS_USER == $this->mNamespace
- && $this->isSubpage()
- && (
- $this->hasContentModel( CONTENT_MODEL_CSS )
- || $this->hasContentModel( CONTENT_MODEL_JSON )
- || $this->hasContentModel( CONTENT_MODEL_JAVASCRIPT )
- )
+ $this->isUserCssConfigPage()
+ || $this->isUserJsonConfigPage()
+ || $this->isUserJsConfigPage()
);
}
return $this->isUserJsConfigPage();
}
+ /**
+ * Is this a sitewide CSS "config" page?
+ *
+ * @return bool
+ * @since 1.32
+ */
+ public function isSiteCssConfigPage() {
+ return (
+ NS_MEDIAWIKI == $this->mNamespace
+ && (
+ $this->hasContentModel( CONTENT_MODEL_CSS )
+ // paranoia - a MediaWiki: namespace page with mismatching extension and content
+ // model is probably by mistake and might get handled incorrectly (see e.g. T112937)
+ || substr( $this->getDBkey(), -4 ) === '.css'
+ )
+ );
+ }
+
+ /**
+ * Is this a sitewide JSON "config" page?
+ *
+ * @return bool
+ * @since 1.32
+ */
+ public function isSiteJsonConfigPage() {
+ return (
+ NS_MEDIAWIKI == $this->mNamespace
+ && (
+ $this->hasContentModel( CONTENT_MODEL_JSON )
+ // paranoia - a MediaWiki: namespace page with mismatching extension and content
+ // model is probably by mistake and might get handled incorrectly (see e.g. T112937)
+ || substr( $this->getDBkey(), -5 ) === '.json'
+ )
+ );
+ }
+
+ /**
+ * Is this a sitewide JS "config" page?
+ *
+ * @return bool
+ * @since 1.31
+ */
+ public function isSiteJsConfigPage() {
+ return (
+ NS_MEDIAWIKI == $this->mNamespace
+ && (
+ $this->hasContentModel( CONTENT_MODEL_JAVASCRIPT )
+ // paranoia - a MediaWiki: namespace page with mismatching extension and content
+ // model is probably by mistake and might get handled incorrectly (see e.g. T112937)
+ || substr( $this->getDBkey(), -3 ) === '.js'
+ )
+ );
+ }
+
/**
* Is this a talk page of some sort?
*
* May provide false positives, but should never provide a false negative.
*
* @param string $action Action that permission needs to be checked for
- * @param User $user User to check (since 1.19); $wgUser will be used if not provided.
+ * @param User|null $user User to check (since 1.19); $wgUser will be used if not provided.
* @return bool
*/
public function quickUserCan( $action, $user = null ) {
* Can $user perform $action on this page?
*
* @param string $action Action that permission needs to be checked for
- * @param User $user User to check (since 1.19); $wgUser will be used if not
+ * @param User|null $user User to check (since 1.19); $wgUser will be used if not
* provided.
* @param string $rigor Same format as Title::getUserPermissionsErrors()
* @return bool
return $errors;
}
+ /**
+ * Check sitewide CSS/JSON/JS permissions
+ *
+ * @param string $action The action to check
+ * @param User $user User to check
+ * @param array $errors List of current errors
+ * @param string $rigor Same format as Title::getUserPermissionsErrors()
+ * @param bool $short Short circuit on first error
+ *
+ * @return array List of errors
+ */
+ private function checkSiteConfigPermissions( $action, $user, $errors, $rigor, $short ) {
+ if ( $action != 'patrol' ) {
+ $error = null;
+ // Sitewide CSS/JSON/JS changes, like all NS_MEDIAWIKI changes, also require the
+ // editinterface right. That's implemented as a restriction so no check needed here.
+ if ( $this->isSiteCssConfigPage() && !$user->isAllowed( 'editsitecss' ) ) {
+ $error = [ 'sitecssprotected', $action ];
+ } elseif ( $this->isSiteJsonConfigPage() && !$user->isAllowed( 'editsitejson' ) ) {
+ $error = [ 'sitejsonprotected', $action ];
+ } elseif ( $this->isSiteJsConfigPage() && !$user->isAllowed( 'editsitejs' ) ) {
+ $error = [ 'sitejsprotected', $action ];
+ }
+
+ if ( $error ) {
+ if ( $user->isAllowed( 'editinterface' ) ) {
+ // Most users / site admins will probably find out about the new, more restrictive
+ // permissions by failing to edit something. Give them more info.
+ // TODO remove this a few release cycles after 1.32
+ $error = [ 'interfaceadmin-info', wfMessage( $error[0], $error[1] ) ];
+ }
+ $errors[] = $error;
+ }
+ }
+
+ return $errors;
+ }
+
/**
* Check CSS/JSON/JS sub-page permissions
*
'checkReadPermissions',
'checkUserBlock', // for wgBlockDisablesLogin
];
- # Don't call checkSpecialsAndNSPermissions or checkUserConfigPermissions
- # here as it will lead to duplicate error messages. This is okay to do
- # since anywhere that checks for create will also check for edit, and
- # those checks are called for edit.
+ # Don't call checkSpecialsAndNSPermissions, checkSiteConfigPermissions
+ # or checkUserConfigPermissions here as it will lead to duplicate
+ # error messages. This is okay to do since anywhere that checks for
+ # create will also check for edit, and those checks are called for edit.
} elseif ( $action == 'create' ) {
$checks = [
'checkQuickPermissions',
'checkQuickPermissions',
'checkPermissionHooks',
'checkSpecialsAndNSPermissions',
+ 'checkSiteConfigPermissions',
'checkUserConfigPermissions',
'checkPageRestrictions',
'checkCascadingSourcesRestrictions',
* Public for usage by LiquidThreads.
*
* @param array $rows Array of db result objects
- * @param string $oldFashionedRestrictions Comma-separated set of permission keys
+ * @param string|null $oldFashionedRestrictions Comma-separated set of permission keys
* indicating who can move or edit the page from the page table, (pre 1.10) rows.
* Edit and move sections are separated by a colon
* Example: "edit=autoconfirmed,sysop:move=sysop"
/**
* Load restrictions from the page_restrictions table
*
- * @param string $oldFashionedRestrictions Comma-separated set of permission keys
+ * @param string|null $oldFashionedRestrictions Comma-separated set of permission keys
* indicating who can move or edit the page from the page table, (pre 1.10) rows.
* Edit and move sections are separated by a colon
* Example: "edit=autoconfirmed,sysop:move=sysop"
/**
* Updates page_touched for this page; called from LinksUpdate.php
*
- * @param string $purgeTime [optional] TS_MW timestamp
+ * @param string|null $purgeTime [optional] TS_MW timestamp
* @return bool True if the update succeeded
*/
public function invalidateCache( $purgeTime = null ) {
/**
* Get the timestamp when this page was updated since the user last saw it.
*
- * @param User $user
+ * @param User|null $user
* @return string|null
*/
public function getNotificationTimestamp( $user = null ) {