Update mediawiki to v1.31.1
Signed-off-by: Florian Pritz <bluewind@xinu.at>
This commit is contained in:
parent
4a852a8107
commit
93d4fc9de0
|
@ -1,4 +1,28 @@
|
|||
== MediaWiki 1.31 ==
|
||||
== MediaWiki 1.31.1 ==
|
||||
|
||||
This is a security and maintenance release of the MediaWiki 1.31 branch.
|
||||
|
||||
=== Changes since MediaWiki 1.31.0 ===
|
||||
* (T169545, CVE-2018-0503) SECURITY: $wgRateLimits entry for 'user' overrides
|
||||
'newbie'.
|
||||
* (T194605, CVE-2018-0505) SECURITY: BotPasswords can bypass CentralAuth's
|
||||
account lock.
|
||||
* (T199029, CVE-2018-13258) SECURITY: Tarball was missing .htaccess files.
|
||||
* (T197229) Bundle Nuke extension, it was accidentally omitted.
|
||||
* (T193995) Fix undefined patchPath() method call in parser tests.
|
||||
* (T198687) Fix various selectFields methods to use the string 'NULL', not null.
|
||||
* Special:BotPasswords now requires reauthentication.
|
||||
* (T191608, T187638) Add 'logid' parameter to Special:Log.
|
||||
* (T193829) Indicate when a Bot Password needs reset.
|
||||
* (T198037) GitInfo: Don't try shelling out if it's disabled.
|
||||
* (T151415) Log email changes.
|
||||
* (T197206) Fix performance regression when multiple DB used without caching.
|
||||
* (T197030) PHPSessionHandler: Suppress headers warnings in initialize().
|
||||
* (T182377, T196793) Exif: Guard against uncountable tag values.
|
||||
* (T200861) Fix total breakage of SQLite web upgrade.
|
||||
* (T200864) Fix pingback over-reporting on non-MySQL databases
|
||||
* (T202550) Unbreak SpecialListusersHeaderForm and SpecialListusersHeader
|
||||
hooks.
|
||||
|
||||
=== Changes since MediaWiki 1.31.0-rc.2 ===
|
||||
* (T195783) Initialize PSR-4 namespaces at same stage as normal autoloader.
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Deny from all
|
|
@ -0,0 +1,9 @@
|
|||
# Protect against bug T30235
|
||||
<IfModule rewrite_module>
|
||||
RewriteEngine On
|
||||
RewriteOptions inherit
|
||||
RewriteCond %{QUERY_STRING} \.[^\\/:*?\x22<>|%]+(#|\?|$) [nocase]
|
||||
RewriteRule . - [forbidden]
|
||||
# Fix for bug T64289
|
||||
Options +FollowSymLinks
|
||||
</IfModule>
|
|
@ -0,0 +1 @@
|
|||
Deny from all
|
|
@ -224,7 +224,7 @@ class Block {
|
|||
'ipb_address',
|
||||
'ipb_by',
|
||||
'ipb_by_text',
|
||||
'ipb_by_actor' => $wgActorTableSchemaMigrationStage > MIGRATION_OLD ? 'ipb_by_actor' : null,
|
||||
'ipb_by_actor' => $wgActorTableSchemaMigrationStage > MIGRATION_OLD ? 'ipb_by_actor' : 'NULL',
|
||||
'ipb_timestamp',
|
||||
'ipb_auto',
|
||||
'ipb_anon_only',
|
||||
|
|
|
@ -71,7 +71,7 @@ $wgConfigRegistry = [
|
|||
* MediaWiki version number
|
||||
* @since 1.2
|
||||
*/
|
||||
$wgVersion = '1.31.0';
|
||||
$wgVersion = '1.31.1';
|
||||
|
||||
/**
|
||||
* Name of the site. It must be changed in LocalSettings.php
|
||||
|
|
|
@ -227,6 +227,7 @@ class GitInfo {
|
|||
$date = false;
|
||||
if ( is_file( $wgGitBin ) &&
|
||||
is_executable( $wgGitBin ) &&
|
||||
!Shell::isDisabled() &&
|
||||
$this->getHead() !== false
|
||||
) {
|
||||
$cmd = [
|
||||
|
|
|
@ -134,7 +134,7 @@ class PHPVersionCheck {
|
|||
If for some reason you are unable to upgrade your {$phpInfo['implementation']} version,
|
||||
you will need to <a href="https://www.mediawiki.org/wiki/Download">download</a> an
|
||||
older version of MediaWiki from our website.
|
||||
See our<a href="https://www.mediawiki.org/wiki/Compatibility#PHP">compatibility page</a>
|
||||
See our <a href="https://www.mediawiki.org/wiki/Compatibility#PHP">compatibility page</a>
|
||||
for details of which versions are compatible with prior versions of {$phpInfo['implementation']}.
|
||||
HTML;
|
||||
// phpcs:enable Generic.Files.LineLength
|
||||
|
|
|
@ -99,7 +99,7 @@ class Pingback {
|
|||
return $dbw->upsert(
|
||||
'updatelog',
|
||||
[ 'ul_key' => $this->key, 'ul_value' => $timestamp ],
|
||||
[ 'ul_key' => $this->key ],
|
||||
[ 'ul_key' ],
|
||||
[ 'ul_value' => $timestamp ],
|
||||
__METHOD__
|
||||
);
|
||||
|
|
|
@ -130,7 +130,11 @@ class ApiLogin extends ApiBase {
|
|||
$session = $status->getValue();
|
||||
$authRes = 'Success';
|
||||
$loginType = 'BotPassword';
|
||||
} elseif ( !$botLoginData[2] || $status->hasMessage( 'login-throttled' ) ) {
|
||||
} elseif ( !$botLoginData[2] ||
|
||||
$status->hasMessage( 'login-throttled' ) ||
|
||||
$status->hasMessage( 'botpasswords-needs-reset' ) ||
|
||||
$status->hasMessage( 'botpasswords-locked' )
|
||||
) {
|
||||
$authRes = 'Failed';
|
||||
$message = $status->getMessage();
|
||||
LoggerFactory::getInstance( 'authentication' )->info(
|
||||
|
|
|
@ -21,10 +21,11 @@
|
|||
*/
|
||||
|
||||
use MediaWiki\MediaWikiServices;
|
||||
use Wikimedia\Rdbms\LoadBalancer;
|
||||
use Wikimedia\Rdbms\ILoadBalancer;
|
||||
use Wikimedia\Rdbms\IDatabase;
|
||||
use Wikimedia\Rdbms\DBConnRef;
|
||||
use Wikimedia\Rdbms\MaintainableDBConnRef;
|
||||
use Wikimedia\Rdbms\DatabaseDomain;
|
||||
|
||||
/**
|
||||
* DB accessible external objects.
|
||||
|
@ -112,7 +113,7 @@ class ExternalStoreDB extends ExternalStoreMedium {
|
|||
* Get a LoadBalancer for the specified cluster
|
||||
*
|
||||
* @param string $cluster Cluster name
|
||||
* @return LoadBalancer
|
||||
* @return ILoadBalancer
|
||||
*/
|
||||
private function getLoadBalancer( $cluster ) {
|
||||
$lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
|
||||
|
@ -128,8 +129,8 @@ class ExternalStoreDB extends ExternalStoreMedium {
|
|||
public function getSlave( $cluster ) {
|
||||
global $wgDefaultExternalStore;
|
||||
|
||||
$wiki = isset( $this->params['wiki'] ) ? $this->params['wiki'] : false;
|
||||
$lb = $this->getLoadBalancer( $cluster );
|
||||
$domainId = $this->getDomainId( $lb->getServerInfo( $lb->getWriterIndex() ) );
|
||||
|
||||
if ( !in_array( "DB://" . $cluster, (array)$wgDefaultExternalStore ) ) {
|
||||
wfDebug( "read only external store\n" );
|
||||
|
@ -138,7 +139,7 @@ class ExternalStoreDB extends ExternalStoreMedium {
|
|||
wfDebug( "writable external store\n" );
|
||||
}
|
||||
|
||||
$db = $lb->getConnectionRef( DB_REPLICA, [], $wiki );
|
||||
$db = $lb->getConnectionRef( DB_REPLICA, [], $domainId );
|
||||
$db->clearFlag( DBO_TRX ); // sanity
|
||||
|
||||
return $db;
|
||||
|
@ -151,15 +152,42 @@ class ExternalStoreDB extends ExternalStoreMedium {
|
|||
* @return MaintainableDBConnRef
|
||||
*/
|
||||
public function getMaster( $cluster ) {
|
||||
$wiki = isset( $this->params['wiki'] ) ? $this->params['wiki'] : false;
|
||||
$lb = $this->getLoadBalancer( $cluster );
|
||||
$domainId = $this->getDomainId( $lb->getServerInfo( $lb->getWriterIndex() ) );
|
||||
|
||||
$db = $lb->getMaintenanceConnectionRef( DB_MASTER, [], $wiki );
|
||||
$db = $lb->getMaintenanceConnectionRef( DB_MASTER, [], $domainId );
|
||||
$db->clearFlag( DBO_TRX ); // sanity
|
||||
|
||||
return $db;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $server Master DB server configuration array for LoadBalancer
|
||||
* @return string|bool Database domain ID or false
|
||||
*/
|
||||
private function getDomainId( array $server ) {
|
||||
if ( isset( $this->params['wiki'] ) ) {
|
||||
return $this->params['wiki']; // explicit domain
|
||||
}
|
||||
|
||||
if ( isset( $server['dbname'] ) ) {
|
||||
// T200471: for b/c, treat any "dbname" field as forcing which database to use.
|
||||
// MediaWiki/LoadBalancer previously did not enforce any concept of a local DB
|
||||
// domain, but rather assumed that the LB server configuration matched $wgDBname.
|
||||
// This check is useful when the external storage DB for this cluster does not use
|
||||
// the same name as the corresponding "main" DB(s) for wikis.
|
||||
$domain = new DatabaseDomain(
|
||||
$server['dbname'],
|
||||
$server['schema'] ?? null,
|
||||
$server['tablePrefix'] ?? ''
|
||||
);
|
||||
|
||||
return $domain->getId();
|
||||
}
|
||||
|
||||
return false; // local LB domain
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the 'blobs' table name for this database
|
||||
*
|
||||
|
|
|
@ -246,7 +246,7 @@ class ArchivedFile {
|
|||
'fa_minor_mime',
|
||||
'fa_user',
|
||||
'fa_user_text',
|
||||
'fa_actor' => $wgActorTableSchemaMigrationStage > MIGRATION_OLD ? 'fa_actor' : null,
|
||||
'fa_actor' => $wgActorTableSchemaMigrationStage > MIGRATION_OLD ? 'fa_actor' : 'NULL',
|
||||
'fa_timestamp',
|
||||
'fa_deleted',
|
||||
'fa_deleted_timestamp', /* Used by LocalFileRestoreBatch */
|
||||
|
|
|
@ -223,7 +223,7 @@ class LocalFile extends File {
|
|||
'img_minor_mime',
|
||||
'img_user',
|
||||
'img_user_text',
|
||||
'img_actor' => $wgActorTableSchemaMigrationStage > MIGRATION_OLD ? 'img_actor' : null,
|
||||
'img_actor' => $wgActorTableSchemaMigrationStage > MIGRATION_OLD ? 'img_actor' : 'NULL',
|
||||
'img_timestamp',
|
||||
'img_sha1',
|
||||
] + CommentStore::getStore()->getFields( 'img_description' );
|
||||
|
|
|
@ -136,7 +136,7 @@ class OldLocalFile extends LocalFile {
|
|||
'oi_minor_mime',
|
||||
'oi_user',
|
||||
'oi_user_text',
|
||||
'oi_actor' => $wgActorTableSchemaMigrationStage > MIGRATION_OLD ? 'oi_actor' : null,
|
||||
'oi_actor' => $wgActorTableSchemaMigrationStage > MIGRATION_OLD ? 'oi_actor' : 'NULL',
|
||||
'oi_timestamp',
|
||||
'oi_deleted',
|
||||
'oi_sha1',
|
||||
|
|
|
@ -220,10 +220,6 @@ class DatabaseSqlite extends Database {
|
|||
return false;
|
||||
}
|
||||
|
||||
public function selectDB( $db ) {
|
||||
return false; // doesn't make sense
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string SQLite DB file path
|
||||
* @since 1.25
|
||||
|
|
|
@ -466,6 +466,10 @@ abstract class LBFactory implements ILBFactory {
|
|||
// Request opted out of using position wait logic. This is useful for requests
|
||||
// done by the job queue or background ETL that do not have a meaningful session.
|
||||
$this->chronProt->setWaitEnabled( false );
|
||||
} elseif ( $this->memStash instanceof EmptyBagOStuff ) {
|
||||
// No where to store any DB positions and wait for them to appear
|
||||
$this->chronProt->setEnabled( false );
|
||||
$this->replLogger->info( 'Cannot use ChronologyProtector with EmptyBagOStuff.' );
|
||||
}
|
||||
|
||||
$this->replLogger->debug( __METHOD__ . ': using request info ' .
|
||||
|
|
|
@ -335,6 +335,14 @@ interface ILoadBalancer {
|
|||
*/
|
||||
public function getServerType( $i );
|
||||
|
||||
/**
|
||||
* Return the server info structure for a given index, or false if the index is invalid.
|
||||
* @param int $i
|
||||
* @return array|bool
|
||||
* @since 1.31
|
||||
*/
|
||||
public function getServerInfo( $i );
|
||||
|
||||
/**
|
||||
* @param int $i Server index
|
||||
* @return array (Database::ATTRIBUTE_* constant => value) for all such constants
|
||||
|
|
|
@ -1173,6 +1173,14 @@ class LoadBalancer implements ILoadBalancer {
|
|||
return ( $name != '' ) ? $name : 'localhost';
|
||||
}
|
||||
|
||||
public function getServerInfo( $i ) {
|
||||
if ( isset( $this->servers[$i] ) ) {
|
||||
return $this->servers[$i];
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function getServerType( $i ) {
|
||||
return isset( $this->servers[$i]['type'] ) ? $this->servers[$i]['type'] : 'unknown';
|
||||
}
|
||||
|
|
|
@ -65,10 +65,11 @@ class LogPager extends ReverseChronologicalPager {
|
|||
* @param int|bool $month The month to start from. Default: false
|
||||
* @param string $tagFilter Tag
|
||||
* @param string $action Specific action (subtype) requested
|
||||
* @param int $logId Log entry ID, to limit to a single log entry.
|
||||
*/
|
||||
public function __construct( $list, $types = [], $performer = '', $title = '',
|
||||
$pattern = '', $conds = [], $year = false, $month = false, $tagFilter = '',
|
||||
$action = ''
|
||||
$action = '', $logId = false
|
||||
) {
|
||||
parent::__construct( $list->getContext() );
|
||||
$this->mConds = $conds;
|
||||
|
@ -81,6 +82,7 @@ class LogPager extends ReverseChronologicalPager {
|
|||
$this->limitAction( $action );
|
||||
$this->getDateCond( $year, $month );
|
||||
$this->mTagFilter = $tagFilter;
|
||||
$this->limitLogId( $logId );
|
||||
|
||||
$this->mDb = wfGetDB( DB_REPLICA, 'logpager' );
|
||||
}
|
||||
|
@ -278,6 +280,17 @@ class LogPager extends ReverseChronologicalPager {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Limit to the (single) specified log ID.
|
||||
* @param int $logId The log entry ID.
|
||||
*/
|
||||
protected function limitLogId( $logId ) {
|
||||
if ( !$logId ) {
|
||||
return;
|
||||
}
|
||||
$this->mConds['log_id'] = $logId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs the most part of the query. Extra conditions are sprinkled in
|
||||
* all over this class.
|
||||
|
|
|
@ -742,12 +742,16 @@ class Exif {
|
|||
$ecount = 1; // checking individual elements
|
||||
}
|
||||
}
|
||||
$count = count( $val );
|
||||
if ( $ecount != $count ) {
|
||||
$this->debug( $val, __FUNCTION__, "Expected $ecount elements for $tag but got $count" );
|
||||
|
||||
return false;
|
||||
$count = 1;
|
||||
if ( is_array( $val ) ) {
|
||||
$count = count( $val );
|
||||
if ( $ecount != $count ) {
|
||||
$this->debug( $val, __FUNCTION__, "Expected $ecount elements for $tag but got $count" );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// If there are multiple values, recursively validate each of them.
|
||||
if ( $count > 1 ) {
|
||||
foreach ( $val as $v ) {
|
||||
if ( !$this->validate( $section, $tag, $v, true ) ) {
|
||||
|
|
|
@ -271,7 +271,7 @@ class FormatMetadata extends ContextSource {
|
|||
// TODO: YCbCrCoefficients #p27 (see annex E)
|
||||
case 'ExifVersion':
|
||||
case 'FlashpixVersion':
|
||||
$val = "$val" / 100;
|
||||
$val = (int)$val / 100;
|
||||
break;
|
||||
|
||||
case 'ColorSpace':
|
||||
|
|
|
@ -117,7 +117,7 @@ class VersionChecker {
|
|||
}
|
||||
break;
|
||||
case 'extensions':
|
||||
case 'skin':
|
||||
case 'skins':
|
||||
foreach ( $values as $dependency => $constraint ) {
|
||||
$extError = $this->handleExtensionDependency(
|
||||
$dependency, $constraint, $extension, $dependencyType
|
||||
|
@ -169,7 +169,7 @@ class VersionChecker {
|
|||
* @param string $dependencyName The name of the dependency
|
||||
* @param string $constraint The required version constraint for this dependency
|
||||
* @param string $checkedExt The Extension, which depends on this dependency
|
||||
* @param string $type Either 'extension' or 'skin'
|
||||
* @param string $type Either 'extensions' or 'skins'
|
||||
* @return bool|array false for no errors, or an array of info
|
||||
*/
|
||||
private function handleExtensionDependency( $dependencyName, $constraint, $checkedExt,
|
||||
|
|
|
@ -122,22 +122,28 @@ class PHPSessionHandler implements \SessionHandlerInterface {
|
|||
// Close any auto-started session, before we replace it
|
||||
session_write_close();
|
||||
|
||||
// Tell PHP not to mess with cookies itself
|
||||
ini_set( 'session.use_cookies', 0 );
|
||||
ini_set( 'session.use_trans_sid', 0 );
|
||||
try {
|
||||
\Wikimedia\suppressWarnings();
|
||||
|
||||
// T124510: Disable automatic PHP session related cache headers.
|
||||
// MediaWiki adds it's own headers and the default PHP behavior may
|
||||
// set headers such as 'Pragma: no-cache' that cause problems with
|
||||
// some user agents.
|
||||
session_cache_limiter( '' );
|
||||
// Tell PHP not to mess with cookies itself
|
||||
ini_set( 'session.use_cookies', 0 );
|
||||
ini_set( 'session.use_trans_sid', 0 );
|
||||
|
||||
// Also set a sane serialization handler
|
||||
\Wikimedia\PhpSessionSerializer::setSerializeHandler();
|
||||
// T124510: Disable automatic PHP session related cache headers.
|
||||
// MediaWiki adds it's own headers and the default PHP behavior may
|
||||
// set headers such as 'Pragma: no-cache' that cause problems with
|
||||
// some user agents.
|
||||
session_cache_limiter( '' );
|
||||
|
||||
// Register this as the save handler, and register an appropriate
|
||||
// shutdown function.
|
||||
session_set_save_handler( self::$instance, true );
|
||||
// Also set a sane serialization handler
|
||||
\Wikimedia\PhpSessionSerializer::setSerializeHandler();
|
||||
|
||||
// Register this as the save handler, and register an appropriate
|
||||
// shutdown function.
|
||||
session_set_save_handler( self::$instance, true );
|
||||
} finally {
|
||||
\Wikimedia\restoreWarnings();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -51,6 +51,10 @@ class SpecialBotPasswords extends FormSpecialPage {
|
|||
return $this->getConfig()->get( 'EnableBotPasswords' );
|
||||
}
|
||||
|
||||
protected function getLoginSecurityLevel() {
|
||||
return $this->getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Main execution point
|
||||
* @param string|null $par
|
||||
|
@ -107,6 +111,9 @@ class SpecialBotPasswords extends FormSpecialPage {
|
|||
'type' => 'check',
|
||||
'label-message' => 'botpasswords-label-resetpassword',
|
||||
];
|
||||
if ( $this->botPassword->isInvalid() ) {
|
||||
$fields['resetPassword']['default'] = true;
|
||||
}
|
||||
}
|
||||
|
||||
$lang = $this->getLanguage();
|
||||
|
@ -153,22 +160,39 @@ class SpecialBotPasswords extends FormSpecialPage {
|
|||
|
||||
} else {
|
||||
$linkRenderer = $this->getLinkRenderer();
|
||||
$passwordFactory = new PasswordFactory();
|
||||
$passwordFactory->init( $this->getConfig() );
|
||||
|
||||
$dbr = BotPassword::getDB( DB_REPLICA );
|
||||
$res = $dbr->select(
|
||||
'bot_passwords',
|
||||
[ 'bp_app_id' ],
|
||||
[ 'bp_app_id', 'bp_password' ],
|
||||
[ 'bp_user' => $this->userId ],
|
||||
__METHOD__
|
||||
);
|
||||
foreach ( $res as $row ) {
|
||||
try {
|
||||
$password = $passwordFactory->newFromCiphertext( $row->bp_password );
|
||||
$passwordInvalid = $password instanceof InvalidPassword;
|
||||
unset( $password );
|
||||
} catch ( PasswordError $ex ) {
|
||||
$passwordInvalid = true;
|
||||
}
|
||||
|
||||
$text = $linkRenderer->makeKnownLink(
|
||||
$this->getPageTitle( $row->bp_app_id ),
|
||||
$row->bp_app_id
|
||||
);
|
||||
if ( $passwordInvalid ) {
|
||||
$text .= $this->msg( 'word-separator' )->escaped()
|
||||
. $this->msg( 'botpasswords-label-needsreset' )->parse();
|
||||
}
|
||||
|
||||
$fields[] = [
|
||||
'section' => 'existing',
|
||||
'type' => 'info',
|
||||
'raw' => true,
|
||||
'default' => $linkRenderer->makeKnownLink(
|
||||
$this->getPageTitle( $row->bp_app_id ),
|
||||
$row->bp_app_id
|
||||
),
|
||||
'default' => $text,
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
*/
|
||||
|
||||
use MediaWiki\Auth\AuthManager;
|
||||
use MediaWiki\Logger\LoggerFactory;
|
||||
|
||||
/**
|
||||
* Let users change their email address.
|
||||
|
@ -167,6 +168,14 @@ class SpecialChangeEmail extends FormSpecialPage {
|
|||
return $status;
|
||||
}
|
||||
|
||||
LoggerFactory::getInstance( 'authentication' )->info(
|
||||
'Changing email address for {user} from {oldemail} to {newemail}', [
|
||||
'user' => $user->getName(),
|
||||
'oldemail' => $oldaddr,
|
||||
'newemail' => $newaddr,
|
||||
]
|
||||
);
|
||||
|
||||
Hooks::run( 'PrefsEmailAudit', [ $user, $oldaddr, $newaddr ] );
|
||||
|
||||
$user->saveSettings();
|
||||
|
|
|
@ -51,6 +51,7 @@ class SpecialLog extends SpecialPage {
|
|||
$opts->add( 'dir', '' );
|
||||
$opts->add( 'offender', '' );
|
||||
$opts->add( 'subtype', '' );
|
||||
$opts->add( 'logid', '' );
|
||||
|
||||
// Set values
|
||||
$opts->fetchValuesFromRequest( $this->getRequest() );
|
||||
|
@ -169,6 +170,16 @@ class SpecialLog extends SpecialPage {
|
|||
return $subpages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set options based on the subpage title parts:
|
||||
* - One part that is a valid log type: Special:Log/logtype
|
||||
* - Two parts: Special:Log/logtype/username
|
||||
* - Otherwise, assume the whole subpage is a username.
|
||||
*
|
||||
* @param FormOptions $opts
|
||||
* @param $par
|
||||
* @throws ConfigException
|
||||
*/
|
||||
private function parseParams( FormOptions $opts, $par ) {
|
||||
# Get parameters
|
||||
$par = $par !== null ? $par : '';
|
||||
|
@ -204,7 +215,8 @@ class SpecialLog extends SpecialPage {
|
|||
$opts->getValue( 'year' ),
|
||||
$opts->getValue( 'month' ),
|
||||
$opts->getValue( 'tagfilter' ),
|
||||
$opts->getValue( 'subtype' )
|
||||
$opts->getValue( 'subtype' ),
|
||||
$opts->getValue( 'logid' )
|
||||
);
|
||||
|
||||
$this->addHeader( $opts->getValue( 'type' ) );
|
||||
|
|
|
@ -162,7 +162,7 @@ class SpecialRedirect extends FormSpecialPage {
|
|||
|
||||
/**
|
||||
* Handle Special:Redirect/logid/xxx
|
||||
* (by redirecting to index.php?title=Special:Log)
|
||||
* (by redirecting to index.php?title=Special:Log&logid=xxx)
|
||||
*
|
||||
* @since 1.27
|
||||
* @return string|null Url to redirect to, or null if $mValue is invalid.
|
||||
|
@ -176,80 +176,8 @@ class SpecialRedirect extends FormSpecialPage {
|
|||
if ( $logid === 0 ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$logQuery = ActorMigration::newMigration()->getJoin( 'log_user' );
|
||||
|
||||
$logparams = [
|
||||
'log_id' => 'log_id',
|
||||
'log_timestamp' => 'log_timestamp',
|
||||
'log_type' => 'log_type',
|
||||
'log_user_text' => $logQuery['fields']['log_user_text'],
|
||||
];
|
||||
|
||||
$dbr = wfGetDB( DB_REPLICA );
|
||||
|
||||
// Gets the nested SQL statement which
|
||||
// returns timestamp of the log with the given log ID
|
||||
$inner = $dbr->selectSQLText(
|
||||
'logging',
|
||||
[ 'log_timestamp' ],
|
||||
[ 'log_id' => $logid ]
|
||||
);
|
||||
|
||||
// Returns all fields mentioned in $logparams of the logs
|
||||
// with the same timestamp as the one returned by the statement above
|
||||
$logsSameTimestamps = $dbr->select(
|
||||
[ 'logging' ] + $logQuery['tables'],
|
||||
$logparams,
|
||||
[ "log_timestamp = ($inner)" ],
|
||||
__METHOD__,
|
||||
[],
|
||||
$logQuery['joins']
|
||||
);
|
||||
if ( $logsSameTimestamps->numRows() === 0 ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Stores the row with the same log ID as the one given
|
||||
$rowMain = [];
|
||||
foreach ( $logsSameTimestamps as $row ) {
|
||||
if ( (int)$row->log_id === $logid ) {
|
||||
$rowMain = $row;
|
||||
}
|
||||
}
|
||||
|
||||
array_shift( $logparams );
|
||||
|
||||
// Stores all the rows with the same values in each column
|
||||
// as $rowMain
|
||||
foreach ( $logparams as $key => $dummy ) {
|
||||
$matchedRows = [];
|
||||
foreach ( $logsSameTimestamps as $row ) {
|
||||
if ( $row->$key === $rowMain->$key ) {
|
||||
$matchedRows[] = $row;
|
||||
}
|
||||
}
|
||||
if ( count( $matchedRows ) === 1 ) {
|
||||
break;
|
||||
}
|
||||
$logsSameTimestamps = $matchedRows;
|
||||
}
|
||||
$query = [ 'title' => 'Special:Log', 'limit' => count( $matchedRows ) ];
|
||||
|
||||
// A map of database field names from table 'logging' to the values of $logparams
|
||||
$keys = [
|
||||
'log_timestamp' => 'offset',
|
||||
'log_type' => 'type',
|
||||
'log_user_text' => 'user'
|
||||
];
|
||||
|
||||
foreach ( $logparams as $logKey => $dummy ) {
|
||||
$query[$keys[$logKey]] = $matchedRows[0]->$logKey;
|
||||
}
|
||||
$query['offset'] = $query['offset'] + 1;
|
||||
$url = $query;
|
||||
|
||||
return wfAppendQuery( wfScript( 'index' ), $url );
|
||||
$query = [ 'title' => 'Special:Log', 'logid' => $logid ];
|
||||
return wfAppendQuery( wfScript( 'index' ), $query );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -751,45 +751,36 @@ class SpecialWatchlist extends ChangesListSpecialPage {
|
|||
}
|
||||
|
||||
function cutoffselector( $options ) {
|
||||
// Cast everything to strings immediately, so that we know all of the values have the same
|
||||
// precision, and can be compared with '==='. 2/24 has a few more decimal places than its
|
||||
// default string representation, for example, and would confuse comparisons.
|
||||
|
||||
// Misleadingly, the 'days' option supports hours too.
|
||||
$days = array_map( 'strval', [ 1 / 24, 2 / 24, 6 / 24, 12 / 24, 1, 3, 7 ] );
|
||||
|
||||
$userWatchlistOption = (string)$this->getUser()->getOption( 'watchlistdays' );
|
||||
// add the user preference, if it isn't available already
|
||||
if ( !in_array( $userWatchlistOption, $days ) && $userWatchlistOption !== '0' ) {
|
||||
$days[] = $userWatchlistOption;
|
||||
}
|
||||
|
||||
$maxDays = (string)$this->maxDays;
|
||||
// add the maximum possible value, if it isn't available already
|
||||
if ( !in_array( $maxDays, $days ) ) {
|
||||
$days[] = $maxDays;
|
||||
}
|
||||
|
||||
$selected = (string)$options['days'];
|
||||
$selected = (float)$options['days'];
|
||||
if ( $selected <= 0 ) {
|
||||
$selected = $maxDays;
|
||||
$selected = $this->maxDays;
|
||||
}
|
||||
|
||||
// add the currently selected value, if it isn't available already
|
||||
if ( !in_array( $selected, $days ) ) {
|
||||
$days[] = $selected;
|
||||
}
|
||||
$selectedHours = round( $selected * 24 );
|
||||
|
||||
$select = new XmlSelect( 'days', 'days', $selected );
|
||||
$hours = array_unique( array_filter( [
|
||||
1,
|
||||
2,
|
||||
6,
|
||||
12,
|
||||
24,
|
||||
72,
|
||||
168,
|
||||
24 * (float)$this->getUser()->getOption( 'watchlistdays', 0 ),
|
||||
24 * $this->maxDays,
|
||||
$selectedHours
|
||||
] ) );
|
||||
asort( $hours );
|
||||
|
||||
asort( $days );
|
||||
foreach ( $days as $value ) {
|
||||
if ( $value < 1 ) {
|
||||
$name = $this->msg( 'hours' )->numParams( $value * 24 )->text();
|
||||
$select = new XmlSelect( 'days', 'days', (float)( $selectedHours / 24 ) );
|
||||
|
||||
foreach ( $hours as $value ) {
|
||||
if ( $value < 24 ) {
|
||||
$name = $this->msg( 'hours' )->numParams( $value )->text();
|
||||
} else {
|
||||
$name = $this->msg( 'days' )->numParams( $value )->text();
|
||||
$name = $this->msg( 'days' )->numParams( $value / 24 )->text();
|
||||
}
|
||||
$select->addOption( $name, $value );
|
||||
$select->addOption( $name, (float)( $value / 24 ) );
|
||||
}
|
||||
|
||||
return $select->getHTML() . "\n<br />\n";
|
||||
|
|
|
@ -321,7 +321,7 @@ class UsersPager extends AlphabeticPager {
|
|||
Hooks::run( 'SpecialListusersHeaderForm', [ $this, &$beforeSubmitButtonHookOut ] );
|
||||
|
||||
if ( $beforeSubmitButtonHookOut !== '' ) {
|
||||
$formDescriptior[ 'beforeSubmitButtonHookOut' ] = [
|
||||
$formDescriptor[ 'beforeSubmitButtonHookOut' ] = [
|
||||
'class' => HTMLInfoField::class,
|
||||
'raw' => true,
|
||||
'default' => $beforeSubmitButtonHookOut
|
||||
|
@ -337,7 +337,7 @@ class UsersPager extends AlphabeticPager {
|
|||
Hooks::run( 'SpecialListusersHeader', [ $this, &$beforeClosingFieldsetHookOut ] );
|
||||
|
||||
if ( $beforeClosingFieldsetHookOut !== '' ) {
|
||||
$formDescriptior[ 'beforeClosingFieldsetHookOut' ] = [
|
||||
$formDescriptor[ 'beforeClosingFieldsetHookOut' ] = [
|
||||
'class' => HTMLInfoField::class,
|
||||
'raw' => true,
|
||||
'default' => $beforeClosingFieldsetHookOut
|
||||
|
|
|
@ -261,6 +261,15 @@ class BotPassword implements IDBAccessObject {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the password is currently invalid
|
||||
* @since 1.32
|
||||
* @return bool
|
||||
*/
|
||||
public function isInvalid() {
|
||||
return $this->getPassword() instanceof InvalidPassword;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the BotPassword to the database
|
||||
* @param string $operation 'update' or 'insert'
|
||||
|
@ -464,6 +473,10 @@ class BotPassword implements IDBAccessObject {
|
|||
return Status::newFatal( 'nosuchuser', $name );
|
||||
}
|
||||
|
||||
if ( $user->isLocked() ) {
|
||||
return Status::newFatal( 'botpasswords-locked' );
|
||||
}
|
||||
|
||||
// Throttle
|
||||
$throttle = null;
|
||||
if ( !empty( $wgPasswordAttemptThrottle ) ) {
|
||||
|
@ -491,7 +504,11 @@ class BotPassword implements IDBAccessObject {
|
|||
}
|
||||
|
||||
// Check the password
|
||||
if ( !$bp->getPassword()->equals( $password ) ) {
|
||||
$passwordObj = $bp->getPassword();
|
||||
if ( $passwordObj instanceof InvalidPassword ) {
|
||||
return Status::newFatal( 'botpasswords-needs-reset', $name, $appId );
|
||||
}
|
||||
if ( !$passwordObj->equals( $password ) ) {
|
||||
return Status::newFatal( 'wrongpassword' );
|
||||
}
|
||||
|
||||
|
|
|
@ -2108,10 +2108,6 @@ class User implements IDBAccessObject, UserIdentity {
|
|||
if ( isset( $limits['user'] ) ) {
|
||||
$userLimit = $limits['user'];
|
||||
}
|
||||
// limits for newbie logged-in users
|
||||
if ( $isNewbie && isset( $limits['newbie'] ) ) {
|
||||
$keys[$cache->makeKey( 'limiter', $action, 'user', $id )] = $limits['newbie'];
|
||||
}
|
||||
}
|
||||
|
||||
// limits for anons and for newbie logged-in users
|
||||
|
@ -2143,6 +2139,11 @@ class User implements IDBAccessObject, UserIdentity {
|
|||
}
|
||||
}
|
||||
|
||||
// limits for newbie logged-in users (override all the normal user limits)
|
||||
if ( $id !== 0 && $isNewbie && isset( $limits['newbie'] ) ) {
|
||||
$userLimit = $limits['newbie'];
|
||||
}
|
||||
|
||||
// Set the user limit key
|
||||
if ( $userLimit !== false ) {
|
||||
list( $max, $period ) = $userLimit;
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Deny from all
|
|
@ -537,6 +537,7 @@
|
|||
"botpasswords-existing": "Existing bot passwords",
|
||||
"botpasswords-createnew": "Create a new bot password",
|
||||
"botpasswords-editexisting": "Edit an existing bot password",
|
||||
"botpasswords-label-needsreset": "(password needs reset)",
|
||||
"botpasswords-label-appid": "Bot name:",
|
||||
"botpasswords-label-create": "Create",
|
||||
"botpasswords-label-update": "Update",
|
||||
|
@ -560,6 +561,8 @@
|
|||
"botpasswords-restriction-failed": "Bot password restrictions prevent this login.",
|
||||
"botpasswords-invalid-name": "The username specified does not contain the bot password separator (\"$1\").",
|
||||
"botpasswords-not-exist": "User \"$1\" does not have a bot password named \"$2\".",
|
||||
"botpasswords-needs-reset": "The bot password for bot name \"$2\" of {{GENDER:$1|user}} \"$1\" must be reset.",
|
||||
"botpasswords-locked": "You cannot login with a bot password as your account is locked.",
|
||||
"resetpass_forbidden": "Passwords cannot be changed",
|
||||
"resetpass_forbidden-reason": "Passwords cannot be changed: $1",
|
||||
"resetpass-no-info": "You must be logged in to access this page directly.",
|
||||
|
|
|
@ -734,6 +734,7 @@
|
|||
"botpasswords-existing": "Form section label for the part of the form listing the user's existing bot passwords.",
|
||||
"botpasswords-createnew": "Form section label for the part of the form related to creating a new bot password.",
|
||||
"botpasswords-editexisting": "Form section label for the part of the form related to editing an existing bot password.",
|
||||
"botpasswords-label-needsreset": "Indicator for when an existing bot password is invalid and needs to be reset.",
|
||||
"botpasswords-label-appid": "Form field label for the \"bot name\", internally known as the \"application ID\".",
|
||||
"botpasswords-label-create": "Button label for the button to create a new bot password.\n{{Identical|Create}}",
|
||||
"botpasswords-label-update": "Button label for the button to save changes to a bot password.\n{{Identical|Update}}",
|
||||
|
@ -757,6 +758,8 @@
|
|||
"botpasswords-restriction-failed": "Error message when login is rejected because the configured restrictions were not satisfied.",
|
||||
"botpasswords-invalid-name": "Error message when a username lacking the separator character is passed to BotPassword. Parameters:\n* $1 - The separator character.",
|
||||
"botpasswords-not-exist": "Error message when a username exists but does not a bot password for the given \"bot name\". Parameters:\n* $1 - username\n* $2 - bot name",
|
||||
"botpasswords-needs-reset": "Error message when a bot password exists but needs to be reset. Parameters:\n* $1 - username\n* $2 - bot name",
|
||||
"botpasswords-locked": "Shown in the event that the underlying account is locked",
|
||||
"resetpass_forbidden": "Used as error message in changing password. Maybe the external auth plugin won't allow local password changes.",
|
||||
"resetpass_forbidden-reason": "Like {{msg-mw|resetpass_forbidden}} but the auth provider gave a reason.\n\nParameters:\n* $1 - reason given by auth provider",
|
||||
"resetpass-no-info": "Error message for [[Special:ChangePassword]].\n\nParameters:\n* $1 (unused) - a link to [[Special:UserLogin]] with {{msg-mw|loginreqlink}} as link description",
|
||||
|
|
|
@ -92,92 +92,92 @@ $namespaceAliases = [
|
|||
];
|
||||
|
||||
$specialPageAliases = [
|
||||
'Allmessages' => [ 'सर्वप्रणाली-संदेश' ],
|
||||
'Allpages' => [ 'सर्वपृष्टानि' ],
|
||||
'Ancientpages' => [ 'पूर्वतनपृष्टानि' ],
|
||||
'Blankpage' => [ 'रिक्तपृष्ठ' ],
|
||||
'Block' => [ 'सदस्यप्रतिबन्ध' ],
|
||||
'Booksources' => [ 'पुस्तकस्रोत' ],
|
||||
'BrokenRedirects' => [ 'खण्डीतपुनर्निर्देशन' ],
|
||||
'Categories' => [ 'वर्गः' ],
|
||||
'ChangePassword' => [ 'सङ्केतशब्दपुन:प्रयुक्ता' ],
|
||||
'Confirmemail' => [ 'विपत्रपुष्टिकृते' ],
|
||||
'Contributions' => [ 'योगदानम्' ],
|
||||
'CreateAccount' => [ 'सृज्उपयोजकसंज्ञा' ],
|
||||
'Deadendpages' => [ 'निराग्रपृष्टानि' ],
|
||||
'DeletedContributions' => [ 'परित्यागितयोगदान' ],
|
||||
'DoubleRedirects' => [ 'पुनर्निर्देशनद्वंद्व' ],
|
||||
'Emailuser' => [ 'विपत्रयोजक' ],
|
||||
'ExpandTemplates' => [ 'बिंबधरविस्तारकरोसि' ],
|
||||
'Export' => [ 'निर्यात' ],
|
||||
'Fewestrevisions' => [ 'स्वल्पपरिवर्तन' ],
|
||||
'FileDuplicateSearch' => [ 'अनुकृतसंचिकाशोध' ],
|
||||
'Filepath' => [ 'संचिकापथ' ],
|
||||
'Import' => [ 'आयात' ],
|
||||
'Invalidateemail' => [ 'अमान्यविपत्र' ],
|
||||
'BlockList' => [ 'प्रतिबन्धसूची' ],
|
||||
'LinkSearch' => [ 'सम्बन्धन्शोध' ],
|
||||
'Listadmins' => [ 'प्रचालकसूची' ],
|
||||
'Listbots' => [ 'स्वयंअनुकृसूची' ],
|
||||
'Listfiles' => [ 'चित्रसूची', 'संचिकासूचि' ],
|
||||
'Listgrouprights' => [ 'गटअधिकारसूची' ],
|
||||
'Listredirects' => [ 'विचालन्सूची' ],
|
||||
'Listusers' => [ 'सदस्यासूची' ],
|
||||
'Lockdb' => [ 'विदाद्वारंबन्ध्' ],
|
||||
'Log' => [ 'अङ्कन' ],
|
||||
'Lonelypages' => [ 'अकलपृष्टानि' ],
|
||||
'Longpages' => [ 'दीर्घपृष्टानि' ],
|
||||
'MergeHistory' => [ 'इतिहाससंयोग' ],
|
||||
'MIMEsearch' => [ 'विविधामाप_(माईम)_शोधसि' ],
|
||||
'Mostcategories' => [ 'अधिकतमवर्ग' ],
|
||||
'Mostimages' => [ 'अधिकतमसम्भन्दिन्_संचिका' ],
|
||||
'Mostlinked' => [ 'अधिकतमसम्भन्दिन्_पृष्टानि', 'अधिकतमसम्भन्दिन्' ],
|
||||
'Mostlinkedcategories' => [ 'अधिकतमसम्भन्दिन्_वर्ग' ],
|
||||
'Mostlinkedtemplates' => [ 'अधिकतमसम्भन्दिन्_फलकानि' ],
|
||||
'Mostrevisions' => [ 'अधिकतमपरिवर्तन' ],
|
||||
'Movepage' => [ 'पृष्ठस्थानान्तर' ],
|
||||
'Mycontributions' => [ 'मदीययोगदानम्' ],
|
||||
'Mypage' => [ 'मम_पृष्टम्' ],
|
||||
'Mytalk' => [ 'मदीयसंवादम्' ],
|
||||
'Newimages' => [ 'नूतनसंचिका', 'नूतनचित्रानि' ],
|
||||
'Newpages' => [ 'नूतनपृष्टानि' ],
|
||||
'PasswordReset' => [ 'सङ्केतशब्दपुन:प्रयु्क्ता' ],
|
||||
'Allmessages' => [ 'सर्वसन्देशाः', 'सर्वप्रणाली-संदेश' ],
|
||||
'Allpages' => [ 'सर्वपृष्ठानि', 'सर्वपृष्टानि' ],
|
||||
'Ancientpages' => [ 'पुरातनपृष्ठानि', 'पूर्वतनपृष्टानि' ],
|
||||
'Blankpage' => [ 'रिक्तपृष्ठानि', 'रिक्तपृष्ठ' ],
|
||||
'Block' => [ 'प्रतिबन्धः', 'सदस्यप्रतिबन्ध' ],
|
||||
'Booksources' => [ 'पुस्तकस्रोतांसि', 'पुस्तकस्रोत' ],
|
||||
'BrokenRedirects' => [ 'भग्नानि_अनुप्रेषणानि', 'खण्डीतपुनर्निर्देशन' ],
|
||||
'Categories' => [ 'वर्गाः', 'वर्गः' ],
|
||||
'ChangePassword' => [ 'कूटशब्दः_परिवर्त्यताम्', 'सङ्केतशब्दपुन:प्रयुक्ता' ],
|
||||
'Confirmemail' => [ 'विपत्रं_पुष्ट्यताम्', 'विपत्रपुष्टिकृते' ],
|
||||
'Contributions' => [ 'योगदानानि', 'योगदानम्' ],
|
||||
'CreateAccount' => [ 'लेखा_सृज्यताम्', 'सृज्उपयोजकसंज्ञा' ],
|
||||
'Deadendpages' => [ 'मृतानि_पृष्ठानि', 'निराग्रपृष्टानि' ],
|
||||
'DeletedContributions' => [ 'अपाकृतानि_योगदानानि', 'परित्यागितयोगदान' ],
|
||||
'DoubleRedirects' => [ 'द्वैधपुनर्निर्देशनम्', 'पुनर्निर्देशनद्वंद्व' ],
|
||||
'Emailuser' => [ 'विपत्रप्रयोक्ता', 'विपत्रयोजक' ],
|
||||
'ExpandTemplates' => [ 'फलकानि_विस्तीर्यन्ताम्', 'बिंबधरविस्तारकरोसि' ],
|
||||
'Export' => [ 'निर्यापयतु', 'निर्यात' ],
|
||||
'Fewestrevisions' => [ 'स्वल्पतमपरिवर्तानानि', 'स्वल्पपरिवर्तन' ],
|
||||
'FileDuplicateSearch' => [ 'समानसञ्चिकान्वेषणम्', 'अनुकृतसंचिकाशोध' ],
|
||||
'Filepath' => [ 'सञ्चिकापथः', 'संचिकापथ' ],
|
||||
'Import' => [ 'आयापयतु', 'आयात' ],
|
||||
'Invalidateemail' => [ 'विपत्रेऽमान्यम्', 'अमान्यविपत्र' ],
|
||||
'BlockList' => [ 'प्रतिबन्धावलिः', 'प्रतिबन्धसूची' ],
|
||||
'LinkSearch' => [ 'परिसन्धेः_अन्वेषणम्', 'सम्बन्धन्शोध' ],
|
||||
'Listadmins' => [ 'प्रबन्धकावलिः', 'प्रचालकसूची' ],
|
||||
'Listbots' => [ 'बॉटसूची', 'स्वयंअनुकृसूची' ],
|
||||
'Listfiles' => [ 'सञ्चिकावलिः', 'चित्रसूची', 'संचिकासूचि' ],
|
||||
'Listgrouprights' => [ 'समूहाधिकारावलिः', 'गटअधिकारसूची' ],
|
||||
'Listredirects' => [ 'अनुप्रेषितावलिः', 'विचालन्सूची' ],
|
||||
'Listusers' => [ 'सदस्यावलिः', 'सदस्यासूची' ],
|
||||
'Lockdb' => [ 'दत्तांशकीलनम्', 'विदाद्वारंबन्ध्' ],
|
||||
'Log' => [ 'संरक्षितावलिः', 'अङ्कन' ],
|
||||
'Lonelypages' => [ 'एकाकिपृष्ठानि', 'अकलपृष्टानि' ],
|
||||
'Longpages' => [ 'दीर्घपृष्ठानि', 'दीर्घपृष्टानि' ],
|
||||
'MergeHistory' => [ 'इतिहासविलयः', 'इतिहाससंयोग' ],
|
||||
'MIMEsearch' => [ 'MIME_अन्वेषणम्', 'विविधामाप_(माईम)_शोधसि' ],
|
||||
'Mostcategories' => [ 'अधिकतमवर्गाः', 'अधिकतमवर्ग' ],
|
||||
'Mostimages' => [ 'अधिकतमसञ्चिकाः', 'अधिकतमसम्भन्दिन्_संचिका' ],
|
||||
'Mostlinked' => [ 'अधिकतमपरिसन्धितम्', 'अधिकतमसम्भन्दिन्_पृष्टानि', 'अधिकतमसम्भन्दिन्' ],
|
||||
'Mostlinkedcategories' => [ 'अधिकतमपरिसन्धितवर्गाः', 'अधिकतमसम्भन्दिन्_वर्ग' ],
|
||||
'Mostlinkedtemplates' => [ 'अधिकतमपरिसन्धितफलकानि', 'अधिकतमसम्भन्दिन्_फलकानि' ],
|
||||
'Mostrevisions' => [ 'अधिकतमसंस्करणानि', 'अधिकतमपरिवर्तन' ],
|
||||
'Movepage' => [ 'पृष्ठस्थानान्तरणम्', 'पृष्ठस्थानान्तर' ],
|
||||
'Mycontributions' => [ 'मम_योगदानानि', 'मदीययोगदानम्' ],
|
||||
'Mypage' => [ 'मम_पृष्ठम्', 'मम_पृष्टम्' ],
|
||||
'Mytalk' => [ 'मम_सम्भाषणम्', 'मदीयसंवादम्' ],
|
||||
'Newimages' => [ 'नवीनचित्राणि', 'नूतनसंचिका', 'नूतनचित्रानि' ],
|
||||
'Newpages' => [ 'नवीनपृष्ठानि', 'नूतनपृष्टानि' ],
|
||||
'PasswordReset' => [ 'कूटशब्दस्य_पुनस्स्थापनम्', 'सङ्केतशब्दपुन:प्रयु्क्ता' ],
|
||||
'Preferences' => [ 'इष्टतमानि' ],
|
||||
'Prefixindex' => [ 'उपसर्गअनुक्रमणी' ],
|
||||
'Protectedpages' => [ 'सुरक्षितपृष्टानि' ],
|
||||
'Protectedtitles' => [ 'सुरक्षितशिर्षकम्' ],
|
||||
'Randompage' => [ 'अविशीष्टपृष्ठम्' ],
|
||||
'RandomInCategory' => [ 'अविशिष्टवर्ग' ],
|
||||
'Randomredirect' => [ 'अविशीष्टविचालन्' ],
|
||||
'Recentchanges' => [ 'नवीनतम_परिवर्तन' ],
|
||||
'Recentchangeslinked' => [ 'नवीनतमसम्भन्दिन_परिवर्त' ],
|
||||
'Revisiondelete' => [ 'आवृत्तीपरित्याग' ],
|
||||
'Search' => [ 'शोध' ],
|
||||
'Shortpages' => [ 'लघुपृष्टानि' ],
|
||||
'Specialpages' => [ 'विशेषपृष्टानि' ],
|
||||
'Statistics' => [ 'सांख्यिकी' ],
|
||||
'Uncategorizedcategories' => [ 'अवर्गीकृतवर्ग' ],
|
||||
'Uncategorizedimages' => [ 'अवर्गीकृतसंचिका', 'अवर्गीकृतचित्रानि' ],
|
||||
'Uncategorizedpages' => [ 'अवर्गीकृतपृष्टानि' ],
|
||||
'Prefixindex' => [ 'उपसर्गानुक्रमणी', 'उपसर्गअनुक्रमणी' ],
|
||||
'Protectedpages' => [ 'सुरक्षितपृष्ठानि', 'सुरक्षितपृष्टानि' ],
|
||||
'Protectedtitles' => [ 'सुरक्षितशीर्षकाणि', 'सुरक्षितशिर्षकम्' ],
|
||||
'Randompage' => [ 'यादृच्छिकपृष्ठम्', 'अविशीष्टपृष्ठम्' ],
|
||||
'RandomInCategory' => [ 'वर्गे_यादृच्छिकम्', 'अविशिष्टवर्ग' ],
|
||||
'Randomredirect' => [ 'यादृच्छिकानुप्रेषितम्', 'अविशीष्टविचालन्' ],
|
||||
'Recentchanges' => [ 'नूतनपरिवर्तनानि', 'नवीनतम_परिवर्तन' ],
|
||||
'Recentchangeslinked' => [ 'नूतनपरिवर्तनानां_परिसन्धयः', 'नवीनतमसम्भन्दिन_परिवर्त' ],
|
||||
'Revisiondelete' => [ 'संस्करणापाकरणम्', 'आवृत्तीपरित्याग' ],
|
||||
'Search' => [ 'अन्वेषणम्', 'शोध' ],
|
||||
'Shortpages' => [ 'लघुपृष्ठानि', 'लघुपृष्टानि' ],
|
||||
'Specialpages' => [ 'विशेषपृष्ठानि', 'विशेषपृष्टानि' ],
|
||||
'Statistics' => [ 'साङ्ख्यिकी', 'सांख्यिकी' ],
|
||||
'Uncategorizedcategories' => [ 'अवर्गीकृतवर्गाः', 'अवर्गीकृतवर्ग' ],
|
||||
'Uncategorizedimages' => [ 'अवर्गीकृतचित्राणि', 'अवर्गीकृतसंचिका', 'अवर्गीकृतचित्रानि' ],
|
||||
'Uncategorizedpages' => [ 'अवर्गीकृतपृष्ठानि', 'अवर्गीकृतपृष्टानि' ],
|
||||
'Uncategorizedtemplates' => [ 'अवर्गीकृतफलकानि' ],
|
||||
'Undelete' => [ 'प्रत्यादिश्_परित्याग' ],
|
||||
'Unlockdb' => [ 'विवृतविदाद्वारंतालक' ],
|
||||
'Unusedcategories' => [ 'अप्रयूक्तवर्ग' ],
|
||||
'Unusedimages' => [ 'अप्रयूक्तसंचिका' ],
|
||||
'Unusedtemplates' => [ 'अप्रयूक्तबिंबधर' ],
|
||||
'Unwatchedpages' => [ 'अनिरिक्षीतपृष्ठ' ],
|
||||
'Upload' => [ 'भारंन्यस्यति' ],
|
||||
'Userlogin' => [ 'सदस्यप्रवेशन' ],
|
||||
'Userlogout' => [ 'सदस्यबहिर्गमन' ],
|
||||
'Userrights' => [ 'योजकआधिकार' ],
|
||||
'Version' => [ 'आवृत्ती' ],
|
||||
'Wantedcategories' => [ 'प्रार्थितवर्ग' ],
|
||||
'Wantedfiles' => [ 'प्रार्थितसंचिका' ],
|
||||
'Wantedpages' => [ 'प्रार्थितपृष्टानि' ],
|
||||
'Wantedtemplates' => [ 'प्रार्थितफलकानि' ],
|
||||
'Watchlist' => [ 'निरीक्षा_सूची' ],
|
||||
'Whatlinkshere' => [ 'किमपृष्ठ_सम्बद्धंकरोति' ],
|
||||
'Withoutinterwiki' => [ 'आन्तरविकिहीन' ],
|
||||
'Undelete' => [ 'पुनस्स्थापनम्', 'प्रत्यादिश्_परित्याग' ],
|
||||
'Unlockdb' => [ 'दत्तांशोद्घाटनम्', 'विवृतविदाद्वारंतालक' ],
|
||||
'Unusedcategories' => [ 'अप्रयुक्तवर्गाः', 'अप्रयूक्तवर्ग' ],
|
||||
'Unusedimages' => [ 'अप्रयुक्तचित्राणि', 'अप्रयूक्तसंचिका' ],
|
||||
'Unusedtemplates' => [ 'अप्रयुक्तफलकानि', 'अप्रयूक्तबिंबधर' ],
|
||||
'Unwatchedpages' => [ 'अनिरीक्षितपृष्ठानि', 'अनिरिक्षीतपृष्ठ' ],
|
||||
'Upload' => [ 'उपारोपणम्', 'भारंन्यस्यति' ],
|
||||
'Userlogin' => [ 'सदस्यप्रवेशः', 'सदस्यप्रवेशन' ],
|
||||
'Userlogout' => [ 'सदस्यनिर्गमनम्', 'सदस्यबहिर्गमन' ],
|
||||
'Userrights' => [ 'सदस्याधिकाराः', 'योजकआधिकार' ],
|
||||
'Version' => [ 'संस्करणम्', 'आवृत्ती' ],
|
||||
'Wantedcategories' => [ 'वाञ्छितवर्गाः', 'प्रार्थितवर्ग' ],
|
||||
'Wantedfiles' => [ 'वाञ्छितसञ्चिकाः', 'प्रार्थितसंचिका' ],
|
||||
'Wantedpages' => [ 'वाञ्छितपृष्ठानि', 'प्रार्थितपृष्टानि' ],
|
||||
'Wantedtemplates' => [ 'वाञ्छितफलकानि', 'प्रार्थितफलकानि' ],
|
||||
'Watchlist' => [ 'निरीक्षा_सूची', 'निरीक्षासूचिः' ],
|
||||
'Whatlinkshere' => [ 'किमत्र_सँल्लग्नम्', 'किमपृष्ठ_सम्बद्धंकरोति' ],
|
||||
'Withoutinterwiki' => [ 'अन्तर्विकिपरिसन्धिहीनम्', 'आन्तरविकिहीन' ],
|
||||
];
|
||||
|
||||
$magicWords = [
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Deny from all
|
|
@ -0,0 +1 @@
|
|||
Deny from all
|
|
@ -0,0 +1 @@
|
|||
Deny from all
|
|
@ -64,8 +64,12 @@ class MonoBookTemplate extends BaseTemplate {
|
|||
[ 'id' => 'contentSub', 'lang' => $this->get( 'userlang' ), 'dir' => $this->get( 'dir' ) ],
|
||||
$this->get( 'subtitle' )
|
||||
) .
|
||||
$this->getIfExists( 'undelete', [ 'wrapper' => 'div', [ 'id' => 'contentSub2' ] ] ) .
|
||||
$this->getIfExists( 'newtalk', [ 'wrapper' => 'div', [ 'class' => 'usermessage' ] ] ) .
|
||||
$this->getIfExists( 'undelete', [ 'wrapper' => 'div', 'parameters' => [
|
||||
'id' => 'contentSub2'
|
||||
] ] ) .
|
||||
$this->getIfExists( 'newtalk', [ 'wrapper' => 'div', 'parameters' => [
|
||||
'class' => 'usermessage'
|
||||
] ] ) .
|
||||
Html::rawElement( 'div', [ 'id' => 'jump-to-nav', 'class' => 'mw-jump' ],
|
||||
$this->getMsg( 'jumpto' )->escaped() .
|
||||
Html::element( 'a', [ 'href' => '#column-one' ],
|
||||
|
|
|
@ -33,20 +33,11 @@ $( function () {
|
|||
} );
|
||||
|
||||
// Close menus on click outside
|
||||
$( document ).click( function ( e ) {
|
||||
$( document ).on( 'click touchstart', function ( e ) {
|
||||
if ( $( e.target ).closest( '#menus-cover' ).length > 0 ) {
|
||||
$( '#personal-inner' ).fadeOut( toggleTime );
|
||||
$( '.sidebar-inner' ).fadeOut( toggleTime );
|
||||
$( '#menus-cover' ).fadeOut( toggleTime );
|
||||
}
|
||||
} );
|
||||
|
||||
// Include alternative closing method for ios
|
||||
$( window ).on( 'swiperight', function () {
|
||||
if ( $( window ).width() < 851 ) {
|
||||
$( '#personal-inner' ).fadeOut( toggleTime );
|
||||
$( '.sidebar-inner' ).fadeOut( toggleTime );
|
||||
$( '#menus-cover' ).fadeOut( toggleTime );
|
||||
}
|
||||
} );
|
||||
} );
|
||||
|
|
|
@ -65,7 +65,6 @@
|
|||
"skins.timeless.mobile": {
|
||||
"targets": [ "desktop", "mobile" ],
|
||||
"scripts": [
|
||||
"resources/libraries/jquery.mobile.custom.js",
|
||||
"resources/mobile.js"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Deny from all
|
|
@ -41,7 +41,8 @@ class DbTestRecorder extends TestRecorder {
|
|||
|| !$this->db->tableExists( 'testitem' )
|
||||
) {
|
||||
print "WARNING> `testrun` table not found in database. Trying to create table.\n";
|
||||
$this->db->sourceFile( $this->db->patchPath( 'patch-testrun.sql' ) );
|
||||
$updater = DatabaseUpdater::newForDB( $this->db );
|
||||
$this->db->sourceFile( $updater->patchPath( $this->db, 'patch-testrun.sql' ) );
|
||||
echo "OK, resuming.\n";
|
||||
}
|
||||
|
||||
|
|
|
@ -17,8 +17,7 @@ class VersionCheckerTest extends PHPUnit\Framework\TestCase {
|
|||
'FakeExtension' => [
|
||||
'MediaWiki' => $constraint,
|
||||
],
|
||||
] )
|
||||
);
|
||||
] ) );
|
||||
}
|
||||
|
||||
public static function provideCheck() {
|
||||
|
@ -50,8 +49,7 @@ class VersionCheckerTest extends PHPUnit\Framework\TestCase {
|
|||
*/
|
||||
public function testType( $given, $expected ) {
|
||||
$checker = new VersionChecker( '1.0.0' );
|
||||
$checker
|
||||
->setLoadedExtensionsAndSkins( [
|
||||
$checker->setLoadedExtensionsAndSkins( [
|
||||
'FakeDependency' => [
|
||||
'version' => '1.0.0',
|
||||
],
|
||||
|
@ -59,8 +57,7 @@ class VersionCheckerTest extends PHPUnit\Framework\TestCase {
|
|||
] );
|
||||
$this->assertEquals( $expected, $checker->checkArray( [
|
||||
'FakeExtension' => $given,
|
||||
] )
|
||||
);
|
||||
] ) );
|
||||
}
|
||||
|
||||
public static function provideType() {
|
||||
|
@ -69,22 +66,22 @@ class VersionCheckerTest extends PHPUnit\Framework\TestCase {
|
|||
[
|
||||
[
|
||||
'extensions' => [
|
||||
'FakeDependency' => '1.0.0'
|
||||
]
|
||||
'FakeDependency' => '1.0.0',
|
||||
],
|
||||
],
|
||||
[]
|
||||
[],
|
||||
],
|
||||
[
|
||||
[
|
||||
'MediaWiki' => '1.0.0'
|
||||
'MediaWiki' => '1.0.0',
|
||||
],
|
||||
[]
|
||||
[],
|
||||
],
|
||||
[
|
||||
[
|
||||
'extensions' => [
|
||||
'NoVersionGiven' => '*'
|
||||
]
|
||||
'NoVersionGiven' => '*',
|
||||
],
|
||||
],
|
||||
[],
|
||||
],
|
||||
|
@ -92,39 +89,59 @@ class VersionCheckerTest extends PHPUnit\Framework\TestCase {
|
|||
[
|
||||
'extensions' => [
|
||||
'NoVersionGiven' => '1.0',
|
||||
]
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
'incompatible' => 'FakeExtension',
|
||||
'type' => 'incompatible-extensions',
|
||||
'msg' => 'NoVersionGiven does not expose its version, but FakeExtension requires: 1.0.',
|
||||
],
|
||||
],
|
||||
[ [
|
||||
'incompatible' => 'FakeExtension',
|
||||
'type' => 'incompatible-extensions',
|
||||
'msg' => 'NoVersionGiven does not expose its version, but FakeExtension requires: 1.0.'
|
||||
] ],
|
||||
],
|
||||
[
|
||||
[
|
||||
'extensions' => [
|
||||
'Missing' => '*',
|
||||
]
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
'missing' => 'Missing',
|
||||
'type' => 'missing-extensions',
|
||||
'msg' => 'FakeExtension requires Missing to be installed.',
|
||||
],
|
||||
],
|
||||
[ [
|
||||
'missing' => 'Missing',
|
||||
'type' => 'missing-extensions',
|
||||
'msg' => 'FakeExtension requires Missing to be installed.',
|
||||
] ],
|
||||
],
|
||||
[
|
||||
[
|
||||
'extensions' => [
|
||||
'FakeDependency' => '2.0.0',
|
||||
]
|
||||
],
|
||||
],
|
||||
[ [
|
||||
'incompatible' => 'FakeExtension',
|
||||
'type' => 'incompatible-extensions',
|
||||
// phpcs:ignore Generic.Files.LineLength.TooLong
|
||||
'msg' => 'FakeExtension is not compatible with the current installed version of FakeDependency (1.0.0), it requires: 2.0.0.'
|
||||
] ],
|
||||
]
|
||||
[
|
||||
[
|
||||
'incompatible' => 'FakeExtension',
|
||||
'type' => 'incompatible-extensions',
|
||||
// phpcs:ignore Generic.Files.LineLength.TooLong
|
||||
'msg' => 'FakeExtension is not compatible with the current installed version of FakeDependency (1.0.0), it requires: 2.0.0.',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
'skins' => [
|
||||
'FakeSkin' => '*',
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
'missing' => 'FakeSkin',
|
||||
'type' => 'missing-skins',
|
||||
'msg' => 'FakeExtension requires FakeSkin to be installed.',
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -134,29 +151,26 @@ class VersionCheckerTest extends PHPUnit\Framework\TestCase {
|
|||
*/
|
||||
public function testInvalidConstraint() {
|
||||
$checker = new VersionChecker( '1.0.0' );
|
||||
$checker
|
||||
->setLoadedExtensionsAndSkins( [
|
||||
$checker->setLoadedExtensionsAndSkins( [
|
||||
'FakeDependency' => [
|
||||
'version' => 'not really valid',
|
||||
],
|
||||
] );
|
||||
$this->assertEquals(
|
||||
[ [
|
||||
$this->assertEquals( [
|
||||
[
|
||||
'type' => 'invalid-version',
|
||||
'msg' => "FakeDependency does not have a valid version string."
|
||||
] ],
|
||||
$checker->checkArray( [
|
||||
'FakeExtension' => [
|
||||
'extensions' => [
|
||||
'FakeDependency' => '1.24.3',
|
||||
],
|
||||
'msg' => "FakeDependency does not have a valid version string.",
|
||||
],
|
||||
], $checker->checkArray( [
|
||||
'FakeExtension' => [
|
||||
'extensions' => [
|
||||
'FakeDependency' => '1.24.3',
|
||||
],
|
||||
] )
|
||||
);
|
||||
],
|
||||
] ) );
|
||||
|
||||
$checker = new VersionChecker( '1.0.0' );
|
||||
$checker
|
||||
->setLoadedExtensionsAndSkins( [
|
||||
$checker->setLoadedExtensionsAndSkins( [
|
||||
'FakeDependency' => [
|
||||
'version' => '1.24.3',
|
||||
],
|
||||
|
@ -166,7 +180,28 @@ class VersionCheckerTest extends PHPUnit\Framework\TestCase {
|
|||
$checker->checkArray( [
|
||||
'FakeExtension' => [
|
||||
'FakeDependency' => 'not really valid',
|
||||
]
|
||||
],
|
||||
] );
|
||||
}
|
||||
|
||||
/**
|
||||
* T197478
|
||||
*/
|
||||
public function testInvalidDependency() {
|
||||
$checker = new VersionChecker( '1.0.0' );
|
||||
$this->setExpectedException( UnexpectedValueException::class,
|
||||
'Dependency type skin unknown in FakeExtension' );
|
||||
$this->assertEquals( [
|
||||
[
|
||||
'type' => 'invalid-version',
|
||||
'msg' => 'FakeDependency does not have a valid version string.',
|
||||
],
|
||||
], $checker->checkArray( [
|
||||
'FakeExtension' => [
|
||||
'skin' => [
|
||||
'FakeSkin' => '*',
|
||||
],
|
||||
],
|
||||
] ) );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Allow from all
|
|
@ -0,0 +1 @@
|
|||
Deny from all
|
|
@ -0,0 +1,2 @@
|
|||
.easymin
|
||||
Autoloader.php
|
Loading…
Reference in New Issue