* $wgDebugPrintHttpHeaders - The default of including HTTP headers in the
debug log channel is no longer configurable. The debug log itself remains
configurable via $wgDebugLogFile.
+* $wgPasswordSalt – This setting, used for migrating exceptionally old, insecure
+ password setups and deprecated since 1.24, is now removed.
=== New user-facing features in 1.34 ===
* Special:Mute has been added as a quick way for users to block unwanted emails
strings like "5 days ago" instead of "5 days 13 hours ago".
* (T220163) Added SpecialMuteModifyFormFields hook to allow extensions
to add fields to Special:Mute.
+* (T100896) Skin authors can define custom OOUI themes using OOUIThemePaths.
+ See <https://www.mediawiki.org/wiki/OOUI/Themes> for details.
=== External library changes in 1.34 ===
==== Changed external libraries ====
* Updated Mustache from 1.0.0 to v3.0.1.
-* Updated OOUI from v0.31.3 to v0.33.2.
+* Updated OOUI from v0.31.3 to v0.33.4.
* Updated composer/semver from 1.4.2 to 1.5.0.
* Updated composer/spdx-licenses from 1.4.0 to 1.5.1 (dev-only).
* Updated mediawiki/codesniffer from 25.0.0 to 26.0.0 (dev-only).
"ext-xml": "*",
"guzzlehttp/guzzle": "6.3.3",
"liuggio/statsd-php-client": "1.0.18",
- "oojs/oojs-ui": "0.33.3",
+ "oojs/oojs-ui": "0.33.4",
"pear/mail": "1.4.1",
"pear/mail_mime": "1.10.2",
"pear/net_smtp": "1.8.1",
\MediaWiki\Auth\PasswordAuthenticationRequest::class,
];
-/**
- * For compatibility with old installations set to false
- * @deprecated since 1.24 will be removed in future
- */
-$wgPasswordSalt = true;
-
/**
* Specifies the minimal length of a user password. If set to 0, empty pass-
* words are allowed.
// Check for *really* old password hashes that don't even have a type
// The old hash format was just an md5 hex hash, with no type information
if ( preg_match( '/^[0-9a-f]{32}$/', $row->user_password ) ) {
- if ( $this->config->get( 'PasswordSalt' ) ) {
- $row->user_password = ":B:{$row->user_id}:{$row->user_password}";
- } else {
- $row->user_password = ":A:{$row->user_password}";
- }
+ $row->user_password = ":B:{$row->user_id}:{$row->user_password}";
}
$status = $this->checkPasswordValidity( $username, $req->password );
return MediaWikiServices::getInstance()->getBlobStore();
}
+ /**
+ * Invokes the given method on the given object, catching and logging any storage related
+ * exceptions.
+ *
+ * @param object $obj
+ * @param string $method
+ * @param array $args
+ * @param string $warning The warning to output in case of a storage related exception.
+ *
+ * @return mixed Returns the method's return value,
+ * or null in case of a storage related exception.
+ * @throws Exception
+ */
+ private function invokeLenient( $obj, $method, $args = [], $warning ) {
+ try {
+ return call_user_func_array( [ $obj, $method ], $args );
+ } catch ( SuppressedDataException $ex ) {
+ return null;
+ } catch ( Exception $ex ) {
+ if ( $ex instanceof MWException || $ex instanceof RuntimeException ) {
+ MWDebug::warning( $warning . ': ' . $ex->getMessage() );
+ return null;
+ } else {
+ throw $ex;
+ }
+ }
+ }
+
/**
* Dumps a "<revision>" section on the output stream, with
* data filled in from the given database row.
if ( $rev->isDeleted( RevisionRecord::DELETED_TEXT ) ) {
$out .= " <sha1/>\n";
} else {
- $out .= " " . Xml::element( 'sha1', null, strval( $rev->getSha1() ) ) . "\n";
+ $sha1 = $this->invokeLenient(
+ $rev,
+ 'getSha1',
+ [],
+ 'failed to determine sha1 for revision ' . $rev->getId()
+ );
+ $out .= " " . Xml::element( 'sha1', null, strval( $sha1 ) ) . "\n";
}
// Avoid PHP 7.1 warning from passing $this by reference
$writer = $this;
$text = '';
if ( $contentMode === self::WRITE_CONTENT ) {
- $text = $rev->getContent( SlotRecord::MAIN, RevisionRecord::RAW );
+ /** @var Content $content */
+ $content = $this->invokeLenient(
+ $rev,
+ 'getContent',
+ [ SlotRecord::MAIN, RevisionRecord::RAW ],
+ 'Failed to load main slot content of revision ' . $rev->getId()
+ );
+
+ $text = $content ? $content->serialize() : '';
}
Hooks::run( 'XmlDumpWriterWriteRevision', [ &$writer, &$out, $row, $text, $rev ] );
$textAttributes = [
'xml:space' => 'preserve',
- 'bytes' => $slot->getSize(),
+ 'bytes' => $this->invokeLenient(
+ $slot,
+ 'getSize',
+ [],
+ 'failed to determine size for slot ' . $slot->getRole() . ' of revision '
+ . $slot->getRevision()
+ ) ?: '0'
];
if ( $isV11 ) {
- $textAttributes['sha1'] = $slot->getSha1();
+ $textAttributes['sha1'] = $this->invokeLenient(
+ $slot,
+ 'getSha1',
+ [],
+ 'failed to determine sha1 for slot ' . $slot->getRole() . ' of revision '
+ . $slot->getRevision()
+ ) ?: '';
}
if ( $contentMode === self::WRITE_CONTENT ) {
- try {
- // write <text> tag
- $out .= $this->writeText( $slot->getContent(), $textAttributes, $indent );
- } catch ( SuppressedDataException $ex ) {
- // NOTE: this shouldn't happen, since the caller is supposed to have checked
- // for suppressed content!
- // write <text> placeholder tag
- $textAttributes['deleted'] = 'deleted';
+ $content = $this->invokeLenient(
+ $slot,
+ 'getContent',
+ [],
+ 'failed to load content for slot ' . $slot->getRole() . ' of revision '
+ . $slot->getRevision()
+ );
+
+ if ( $content === null ) {
$out .= $indent . Xml::element( 'text', $textAttributes ) . "\n";
- }
- catch ( Exception $ex ) {
- if ( $ex instanceof MWException || $ex instanceof RuntimeException ) {
- // there's no provision in the schema for an attribute that will let
- // the user know this element was unavailable due to error; an empty
- // tag is the best we can do
- $out .= $indent . Xml::element( 'text' ) . "\n";
- wfLogWarning(
- 'failed to load content slot ' . $slot->getRole() . ' for revision '
- . $slot->getRevision() . "\n"
- );
- } else {
- throw $ex;
- }
+ } else {
+ $out .= $this->writeText( $content, $textAttributes, $indent );
}
} elseif ( $contentMode === self::WRITE_STUB_DELETED ) {
// write <text> placeholder tag
// Output the numerical text ID if possible, for backwards compatibility.
// Note that this is currently the ONLY reason we have a BlobStore here at all.
// When removing this line, check whether the BlobStore has become unused.
- $textId = $this->getBlobStore()->getTextIdFromAddress( $slot->getAddress() );
+ try {
+ // NOTE: this will only work for addresses of the form "tt:12345".
+ // If we want to support other kinds of addresses in the future,
+ // we will have to silently ignore failures here.
+ // For now, this fails for "tt:0", which is present in the WMF production
+ // database of of Juli 2019, due to data corruption.
+ $textId = $this->getBlobStore()->getTextIdFromAddress( $slot->getAddress() );
+ } catch ( InvalidArgumentException $ex ) {
+ MWDebug::warning( 'Bad content address for slot ' . $slot->getRole()
+ . ' of revision ' . $slot->getRevision() . ': ' . $ex->getMessage() );
+ $textId = 0;
+ }
+
if ( $textId ) {
$textAttributes['id'] = $textId;
- } elseif ( !$isV11 ) {
- throw new InvalidArgumentException(
- 'Cannot produce stubs for non-text-table content blobs with schema version '
- . $this->schemaVersion
- );
}
$out .= $indent . Xml::element( 'text', $textAttributes ) . "\n";
$config = $this->managers[$name]['config'];
if ( $class === DBLockManager::class ) {
$lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
- $lb = $lbFactory->newMainLB( $config['domain'] );
- $dbw = $lb->getLazyConnectionRef( DB_MASTER, [], $config['domain'] );
-
- $config['dbServers']['localDBMaster'] = $dbw;
+ $lb = $lbFactory->getMainLB( $config['domain'] );
+ $config['dbServers']['localDBMaster'] = $lb->getLazyConnectionRef(
+ DB_MASTER,
+ [],
+ $config['domain'],
+ $lb::CONN_TRX_AUTOCOMMIT
+ );
$config['srvCache'] = ObjectCache::getLocalServerInstance( 'hash' );
}
$config['logger'] = LoggerFactory::getInstance( 'LockManager' );
return $html;
},
- [ 'pcTTL' => WANObjectCache::TTL_PROC_LONG ]
+ [ 'pcGroup' => 'http-get:3', 'pcTTL' => WANObjectCache::TTL_PROC_LONG ]
);
}
*
* @since 1.27
* @param string $class Key class
- * @param string|null $component [optional] Key component (starting with a key collection name)
- * @return string Colon-delimited list of $keyspace followed by escaped components of $args
+ * @param string ...$components Key components (starting with a key collection name)
+ * @return string Colon-delimited list of $keyspace followed by escaped components
*/
- abstract public function makeGlobalKey( $class, $component = null );
+ abstract public function makeGlobalKey( $class, ...$components );
/**
* Make a cache key, scoped to this instance's keyspace.
*
* @since 1.27
* @param string $class Key class
- * @param string|null $component [optional] Key component (starting with a key collection name)
- * @return string Colon-delimited list of $keyspace followed by escaped components of $args
+ * @param string ...$components Key components (starting with a key collection name)
+ * @return string Colon-delimited list of $keyspace followed by escaped components
*/
- abstract public function makeKey( $class, $component = null );
+ abstract public function makeKey( $class, ...$components );
/**
* @param int $flag ATTR_* class constant
}
public function makeKeyInternal( $keyspace, $args ) {
- return $this->backend->makeKeyInternal( ...func_get_args() );
+ return $this->backend->makeKeyInternal( $keyspace, $args );
}
- public function makeKey( $class, $component = null ) {
- return $this->backend->makeKey( ...func_get_args() );
+ public function makeKey( $class, ...$components ) {
+ return $this->backend->makeKey( $class, ...$components );
}
- public function makeGlobalKey( $class, $component = null ) {
- return $this->backend->makeGlobalKey( ...func_get_args() );
+ public function makeGlobalKey( $class, ...$components ) {
+ return $this->backend->makeGlobalKey( $class, ...$components );
}
public function getLastError() {
* Make a global cache key.
*
* @param string $class Key class
- * @param string|null $component [optional] Key component (starting with a key collection name)
- * @return string Colon-delimited list of $keyspace followed by escaped components of $args
+ * @param string ...$components Key components (starting with a key collection name)
+ * @return string Colon-delimited list of $keyspace followed by escaped components
*/
- public function makeGlobalKey( $class, $component = null );
+ public function makeGlobalKey( $class, ...$components );
/**
* Make a cache key, scoped to this instance's keyspace.
*
* @param string $class Key class
- * @param string|null $component [optional] Key component (starting with a key collection name)
- * @return string Colon-delimited list of $keyspace followed by escaped components of $args
+ * @param string ...$components Key components (starting with a key collection name)
+ * @return string Colon-delimited list of $keyspace followed by escaped components
*/
- public function makeKey( $class, $component = null );
+ public function makeKey( $class, ...$components );
}
* Make a global cache key.
*
* @param string $class Key class
- * @param string|null $component [optional] Key component (starting with a key collection name)
- * @return string Colon-delimited list of $keyspace followed by escaped components of $args
+ * @param string ...$components Key components (starting with a key collection name)
+ * @return string Colon-delimited list of $keyspace followed by escaped components
* @since 1.27
*/
- public function makeGlobalKey( $class, $component = null ) {
+ public function makeGlobalKey( $class, ...$components ) {
return $this->makeKeyInternal( 'global', func_get_args() );
}
* Make a cache key, scoped to this instance's keyspace.
*
* @param string $class Key class
- * @param string|null $component [optional] Key component (starting with a key collection name)
- * @return string Colon-delimited list of $keyspace followed by escaped components of $args
+ * @param string ...$components Key components (starting with a key collection name)
+ * @return string Colon-delimited list of $keyspace followed by escaped components
* @since 1.27
*/
- public function makeKey( $class, $component = null ) {
+ public function makeKey( $class, ...$components ) {
return $this->makeKeyInternal( $this->keyspace, func_get_args() );
}
}
public function makeKeyInternal( $keyspace, $args ) {
- return $this->caches[0]->makeKeyInternal( ...func_get_args() );
+ return $this->caches[0]->makeKeyInternal( $keyspace, $args );
}
- public function makeKey( $class, $component = null ) {
+ public function makeKey( $class, ...$components ) {
return $this->caches[0]->makeKey( ...func_get_args() );
}
- public function makeGlobalKey( $class, $component = null ) {
+ public function makeGlobalKey( $class, ...$components ) {
return $this->caches[0]->makeGlobalKey( ...func_get_args() );
}
return $this->writeStore->makeKeyInternal( ...func_get_args() );
}
- public function makeKey( $class, $component = null ) {
+ public function makeKey( $class, ...$components ) {
return $this->writeStore->makeKey( ...func_get_args() );
}
- public function makeGlobalKey( $class, $component = null ) {
+ public function makeGlobalKey( $class, ...$components ) {
return $this->writeStore->makeGlobalKey( ...func_get_args() );
}
/**
* @see BagOStuff::makeKey()
* @param string $class Key class
- * @param string|null $component [optional] Key component (starting with a key collection name)
- * @return string Colon-delimited list of $keyspace followed by escaped components of $args
+ * @param string ...$components Key components (starting with a key collection name)
+ * @return string Colon-delimited list of $keyspace followed by escaped components
* @since 1.27
*/
- public function makeKey( $class, $component = null ) {
+ public function makeKey( $class, ...$components ) {
return $this->cache->makeKey( ...func_get_args() );
}
/**
* @see BagOStuff::makeGlobalKey()
* @param string $class Key class
- * @param string|null $component [optional] Key component (starting with a key collection name)
- * @return string Colon-delimited list of $keyspace followed by escaped components of $args
+ * @param string ...$components Key components (starting with a key collection name)
+ * @return string Colon-delimited list of $keyspace followed by escaped components
* @since 1.27
*/
- public function makeGlobalKey( $class, $component = null ) {
+ public function makeGlobalKey( $class, ...$components ) {
return $this->cache->makeGlobalKey( ...func_get_args() );
}
// stream_select parameter names are from the POV of us being able to do the operation;
// proc_open desriptor types are from the POV of the process doing it.
// So $writePipes is passed as the $read parameter and $readPipes as $write.
- // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
- $numReadyPipes = @stream_select( $writePipes, $readPipes, $emptyArray, $timeout );
+ AtEase::suppressWarnings();
+ $numReadyPipes = stream_select( $writePipes, $readPipes, $emptyArray, $timeout );
+ AtEase::restoreWarnings();
if ( $numReadyPipes === false ) {
$error = error_get_last();
if ( strncmp( $error['message'], $eintrMessage, strlen( $eintrMessage ) ) == 0 ) {
/**
* Turkish (Türkçe)
*
- * Turkish has two different i, one with a dot and another without a dot. They
- * are totally different letters in this language, so we have to override the
+ * The Turkish language, like other Turkic languages, distinguishes
+ * a dotted letter 'i' from a dotless letter 'ı' (U+0131 LATIN SMALL LETTER DOTLESS I).
+ * In these languages, each has an equivalent uppercase mapping:
+ * ı (U+0131 LATIN SMALL LETTER DOTLESS I) -> I (U+0049 LATIN CAPITAL LETTER I),
+ * i (U+0069 LATIN SMALL LETTER I) -> İ (U+0130 LATIN CAPITAL LETTER I WITH DOT ABOVE).
+ *
+ * Unicode CaseFolding.txt defines this case as type 'T', a special case for Turkic languages:
+ * tr and az. PHP 7.3 parser ignores this special cases. so we have to override the
* ucfirst and lcfirst methods.
+ *
* See https://en.wikipedia.org/wiki/Dotted_and_dotless_I and T30040
* @ingroup Language
*/
class LanguageTr extends Language {
+ private $uc = [ 'I', 'İ' ];
+ private $lc = [ 'ı', 'i' ];
+
/**
* @param string $string
* @return string
*/
public function ucfirst( $string ) {
- if ( strlen( $string ) && $string[0] == 'i' ) {
- return 'İ' . substr( $string, 1 );
+ $first = mb_substr( $string, 0, 1 );
+ if ( in_array( $first, $this->lc ) ) {
+ $first = str_replace( $this->lc, $this->uc, $first );
+ return $first . mb_substr( $string, 1 );
}
return parent::ucfirst( $string );
}
* @return mixed|string
*/
function lcfirst( $string ) {
- if ( strlen( $string ) && $string[0] == 'I' ) {
- return 'ı' . substr( $string, 1 );
+ $first = mb_substr( $string, 0, 1 );
+ if ( in_array( $first, $this->uc ) ) {
+ $first = str_replace( $this->uc, $this->lc, $first );
+ return $first . mb_substr( $string, 1 );
}
return parent::lcfirst( $string );
}
"backend-fail-maxsize": "Файлът „$1“ не може да бъде съхранен, тъй като размерът му надвишава {{PLURAL:$2|един байт|$2 байт}}.",
"backend-fail-connect": "Не е възможно свързването към бекенда за съхранение „$1“.",
"backend-fail-internal": "Възникна неизвестна грешка в бекенда за съхранение „$1“.",
+ "backend-fail-contenttype": "Не може да бъде определен типът на съдържанието на този файл, за да бъде съхранен в „$1“.",
"zip-file-open-error": "Възникна грешка при отваряне на файла за проверка на ZIP.",
"zip-wrong-format": "Указаният файл не е ZIP файл.",
"zip-bad": "Файлът е повреден или е нечетим ZIP файл.\nСигурността му не може да бъде проверена.",
"uploadstash-errclear": "Изчистването на файловете беше неуспешно.",
"uploadstash-refresh": "Обновяване на списъка с файлове",
"uploadstash-thumbnail": "преглед на миниатюра",
+ "uploadstash-bad-path": "Пътят не съществува.",
+ "uploadstash-bad-path-invalid": "Пътят не е валиден.",
"uploadstash-bad-path-unknown-type": "Неизвестен тип „$1“.",
+ "uploadstash-bad-path-unrecognized-thumb-name": "Неразпознато име на миниатюрата.",
+ "uploadstash-bad-path-bad-format": "Ключът „$1“ не е в подходящ формат.",
+ "uploadstash-file-not-found-missing-content-type": "Липсващо заглавие за типа на съдържание.",
+ "uploadstash-file-not-found-not-exists": "Не може да бъде намерен пътят или файлът не е обикновен.",
"uploadstash-wrong-owner": "Файлът ($1) не принадлежи на текущия потребител.",
"uploadstash-no-such-key": "Няма такъв ключ ($1), не може да бъде премахнат.",
"uploadstash-no-extension": "Разширението е нулево.",
"blocklist-userblocks": "Скриване блокирането на потребителски сметки",
"blocklist-tempblocks": "Скриване на временни блокирания",
"blocklist-addressblocks": "Скриване на отделни блокирания на IP адреси",
+ "blocklist-type-opt-all": "Всички",
"blocklist-type-opt-sitewide": "За всички уикита",
"blocklist-type-opt-partial": "Частично",
"blocklist-rangeblocks": "Скриване на блокиранията по IP диапазон",
"blocklink": "блокиране",
"unblocklink": "отблокиране",
"change-blocklink": "промяна на параметрите на блокирането",
+ "empty-username": "(недостъпно потребителско име)",
"contribslink": "приноси",
"emaillink": "изпращане на е-писмо",
"autoblocker": "Бяхте блокиран автоматично, тъй като неотдавна IP-адресът Ви е бил ползван от блокирания в момента потребител „[[User:$1|$1]]“.\nПричината за блокирането на „$1“ е: „$2“.",
"limitreport-ppgeneratednodes-value": "$1/$2",
"limitreport-postexpandincludesize-value": "$1/$2 {{PLURAL:$2|байт|байта}}",
"limitreport-templateargumentsize-value": "$1/$2 {{PLURAL:$2|байт|байта}}",
+ "limitreport-expansiondepth": "Най-голяма дълбочина на разгръщане",
"limitreport-expansiondepth-value": "$1/$2",
"limitreport-expensivefunctioncount-value": "$1/$2",
"expandtemplates": "Разгръщане на шаблони",
"authmanager-provider-password": "Удостоверяване с парола",
"authmanager-provider-temporarypassword": "Временна парола",
"authprovider-confirmlink-option": "$1 ($2)",
+ "authprovider-confirmlink-success-line": "$1: Успешно свързано.",
"authprovider-confirmlink-failed-line": "$1: $2",
+ "authprovider-confirmlink-failed": "Свързването на сметката не е напълно успешно: $1",
+ "authprovider-confirmlink-ok-help": "Продължаване след показване на съобщения за неуспешно свързване.",
"authprovider-resetpass-skip-label": "Пропускане",
"authform-newtoken": "Липсва маркер. $1",
"authform-notoken": "Липсва маркер",
"revdelete-unsuppress": "حذف محدودیتها در بازبینیهای ترمیمشده",
"revdelete-log": "دلیل:",
"revdelete-submit": "اعمال بر {{PLURAL:$1|نسخهٔ|نسخههای}} انتخاب شده",
- "revdelete-success": "پیدایی نسخه، روزآمد شد.",
+ "revdelete-success": "پیدایی نسخه روزآمد شد.",
"revdelete-failure": "'''پیدایی نسخهها قابل به روز کردن نیست:'''\n$1",
"logdelete-success": "تغییر پیدایی مورد انجام شد.",
"logdelete-failure": "'''پیدایی سیاههها قابل تنظیم نیست:'''\n$1",
"systemblockedtext": "שם המשתמש או כתובת ה־IP שלך נחסמו באופן אוטומטי על־ידי תוכנת מדיה־ויקי.\nהסיבה שניתנה לחסימה היא:\n\n:<em>$2</em>\n\n* תחילת החסימה: $8\n* פקיעת החסימה: $6\n* החסימה שבוצעה: $7\n\nכתובת ה־IP הנוכחית שלך היא $3.\nיש לציין את כל הפרטים הללו בכל פנייה לבירור החסימה.",
"blockednoreason": "לא ניתנה סיבה",
"blockedtext-composite": "<strong>שם המשתמש או כתובת ה־IP שלך נחסמו.</strong>\n\nהסיבה שניתנה לכך היא:\n\n:<em>$2</em>.\n\n* תחילת החסימה: $8\n* פקיעת החסימה הארוכה ביותר: $6\n\n* $5\n\nכתובת ה־IP הנוכחית שלך היא $3.\nיש לציין את כל הפרטים הללו בכל פנייה לבירור החסימה.",
+ "blockedtext-composite-ids": "מזהי החסימות הרלוונטיים: $1 (גם כתובת ה־IP שלך יכולה להיות ברשימה השחורה)",
+ "blockedtext-composite-no-ids": "כתובת ה־IP שלך מופיעה במספר רשימות שחורות",
"blockedtext-composite-reason": "הופעלו מספר חסימות על חשבון המשתמש שלך או על כתובת ה־IP שלך (או על שניהם)",
"whitelistedittext": "נדרשת $1 כדי לערוך דפים.",
"confirmedittext": "יש לאמת את כתובת הדוא\"ל לפני עריכת דפים.\nנא להגדיר ולאמת את כתובת הדוא\"ל שלך באמצעות [[Special:Preferences|העדפות המשתמש]] שלך.",
"right-editmyusercss": "עריכת קובצי CSS של המשתמש עצמו",
"right-editmyuserjson": "עריכת קובצי JSON של המשתמש עצמו",
"right-editmyuserjs": "עריכת קובצי JavaScript של המשתמש עצמו",
+ "right-editmyuserjsredirect": "עריכת דפי JavaScript שלך שהם הפניות",
"right-viewmywatchlist": "צפייה ברשימת המעקב של המשתמש עצמו",
"right-editmywatchlist": "עריכת רשימת המעקב של המשתמש עצמו. מספר פעולות יוסיפו דפים גם ללא הרשאה זו.",
"right-viewmyprivateinfo": "צפייה במידע הפרטי של המשתמש עצמו (כגון: כתובת דוא\"ל, שם אמיתי)",
"action-editmyusercss": "לערוך קובצי CSS של עצמך",
"action-editmyuserjson": "לערוך קובצי JSON של עצמך",
"action-editmyuserjs": "לערוך קובצי JavaScript של עצמך",
+ "action-editmyuserjsredirect": "לערוך את דפי ה־JavaScript שלך שהם הפניות",
"action-viewsuppressed": "לצפות בגרסאות שהוסתרו מכל המשתמשים",
"action-hideuser": "לחסום שם משתמש תוך הסתרתו מהציבור",
"action-ipblock-exempt": "לעקוף חסימות של כתובות IP, חסימות אוטומטיות וחסימות טווחים",
"specialmute-label-mute-email": "השתקת הודעות דואר אלקטרוני מהמשתמש הזה",
"specialmute-header": "נא לבחור את העדפות ההשתקה שלך עבור המשתמש <b>{{BIDI:[[User:$1|$1]]}}</b>.",
"specialmute-error-invalid-user": "שם המשתמש המבוקש לא נמצא.",
+ "specialmute-error-no-options": "אפשרויות ההשתקה אינן זמינות. ייתכן שזה קורה כי: לא עשית אימות כתובת דואר אלקטרוני או שמנהל הוויקי כיבה את אפשרויות הדואר האלקטרוני או את הרשימה השחורה של הדואר האלקטרוני עבור הוויקי הזה.",
"specialmute-email-footer": "כדי לנהל את העדפות קבלת הדואר האלקטרוני שנשלח על־ידי המשתמש {{BIDI:$2}}, באפשרותך לבקר בדף <$1>.",
"specialmute-login-required": "נדרשת כניסה לחשבון כדי לשנות את העדפות ההשתקה שלך.",
"mute-preferences": "העדפות השתקה",
"passwordpolicies-policy-passwordnotinlargeblacklist": "הסיסמה לא יכולה להיות ברשימת 100,000 הסיסמאות הנפוצות ביותר.",
"passwordpolicies-policyflag-forcechange": "לדרוש שינוי בעת כניסה לחשבון",
"passwordpolicies-policyflag-suggestchangeonlogin": "להציע שינוי בעת כניסה לחשבון",
+ "mycustomjsredirectprotected": "אין לך הרשאה לערוך את דף ה־JavaScript הזה כי זאת הפניה ואינה מצביעה לדף בתוך מרחב המשתמש שלך.",
"easydeflate-invaliddeflate": "התוכן שהועבר אינו דחוס כנדרש",
"unprotected-js": "מסיבות אבטחה, לא ניתן לטעון JavaScript מדפים שאינם מוגנים. ניתן ליצור סקריפטי JavaScript רק במרחב השם \"מדיה ויקי:\" או בדפי משנה של דף המשתמש.",
"userlogout-continue": "האם ברצונך לצאת מהחשבון?"
"changepassword": "Чажыт сөстү өскертири",
"resetpass_text": "<!-- Маңаа сөзүглелди немерелээри -->",
"resetpass_header": "Чажыт сөстү катап чогаадып кылыры",
- "oldpassword": "Эгри чажыт сөзүңер:",
+ "oldpassword": "Эрги уруң (чажыт сөс):",
"newpassword": "Чаа чажыт сөзүңер:",
"retypenew": "Чажыт сөзүңерни катап бижиңер:",
"resetpass_submit": "Чажыт сөстү чоогадып кылыр база кирер.",
"page_first": "бирги",
"page_last": "сөөлгү",
"histlegend": "Версиялар шилиири: деңнээр дээн арыныңар версияларын имнеңеш, бээр базыптыңар '''{{int:compare-submit}}'''.<br />\nТайылбыр: '''({{int:cur}})''' — амгы версиядан ылгавыр; '''({{int:last}})''' — эрткен версиядан ылгавыр; '''{{int:minoreditletter}}''' — биче өскерилгелер.",
- "history-fieldset-title": "Ð\9aаÑ\80алааÑ\80Ñ\8b Ñ\82өөгүзү",
+ "history-fieldset-title": "ÐдилгелеÑ\80ни Ñ\88Ò¯Ò¯Ñ\80",
"history-show-deleted": "Чүгле казыттынган",
"histfirst": "Эң эрги",
"histlast": "Эң чаа",
"unusedcategories": "Ажыглаваан бөлүктер",
"unusedimages": "Ажыглаваан файлдар",
"wantedcategories": "Күзээринге бөлүктер",
- "wantedpages": "Күзээрүнге арыннар",
+ "wantedpages": "Күзээн арыннар",
"mostlinked": "Эң холбаалар арыннар",
"mostlinkedcategories": "Эң холбаалар бөлүктер",
"mostlinkedtemplates": "Эң холбаалар майыктар",
"duration-years": "$1 {{PLURAL:$1|чыл|чыл}}",
"duration-decades": "$1 {{PLURAL:$1|1=он хонук|он хонук}}",
"duration-centuries": "$1 {{PLURAL:$1|1=чүс чыл|чүс чыл}}",
- "mw-widgets-abandonedit-title": "Бүзүрелдиг-дир бе?"
+ "mw-widgets-abandonedit-title": "Бүзүрелдиг-дир бе?",
+ "mw-widgets-dateinput-no-date": "Ай-хүн шилитинмээн",
+ "date-range-to": "Ай-хүнге чедир:"
}
'ApiHelp' => [ 'עזרת_API' ],
'ApiSandbox' => [ 'ארגז_חול_של_API' ],
'Ancientpages' => [ 'דפים_מוזנחים' ],
+ 'AutoblockList' => [ 'חסימות_אוטומטיות', 'רשימת_חסימות_אוטומטיות' ],
'Badtitle' => [ 'כותרת_שגויה' ],
'Blankpage' => [ 'דף_ריק' ],
'Block' => [ 'חסימה', 'חסימת_כתובת', 'חסימת_משתמש' ],
'Booksources' => [ 'משאבי_ספרות', 'משאבי_ספרות_חיצוניים' ],
+ 'BotPasswords' => [ 'סיסמאות_בוט' ],
'BrokenRedirects' => [ 'הפניות_לא_תקינות', 'הפניות_שבורות' ],
'Categories' => [ 'קטגוריות', 'רשימת_קטגוריות' ],
+ 'ChangeContentModel' => [ 'שינוי_מודל_התוכן' ],
+ 'ChangeCredentials' => [ 'שינוי_נתוני_ההזדהות' ],
'ChangeEmail' => [ 'שינוי_דואר_אלקטרוני', 'שינוי_דוא"ל' ],
'ChangePassword' => [ 'שינוי_סיסמה' ],
'ComparePages' => [ 'השוואת_דפים' ],
'Confirmemail' => [ 'אימות_כתובת_דואר' ],
'Contributions' => [ 'תרומות', 'תרומות_המשתמש' ],
- 'CreateAccount' => [ 'הרשמה_לחשבון' ],
+ 'CreateAccount' => [ 'הרשמה_לחשבון', 'יצירת_חשבון' ],
'Deadendpages' => [ 'דפים_ללא_קישורים' ],
'DeletedContributions' => [ 'תרומות_מחוקות' ],
'Diff' => [ 'הבדלים', 'הבדל' ],
'DoubleRedirects' => [ 'הפניות_כפולות' ],
+ 'EditTags' => [ 'עריכת_תגיות' ],
'EditWatchlist' => [ 'עריכת_רשימת_המעקב' ],
'Emailuser' => [ 'שליחת_דואר_למשתמש' ],
'ExpandTemplates' => [ 'פריסת_תבניות' ],
'Fewestrevisions' => [ 'הגרסאות_המעטות_ביותר', 'הדפים_בעלי_מספר_העריכות_הנמוך_ביותר' ],
'FileDuplicateSearch' => [ 'חיפוש_קבצים_כפולים' ],
'Filepath' => [ 'נתיב_לקובץ' ],
+ 'GoToInterwiki' => [ 'מעבר_לאתר_אחר' ],
'Import' => [ 'ייבוא', 'ייבוא_דפים' ],
'Invalidateemail' => [ 'ביטול_דואר' ],
'JavaScriptTest' => [ 'בדיקת_JavaScript' ],
'BlockList' => [ 'רשימת_חסומים', 'רשימת_משתמשים_חסומים', 'משתמשים_חסומים' ],
'LinkSearch' => [ 'חיפוש_קישורים_חיצוניים' ],
+ 'LinkAccounts' => [ 'קישור_חשבונות' ],
'Listadmins' => [ 'רשימת_מפעילים' ],
'Listbots' => [ 'רשימת_בוטים' ],
'Listfiles' => [ 'רשימת_קבצים', 'רשימת_תמונות', 'קבצים', 'תמונות' ],
'Listgrouprights' => [ 'רשימת_הרשאות_לקבוצה' ],
+ 'Listgrants' => [ 'רשימת_זיכיונות', 'זיכיונות' ],
'Listredirects' => [ 'רשימת_הפניות', 'הפניות' ],
'ListDuplicatedFiles' => [ 'רשימת_קבצים_כפולים' ],
'Listusers' => [ 'רשימת_משתמשים', 'משתמשים' ],
'Newimages' => [ 'קבצים_חדשים', 'תמונות_חדשות', 'גלריית_קבצים_חדשים', 'גלריית_תמונות_חדשות' ],
'Newpages' => [ 'דפים_חדשים' ],
'PagesWithProp' => [ 'דפים_עם_מאפיינים', 'דפים_לפי_מאפיינים' ],
+ 'PageData' => [ 'מידע_על_הדף' ],
'PageLanguage' => [ 'שפת_הדף' ],
+ 'PasswordPolicies' => [ 'מדיניות_הסיסמאות' ],
'PasswordReset' => [ 'איפוס_סיסמה' ],
'PermanentLink' => [ 'קישור_קבוע' ],
'Preferences' => [ 'העדפות', 'ההעדפות_שלי' ],
'Randompage' => [ 'אקראי', 'דף_אקראי' ],
'RandomInCategory' => [ 'דף_אקראי_בקטגוריה' ],
'Randomredirect' => [ 'הפניה_אקראית' ],
+ 'Randomrootpage' => [ 'דף_בסיס_אקראי' ],
'Recentchanges' => [ 'שינויים_אחרונים' ],
'Recentchangeslinked' => [ 'שינויים_בדפים_המקושרים' ],
'Redirect' => [ 'הפניה' ],
+ 'RemoveCredentials' => [ 'הסרת_נתוני_ההזדהות' ],
'ResetTokens' => [ 'איפוס_אסימונים' ],
'Revisiondelete' => [ 'מחיקת_ושחזור_גרסאות' ],
'RunJobs' => [ 'הרצת_משימות' ],
'Uncategorizedpages' => [ 'דפים_חסרי_קטגוריה' ],
'Uncategorizedtemplates' => [ 'תבניות_חסרות_קטגוריות' ],
'Undelete' => [ 'צפייה_בדפים_מחוקים' ],
+ 'UnlinkAccounts' => [ 'ביטול_הקישור_בין_חשבונות' ],
'Unlockdb' => [ 'שחרור_בסיס_הנתונים' ],
'Unusedcategories' => [ 'קטגוריות_שאינן_בשימוש' ],
'Unusedimages' => [ 'קבצים_שאינם_בשימוש', 'תמונות_שאינן_בשימוש' ],
// Clean up spam on all wikis
$this->output( "Finding spam on " . count( $wgLocalDatabases ) . " wikis\n" );
$found = false;
- foreach ( $wgLocalDatabases as $wikiID ) {
+ foreach ( $wgLocalDatabases as $wikiId ) {
/** @var Database $dbr */
- $dbr = $this->getDB( DB_REPLICA, [], $wikiID );
+ $dbr = $this->getDB( DB_REPLICA, [], $wikiId );
foreach ( $protConds as $conds ) {
$count = $dbr->selectField(
$found = true;
$cmd = wfShellWikiCmd(
"$IP/maintenance/cleanupSpam.php",
- [ '--wiki', $wikiID, $spec ]
+ [ '--wiki', $wikiId, $spec ]
);
- passthru( "$cmd | sed 's/^/$wikiID: /'" );
+ passthru( "$cmd | sed 's/^/$wikiId: /'" );
}
}
}
$prefixes[] = $row->iw_prefix;
}
- foreach ( $wgLocalDatabases as $db ) {
- $this->output( "$db..." );
+ foreach ( $wgLocalDatabases as $wikiId ) {
+ $this->output( "$wikiId..." );
foreach ( $prefixes as $prefix ) {
- $wgMemc->delete( "$db:interwiki:$prefix" );
+ $wgMemc->delete( "$wikiId:interwiki:$prefix" );
}
$this->output( "done\n" );
}
? JobQueueGroup::singleton()->getQueueTypes()
: [ $this->getOption( 'type' ) ];
+ $dbDomain = WikiMap::getCurrentWikiDbDomain()->getId();
foreach ( $types as $type ) {
- $baseConfig = [ 'type' => $type, 'wiki' => wfWikiID() ];
+ $baseConfig = [ 'type' => $type, 'domain' => $dbDomain ];
$src = JobQueue::factory( $baseConfig + $wgJobQueueMigrationConfig[$srcKey] );
$dst = JobQueue::factory( $baseConfig + $wgJobQueueMigrationConfig[$dstKey] );
$this->fatalError( "Can not create directory $fspath." );
}
+ $dbDomain = WikiMap::getCurrentWikiDbDomain()->getId();
$this->fspath = realpath( $fspath ) . DIRECTORY_SEPARATOR;
$this->urlpath = $this->getOption( 'urlpath', "" );
if ( $this->urlpath !== "" && substr( $this->urlpath, -1 ) !== '/' ) {
$this->urlpath .= '/';
}
- $this->identifier = $this->getOption( 'identifier', wfWikiID() );
+ $this->identifier = $this->getOption( 'identifier', $dbDomain );
$this->compress = $this->getOption( 'compress', 'yes' ) !== 'no';
$this->skipRedirects = $this->hasOption( 'skip-redirects' );
$this->dbr = $this->getDB( DB_REPLICA );
$this->generateNamespaces();
$this->timestamp = wfTimestamp( TS_ISO_8601, wfTimestampNow() );
- $this->findex = fopen( "{$this->fspath}sitemap-index-{$this->identifier}.xml", 'wb' );
+ $encIdentifier = rawurlencode( $this->identifier );
+ $this->findex = fopen( "{$this->fspath}sitemap-index-{$encIdentifier}.xml", 'wb' );
$this->main();
}
function openSpawn() {
global $IP;
+ $wiki = WikiMap::getWikiIdFromDbDomain( WikiMap::getCurrentWikiDbDomain() );
if ( count( $this->php ) == 2 ) {
$mwscriptpath = $this->php[1];
} else {
$this->php[0],
$mwscriptpath,
"fetchText.php",
- '--wiki', wfWikiID() ] ) );
+ '--wiki', $wiki ] ) );
} else {
$cmd = implode( " ",
array_map( [ Shell::class, 'escape' ],
[
$this->php[0],
"$IP/maintenance/fetchText.php",
- '--wiki', wfWikiID() ] ) );
+ '--wiki', $wiki ] ) );
}
$spec = [
0 => [ "pipe", "r" ],
* writing are all slow.
*/
function startReplicaProcs() {
+ $wiki = WikiMap::getWikiIdFromDbDomain( WikiMap::getCurrentWikiDbDomain() );
+
$cmd = 'php ' . Shell::escape( __FILE__ );
foreach ( self::$cmdLineOptionMap as $cmdOption => $classOption ) {
if ( $cmdOption == 'replica-id' ) {
}
}
$cmd .= ' --child' .
- ' --wiki ' . Shell::escape( wfWikiID() ) .
+ ' --wiki ' . Shell::escape( $wiki ) .
' ' . Shell::escape( ...$this->destClusters );
$this->replicaPipes = $this->replicaProcs = [];
$userValue = $user->getOption( $option );
if ( $userValue <> $defaultOptions[$option] ) {
- // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
- @$ret[$option][$userValue]++;
+ $ret[$option][$userValue] = ( $ret[$option][$userValue] ?? 0 ) + 1;
}
} else {
foreach ( $defaultOptions as $name => $defaultValue ) {
$userValue = $user->getOption( $name );
if ( $userValue != $defaultValue ) {
- // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
- @$ret[$name][$userValue]++;
+ $ret[$option][$userValue] = ( $ret[$option][$userValue] ?? 0 ) + 1;
}
}
}
ooui:
type: tar
- src: https://registry.npmjs.org/oojs-ui/-/oojs-ui-0.33.3.tgz
- integrity: sha384-eM78ktDU9DG7WIjxnAHWUsPa9VHCaltqLya4afg0C10gd+c5c5q9NJSnNdFgy76J
+ src: https://registry.npmjs.org/oojs-ui/-/oojs-ui-0.33.4.tgz
+ integrity: sha384-ZqQ9VxkRqt444Xthv89HNZB1PyM1SmNz+7gnC2HfaXUtBh+coJdXv7JxlaBjAouq
dest:
# Main stuff
# OOUI Release History
+## v0.33.4 / 2019-07-22
+### Styles
+* Frameless buttons should feature hover and active states (Volker E.)
+* Revert "WikimediaUI theme: Apply primary flag to ButtonWidget (frameless)" (Volker E.)
+* icons: Add 'bellOutline' and 'userAvatarOutline' and amend 'search' (Volker E.)
+
+
## v0.33.3 / 2019-07-16
### Styles
* MessageWidget: Apply `bold` only to inline message types (Volker E.)
/*!
- * OOUI v0.33.3
+ * OOUI v0.33.4
* https://www.mediawiki.org/wiki/OOUI
*
* Copyright 2011–2019 OOUI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2019-07-16T21:33:36Z
+ * Date: 2019-07-23T03:23:32Z
*/
( function ( OO ) {
/*!
- * OOUI v0.33.3
+ * OOUI v0.33.4
* https://www.mediawiki.org/wiki/OOUI
*
* Copyright 2011–2019 OOUI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2019-07-16T21:33:43Z
+ * Date: 2019-07-23T03:23:40Z
*/
.oo-ui-element-hidden {
display: none !important;
.oo-ui-buttonElement-frameless > .oo-ui-buttonElement-button:focus > .oo-ui-labelElement-label {
color: #000;
}
+.oo-ui-buttonElement-frameless > .oo-ui-buttonElement-button:hover {
+ background-color: #fafafa;
+ color: #000;
+}
+.oo-ui-buttonElement-frameless > .oo-ui-buttonElement-button:active {
+ background-color: #ddd;
+ color: #000;
+}
.oo-ui-buttonElement-frameless.oo-ui-labelElement:first-child,
.oo-ui-buttonElement-frameless.oo-ui-iconElement:first-child {
margin-left: -0.3125em;
/*!
- * OOUI v0.33.3
+ * OOUI v0.33.4
* https://www.mediawiki.org/wiki/OOUI
*
* Copyright 2011–2019 OOUI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2019-07-16T21:33:43Z
+ * Date: 2019-07-23T03:23:40Z
*/
.oo-ui-element-hidden {
display: none !important;
color: #222;
}
.oo-ui-buttonElement-frameless.oo-ui-widget-enabled > .oo-ui-buttonElement-button:hover {
+ background-color: #f8f9fa;
+ color: #000;
+}
+.oo-ui-buttonElement-frameless.oo-ui-widget-enabled > .oo-ui-buttonElement-button:active {
+ background-color: #eaecf0;
color: #444;
}
.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-iconElement > .oo-ui-buttonElement-button:focus,
color: #b32424;
box-shadow: none;
}
-.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive > .oo-ui-buttonElement-button {
- color: #fff;
- background-color: #36c;
- border-color: #36c;
-}
-.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive > .oo-ui-buttonElement-button:hover {
- background-color: #447ff5;
- border-color: #447ff5;
-}
-.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive > .oo-ui-buttonElement-button:active,
-.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive > .oo-ui-buttonElement-button:active:focus,
-.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button,
-.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive.oo-ui-buttonElement-active > .oo-ui-buttonElement-button,
-.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive.oo-ui-popupToolGroup-active > .oo-ui-buttonElement-button {
- color: #fff;
- background-color: #2a4b8d;
- border-color: #2a4b8d;
- box-shadow: none;
-}
-.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive > .oo-ui-buttonElement-button:focus {
- border-color: #36c;
- box-shadow: inset 0 0 0 1px #36c, inset 0 0 0 2px #fff;
-}
-.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-destructive > .oo-ui-buttonElement-button {
- color: #fff;
- background-color: #d33;
- border-color: #d33;
-}
-.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-destructive > .oo-ui-buttonElement-button:hover {
- background-color: #ff4242;
- border-color: #ff4242;
-}
-.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-destructive > .oo-ui-buttonElement-button:active,
-.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-destructive > .oo-ui-buttonElement-button:active:focus,
-.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-destructive.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button,
-.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-destructive.oo-ui-buttonElement-active > .oo-ui-buttonElement-button,
-.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-destructive.oo-ui-popupToolGroup-active > .oo-ui-buttonElement-button {
- color: #fff;
- background-color: #b32424;
- border-color: #b32424;
- box-shadow: none;
-}
-.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-destructive > .oo-ui-buttonElement-button:focus {
- border-color: #d33;
- box-shadow: inset 0 0 0 1px #d33, inset 0 0 0 2px #fff;
-}
.oo-ui-buttonElement-frameless.oo-ui-widget-enabled[class*='oo-ui-flaggedElement'] > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon,
.oo-ui-buttonElement-frameless.oo-ui-widget-enabled[class*='oo-ui-flaggedElement'] > .oo-ui-buttonElement-button > .oo-ui-indicatorElement-indicator {
opacity: 1;
padding-top: 1.42857143em;
padding-right: 0;
}
+.oo-ui-fieldLayout .oo-ui-fieldLayout-help .oo-ui-buttonElement-button:hover,
+.oo-ui-fieldLayout .oo-ui-fieldLayout-help .oo-ui-buttonElement-button:active {
+ background-color: transparent;
+}
.oo-ui-fieldLayout.oo-ui-fieldLayout-align-top > .oo-ui-fieldLayout-body > .oo-ui-inline-help {
margin-top: 0.28571429em;
}
padding-top: 1.42857143em;
padding-right: 0;
}
+.oo-ui-fieldsetLayout .oo-ui-fieldsetLayout-help .oo-ui-buttonElement-button:hover,
+.oo-ui-fieldsetLayout .oo-ui-fieldsetLayout-help .oo-ui-buttonElement-button:active {
+ background-color: transparent;
+}
.oo-ui-formLayout + .oo-ui-fieldsetLayout,
.oo-ui-formLayout + .oo-ui-formLayout {
/*!
- * OOUI v0.33.3
+ * OOUI v0.33.4
* https://www.mediawiki.org/wiki/OOUI
*
* Copyright 2011–2019 OOUI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2019-07-16T21:33:36Z
+ * Date: 2019-07-23T03:23:32Z
*/
( function ( OO ) {
/*!
- * OOUI v0.33.3
+ * OOUI v0.33.4
* https://www.mediawiki.org/wiki/OOUI
*
* Copyright 2011–2019 OOUI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2019-07-16T21:33:43Z
+ * Date: 2019-07-23T03:23:40Z
*/
.oo-ui-tool > .oo-ui-tool-link > .oo-ui-tool-checkIcon {
display: none;
/*!
- * OOUI v0.33.3
+ * OOUI v0.33.4
* https://www.mediawiki.org/wiki/OOUI
*
* Copyright 2011–2019 OOUI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2019-07-16T21:33:43Z
+ * Date: 2019-07-23T03:23:40Z
*/
.oo-ui-tool {
-webkit-box-sizing: border-box;
/*!
- * OOUI v0.33.3
+ * OOUI v0.33.4
* https://www.mediawiki.org/wiki/OOUI
*
* Copyright 2011–2019 OOUI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2019-07-16T21:33:36Z
+ * Date: 2019-07-23T03:23:32Z
*/
( function ( OO ) {
/*!
- * OOUI v0.33.3
+ * OOUI v0.33.4
* https://www.mediawiki.org/wiki/OOUI
*
* Copyright 2011–2019 OOUI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2019-07-16T21:33:43Z
+ * Date: 2019-07-23T03:23:40Z
*/
.oo-ui-draggableElement-handle:not( .oo-ui-draggableElement-undraggable ).oo-ui-widget {
cursor: move;
/*!
- * OOUI v0.33.3
+ * OOUI v0.33.4
* https://www.mediawiki.org/wiki/OOUI
*
* Copyright 2011–2019 OOUI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2019-07-16T21:33:43Z
+ * Date: 2019-07-23T03:23:40Z
*/
.oo-ui-draggableElement-handle:not( .oo-ui-draggableElement-undraggable ).oo-ui-widget {
cursor: move;
/*!
- * OOUI v0.33.3
+ * OOUI v0.33.4
* https://www.mediawiki.org/wiki/OOUI
*
* Copyright 2011–2019 OOUI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2019-07-16T21:33:36Z
+ * Date: 2019-07-23T03:23:32Z
*/
( function ( OO ) {
/*!
- * OOUI v0.33.3
+ * OOUI v0.33.4
* https://www.mediawiki.org/wiki/OOUI
*
* Copyright 2011–2019 OOUI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2019-07-16T21:33:36Z
+ * Date: 2019-07-23T03:23:32Z
*/
( function ( OO ) {
/*!
- * OOUI v0.33.3
+ * OOUI v0.33.4
* https://www.mediawiki.org/wiki/OOUI
*
* Copyright 2011–2019 OOUI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2019-07-16T21:33:43Z
+ * Date: 2019-07-23T03:23:40Z
*/
.oo-ui-window {
/*!
- * OOUI v0.33.3
+ * OOUI v0.33.4
* https://www.mediawiki.org/wiki/OOUI
*
* Copyright 2011–2019 OOUI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2019-07-16T21:33:43Z
+ * Date: 2019-07-23T03:23:40Z
*/
.oo-ui-window {
/*!
- * OOUI v0.33.3
+ * OOUI v0.33.4
* https://www.mediawiki.org/wiki/OOUI
*
* Copyright 2011–2019 OOUI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2019-07-16T21:33:36Z
+ * Date: 2019-07-23T03:23:32Z
*/
( function ( OO ) {
"bell": {
"file": "../wikimediaui/images/icons/bell.svg"
},
+ "bellOutline": {
+ "file": "../wikimediaui/images/icons/bellOutline.svg"
+ },
"error": {
"file": "../wikimediaui/images/icons/error.svg"
},
"userAvatar": {
"file": "../wikimediaui/images/icons/userAvatar.svg"
},
+ "userAvatarOutline": {
+ "file": "../wikimediaui/images/icons/userAvatarOutline.svg"
+ },
"userTalk": {
"file": {
"ltr": "../wikimediaui/images/icons/userTalk-ltr.svg",
"bell": {
"file": "images/icons/bell.svg"
},
+ "bellOutline": {
+ "file": "images/icons/bellOutline.svg"
+ },
"error": {
"file": "images/icons/error.svg",
"variants": [
"userAvatar": {
"file": "images/icons/userAvatar.svg"
},
+ "userAvatarOutline": {
+ "file": "images/icons/userAvatarOutline.svg"
+ },
"userTalk": {
"file": {
"ltr": "images/icons/userTalk-ltr.svg",
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>bell</title><path fill="#fff" fill-rule="evenodd" d="M11.5 2.19C14.09 2.86 16 5.2 16 8v6l2 2v1H2v-1l2-2V8c0-2.8 1.91-5.14 4.5-5.81V1.5C8.5.67 9.17 0 10 0s1.5.67 1.5 1.5v.69zM10 4C7.79 4 6 5.79 6 8v7h8V8c0-2.21-1.79-4-4-4zM8 18h4c0 1.1-.9 2-2 2s-2-.9-2-2z"/></svg>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>bell</title><path fill="#36c" fill-rule="evenodd" d="M11.5 2.19C14.09 2.86 16 5.2 16 8v6l2 2v1H2v-1l2-2V8c0-2.8 1.91-5.14 4.5-5.81V1.5C8.5.67 9.17 0 10 0s1.5.67 1.5 1.5v.69zM10 4C7.79 4 6 5.79 6 8v7h8V8c0-2.21-1.79-4-4-4zM8 18h4c0 1.1-.9 2-2 2s-2-.9-2-2z"/></svg>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>bell</title><path fill-rule="evenodd" d="M11.5 2.19C14.09 2.86 16 5.2 16 8v6l2 2v1H2v-1l2-2V8c0-2.8 1.91-5.14 4.5-5.81V1.5C8.5.67 9.17 0 10 0s1.5.67 1.5 1.5v.69zM10 4C7.79 4 6 5.79 6 8v7h8V8c0-2.21-1.79-4-4-4zM8 18h4c0 1.1-.9 2-2 2s-2-.9-2-2z"/></svg>
\ No newline at end of file
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>search</title><path fill="#fff" d="M19 17l-5.15-5.15a7 7 0 1 0-2 2L17 19zM3.5 8A4.5 4.5 0 1 1 8 12.5 4.5 4.5 0 0 1 3.5 8z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>search</title><path fill="#fff" d="M7.5 13c3.04 0 5.5-2.46 5.5-5.5S10.54 2 7.5 2 2 4.46 2 7.5 4.46 13 7.5 13zm4.55.46A7.432 7.432 0 0 1 7.5 15C3.36 15 0 11.64 0 7.5S3.36 0 7.5 0C11.64 0 15 3.36 15 7.5c0 1.71-.57 3.29-1.54 4.55l6.49 6.49-1.41 1.41-6.49-6.49z"/></svg>
\ No newline at end of file
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>search</title><path fill="#36c" d="M19 17l-5.15-5.15a7 7 0 1 0-2 2L17 19zM3.5 8A4.5 4.5 0 1 1 8 12.5 4.5 4.5 0 0 1 3.5 8z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>search</title><path fill="#36c" d="M7.5 13c3.04 0 5.5-2.46 5.5-5.5S10.54 2 7.5 2 2 4.46 2 7.5 4.46 13 7.5 13zm4.55.46A7.432 7.432 0 0 1 7.5 15C3.36 15 0 11.64 0 7.5S3.36 0 7.5 0C11.64 0 15 3.36 15 7.5c0 1.71-.57 3.29-1.54 4.55l6.49 6.49-1.41 1.41-6.49-6.49z"/></svg>
\ No newline at end of file
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>search</title><path d="M19 17l-5.15-5.15a7 7 0 1 0-2 2L17 19zM3.5 8A4.5 4.5 0 1 1 8 12.5 4.5 4.5 0 0 1 3.5 8z"/></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>search</title><path d="M7.5 13c3.04 0 5.5-2.46 5.5-5.5S10.54 2 7.5 2 2 4.46 2 7.5 4.46 13 7.5 13zm4.55.46A7.432 7.432 0 0 1 7.5 15C3.36 15 0 11.64 0 7.5S3.36 0 7.5 0C11.64 0 15 3.36 15 7.5c0 1.71-.57 3.29-1.54 4.55l6.49 6.49-1.41 1.41-6.49-6.49z"/></svg>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>user avatar</title><path fill="#fff" d="M10 8c1.7 0 3.06-1.35 3.06-3S11.7 2 10 2 6.94 3.35 6.94 5 8.3 8 10 8zm0 2c-2.8 0-5.06-2.24-5.06-5S7.2 0 10 0s5.06 2.24 5.06 5-2.26 5-5.06 5zm-7 8h14v-1.33c0-1.75-2.31-3.56-7-3.56s-7 1.81-7 3.56V18zm7-6.89c6.66 0 9 3.33 9 5.56V20H1v-3.33c0-2.23 2.34-5.56 9-5.56z"/></svg>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>user avatar</title><path fill="#36c" d="M10 8c1.7 0 3.06-1.35 3.06-3S11.7 2 10 2 6.94 3.35 6.94 5 8.3 8 10 8zm0 2c-2.8 0-5.06-2.24-5.06-5S7.2 0 10 0s5.06 2.24 5.06 5-2.26 5-5.06 5zm-7 8h14v-1.33c0-1.75-2.31-3.56-7-3.56s-7 1.81-7 3.56V18zm7-6.89c6.66 0 9 3.33 9 5.56V20H1v-3.33c0-2.23 2.34-5.56 9-5.56z"/></svg>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>user avatar</title><path d="M10 8c1.7 0 3.06-1.35 3.06-3S11.7 2 10 2 6.94 3.35 6.94 5 8.3 8 10 8zm0 2c-2.8 0-5.06-2.24-5.06-5S7.2 0 10 0s5.06 2.24 5.06 5-2.26 5-5.06 5zm-7 8h14v-1.33c0-1.75-2.31-3.56-7-3.56s-7 1.81-7 3.56V18zm7-6.89c6.66 0 9 3.33 9 5.56V20H1v-3.33c0-2.23 2.34-5.56 9-5.56z"/></svg>
\ No newline at end of file
);
// Correct handling of really old password hashes
- $this->config->set( 'PasswordSalt', false );
- $password = md5( 'FooBar' );
- $dbw->update( 'user', [ 'user_password' => $password ], [ 'user_name' => $userName ] );
- $req->password = 'FooBar';
- $this->assertEquals(
- AuthenticationResponse::newPass( $userName ),
- $provider->beginPrimaryAuthentication( $reqs )
- );
-
$this->config->set( 'PasswordSalt', true );
$password = md5( "$id-" . md5( 'FooBar' ) );
$dbw->update( 'user', [ 'user_password' => $password ], [ 'user_name' => $userName ] );
* @covers CachedBagOStuff::makeKey
*/
public function testMakeKey() {
+ if ( defined( 'HHVM_VERSION' ) ) {
+ // This works fine on HHVM (and verified by integration tests), but due to
+ // a bug in HHVM's Reflection, PHPUnit 4 fails to create a mock (T228563)
+ $this->markTestSkipped( 'HHVM Reflection buggy' );
+ }
+
$backend = $this->getMockBuilder( HashBagOStuff::class )
->setMethods( [ 'makeKey' ] )
->getMock();
* @covers CachedBagOStuff::makeGlobalKey
*/
public function testMakeGlobalKey() {
+ if ( defined( 'HHVM_VERSION' ) ) {
+ $this->markTestSkipped( 'HHVM Reflection buggy' );
+ }
+
$backend = $this->getMockBuilder( HashBagOStuff::class )
->setMethods( [ 'makeGlobalKey' ] )
->getMock();
* @covers MultiWriteBagOStuff::makeKey
*/
public function testMakeKey() {
+ if ( defined( 'HHVM_VERSION' ) ) {
+ $this->markTestSkipped( 'HHVM Reflection buggy' );
+ }
+
$cache1 = $this->getMockBuilder( HashBagOStuff::class )
->setMethods( [ 'makeKey' ] )->getMock();
$cache1->expects( $this->once() )->method( 'makeKey' )
* @covers MultiWriteBagOStuff::makeGlobalKey
*/
public function testMakeGlobalKey() {
+ if ( defined( 'HHVM_VERSION' ) ) {
+ $this->markTestSkipped( 'HHVM Reflection buggy' );
+ }
+
$cache1 = $this->getMockBuilder( HashBagOStuff::class )
->setMethods( [ 'makeGlobalKey' ] )->getMock();
$cache1->expects( $this->once() )->method( 'makeGlobalKey' )
* @covers WANObjectCache::makeKey
*/
public function testMakeKey() {
+ if ( defined( 'HHVM_VERSION' ) ) {
+ $this->markTestSkipped( 'HHVM Reflection buggy' );
+ }
+
$backend = $this->getMockBuilder( HashBagOStuff::class )
->setMethods( [ 'makeKey' ] )->getMock();
$backend->expects( $this->once() )->method( 'makeKey' )
* @covers WANObjectCache::makeGlobalKey
*/
public function testMakeGlobalKey() {
+ if ( defined( 'HHVM_VERSION' ) ) {
+ $this->markTestSkipped( 'HHVM Reflection buggy' );
+ }
+
$backend = $this->getMockBuilder( HashBagOStuff::class )
->setMethods( [ 'makeGlobalKey' ] )->getMock();
$backend->expects( $this->once() )->method( 'makeGlobalKey' )
* @return PHPUnit_Framework_MockObject_MockObject|HashBagOStuff
*/
private function getMockCache() {
+ if ( defined( 'HHVM_VERSION' ) ) {
+ $this->markTestSkipped( 'HHVM Reflection buggy' );
+ }
+
$mock = $this->getMockBuilder( HashBagOStuff::class )
->disableOriginalConstructor()
->setMethods( [ 'get', 'set', 'delete', 'makeKey' ] )
use Exception;
use MediaWiki\MediaWikiServices;
use MediaWiki\Revision\RevisionRecord;
+use MediaWiki\Revision\SlotRecord;
use MediaWikiTestCase;
use MWException;
use RequestContext;
// We'll add several pages, revision and texts. The following variables hold the
// corresponding ids.
- private $pageId1, $pageId2, $pageId3, $pageId4;
- private $pageTitle1, $pageTitle2, $pageTitle3, $pageTitle4;
+ private $pageId1, $pageId2, $pageId3, $pageId4, $pageId5;
+ private $pageTitle1, $pageTitle2, $pageTitle3, $pageTitle4, $pageTitle5;
private $revId1_1, $textId1_1;
private $revId2_1, $textId2_1, $revId2_2, $textId2_2;
private $revId2_3, $textId2_3, $revId2_4, $textId2_4;
private $revId3_1, $textId3_1, $revId3_2, $textId3_2;
private $revId4_1, $textId4_1;
+ private $revId5_1, $textId5_1;
private $namespace, $talk_namespace;
/**
"Talk about BackupDumperTestP1 Text1",
"Talk BackupDumperTestP1 Summary1" );
$this->pageId4 = $page->getId();
+
+ $this->pageTitle5 = Title::newFromText( 'BackupDumperTestP5' );
+ $page = WikiPage::factory( $this->pageTitle5 );
+ list( $this->revId5_1, $this->textId5_1 ) = $this->addRevision( $page,
+ "BackupDumperTestP5 Text1",
+ "BackupDumperTestP5 Summary1" );
+ $this->pageId5 = $page->getId();
+
+ $this->corruptRevisionData( $page->getRevision()->getRevisionRecord() );
} catch ( Exception $e ) {
// We'd love to pass $e directly. However, ... see
// documentation of exceptionFromAddDBData in
}
}
+ /**
+ * Corrupt the information about the given revision in the database.
+ *
+ * @param RevisionRecord $revision
+ */
+ private function corruptRevisionData( RevisionRecord $revision ) {
+ global $wgMultiContentRevisionSchemaMigrationStage;
+
+ if ( ( $wgMultiContentRevisionSchemaMigrationStage & SCHEMA_COMPAT_WRITE_OLD ) ) {
+ $this->db->update(
+ 'revision',
+ [
+ 'rev_text_id' => 0,
+ 'rev_sha1' => '',
+ 'rev_len' => '0',
+ ],
+ [ 'rev_id' => $revision->getId() ]
+ );
+ }
+
+ if ( ( $wgMultiContentRevisionSchemaMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) ) {
+ $this->db->update(
+ 'content',
+ [
+ 'content_address' => 'tt:0',
+ 'content_sha1' => '',
+ 'content_size' => '0',
+ ],
+ [ 'content_id' => $revision->getSlot( SlotRecord::MAIN )->getContentId() ]
+ );
+ }
+ }
+
protected function setUp() {
parent::setUp();
$dumper = $this->newDumpBackup(
[ '--full', '--quiet', '--output', 'file:' . $fname, '--schema-version', $schemaVersion ],
$this->pageId1,
- $this->pageId4 + 1
+ $this->pageId5 + 1
);
- // Performing the dump
+ // Performing the dump. Suppress warnings, since we want to test
+ // accessing broken revision data (page 5).
+ $this->setMwGlobals( 'wgDevelopmentWarnings', false );
$dumper->execute();
+ $this->setMwGlobals( 'wgDevelopmentWarnings', true );
// Checking the dumped data
$this->assertDumpSchema( $fname, $this->getXmlSchemaPath( $schemaVersion ) );
);
$asserter->assertPageEnd();
+ // Page 5 (broken revision data)
+ $asserter->assertPageStart(
+ $this->pageId5,
+ $this->namespace,
+ $this->pageTitle5->getPrefixedText()
+ );
+ $asserter->assertRevision(
+ $this->revId5_1,
+ "BackupDumperTestP5 Summary1",
+ null,
+ 0,
+ "",
+ false,
+ false,
+ CONTENT_MODEL_WIKITEXT,
+ CONTENT_FORMAT_WIKITEXT,
+ $schemaVersion
+ );
+ $asserter->assertPageEnd();
+
$asserter->assertDumpEnd();
// FIXME: add multi-slot test case!
'--schema-version', $schemaVersion,
],
$this->pageId1,
- $this->pageId4 + 1
+ $this->pageId5 + 1
);
- // Performing the dump
+ // Performing the dump. Suppress warnings, since we want to test
+ // accessing broken revision data (page 5).
+ $this->setMwGlobals( 'wgDevelopmentWarnings', false );
$dumper->execute();
+ $this->setMwGlobals( 'wgDevelopmentWarnings', true );
// Checking the dumped data
$this->assertDumpSchema( $fname, $this->getXmlSchemaPath( $schemaVersion ) );
);
$asserter->assertPageEnd();
+ // Page 5 (broken revision data)
+ $asserter->assertPageStart(
+ $this->pageId5,
+ $this->namespace,
+ $this->pageTitle5->getPrefixedText()
+ );
+ $asserter->assertRevision(
+ $this->revId5_1,
+ "BackupDumperTestP5 Summary1",
+ null,
+ 0,
+ ""
+ );
+ $asserter->assertPageEnd();
+
$asserter->assertDumpEnd();
}
protected function setUp() {
parent::setUp();
+
+ if ( defined( 'HHVM_VERSION' ) ) {
+ $this->markTestSkipped( 'HHVM Reflection buggy' );
+ }
+
$cache = $this->getMockBuilder( RedisBagOStuff::class )
->disableOriginalConstructor()
->getMock();