135 lines
3.6 KiB
PHP
135 lines
3.6 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
namespace MediaWiki\User\Options;
|
||
|
|
|
||
|
|
use InvalidArgumentException;
|
||
|
|
use MediaWiki\Config\ServiceOptions;
|
||
|
|
use MediaWiki\MainConfigNames;
|
||
|
|
use MediaWiki\User\Registration\UserRegistrationLookup;
|
||
|
|
use MediaWiki\User\UserIdentity;
|
||
|
|
use Wikimedia\Timestamp\ConvertibleTimestamp;
|
||
|
|
|
||
|
|
class ConditionalDefaultsLookup {
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @internal Exposed for ServiceWiring only
|
||
|
|
*/
|
||
|
|
public const CONSTRUCTOR_OPTIONS = [
|
||
|
|
MainConfigNames::ConditionalUserOptions,
|
||
|
|
];
|
||
|
|
|
||
|
|
private ServiceOptions $options;
|
||
|
|
private UserRegistrationLookup $userRegistrationLookup;
|
||
|
|
|
||
|
|
public function __construct(
|
||
|
|
ServiceOptions $options,
|
||
|
|
UserRegistrationLookup $userRegistrationLookup
|
||
|
|
) {
|
||
|
|
$options->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS );
|
||
|
|
|
||
|
|
$this->options = $options;
|
||
|
|
$this->userRegistrationLookup = $userRegistrationLookup;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Does the option support conditional defaults?
|
||
|
|
*
|
||
|
|
* @param string $option
|
||
|
|
* @return bool
|
||
|
|
*/
|
||
|
|
public function hasConditionalDefault( string $option ): bool {
|
||
|
|
return array_key_exists(
|
||
|
|
$option,
|
||
|
|
$this->options->get( MainConfigNames::ConditionalUserOptions )
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get all conditionally default user options
|
||
|
|
*
|
||
|
|
* @return string[]
|
||
|
|
*/
|
||
|
|
public function getConditionallyDefaultOptions(): array {
|
||
|
|
return array_keys(
|
||
|
|
$this->options->get( MainConfigNames::ConditionalUserOptions )
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get the conditional default for user and option
|
||
|
|
*
|
||
|
|
* @param string $optionName
|
||
|
|
* @param UserIdentity $userIdentity
|
||
|
|
* @return mixed|null The default value if set, or null if it cannot be determined
|
||
|
|
* conditionally (default from DefaultOptionsLookup should be used in that case).
|
||
|
|
*/
|
||
|
|
public function getOptionDefaultForUser(
|
||
|
|
string $optionName,
|
||
|
|
UserIdentity $userIdentity
|
||
|
|
) {
|
||
|
|
$conditionalDefaults = $this->options
|
||
|
|
->get( MainConfigNames::ConditionalUserOptions )[$optionName] ?? [];
|
||
|
|
foreach ( $conditionalDefaults as $conditionalDefault ) {
|
||
|
|
// At the zeroth index of the conditional case, the intended value is found; the rest
|
||
|
|
// of the array are conditions, which are evaluated in checkConditionsForUser().
|
||
|
|
$value = array_shift( $conditionalDefault );
|
||
|
|
if ( $this->checkConditionsForUser( $userIdentity, $conditionalDefault ) ) {
|
||
|
|
return $value;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Are ALL conditions satisfied for the given user?
|
||
|
|
*
|
||
|
|
* @param UserIdentity $userIdentity
|
||
|
|
* @param array $conditions
|
||
|
|
* @return bool
|
||
|
|
*/
|
||
|
|
private function checkConditionsForUser( UserIdentity $userIdentity, array $conditions ): bool {
|
||
|
|
foreach ( $conditions as $condition ) {
|
||
|
|
if ( !$this->checkConditionForUser( $userIdentity, $condition ) ) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Is ONE condition satisfied for the given user?
|
||
|
|
*
|
||
|
|
* @param UserIdentity $userIdentity
|
||
|
|
* @param array|int $cond Either [ CUDCOND_*, args ] or CUDCOND_*, depending on whether the
|
||
|
|
* condition has any arguments.
|
||
|
|
* @return bool
|
||
|
|
*/
|
||
|
|
private function checkConditionForUser(
|
||
|
|
UserIdentity $userIdentity,
|
||
|
|
$cond
|
||
|
|
): bool {
|
||
|
|
if ( !is_array( $cond ) ) {
|
||
|
|
$cond = [ $cond ];
|
||
|
|
}
|
||
|
|
if ( $cond === [] ) {
|
||
|
|
throw new InvalidArgumentException( 'Empty condition' );
|
||
|
|
}
|
||
|
|
$condName = array_shift( $cond );
|
||
|
|
switch ( $condName ) {
|
||
|
|
case CUDCOND_AFTER:
|
||
|
|
$registration = $this->userRegistrationLookup->getRegistration( $userIdentity );
|
||
|
|
if ( $registration === null || $registration === false ) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
return (
|
||
|
|
(int)ConvertibleTimestamp::convert( TS_UNIX, $registration ) -
|
||
|
|
(int)ConvertibleTimestamp::convert( TS_UNIX, $cond[0] )
|
||
|
|
) > 0;
|
||
|
|
default:
|
||
|
|
throw new InvalidArgumentException( 'Unsupported condition ' . $condName );
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|