MediaWiki only supports 14 character timestamps, and most date input
fields accordingly limit the accepted input range to fit within that
constraint, so the largest acceptable date is 9999-12-31 23:59:59.
However, if an user's own timezone preference is set to a timezone with
a higher offset than the server timezone, such dates may overflow into
the year 10000 and cause an error ("The timestamp XYZ should have 14
characters"). This very commonly happens when an admin decides to block
an user until 9999-12-31 instead of using the infinite expiry for some
reason, effectively breaking the block log for every user with a
timezone offset higher than the server offset.
Making MediaWiki support dates beyond the year 10000 would be a larger
undertaking, so for now, limit the impact of this problem by ensuring
that userAdjust() does not generate a local date that sprintfDate()
would not be able to handle.
Bug: T32148
Bug: T277809
Change-Id: I17ceee6c80dcc1559c6d66f1956ba1f0a4b519a3
Special pages belong to the interaction layer, lower level code should
not access them. That is especially true for something used everywhere
in the code base, like Language.
Change-Id: I46a2a7d60ff73dac3ce72e657c6232b6168a98e8
Two messages were added to wgRawHtmlMessages instead of just
fixing the way they were parsed so they can't contain raw
HTML. This fixes that.
In order to avoid breakage on-wiki for old customized messages
that took advantage of them being parsed as raw HTML, rename
the messages too. Also rename a few other messages from the
same set to stay consistent.
Note: These messages are suppressed in favour of Echo's messages
when Echo is enabled, and Echo is enabled on all Wikimedia wikis,
so the existing customized messages on Wikimedia wikis are basically
no-ops.
Bug: T353316
Change-Id: Ib0d1c79247fe091f2806b7c23ffb2fe22cc4df4a
Changes to the use statements done automatically via script
Addition of missing use statements and changes to docs done manually
Change-Id: Ib326ae1e5c8409a98398c721e8b8ce42c73bd012
There are a couple of user options related classes already,
and the T321527 work on dynamic defaults is going to add
even more. Let's move them into a separate namespace
to make core a bit more organized.
Old name is kept as an alias for compatibility purposes.
Bug: T321527
Bug: T352284
Change-Id: I9822eb1553870b876d0b8a927e4e86c27d83bd52
This has been constantly mentioned as buggy and broken and there is no
official version of latin or Arabic (see the ticket for more details).
This can be turned back as an extension if needed by third party users.
Bug: T350684
Bug: T268143
Depends-On: I6180dca2c49b3119751766268acc56087aaf8414
Change-Id: Ifbf3c8954d885daf891f8d9efc11743d898302f0
This was done automatically using the
`Universal.WhiteSpace.CommaSpacing` sniff, which will be included in the
next release of the MW PHPCS config.
Some of these have been adjusted manually where the autofix broke
vertical alignment.
Change-Id: I54a4668d8a2759b9d7de47742c943a535a04e211
Use
$this->getServiceContainer()
instead of
MediaWikiServices::getInstance()
in tests where possible.
Change-Id: I798b2941f37a43b9073072935b54c3ea0cfe70dd
This creates a new language code, 'x-xss', which is enabled using the
setting $wgUseXssLanguage (similar to how $wgUsePigLatinVariant enables
the 'en-x-piglatin' language code, and likewise defaults to false; will
be enabled in development settings soon).
In this language code, all messages become “malicious”, trying to run
some alert() JavaScript; if any alert() actually fires in the browser,
the message was not escaped properly. ($wgRawHtmlMessages are exempt,
since they’re already known to be “unsafe” and require more rights to
edit on-wiki.) Messages that are not escaped properly are generally a
minor security issue; they effectively let a user with 'editinterface'
right (such as a sysop, on many wikis) run arbitrary JS, without needing
the 'editsitejs' right (normally restricted to interface admins).
Developers can use this language code to more easily check their code
for escaping issues / cross-site scripting vulnerabilities.
Bug: T340201
Change-Id: Ia9a1cf712b139fea5da72046e37035e6de39d8d5
On LanguageNameUtils, the method is called getLanguageName(), not
fetchLanguageName() like on Language.
As far as I can tell, this must have been broken since change
I016b1c1731 (commit 0f935809fd). It might have worked in MediaWiki core
CI because the cldr extension isn’t installed there (and thus the test
is skipped); I have no idea why it seemingly didn’t break cldr’s own CI;
but locally, the test consistently fails.
Bug: T325962
Change-Id: I0a2ff0a41ebe4f3007316e4511926f6b10c71e1d
This reverts change I6490ffba96 (commit e4e613b0d1), restoring
change I7ec2d87c0f (commit cf8e22e1e4). The issues with the last version
should be fixed by the parent change (Icc3324aca7), and we also have
some tests for these issues now (change Iee11cb5c52).
Bug: T342418
Bug: T343343
Bug: T343375
Change-Id: Id9e718f1791c937f53195613a7b76c23d3376a13
The new block in testRecacheExtensionMessagesFiles() covers the
underlying issue of T343343 and T343375; see change Icc3324aca7 for an
explanation of the issue.
In order for this test to not crash, we also need to adjust some of the
other tests and data. MessagesEn.php defines $preloadedMessages, and
LocalisationCache assumes (quite rightly so, really) that all of these
messages will be found in the configured MessagesDirs. But in the test,
we override MessagesDirs to point at the test’s JSON files, while still
using the original MessagesEn.php with its $preloadedMessages. Now that
we are triggering the preload mechanism (I think it wasn’t reached by
the tests previously?), it triggers a PHP deprecation (since PHP 8) on
the missing messages, which makes the test fail:
> explode(): Passing null to parameter #2 ($string) of type string is deprecated
I decided to fix this by adding fake entries for all $preloadedMessages
to the test en.json file. This makes the other tests that compare the
entire messages array fail, so instead only compare the three messages
those tests care about ("present-*"). I don’t like this very much, but I
dislike the other two approaches I can think of even more: check
defined( 'MW_PHPUNIT_TEST' ) in the original MessagesEn.php file, or add
a test-specific MessagesEn.php using the Language::getMessagesFileName
hook.
Bug: T342418
Bug: T343343
Bug: T343375
Change-Id: Iee11cb5c52cb9dd777b70a1daa06f41f2c3ca187
Mock the needed dependencies to avoid database access when possible, and
add the test to the Database group otherwise.
Bug: T155147
Change-Id: Ic5c39ab35ab4d993721713285180f072497a5a40
Mock the relevant services that need the DB instead, when possible. When
not possible, e.g. because DB access is needed for the test to make
sense, add the test to the Database group instead.
Change-Id: Iefbfe00bedc243906c6b860572568343268646cc
Extract loadCoreData(), which loads only the core, non-mergeable keys
from the core messages files, not the extension messages files or the
JSON files. Have loadItem() call this method, skipping the full
initLanguage() + recache(), if possible.
Because compiling the plural rules takes up a significant amount of
loading the core-only data (see discussion on Gerrit), extract
readPluralFilesAndRegisterDeps() from readSourceFilesAndRegisterDeps(),
and only call the latter in loadCoreData() (while recache() calls both).
Also remove a comment about readSourceFilesAndRegisterDeps() returning
false if the localisation doesn’t exist, which AFAICT hasn’t been true
since change I35bbb3a7a1 (commit 8e0c0a9fc9) in 2014.
Note that the new “core-only data” path in loadItem() bypasses the
underlying LCStore even if the core data (or indeed all data) happens to
be present in it. Some investigation and benchmarks (see the discussion
on this change on Gerrit) indicate that this is usually a performance
win; in particular, unless manualRecache is set, just checking whether
the LCStore is expired is relatively expensive.
[For further discussion, see also changes I00f2018400 and I64822e050e on
Gerrit, which were later squashed into this change.]
Bug: T342418
Change-Id: I7ec2d87c0f864c7dbfd629f0b47f22dc8a6fa552
All Messages*.php variables are supposed to be documented in
MessagesEn.php.
I don't see the point in having Language::minimumGroupingDigits() return
null, and then expecting every caller to cast null to zero.
The default for English is properly 1, not 0, since 3-digit numbers do
not need grouping. We don't write 999 as ",999". Setting it to 1
instead of null should improve the performance of the JS commafyNumber()
by avoiding the unnecessary loop body. Change the QUnit test data to
confirm that this works.
In the PHP implementation, adjust the comparison to avoid the
preg_match() when minimumGroupingDigits is 1.
Change-Id: I6679d69e7094502303389039550e17a47189e2dc
Previously, it was technically possible to set some keys in extension
messages files that didn’t make much sense (e.g. $rtl['en'] = true;).
This prevents optimizing language creation, so going forward, we will no
longer support that; ALL_KEYS is now split into CORE_ONLY_KEYS and
ALL_EXCEPT_CORE_ONLY_KEYS (with a test verifying that no key is missing
or overlapping or anything), and ALL_EXCEPT_CORE_ONLY_KEYS are silently
skipped when loading extension messages files.
To demonstrate that it’s okay to silently skip these keys, patch set 1
of this change on Gerrit instead raised a deprecation warning; CI
indicated that this warning was never hit. Codesearch [1] also suggests
that no known extension was actually using any of these keys. (The
DonationInterface [2] and LandingCheck [3] codesearch results can be
ignored: both of these define es-419 as a new language, using the
Language::getMessagesFileName hook to register their MessagesEs_419.php
as a “core” message file, not an extension message file.)
[1]: https://codesearch.wmcloud.org/search/?q=^\%24(fallback|rtl|(digit|separator)TransformTable|fallback8bitEncoding|link(PrefixExtension|Trail|PrefixCharset)|date(Formats|Preferences|PreferenceMigrationMap)|defaultDateFormat|digitGroupingPattern).*%3D&files=\.php%24
[2]: f8b5fe95f7/gateway_common/messages/MessagesEs_419.php (11)
[3]: 2537439aee/messages/MessagesEs_419.php (11)
Bug: T342418
Change-Id: Ia3dffea390d4efdfa3a3cea549d079507718ef48
The classes were already moved in change I62c701d574 (commit
051e127bdb).
Ideally, the tests should have a namespace, but the other tests in
/language are also unnamespaced, so let’s not do that yet.
Change-Id: Ieef8728a1f474ce6b16fa534c9697e1e89a4a36d
We are introducing a new phpcs sniff to make sure this doesn't happen
That sniff found this so far.
Bug: T342297
Change-Id: Ibce3f3d28e7d2cb5b0ff7230f584e76446965ddc
Also use ::class for class names
instanceof is not exactly the same as compare with get_class,
but that is only relevant for sub-sub-types,
which are not in use on converters
Change-Id: Ib07e14bd57211920d72f7e27668bf32c604ae03c
Only update test cases that tests non-deprecated functions.
Test cases that tests deprecated functions can be removed together with
the removal of the deprecated functions.
Also consistently use
$this->getServiceContainer()
instead of
MediaWikiServices::getInstance()
Change-Id: Iac40d6c66a31dd699ab8771244c701232e4354e8
The service was previously accessing the global ExtensionRegistry
singleton, making it lose its statelessness. Dependencies should always
be injected, so add constructor parameters for that.
Simplify tests accordingly.
Change-Id: Iae375a81cab411fab607cba0addb2088131b3c81
There should be no need to call hook handlers directly,
this should only be done by HookContainer.
Change-Id: I8fa46c2eb6a40ad98e564c31dcfb103825608426
This reverts change I50c3d1c5df (commit b0317287bc), thus reinstating
change I7d690a1172 (commit d139eb07fe). The only change from the
original is in getHookMethodName(), additionally replacing '-' with '_'
(not just ':' and '\'). The original commit message follows:
This converts all hook handlers to the same internal representation.
This is done lazily, when the hook is run for the first time.
The logic for temporarily disabling handlers by calling scopedRegister()
with the $replace parameter set has been greatly simplified.
There are some minor changes to the class's interface and behavior,
none of which should be breaking changes:
* run() will emit deprecation warnings if and only if it was called
with the deprecationVersion option set, for all kinds of handlers.
The idea is that deprecated hooks should emit a warning either from
run(), or from emitDeprecationWarnings(). The latter happens if the
hook is listed in DeprecatedHooks.
* register() now also accepts hook handlers declared in the way that
extensions register hooks.
* Attempts to call register() with an invalid hook definition now
result in an invalidArgumentException.
* Attempts to call register() for a deprecated hook will consistently
result in a deprecation warning.
* The internal getRegisteredHooks() method has been removed in favor
of the identical getHookNames() method.
* The internal getLegacyHandlers method has been removed in favor
of getHandlerDescriptions() and getHandlerCallbacks().
* The call order changed so that dynamically registered handlers
are called last, instead of getting called before handler objects
from extensions.
Bug: T338213
Change-Id: I6efb09e314ad2b124a33a757fdda2a07ae0d8f7c
This apparently caused some change in how hook handlers are called (it
now calls e.g. AbuseFilterHookHandler::onAbuseFilter-generateUserVars()
instead of AbuseFilterHookHandler::onAbuseFilter_generateUserVars()),
causing both test failures and errors on Beta.
This reverts commit d139eb07fe.
Bug: T338213
Change-Id: I50c3d1c5dfd2d7eeac59992156a8a644cf0197e5
This converts all hook handlers to the same internal representation.
This is done lazily, when the hook is run for the first time.
The logic for temporarily disabling handlers by calling scopedRegister()
with the $replace parameter set has been greatly simplified.
There are some minor changes to the class's interface and behavior,
none of which should be breaking changes:
* run() will emit deprecation warnings if and only if it was called
with the deprecationVersion option set, for all kinds of handlers.
The idea is that deprecated hooks should emit a warning either from
run(), or from emitDeprecationWarnings(). The latter happens if the
hook is listed in DeprecatedHooks.
* register() now also accepts hook handlers declared in the way that
extensions register hooks.
* Attempts to call register() with an invalid hook definition now
result in an invalidArgumentException.
* Attempts to call register() for a deprecated hook will consistently
result in a deprecation warning.
* The internal getRegisteredHooks() method has been removed in favor
of the identical getHookNames() method.
* The internal getLegacyHandlers method has been removed in favor
of getHandlerDescriptions() and getHandlerCallbacks().
* The call order changed so that dynamically registered handlers
are called last, instead of getting called before handler objects
from extensions.
Change-Id: I7d690a1172af44a90b957b2274d68e51b7f09938