Page MenuHomePhabricator

Consolidate logic for parsing expiries
Open, Needs TriagePublic

Description

As a watchlist user, I want the logic for parsing expiries to be consolidated, so that the tool can run with efficiency and reliability in the back-end.

Background: We have basically the same logic for parsing "expiry" user inputs in WatchedItemStore::updateOrDeleteExpiries(), SpecialBlock::parseExpiryInput(), SpecialUserrights::expiryToTimestamp(), ProtectionForm::getExpiry(), ApiProtect::execute(), FlaggedRevs PageStabilityForm::getExpiry(), and possibly other extensions as well. With minor variations, that code is generally[1]

if ( wfIsInfinity( $expiry ) ) {
    return 'infinity';
}

$unix = strtotime( $expiry );
return $unix === false ? false : wfTimestamp( TS_MW, $unix );

We should probably consolidate that logic into one place, possibly with additional error checking to avoid accepting past expiries and such. Also, for the benefit of APIs[2] we might also add 'expiry' as a type to ParamValidator.

[1]: Well, most of them still have checks for PHP 5.0 returning -1 instead of false on invalid input. I left that out here.
[2]: In the Action API in core, we could use it in ApiBlock, ApiProtect, and ApiUserrights, and ApiWatch.

Acceptance Criteria:

  • Consolidate logic for parsing expiries

Related

Event Timeline

Restricted Application added a subscriber: Aklapper. · View Herald Transcript

Change 983968 had a related patch set uploaded (by MusikAnimal; author: MusikAnimal):

[mediawiki/core@master] BlockUser: parse expiries using ExpiryDef::normalizeExpiry

https://gerrit.wikimedia.org/r/983968

This task was created before we introduced ExpiryDef, which largely addresses the issue. We just need to make use of ExpiryDef::nomralizeExpiry in more places.

Change 983969 had a related patch set uploaded (by MusikAnimal; author: MusikAnimal):

[mediawiki/core@master] ApiProtect: parse expiries using ExpiryDef::normalizeExpiry

https://gerrit.wikimedia.org/r/983969

Change 983970 had a related patch set uploaded (by MusikAnimal; author: MusikAnimal):

[mediawiki/core@master] ProtectionForm: parse expiries using ExpiryDef::normalizeExpiry

https://gerrit.wikimedia.org/r/983970

Change 983968 merged by jenkins-bot:

[mediawiki/core@master] BlockUser: parse expiries using ExpiryDef::normalizeExpiry

https://gerrit.wikimedia.org/r/983968

Change #1113249 had a related patch set uploaded (by Samwilson; author: Samwilson):

[mediawiki/core@master] API: Use ExpiryDef for action=block expiry parameter

https://gerrit.wikimedia.org/r/1113249

Change #1113249 merged by jenkins-bot:

[mediawiki/core@master] API: Use ExpiryDef for action=block expiry parameter

https://gerrit.wikimedia.org/r/1113249

Probably introduced by 257d6f3ba0517265471165cfdf4ba8576cc4ece8, blocking a user for a limited duration now generates a block log with an ISO timestamp, even if a relative duration (e.g. 1 day) is used for the expiry parameter of action=block.

new mw.Api().postWithToken('csrf', {
    action: 'block',
    user: 'DragoTest',
    expiry: '1 day',
    reason: 'Test',
    formatversion: '2'
}).then(console.log).catch(console.log);

testwiki:Special:Redirect/logid/415300

2025-02-08T18:19:27 Dragoniez (talk | contribs | block) blocked DragoTest (talk | contribs) with an expiration time of 2025-02-09T18:19:27 (autoblock disabled, cannot edit own talk page) (Test)

What is expected is:

2025-02-08T18:19:27 Dragoniez (talk | contribs | block) blocked DragoTest (talk | contribs) with an expiration time of 1 day (autoblock disabled, cannot edit own talk page) (Test)

Probably introduced by 257d6f3ba0517265471165cfdf4ba8576cc4ece8, blocking a user for a limited duration now generates a block log with an ISO timestamp, even if a relative duration (e.g. 1 day) is used for the expiry parameter of action=block.

I know it's not the main bug you're pointing out, but actually the timestamp is formatted according to your preferences. So I'm seeing e.g.:

19:45, 9 February 2025 Admin talk contribs block added a block for BlockedBob talk contribs with an expiration time of 19:45, 12 February 2025 (account creation disabled) (remove block | change block)

However, the main point is that it should say "x days" or "y months" rather than the actual expiry time — and also should it say "indefinite" or "infinity", for infinite blocks? Because that reads a bit peculiarly I think, e.g.:

2025-02-09T06:56:40 Admin talk contribs block changed block settings for BlockedBob talk contribs with an expiry time of indefinite (account creation disabled) (remove block | change block)

Change #1118260 had a related patch set uploaded (by Tim Starling; author: Tim Starling):

[mediawiki/core@master] Revert "API: Use ExpiryDef for action=block expiry parameter"

https://gerrit.wikimedia.org/r/1118260

Change #1118262 had a related patch set uploaded (by Tim Starling; author: Tim Starling):

[mediawiki/core@wmf/1.44.0-wmf.15] Revert "API: Use ExpiryDef for action=block expiry parameter"

https://gerrit.wikimedia.org/r/1118262

Change #1118260 merged by jenkins-bot:

[mediawiki/core@master] Revert "API: Use ExpiryDef for action=block expiry parameter"

https://gerrit.wikimedia.org/r/1118260

Change #1118262 merged by jenkins-bot:

[mediawiki/core@wmf/1.44.0-wmf.15] Revert "API: Use ExpiryDef for action=block expiry parameter"

https://gerrit.wikimedia.org/r/1118262

Mentioned in SAL (#wikimedia-operations) [2025-02-10T04:54:47Z] <tstarling@deploy2002> Started scap sync-world: Backport for [[gerrit:1118262|Revert "API: Use ExpiryDef for action=block expiry parameter" (T248196)]]

Mentioned in SAL (#wikimedia-operations) [2025-02-10T05:07:39Z] <tstarling@deploy2002> tstarling: Backport for [[gerrit:1118262|Revert "API: Use ExpiryDef for action=block expiry parameter" (T248196)]] synced to the testservers (https://wikitech.wikimedia.org/wiki/Mwdebug)

Mentioned in SAL (#wikimedia-operations) [2025-02-10T05:18:51Z] <tstarling@deploy2002> Finished scap sync-world: Backport for [[gerrit:1118262|Revert "API: Use ExpiryDef for action=block expiry parameter" (T248196)]] (duration: 24m 04s)

Change #983969 merged by jenkins-bot:

[mediawiki/core@master] ApiProtect: parse expiries using ExpiryDef::normalizeExpiry

https://gerrit.wikimedia.org/r/983969

Change #1118768 had a related patch set uploaded (by Tim Starling; author: Tim Starling):

[mediawiki/core@master] block: Add test for block log expiry formatting

https://gerrit.wikimedia.org/r/1118768

Change #983970 merged by jenkins-bot:

[mediawiki/core@master] ProtectionForm: parse expiries using ExpiryDef::normalizeExpiry

https://gerrit.wikimedia.org/r/983970

Change #1118768 merged by jenkins-bot:

[mediawiki/core@master] block: Add test for block log expiry formatting

https://gerrit.wikimedia.org/r/1118768

Honestly kind of would like to have both formats displayed i.e. the duration and the absolute time (to the minute resolution IMO) at which the block ends. Would save having to look back at the block issue time and then having to do math for when it will end.