From a047c14805dcbe9fc23d7846c289a7ea32c4c3be Mon Sep 17 00:00:00 2001 From: Carl Schwan Date: Mon, 13 Mar 2023 18:46:30 +0100 Subject: [PATCH] Introduce user id assigned typed events for LDAP usage Based on work from https://github.com/nextcloud/server/pull/32019 Signed-off-by: Thomas Citharel --- apps/user_ldap/ajax/clearMappings.php | 14 +- apps/user_ldap/lib/Access.php | 47 ++-- apps/user_ldap/lib/AccessFactory.php | 9 +- apps/user_ldap/lib/Jobs/Sync.php | 219 +++++++----------- apps/user_ldap/tests/AccessTest.php | 50 ++-- apps/user_ldap/tests/Jobs/SyncTest.php | 72 +++--- lib/composer/composer/autoload_classmap.php | 3 + lib/composer/composer/autoload_static.php | 3 + .../Events/BeforeUserIdUnassignedEvent.php | 49 ++++ .../User/Events/UserIdAssignedEvent.php | 49 ++++ .../User/Events/UserIdUnassignedEvent.php | 49 ++++ 11 files changed, 341 insertions(+), 223 deletions(-) create mode 100644 lib/public/User/Events/BeforeUserIdUnassignedEvent.php create mode 100644 lib/public/User/Events/UserIdAssignedEvent.php create mode 100644 lib/public/User/Events/UserIdUnassignedEvent.php diff --git a/apps/user_ldap/ajax/clearMappings.php b/apps/user_ldap/ajax/clearMappings.php index f8469cc85b11c..fec36890b9932 100644 --- a/apps/user_ldap/ajax/clearMappings.php +++ b/apps/user_ldap/ajax/clearMappings.php @@ -25,6 +25,10 @@ */ use OCA\User_LDAP\Mapping\UserMapping; use OCA\User_LDAP\Mapping\GroupMapping; +use OCP\EventDispatcher\IEventDispatcher; +use OCP\Server; +use OCP\User\Events\BeforeUserIdUnassignedEvent; +use OCP\User\Events\UserIdUnassignedEvent; // Check user and app status \OC_JSON::checkAdminUser(); @@ -35,12 +39,16 @@ $mapping = null; try { if ($subject === 'user') { - $mapping = \OCP\Server::get(UserMapping::class); + $mapping = Server::get(UserMapping::class); + /** @var IEventDispatcher $dispatcher */ + $dispatcher = Server::get(IEventDispatcher::class); $result = $mapping->clearCb( - function ($uid) { + function (string $uid) use ($dispatcher): void { + $dispatcher->dispatchTyped(new BeforeUserIdUnassignedEvent($uid)); \OC::$server->getUserManager()->emit('\OC\User', 'preUnassignedUserId', [$uid]); }, - function ($uid) { + function (string $uid) use ($dispatcher): void { + $dispatcher->dispatchTyped(new UserIdUnassignedEvent($uid)); \OC::$server->getUserManager()->emit('\OC\User', 'postUnassignedUserId', [$uid]); } ); diff --git a/apps/user_ldap/lib/Access.php b/apps/user_ldap/lib/Access.php index 9a97a28c376cc..ee6c492f7af05 100644 --- a/apps/user_ldap/lib/Access.php +++ b/apps/user_ldap/lib/Access.php @@ -54,6 +54,8 @@ use OCA\User_LDAP\Mapping\AbstractMapping; use OCA\User_LDAP\User\Manager; use OCA\User_LDAP\User\OfflineUser; +use OCP\EventDispatcher\IEventDispatcher; +use OCP\User\Events\UserIdAssignedEvent; use OCP\HintException; use OCP\IConfig; use OCP\IUserManager; @@ -69,32 +71,18 @@ class Access extends LDAPUtility { public const UUID_ATTRIBUTES = ['entryuuid', 'nsuniqueid', 'objectguid', 'guid', 'ipauniqueid']; - /** @var \OCA\User_LDAP\Connection */ - public $connection; - /** @var Manager */ - public $userManager; - /** - * never ever check this var directly, always use getPagedSearchResultState - * @var ?bool - */ - protected $pagedSearchedSuccessful; - - /** @var ?AbstractMapping */ - protected $userMapper; - - /** @var ?AbstractMapping */ - protected $groupMapper; - - /** - * @var \OCA\User_LDAP\Helper - */ - private $helper; - /** @var IConfig */ - private $config; - /** @var IUserManager */ - private $ncUserManager; - /** @var LoggerInterface */ - private $logger; + public Connection $connection; + public Manager $userManager; + /** never ever check this var directly, always use getPagedSearchResultState */ + protected ?bool $pagedSearchedSuccessful; + protected ?AbstractMapping $userMapper; + protected ?AbstractMapping $groupMapper; + + private Helper $helper; + private IConfig $config; + private IUserManager $ncUserManager; + private LoggerInterface $logger; + private IEventDispatcher $dispatcher; private string $lastCookie = ''; public function __construct( @@ -104,7 +92,8 @@ public function __construct( Helper $helper, IConfig $config, IUserManager $ncUserManager, - LoggerInterface $logger + LoggerInterface $logger, + IEventDispatcher $dispatcher ) { parent::__construct($ldap); $this->connection = $connection; @@ -114,6 +103,7 @@ public function __construct( $this->config = $config; $this->ncUserManager = $ncUserManager; $this->logger = $logger; + $this->dispatcher = $dispatcher; } /** @@ -616,6 +606,9 @@ public function mapAndAnnounceIfApplicable( bool $isUser ): bool { if ($mapper->map($fdn, $name, $uuid)) { + if ($isUser) { + $this->dispatcher->dispatchTyped(new UserIdAssignedEvent($name)); + } if ($this->ncUserManager instanceof PublicEmitter && $isUser) { $this->cacheUserExists($name); $this->ncUserManager->emit('\OC\User', 'assignedUserId', [$name]); diff --git a/apps/user_ldap/lib/AccessFactory.php b/apps/user_ldap/lib/AccessFactory.php index f0820f1444fa2..8b0964a5cc023 100644 --- a/apps/user_ldap/lib/AccessFactory.php +++ b/apps/user_ldap/lib/AccessFactory.php @@ -24,6 +24,7 @@ namespace OCA\User_LDAP; use OCA\User_LDAP\User\Manager; +use OCP\EventDispatcher\IEventDispatcher; use OCP\IConfig; use OCP\IUserManager; use Psr\Log\LoggerInterface; @@ -35,6 +36,7 @@ class AccessFactory { private IConfig $config; private IUserManager $ncUserManager; private LoggerInterface $logger; + private IEventDispatcher $dispatcher; public function __construct( ILDAPWrapper $ldap, @@ -42,13 +44,15 @@ public function __construct( Helper $helper, IConfig $config, IUserManager $ncUserManager, - LoggerInterface $logger) { + LoggerInterface $logger, + IEventDispatcher $dispatcher) { $this->ldap = $ldap; $this->userManager = $userManager; $this->helper = $helper; $this->config = $config; $this->ncUserManager = $ncUserManager; $this->logger = $logger; + $this->dispatcher = $dispatcher; } public function get(Connection $connection): Access { @@ -59,7 +63,8 @@ public function get(Connection $connection): Access { $this->helper, $this->config, $this->ncUserManager, - $this->logger + $this->logger, + $this->dispatcher ); } } diff --git a/apps/user_ldap/lib/Jobs/Sync.php b/apps/user_ldap/lib/Jobs/Sync.php index 1ba24af5399b6..dcc706624180c 100644 --- a/apps/user_ldap/lib/Jobs/Sync.php +++ b/apps/user_ldap/lib/Jobs/Sync.php @@ -5,6 +5,7 @@ * @author Arthur Schiwon * @author Christoph Wurst * @author Joas Schilling + * @author Carl Schwan * * @license GNU AGPL version 3 or any later version * @@ -34,6 +35,7 @@ use OCA\User_LDAP\User\Manager; use OCP\AppFramework\Utility\ITimeFactory; use OCP\BackgroundJob\TimedJob; +use OCP\EventDispatcher\IEventDispatcher; use OCP\IAvatarManager; use OCP\IConfig; use OCP\IDBConnection; @@ -44,47 +46,72 @@ class Sync extends TimedJob { public const MAX_INTERVAL = 12 * 60 * 60; // 12h public const MIN_INTERVAL = 30 * 60; // 30min - /** @var Helper */ - protected $ldapHelper; - /** @var LDAP */ - protected $ldap; - /** @var Manager */ - protected $userManager; - /** @var UserMapping */ - protected $mapper; - /** @var IConfig */ - protected $config; - /** @var IAvatarManager */ - protected $avatarManager; - /** @var IDBConnection */ - protected $dbc; - /** @var IUserManager */ - protected $ncUserManager; - /** @var LoggerInterface */ - protected $logger; - /** @var IManager */ - protected $notificationManager; - /** @var ConnectionFactory */ - protected $connectionFactory; - /** @var AccessFactory */ - protected $accessFactory; - - public function __construct(Manager $userManager, ITimeFactory $time) { - parent::__construct($time); + protected Helper $ldapHelper; + protected LDAP $ldap; + protected Manager $userManager; + protected UserMapping $mapper; + protected IConfig $config; + protected IAvatarManager $avatarManager; + protected IDBConnection $dbc; + protected IUserManager $ncUserManager; + protected LoggerInterface $logger; + protected IManager $notificationManager; + protected ConnectionFactory $connectionFactory; + protected AccessFactory $accessFactory; + protected IEventDispatcher $dispatcher; + + public function __construct( + Manager $userManager, + IEventDispatcher $dispatcher, + IConfig $config, + ITimeFactory $timeFactory, + IDBConnection $dbConnection, + IAvatarManager $avatarManager, + IUserManager $ncUserManager, + LoggerInterface $logger, + IManager $notificationManager, + UserMapping $userMapping, + Helper $ldapHelper, + ConnectionFactory $connectionFactory + ) { + parent::__construct($timeFactory); $this->userManager = $userManager; + $this->config = $config; + $this->dispatcher = $dispatcher; + $this->setInterval( - (int)\OC::$server->getConfig()->getAppValue( + (int) $this->config->getAppValue( 'user_ldap', 'background_sync_interval', (string)self::MIN_INTERVAL ) ); + $this->ldapHelper = $ldapHelper; + $this->ldap = new LDAP($this->config->getSystemValueString('ldap_log_file')); + $this->avatarManager = $avatarManager; + $this->dbc = $dbConnection; + $this->ncUserManager = $ncUserManager; + $this->logger = $logger; + $this->userManager = $userManager; + $this->notificationManager = $notificationManager; + $this->mapper = $userMapping; + $this->connectionFactory = $connectionFactory; + + $this->accessFactory = new AccessFactory( + $this->ldap, + $this->userManager, + $this->ldapHelper, + $this->config, + $this->ncUserManager, + $this->logger, + $this->dispatcher + ); } /** - * updates the interval + * Updates the interval * - * the idea is to adjust the interval depending on the amount of known users + * The idea is to adjust the interval depending on the amount of known users * and the attempt to update each user one day. At most it would run every * 30 minutes, and at least every 12 hours. */ @@ -104,7 +131,7 @@ public function updateInterval() { * returns the smallest configured paging size * @return int */ - protected function getMinPagingSize() { + protected function getMinPagingSize(): int { $configKeys = $this->config->getAppKeys('user_ldap'); $configKeys = array_filter($configKeys, function ($key) { return strpos($key, 'ldap_paging_size') !== false; @@ -121,8 +148,6 @@ protected function getMinPagingSize() { * @param array $argument */ public function run($argument) { - $this->setArgument($argument); - $isBackgroundJobModeAjax = $this->config ->getAppValue('core', 'backgroundjobs_mode', 'ajax') === 'ajax'; if ($isBackgroundJobModeAjax) { @@ -157,10 +182,10 @@ public function run($argument) { } /** - * @param array $cycleData + * @param array{offset: int, prefix: string} $cycleData * @return bool whether more results are expected from the same configuration */ - public function runCycle($cycleData) { + public function runCycle(array $cycleData): bool { $connection = $this->connectionFactory->get($cycleData['prefix']); $access = $this->accessFactory->get($connection); $access->setUserMapper($this->mapper); @@ -185,24 +210,24 @@ public function runCycle($cycleData) { } /** - * returns the info about the current cycle that should be run, if any, + * Returns the info about the current cycle that should be run, if any, * otherwise null * * @return array|null */ - public function getCycle() { + public function getCycle(): ?array { $prefixes = $this->ldapHelper->getServerConfigurationPrefixes(true); if (count($prefixes) === 0) { return null; } $cycleData = [ - 'prefix' => $this->config->getAppValue('user_ldap', 'background_sync_prefix', null), + 'prefix' => $this->config->getAppValue('user_ldap', 'background_sync_prefix', 'none'), 'offset' => (int)$this->config->getAppValue('user_ldap', 'background_sync_offset', '0'), ]; if ( - $cycleData['prefix'] !== null + $cycleData['prefix'] !== 'none' && in_array($cycleData['prefix'], $prefixes) ) { return $cycleData; @@ -214,11 +239,11 @@ public function getCycle() { /** * Save the provided cycle information in the DB * - * @param array $cycleData + * @param array{prefix: ?string, offset: int} $cycleData */ - public function setCycle(array $cycleData) { + public function setCycle(array $cycleData): void { $this->config->setAppValue('user_ldap', 'background_sync_prefix', $cycleData['prefix']); - $this->config->setAppValue('user_ldap', 'background_sync_offset', $cycleData['offset']); + $this->config->setAppValue('user_ldap', 'background_sync_offset', (string) $cycleData['offset']); } /** @@ -226,9 +251,9 @@ public function setCycle(array $cycleData) { * null. It also always goes for the next LDAP configuration! * * @param array|null $cycleData the old cycle - * @return array|null + * @return ?array{prefix: string, offset: int} */ - public function determineNextCycle(array $cycleData = null) { + public function determineNextCycle(array $cycleData = null): ?array { $prefixes = $this->ldapHelper->getServerConfigurationPrefixes(true); if (count($prefixes) === 0) { return null; @@ -242,19 +267,18 @@ public function determineNextCycle(array $cycleData = null) { } $cycleData['prefix'] = $prefix; $cycleData['offset'] = 0; - $this->setCycle(['prefix' => $prefix, 'offset' => 0]); + $this->setCycle($cycleData); return $cycleData; } /** - * Checks whether the provided cycle should be run. Currently only the + * Checks whether the provided cycle should be run. Currently, only the * last configuration change goes into account (at least one hour). * - * @param $cycleData - * @return bool + * @param $cycleData{prefix: string} */ - public function qualifiesToRun($cycleData) { + public function qualifiesToRun(array $cycleData): bool { $lastChange = (int)$this->config->getAppValue('user_ldap', $cycleData['prefix'] . '_lastChange', '0'); if ((time() - $lastChange) > 60 * 30) { return true; @@ -263,23 +287,20 @@ public function qualifiesToRun($cycleData) { } /** - * increases the offset of the current cycle for the next run + * Increases the offset of the current cycle for the next run * - * @param $cycleData + * @param array{prefix: string, offset: int} $cycleData */ - protected function increaseOffset($cycleData) { + protected function increaseOffset(array $cycleData): void { $ldapConfig = new Configuration($cycleData['prefix']); - $cycleData['offset'] += (int)$ldapConfig->ldapPagingSize; + $cycleData['offset'] += $ldapConfig->ldapPagingSize; $this->setCycle($cycleData); } /** - * determines the next configuration prefix based on the last one (if any) - * - * @param string|null $lastPrefix - * @return string|null + * Determines the next configuration prefix based on the last one (if any) */ - protected function getNextPrefix($lastPrefix) { + protected function getNextPrefix(?string $lastPrefix): ?string { $prefixes = $this->ldapHelper->getServerConfigurationPrefixes(true); $noOfPrefixes = count($prefixes); if ($noOfPrefixes === 0) { @@ -299,84 +320,10 @@ protected function getNextPrefix($lastPrefix) { } /** - * "fixes" DI + * Only used in tests */ - public function setArgument($argument) { - if (isset($argument['config'])) { - $this->config = $argument['config']; - } else { - $this->config = \OC::$server->getConfig(); - } - - if (isset($argument['helper'])) { - $this->ldapHelper = $argument['helper']; - } else { - $this->ldapHelper = new Helper($this->config, \OC::$server->getDatabaseConnection()); - } - - if (isset($argument['ldapWrapper'])) { - $this->ldap = $argument['ldapWrapper']; - } else { - $this->ldap = new LDAP($this->config->getSystemValueString('ldap_log_file')); - } - - if (isset($argument['avatarManager'])) { - $this->avatarManager = $argument['avatarManager']; - } else { - $this->avatarManager = \OC::$server->getAvatarManager(); - } - - if (isset($argument['dbc'])) { - $this->dbc = $argument['dbc']; - } else { - $this->dbc = \OC::$server->getDatabaseConnection(); - } - - if (isset($argument['ncUserManager'])) { - $this->ncUserManager = $argument['ncUserManager']; - } else { - $this->ncUserManager = \OC::$server->getUserManager(); - } - - if (isset($argument['logger'])) { - $this->logger = $argument['logger']; - } else { - $this->logger = \OC::$server->get(LoggerInterface::class); - } - - if (isset($argument['notificationManager'])) { - $this->notificationManager = $argument['notificationManager']; - } else { - $this->notificationManager = \OC::$server->getNotificationManager(); - } - - if (isset($argument['userManager'])) { - $this->userManager = $argument['userManager']; - } - - if (isset($argument['mapper'])) { - $this->mapper = $argument['mapper']; - } else { - $this->mapper = \OCP\Server::get(UserMapping::class); - } - - if (isset($argument['connectionFactory'])) { - $this->connectionFactory = $argument['connectionFactory']; - } else { - $this->connectionFactory = new ConnectionFactory($this->ldap); - } - - if (isset($argument['accessFactory'])) { - $this->accessFactory = $argument['accessFactory']; - } else { - $this->accessFactory = new AccessFactory( - $this->ldap, - $this->userManager, - $this->ldapHelper, - $this->config, - $this->ncUserManager, - $this->logger - ); - } + public function overwritePropertiesForTest(LDAP $ldapWrapper, AccessFactory $accessFactory): void { + $this->ldap = $ldapWrapper; + $this->accessFactory = $accessFactory; } } diff --git a/apps/user_ldap/tests/AccessTest.php b/apps/user_ldap/tests/AccessTest.php index ce05839c842b2..5b7aaeab3be3a 100644 --- a/apps/user_ldap/tests/AccessTest.php +++ b/apps/user_ldap/tests/AccessTest.php @@ -44,12 +44,14 @@ use OCA\User_LDAP\User\Manager; use OCA\User_LDAP\User\OfflineUser; use OCA\User_LDAP\User\User; +use OCP\EventDispatcher\IEventDispatcher; use OCP\IAvatarManager; use OCP\IConfig; use OCP\Image; use OCP\IUserManager; use OCP\Notification\IManager as INotificationManager; use OCP\Share\IManager; +use PHPUnit\Framework\MockObject\MockObject; use Psr\Log\LoggerInterface; use Test\TestCase; @@ -61,28 +63,29 @@ * @package OCA\User_LDAP\Tests */ class AccessTest extends TestCase { - /** @var UserMapping|\PHPUnit\Framework\MockObject\MockObject */ + /** @var UserMapping|MockObject */ protected $userMapper; - /** @var IManager|\PHPUnit\Framework\MockObject\MockObject */ + /** @var IManager|MockObject */ protected $shareManager; - /** @var GroupMapping|\PHPUnit\Framework\MockObject\MockObject */ + /** @var GroupMapping|MockObject */ protected $groupMapper; - /** @var Connection|\PHPUnit\Framework\MockObject\MockObject */ + /** @var Connection|MockObject */ private $connection; - /** @var LDAP|\PHPUnit\Framework\MockObject\MockObject */ + /** @var LDAP|MockObject */ private $ldap; - /** @var Manager|\PHPUnit\Framework\MockObject\MockObject */ + /** @var Manager|MockObject */ private $userManager; - /** @var Helper|\PHPUnit\Framework\MockObject\MockObject */ + /** @var Helper|MockObject */ private $helper; - /** @var IConfig|\PHPUnit\Framework\MockObject\MockObject */ + /** @var IConfig|MockObject */ private $config; - /** @var IUserManager|\PHPUnit\Framework\MockObject\MockObject */ + /** @var IUserManager|MockObject */ private $ncUserManager; /** @var LoggerInterface|MockObject */ private $logger; - /** @var Access */ - private $access; + /** @var IEventDispatcher|MockObject */ + private $dispatcher; + private Access $access; protected function setUp(): void { $this->connection = $this->createMock(Connection::class); @@ -95,6 +98,7 @@ protected function setUp(): void { $this->ncUserManager = $this->createMock(IUserManager::class); $this->shareManager = $this->createMock(IManager::class); $this->logger = $this->createMock(LoggerInterface::class); + $this->dispatcher = $this->createMock(IEventDispatcher::class); $this->access = new Access( $this->connection, @@ -103,8 +107,10 @@ protected function setUp(): void { $this->helper, $this->config, $this->ncUserManager, - $this->logger + $this->logger, + $this->dispatcher ); + $this->dispatcher->expects($this->any())->method('dispatchTyped'); $this->access->setUserMapper($this->userMapper); $this->access->setGroupMapper($this->groupMapper); } @@ -241,9 +247,9 @@ public function dnInputDataProvider() { */ public function testStringResemblesDN($case) { [$lw, $con, $um, $helper] = $this->getConnectorAndLdapMock(); - /** @var IConfig|\PHPUnit\Framework\MockObject\MockObject $config */ + /** @var IConfig|MockObject $config */ $config = $this->createMock(IConfig::class); - $access = new Access($con, $lw, $um, $helper, $config, $this->ncUserManager, $this->logger); + $access = new Access($con, $lw, $um, $helper, $config, $this->ncUserManager, $this->logger, $this->dispatcher); $lw->expects($this->exactly(1)) ->method('explodeDN') @@ -263,10 +269,10 @@ public function testStringResemblesDN($case) { */ public function testStringResemblesDNLDAPmod($case) { [, $con, $um, $helper] = $this->getConnectorAndLdapMock(); - /** @var IConfig|\PHPUnit\Framework\MockObject\MockObject $config */ + /** @var IConfig|MockObject $config */ $config = $this->createMock(IConfig::class); $lw = new LDAP(); - $access = new Access($con, $lw, $um, $helper, $config, $this->ncUserManager, $this->logger); + $access = new Access($con, $lw, $um, $helper, $config, $this->ncUserManager, $this->logger, $this->dispatcher); if (!function_exists('ldap_explode_dn')) { $this->markTestSkipped('LDAP Module not available'); @@ -291,7 +297,7 @@ public function testBatchApplyUserAttributes() { ->method('getAttributes') ->willReturn(['displayname' => ['bar', 'count' => 1]]); - /** @var UserMapping|\PHPUnit\Framework\MockObject\MockObject $mapperMock */ + /** @var UserMapping|MockObject $mapperMock */ $mapperMock = $this->createMock(UserMapping::class); $mapperMock->expects($this->any()) ->method('getNameByDN') @@ -336,7 +342,7 @@ public function testBatchApplyUserAttributes() { } public function testBatchApplyUserAttributesSkipped() { - /** @var UserMapping|\PHPUnit\Framework\MockObject\MockObject $mapperMock */ + /** @var UserMapping|MockObject $mapperMock */ $mapperMock = $this->createMock(UserMapping::class); $mapperMock->expects($this->any()) ->method('getNameByDN') @@ -377,7 +383,7 @@ public function testBatchApplyUserAttributesSkipped() { } public function testBatchApplyUserAttributesDontSkip() { - /** @var UserMapping|\PHPUnit\Framework\MockObject\MockObject $mapperMock */ + /** @var UserMapping|MockObject $mapperMock */ $mapperMock = $this->createMock(UserMapping::class); $mapperMock->expects($this->any()) ->method('getNameByDN') @@ -433,7 +439,7 @@ public function dNAttributeProvider() { */ public function testSanitizeDN($attribute) { [$lw, $con, $um, $helper] = $this->getConnectorAndLdapMock(); - /** @var IConfig|\PHPUnit\Framework\MockObject\MockObject $config */ + /** @var IConfig|MockObject $config */ $config = $this->createMock(IConfig::class); $dnFromServer = 'cn=Mixed Cases,ou=Are Sufficient To,ou=Test,dc=example,dc=org'; @@ -447,7 +453,7 @@ public function testSanitizeDN($attribute) { $attribute => ['count' => 1, $dnFromServer] ]); - $access = new Access($con, $lw, $um, $helper, $config, $this->ncUserManager, $this->logger); + $access = new Access($con, $lw, $um, $helper, $config, $this->ncUserManager, $this->logger, $this->dispatcher); $values = $access->readAttribute('uid=whoever,dc=example,dc=org', $attribute); $this->assertSame($values[0], strtolower($dnFromServer)); } @@ -763,7 +769,7 @@ public function testUserStateUpdate() { ->with('detta') ->willReturnOnConsecutiveCalls($offlineUserMock, $regularUserMock); - /** @var UserMapping|\PHPUnit\Framework\MockObject\MockObject $mapperMock */ + /** @var UserMapping|MockObject $mapperMock */ $mapperMock = $this->createMock(UserMapping::class); $mapperMock->expects($this->any()) ->method('getNameByDN') diff --git a/apps/user_ldap/tests/Jobs/SyncTest.php b/apps/user_ldap/tests/Jobs/SyncTest.php index 8d23efb4da83a..afc4cf30acd96 100644 --- a/apps/user_ldap/tests/Jobs/SyncTest.php +++ b/apps/user_ldap/tests/Jobs/SyncTest.php @@ -35,40 +35,43 @@ use OCA\User_LDAP\Mapping\UserMapping; use OCA\User_LDAP\User\Manager; use OCP\AppFramework\Utility\ITimeFactory; +use OCP\EventDispatcher\IEventDispatcher; use OCP\IAvatarManager; use OCP\IConfig; use OCP\IDBConnection; use OCP\IUserManager; use OCP\Notification\IManager; +use OCP\Server; +use PHPUnit\Framework\MockObject\MockObject; +use Psr\Log\LoggerInterface; use Test\TestCase; class SyncTest extends TestCase { /** @var array */ protected $arguments; - /** @var Helper|\PHPUnit\Framework\MockObject\MockObject */ + /** @var Helper|MockObject */ protected $helper; - /** @var LDAP|\PHPUnit\Framework\MockObject\MockObject */ + /** @var LDAP|MockObject */ protected $ldapWrapper; - /** @var Manager|\PHPUnit\Framework\MockObject\MockObject */ + /** @var Manager|MockObject */ protected $userManager; - /** @var UserMapping|\PHPUnit\Framework\MockObject\MockObject */ + /** @var UserMapping|MockObject */ protected $mapper; - /** @var Sync */ - protected $sync; - /** @var IConfig|\PHPUnit\Framework\MockObject\MockObject */ + protected Sync $sync; + /** @var IConfig|MockObject */ protected $config; - /** @var IAvatarManager|\PHPUnit\Framework\MockObject\MockObject */ + /** @var IAvatarManager|MockObject */ protected $avatarManager; - /** @var IDBConnection|\PHPUnit\Framework\MockObject\MockObject */ + /** @var IDBConnection|MockObject */ protected $dbc; - /** @var IUserManager|\PHPUnit\Framework\MockObject\MockObject */ + /** @var IUserManager|MockObject */ protected $ncUserManager; - /** @var IManager|\PHPUnit\Framework\MockObject\MockObject */ + /** @var IManager|MockObject */ protected $notificationManager; - /** @var ConnectionFactory|\PHPUnit\Framework\MockObject\MockObject */ + /** @var ConnectionFactory|MockObject */ protected $connectionFactory; - /** @var AccessFactory|\PHPUnit\Framework\MockObject\MockObject */ + /** @var AccessFactory|MockObject */ protected $accessFactory; protected function setUp(): void { @@ -86,23 +89,26 @@ protected function setUp(): void { $this->connectionFactory = $this->createMock(ConnectionFactory::class); $this->accessFactory = $this->createMock(AccessFactory::class); - $this->arguments = [ - 'helper' => $this->helper, - 'ldapWrapper' => $this->ldapWrapper, - 'mapper' => $this->mapper, - 'config' => $this->config, - 'avatarManager' => $this->avatarManager, - 'dbc' => $this->dbc, - 'ncUserManager' => $this->ncUserManager, - 'notificationManager' => $this->notificationManager, - 'connectionFactory' => $this->connectionFactory, - 'accessFactory' => $this->accessFactory, - ]; - - $this->sync = new Sync($this->userManager, $this->createMock(ITimeFactory::class)); + $this->sync = new Sync( + $this->userManager, + Server::get(IEventDispatcher::class), + $this->config, + Server::get(ITimeFactory::class), + $this->dbc, + $this->avatarManager, + $this->ncUserManager, + Server::get(LoggerInterface::class), + $this->notificationManager, + $this->mapper, + $this->helper, + $this->connectionFactory + ); + + // FIXME + $this->sync->overwritePropertiesForTest($this->ldapWrapper, $this->accessFactory); } - public function intervalDataProvider() { + public function intervalDataProvider(): array { return [ [ 0, 1000, 750 @@ -125,7 +131,7 @@ public function intervalDataProvider() { /** * @dataProvider intervalDataProvider */ - public function testUpdateInterval($userCount, $pagingSize1, $pagingSize2) { + public function testUpdateInterval(int $userCount, int $pagingSize1, int $pagingSize2): void { $this->config->expects($this->once()) ->method('setAppValue') ->with('user_ldap', 'background_sync_interval', $this->anything()) @@ -182,7 +188,7 @@ public function testMoreResults($pagingSize, $results, $expected) { return null; }); - /** @var Access|\PHPUnit\Framework\MockObject\MockObject $access */ + /** @var Access|MockObject $access */ $access = $this->createMock(Access::class); $this->accessFactory->expects($this->any()) ->method('get') @@ -252,7 +258,7 @@ public function testDetermineNextCycle($cycleData, $prefixes, $expectedCycle) { } } - public function testQualifiesToRun() { + public function testQualifiesToRun(): void { $cycleData = ['prefix' => 's01']; $this->config->expects($this->exactly(2)) @@ -264,7 +270,7 @@ public function testQualifiesToRun() { $this->assertFalse($this->sync->qualifiesToRun($cycleData)); } - public function runDataProvider() { + public function runDataProvider(): array { return [ #0 - one LDAP server, reset [[ @@ -356,7 +362,7 @@ public function testRun($runData) { return null; }); - /** @var Access|\PHPUnit\Framework\MockObject\MockObject $access */ + /** @var Access|MockObject $access */ $access = $this->createMock(Access::class); $this->accessFactory->expects($this->any()) ->method('get') diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index d017628727c0d..aa8e7bdb59f2b 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -646,6 +646,7 @@ 'OCP\\User\\Events\\BeforePasswordUpdatedEvent' => $baseDir . '/lib/public/User/Events/BeforePasswordUpdatedEvent.php', 'OCP\\User\\Events\\BeforeUserCreatedEvent' => $baseDir . '/lib/public/User/Events/BeforeUserCreatedEvent.php', 'OCP\\User\\Events\\BeforeUserDeletedEvent' => $baseDir . '/lib/public/User/Events/BeforeUserDeletedEvent.php', + 'OCP\\User\\Events\\BeforeUserIdUnassignedEvent' => $baseDir . '/lib/public/User/Events/BeforeUserIdUnassignedEvent.php', 'OCP\\User\\Events\\BeforeUserLoggedInEvent' => $baseDir . '/lib/public/User/Events/BeforeUserLoggedInEvent.php', 'OCP\\User\\Events\\BeforeUserLoggedInWithCookieEvent' => $baseDir . '/lib/public/User/Events/BeforeUserLoggedInWithCookieEvent.php', 'OCP\\User\\Events\\BeforeUserLoggedOutEvent' => $baseDir . '/lib/public/User/Events/BeforeUserLoggedOutEvent.php', @@ -654,6 +655,8 @@ 'OCP\\User\\Events\\UserChangedEvent' => $baseDir . '/lib/public/User/Events/UserChangedEvent.php', 'OCP\\User\\Events\\UserCreatedEvent' => $baseDir . '/lib/public/User/Events/UserCreatedEvent.php', 'OCP\\User\\Events\\UserDeletedEvent' => $baseDir . '/lib/public/User/Events/UserDeletedEvent.php', + 'OCP\\User\\Events\\UserIdAssignedEvent' => $baseDir . '/lib/public/User/Events/UserIdAssignedEvent.php', + 'OCP\\User\\Events\\UserIdUnassignedEvent' => $baseDir . '/lib/public/User/Events/UserIdUnassignedEvent.php', 'OCP\\User\\Events\\UserLiveStatusEvent' => $baseDir . '/lib/public/User/Events/UserLiveStatusEvent.php', 'OCP\\User\\Events\\UserLoggedInEvent' => $baseDir . '/lib/public/User/Events/UserLoggedInEvent.php', 'OCP\\User\\Events\\UserLoggedInWithCookieEvent' => $baseDir . '/lib/public/User/Events/UserLoggedInWithCookieEvent.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index c1797f98ce2be..62bc4e4fd546e 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -679,6 +679,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OCP\\User\\Events\\BeforePasswordUpdatedEvent' => __DIR__ . '/../../..' . '/lib/public/User/Events/BeforePasswordUpdatedEvent.php', 'OCP\\User\\Events\\BeforeUserCreatedEvent' => __DIR__ . '/../../..' . '/lib/public/User/Events/BeforeUserCreatedEvent.php', 'OCP\\User\\Events\\BeforeUserDeletedEvent' => __DIR__ . '/../../..' . '/lib/public/User/Events/BeforeUserDeletedEvent.php', + 'OCP\\User\\Events\\BeforeUserIdUnassignedEvent' => __DIR__ . '/../../..' . '/lib/public/User/Events/BeforeUserIdUnassignedEvent.php', 'OCP\\User\\Events\\BeforeUserLoggedInEvent' => __DIR__ . '/../../..' . '/lib/public/User/Events/BeforeUserLoggedInEvent.php', 'OCP\\User\\Events\\BeforeUserLoggedInWithCookieEvent' => __DIR__ . '/../../..' . '/lib/public/User/Events/BeforeUserLoggedInWithCookieEvent.php', 'OCP\\User\\Events\\BeforeUserLoggedOutEvent' => __DIR__ . '/../../..' . '/lib/public/User/Events/BeforeUserLoggedOutEvent.php', @@ -687,6 +688,8 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OCP\\User\\Events\\UserChangedEvent' => __DIR__ . '/../../..' . '/lib/public/User/Events/UserChangedEvent.php', 'OCP\\User\\Events\\UserCreatedEvent' => __DIR__ . '/../../..' . '/lib/public/User/Events/UserCreatedEvent.php', 'OCP\\User\\Events\\UserDeletedEvent' => __DIR__ . '/../../..' . '/lib/public/User/Events/UserDeletedEvent.php', + 'OCP\\User\\Events\\UserIdAssignedEvent' => __DIR__ . '/../../..' . '/lib/public/User/Events/UserIdAssignedEvent.php', + 'OCP\\User\\Events\\UserIdUnassignedEvent' => __DIR__ . '/../../..' . '/lib/public/User/Events/UserIdUnassignedEvent.php', 'OCP\\User\\Events\\UserLiveStatusEvent' => __DIR__ . '/../../..' . '/lib/public/User/Events/UserLiveStatusEvent.php', 'OCP\\User\\Events\\UserLoggedInEvent' => __DIR__ . '/../../..' . '/lib/public/User/Events/UserLoggedInEvent.php', 'OCP\\User\\Events\\UserLoggedInWithCookieEvent' => __DIR__ . '/../../..' . '/lib/public/User/Events/UserLoggedInWithCookieEvent.php', diff --git a/lib/public/User/Events/BeforeUserIdUnassignedEvent.php b/lib/public/User/Events/BeforeUserIdUnassignedEvent.php new file mode 100644 index 0000000000000..c8de53ab84886 --- /dev/null +++ b/lib/public/User/Events/BeforeUserIdUnassignedEvent.php @@ -0,0 +1,49 @@ + + * + * @author Thomas Citharel + * + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see + * + */ +namespace OCP\User\Events; + +use OCP\EventDispatcher\Event; + +/** + * @since 27.0.0 + */ +class BeforeUserIdUnassignedEvent extends Event { + private string $userId; + + /** + * @since 27.0.0 + */ + public function __construct(string $userId) { + parent::__construct(); + $this->userId = $userId; + } + + /** + * @since 27.0.0 + */ + public function getUserId(): string { + return $this->userId; + } +} diff --git a/lib/public/User/Events/UserIdAssignedEvent.php b/lib/public/User/Events/UserIdAssignedEvent.php new file mode 100644 index 0000000000000..fc5f2ebf989a1 --- /dev/null +++ b/lib/public/User/Events/UserIdAssignedEvent.php @@ -0,0 +1,49 @@ + + * + * @author Thomas Citharel + * + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see + * + */ +namespace OCP\User\Events; + +use OCP\EventDispatcher\Event; + +/** + * @since 27.0.0 + */ +class UserIdAssignedEvent extends Event { + private string $userId; + + /** + * @since 27.0.0 + */ + public function __construct(string $userId) { + parent::__construct(); + $this->userId = $userId; + } + + /** + * @since 27.0.0 + */ + public function getUserId(): string { + return $this->userId; + } +} diff --git a/lib/public/User/Events/UserIdUnassignedEvent.php b/lib/public/User/Events/UserIdUnassignedEvent.php new file mode 100644 index 0000000000000..359f170bef8cb --- /dev/null +++ b/lib/public/User/Events/UserIdUnassignedEvent.php @@ -0,0 +1,49 @@ + + * + * @author Thomas Citharel + * + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see + * + */ +namespace OCP\User\Events; + +use OCP\EventDispatcher\Event; + +/** + * @since 27.0.0 + */ +class UserIdUnassignedEvent extends Event { + private string $userId; + + /** + * @since 27.0.0 + */ + public function __construct(string $userId) { + parent::__construct(); + $this->userId = $userId; + } + + /** + * @since 27.0.0 + */ + public function getUserId(): string { + return $this->userId; + } +}