TempUserConfig: Add getMatchPattern
Why: There are extensions that need to check a handful of users for temp-ness at once (such as GrowthExperiments). This is not really possible as of now (it would be necessary to call UserIdentityUtils::isTemp several times, which can get slow for large bulks of users). What: Add TempUserConfig::getMatchPattern() that can be used to generate a LIKE database condition. While at it, this patch also adds named() and temp() to UserSelectQueryBuilder. Bug: T341389 Change-Id: I90b5c59462c5c98bf5dcf9fa15d20553ef6599a5
This commit is contained in:
parent
7f22129e60
commit
0a2b654e55
9 changed files with 85 additions and 2 deletions
|
|
@ -255,6 +255,7 @@ return [
|
|||
new ServiceOptions( ActorStoreFactory::CONSTRUCTOR_OPTIONS, $services->getMainConfig() ),
|
||||
$services->getDBLoadBalancerFactory(),
|
||||
$services->getUserNameUtils(),
|
||||
$services->getTempUserConfig(),
|
||||
LoggerFactory::getInstance( 'ActorStore' )
|
||||
);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ use DBAccessObjectUtils;
|
|||
use ExternalUserNames;
|
||||
use InvalidArgumentException;
|
||||
use MediaWiki\DAO\WikiAwareEntity;
|
||||
use MediaWiki\User\TempUser\TempUserConfig;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use stdClass;
|
||||
use User;
|
||||
|
|
@ -52,6 +53,7 @@ class ActorStore implements UserIdentityLookup, ActorNormalization {
|
|||
|
||||
/** @var UserNameUtils */
|
||||
private $userNameUtils;
|
||||
private TempUserConfig $tempUserConfig;
|
||||
|
||||
/** @var LoggerInterface */
|
||||
private $logger;
|
||||
|
|
@ -65,12 +67,14 @@ class ActorStore implements UserIdentityLookup, ActorNormalization {
|
|||
/**
|
||||
* @param ILoadBalancer $loadBalancer
|
||||
* @param UserNameUtils $userNameUtils
|
||||
* @param TempUserConfig $tempUserConfig
|
||||
* @param LoggerInterface $logger
|
||||
* @param string|false $wikiId
|
||||
*/
|
||||
public function __construct(
|
||||
ILoadBalancer $loadBalancer,
|
||||
UserNameUtils $userNameUtils,
|
||||
TempUserConfig $tempUserConfig,
|
||||
LoggerInterface $logger,
|
||||
$wikiId = WikiAwareEntity::LOCAL
|
||||
) {
|
||||
|
|
@ -78,6 +82,7 @@ class ActorStore implements UserIdentityLookup, ActorNormalization {
|
|||
|
||||
$this->loadBalancer = $loadBalancer;
|
||||
$this->userNameUtils = $userNameUtils;
|
||||
$this->tempUserConfig = $tempUserConfig;
|
||||
$this->logger = $logger;
|
||||
$this->wikiId = $wikiId;
|
||||
|
||||
|
|
@ -718,7 +723,7 @@ class ActorStore implements UserIdentityLookup, ActorNormalization {
|
|||
[ $db, $options ] = $this->getDBConnectionRefForQueryFlags( $dbOrQueryFlags );
|
||||
}
|
||||
|
||||
return ( new UserSelectQueryBuilder( $db, $this ) )->options( $options );
|
||||
return ( new UserSelectQueryBuilder( $db, $this, $this->tempUserConfig ) )->options( $options );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ namespace MediaWiki\User;
|
|||
use MediaWiki\Config\ServiceOptions;
|
||||
use MediaWiki\DAO\WikiAwareEntity;
|
||||
use MediaWiki\MainConfigNames;
|
||||
use MediaWiki\User\TempUser\TempUserConfig;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Wikimedia\Rdbms\ILBFactory;
|
||||
use Wikimedia\Rdbms\ILoadBalancer;
|
||||
|
|
@ -46,6 +47,7 @@ class ActorStoreFactory {
|
|||
|
||||
/** @var UserNameUtils */
|
||||
private $userNameUtils;
|
||||
private TempUserConfig $tempUserConfig;
|
||||
|
||||
/** @var LoggerInterface */
|
||||
private $logger;
|
||||
|
|
@ -63,12 +65,14 @@ class ActorStoreFactory {
|
|||
* @param ServiceOptions $options
|
||||
* @param ILBFactory $loadBalancerFactory
|
||||
* @param UserNameUtils $userNameUtils
|
||||
* @param TempUserConfig $tempUserConfig
|
||||
* @param LoggerInterface $logger
|
||||
*/
|
||||
public function __construct(
|
||||
ServiceOptions $options,
|
||||
ILBFactory $loadBalancerFactory,
|
||||
UserNameUtils $userNameUtils,
|
||||
TempUserConfig $tempUserConfig,
|
||||
LoggerInterface $logger
|
||||
) {
|
||||
$options->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS );
|
||||
|
|
@ -76,6 +80,7 @@ class ActorStoreFactory {
|
|||
$this->sharedDB = $options->get( MainConfigNames::SharedDB );
|
||||
$this->sharedTables = $options->get( MainConfigNames::SharedTables );
|
||||
$this->userNameUtils = $userNameUtils;
|
||||
$this->tempUserConfig = $tempUserConfig;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
|
|
@ -104,6 +109,7 @@ class ActorStoreFactory {
|
|||
$this->storeCache[$storeCacheKey] = new ActorStore(
|
||||
$this->getLoadBalancerForTable( 'actor', $wikiId ),
|
||||
$this->userNameUtils,
|
||||
$this->tempUserConfig,
|
||||
$this->logger,
|
||||
$wikiId
|
||||
);
|
||||
|
|
|
|||
|
|
@ -96,6 +96,14 @@ class RealTempUserConfig implements TempUserConfig {
|
|||
}
|
||||
}
|
||||
|
||||
public function getMatchPattern(): Pattern {
|
||||
if ( $this->enabled ) {
|
||||
return $this->matchPattern;
|
||||
} else {
|
||||
throw new BadMethodCallException( __METHOD__ . ' is disabled' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal For TempUserCreator only
|
||||
* @return Pattern
|
||||
|
|
|
|||
|
|
@ -65,4 +65,13 @@ interface TempUserConfig {
|
|||
* @return string
|
||||
*/
|
||||
public function getPlaceholderName(): string;
|
||||
|
||||
/**
|
||||
* Get a Pattern indicating how temporary account can be detected
|
||||
*
|
||||
* Used to avoid selecting a temp account via select queries.
|
||||
*
|
||||
* @return Pattern
|
||||
*/
|
||||
public function getMatchPattern(): Pattern;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -167,6 +167,10 @@ class TempUserCreator implements TempUserConfig {
|
|||
return $this->config->getPlaceholderName();
|
||||
}
|
||||
|
||||
public function getMatchPattern(): Pattern {
|
||||
return $this->config->getMatchPattern();
|
||||
}
|
||||
|
||||
/**
|
||||
* Acquire a new username and return it. Permanently reserve the ID in
|
||||
* the database.
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
namespace MediaWiki\User;
|
||||
|
||||
use Iterator;
|
||||
use MediaWiki\User\TempUser\TempUserConfig;
|
||||
use Wikimedia\Assert\Assert;
|
||||
use Wikimedia\Assert\PreconditionException;
|
||||
use Wikimedia\Rdbms\IReadableDatabase;
|
||||
|
|
@ -30,15 +31,23 @@ class UserSelectQueryBuilder extends SelectQueryBuilder {
|
|||
|
||||
/** @var ActorStore */
|
||||
private $actorStore;
|
||||
private TempUserConfig $tempUserConfig;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @param IReadableDatabase $db
|
||||
* @param ActorStore $actorStore
|
||||
* @param TempUserConfig $tempUserConfig
|
||||
*/
|
||||
public function __construct( IReadableDatabase $db, ActorStore $actorStore ) {
|
||||
public function __construct(
|
||||
IReadableDatabase $db,
|
||||
ActorStore $actorStore,
|
||||
TempUserConfig $tempUserConfig
|
||||
) {
|
||||
parent::__construct( $db );
|
||||
|
||||
$this->actorStore = $actorStore;
|
||||
$this->tempUserConfig = $tempUserConfig;
|
||||
$this->table( 'actor' );
|
||||
}
|
||||
|
||||
|
|
@ -161,6 +170,42 @@ class UserSelectQueryBuilder extends SelectQueryBuilder {
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Only return named users.
|
||||
*
|
||||
* @return UserSelectQueryBuilder
|
||||
*/
|
||||
public function named(): self {
|
||||
if ( !$this->tempUserConfig->isEnabled() ) {
|
||||
// nothing to do: getMatchPattern throws if temp accounts aren't enabled
|
||||
return $this;
|
||||
}
|
||||
|
||||
$this->conds( [
|
||||
'actor_name NOT ' . $this->tempUserConfig->getMatchPattern()
|
||||
->buildLike( $this->db )
|
||||
] );
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Only return temp users
|
||||
*
|
||||
* @return UserSelectQueryBuilder
|
||||
*/
|
||||
public function temp(): self {
|
||||
if ( !$this->tempUserConfig->isEnabled() ) {
|
||||
// nothing to do: getMatchPattern throws if temp accounts aren't enabled
|
||||
return $this;
|
||||
}
|
||||
|
||||
$this->conds( [
|
||||
'actor_name ' . $this->tempUserConfig->getMatchPattern()
|
||||
->buildLike( $this->db )
|
||||
] );
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter based on user hidden status
|
||||
*
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ abstract class ActorStoreTestBase extends MediaWikiIntegrationTestCase {
|
|||
$store = new ActorStore(
|
||||
$dbLoadBalancer,
|
||||
$this->getServiceContainer()->getUserNameUtils(),
|
||||
$this->getServiceContainer()->getTempUserConfig(),
|
||||
new NullLogger(),
|
||||
$wikiId
|
||||
);
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ use MediaWiki\MainConfigNames;
|
|||
use MediaWiki\User\ActorNormalization;
|
||||
use MediaWiki\User\ActorStore;
|
||||
use MediaWiki\User\ActorStoreFactory;
|
||||
use MediaWiki\User\TempUser\TempUserConfig;
|
||||
use MediaWiki\User\UserIdentityLookup;
|
||||
use MediaWiki\User\UserNameUtils;
|
||||
use MediaWikiUnitTestCase;
|
||||
|
|
@ -65,6 +66,7 @@ class ActorStoreFactoryTest extends MediaWikiUnitTestCase {
|
|||
new ServiceOptions( ActorStoreFactory::CONSTRUCTOR_OPTIONS, $config ),
|
||||
$this->getMockLoadBalancerFactory( $expectedDomain ),
|
||||
$this->createNoOpMock( UserNameUtils::class ),
|
||||
$this->createNoOpMock( TempUserConfig::class ),
|
||||
new NullLogger()
|
||||
);
|
||||
$notFromCache = $factory->getActorStore( $domain );
|
||||
|
|
@ -80,6 +82,7 @@ class ActorStoreFactoryTest extends MediaWikiUnitTestCase {
|
|||
new ServiceOptions( ActorStoreFactory::CONSTRUCTOR_OPTIONS, $config ),
|
||||
$this->getMockLoadBalancerFactory( $expectedDomain ),
|
||||
$this->createNoOpMock( UserNameUtils::class ),
|
||||
$this->createNoOpMock( TempUserConfig::class ),
|
||||
new NullLogger()
|
||||
);
|
||||
$notFromCache = $factory->getActorNormalization( $domain );
|
||||
|
|
@ -95,6 +98,7 @@ class ActorStoreFactoryTest extends MediaWikiUnitTestCase {
|
|||
new ServiceOptions( ActorStoreFactory::CONSTRUCTOR_OPTIONS, $config ),
|
||||
$this->getMockLoadBalancerFactory( $expectedDomain ),
|
||||
$this->createNoOpMock( UserNameUtils::class ),
|
||||
$this->createNoOpMock( TempUserConfig::class ),
|
||||
new NullLogger()
|
||||
);
|
||||
$notFromCache = $factory->getUserIdentityLookup( $domain );
|
||||
|
|
|
|||
Loading…
Reference in a new issue