diff --git a/.gitmodules b/.gitmodules index 8011d8c0460ec..a7c0d60e7e858 100644 --- a/.gitmodules +++ b/.gitmodules @@ -88,3 +88,6 @@ [submodule "apps-external/twofactor_totp"] path = apps-external/twofactor_totp url = git@github.com:nextcloud/twofactor_totp.git +[submodule "apps-external/ncw_tools"] + path = apps-external/ncw_tools + url = git@github.com:IONOS-Productivity/ncw-tools.git diff --git a/IONOS b/IONOS index 81256d62e4b76..5823634d2b872 160000 --- a/IONOS +++ b/IONOS @@ -1 +1 @@ -Subproject commit 81256d62e4b7669b6ce9fde7a80166089d76af87 +Subproject commit 5823634d2b872b8c116350bacc3ccc08836436db diff --git a/apps-external/ncw_tools b/apps-external/ncw_tools new file mode 160000 index 0000000000000..001285c22ae00 --- /dev/null +++ b/apps-external/ncw_tools @@ -0,0 +1 @@ +Subproject commit 001285c22ae0028bdcf5ac66654d8121ea472375 diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index 2c1872e23d929..96afbc078005d 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -606,6 +606,7 @@ 'OCP\\IUserManager' => $baseDir . '/lib/public/IUserManager.php', 'OCP\\IUserSession' => $baseDir . '/lib/public/IUserSession.php', 'OCP\\Image' => $baseDir . '/lib/public/Image.php', + 'OCP\\Install\\Events\\InstallationCompletedEvent' => $baseDir . '/lib/public/Install/Events/InstallationCompletedEvent.php', 'OCP\\L10N\\IFactory' => $baseDir . '/lib/public/L10N/IFactory.php', 'OCP\\L10N\\ILanguageIterator' => $baseDir . '/lib/public/L10N/ILanguageIterator.php', 'OCP\\LDAP\\IDeletionFlagSupport' => $baseDir . '/lib/public/LDAP/IDeletionFlagSupport.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index 9e843c976d56a..cab5e0e46bf8f 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -655,6 +655,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OCP\\IUserManager' => __DIR__ . '/../../..' . '/lib/public/IUserManager.php', 'OCP\\IUserSession' => __DIR__ . '/../../..' . '/lib/public/IUserSession.php', 'OCP\\Image' => __DIR__ . '/../../..' . '/lib/public/Image.php', + 'OCP\\Install\\Events\\InstallationCompletedEvent' => __DIR__ . '/../../..' . '/lib/public/Install/Events/InstallationCompletedEvent.php', 'OCP\\L10N\\IFactory' => __DIR__ . '/../../..' . '/lib/public/L10N/IFactory.php', 'OCP\\L10N\\ILanguageIterator' => __DIR__ . '/../../..' . '/lib/public/L10N/ILanguageIterator.php', 'OCP\\LDAP\\IDeletionFlagSupport' => __DIR__ . '/../../..' . '/lib/public/LDAP/IDeletionFlagSupport.php', diff --git a/lib/private/Setup.php b/lib/private/Setup.php index b4102e73b5cf5..775731fbc8c51 100644 --- a/lib/private/Setup.php +++ b/lib/private/Setup.php @@ -22,11 +22,13 @@ use OCP\AppFramework\Utility\ITimeFactory; use OCP\BackgroundJob\IJobList; use OCP\Defaults; +use OCP\EventDispatcher\IEventDispatcher; use OCP\IAppConfig; use OCP\IConfig; use OCP\IGroup; use OCP\IGroupManager; use OCP\IL10N; +use OCP\Install\Events\InstallationCompletedEvent; use OCP\IRequest; use OCP\IUserManager; use OCP\IUserSession; @@ -48,6 +50,7 @@ public function __construct( protected LoggerInterface $logger, protected ISecureRandom $random, protected Installer $installer, + protected IEventDispatcher $eventDispatcher, ) { $this->l10n = $l10nFactory->get('lib'); } @@ -408,6 +411,13 @@ public function install(array $options, ?IOutput $output = null): array { $user->setSystemEMailAddress($options['adminemail']); } + // Dispatch installation completed event + $adminUsername = !empty($username) ? $username : null; + $adminEmail = !empty($options['adminemail']) ? $options['adminemail'] : null; + $this->eventDispatcher->dispatchTyped( + new InstallationCompletedEvent($dataDir, $adminUsername, $adminEmail) + ); + return $error; } diff --git a/lib/public/Install/Events/InstallationCompletedEvent.php b/lib/public/Install/Events/InstallationCompletedEvent.php new file mode 100644 index 0000000000000..7cf75d76d6fce --- /dev/null +++ b/lib/public/Install/Events/InstallationCompletedEvent.php @@ -0,0 +1,79 @@ +dataDirectory; + } + + /** + * Get the admin username if an admin user was created + * + * @since 33.0.0 + */ + public function getAdminUsername(): ?string { + return $this->adminUsername; + } + + /** + * Get the admin email if configured + * + * @since 33.0.0 + */ + public function getAdminEmail(): ?string { + return $this->adminEmail; + } + + /** + * Check if an admin user was created during installation + * + * @since 33.0.0 + */ + public function hasAdminUser(): bool { + return $this->adminUsername !== null; + } +} diff --git a/tests/lib/Install/Events/InstallationCompletedEventTest.php b/tests/lib/Install/Events/InstallationCompletedEventTest.php new file mode 100644 index 0000000000000..3a973e008b90b --- /dev/null +++ b/tests/lib/Install/Events/InstallationCompletedEventTest.php @@ -0,0 +1,89 @@ +assertEquals($dataDir, $event->getDataDirectory()); + $this->assertEquals($adminUsername, $event->getAdminUsername()); + $this->assertEquals($adminEmail, $event->getAdminEmail()); + $this->assertTrue($event->hasAdminUser()); + } + + public function testConstructorWithMinimalParameters(): void { + $dataDir = '/path/to/data'; + + $event = new InstallationCompletedEvent($dataDir); + + $this->assertEquals($dataDir, $event->getDataDirectory()); + $this->assertNull($event->getAdminUsername()); + $this->assertNull($event->getAdminEmail()); + $this->assertFalse($event->hasAdminUser()); + } + + public function testConstructorWithUsernameOnly(): void { + $dataDir = '/path/to/data'; + $adminUsername = 'admin'; + + $event = new InstallationCompletedEvent($dataDir, $adminUsername); + + $this->assertEquals($dataDir, $event->getDataDirectory()); + $this->assertEquals($adminUsername, $event->getAdminUsername()); + $this->assertNull($event->getAdminEmail()); + $this->assertTrue($event->hasAdminUser()); + } + + public function testConstructorWithUsernameAndEmail(): void { + $dataDir = '/path/to/data'; + $adminUsername = 'admin'; + $adminEmail = 'admin@example.com'; + + $event = new InstallationCompletedEvent($dataDir, $adminUsername, $adminEmail); + + $this->assertEquals($dataDir, $event->getDataDirectory()); + $this->assertEquals($adminUsername, $event->getAdminUsername()); + $this->assertEquals($adminEmail, $event->getAdminEmail()); + $this->assertTrue($event->hasAdminUser()); + } + + public function testHasAdminUserReturnsFalseWhenUsernameIsNull(): void { + $event = new InstallationCompletedEvent('/path/to/data', null, 'admin@example.com'); + + $this->assertFalse($event->hasAdminUser()); + $this->assertNull($event->getAdminUsername()); + $this->assertEquals('admin@example.com', $event->getAdminEmail()); + } + + public function testDataDirectoryCanBeAnyString(): void { + $customPath = '/custom/data/directory'; + $event = new InstallationCompletedEvent($customPath); + + $this->assertEquals($customPath, $event->getDataDirectory()); + } + + public function testEmailCanBeSetWithoutUsername(): void { + $dataDir = '/path/to/data'; + $email = 'admin@example.com'; + + $event = new InstallationCompletedEvent($dataDir, null, $email); + + $this->assertNull($event->getAdminUsername()); + $this->assertEquals($email, $event->getAdminEmail()); + $this->assertFalse($event->hasAdminUser()); + } +} diff --git a/tests/lib/SetupTest.php b/tests/lib/SetupTest.php index b5e1b7000c339..5e7db440c0a48 100644 --- a/tests/lib/SetupTest.php +++ b/tests/lib/SetupTest.php @@ -12,6 +12,7 @@ use OC\Setup; use OC\SystemConfig; use OCP\Defaults; +use OCP\EventDispatcher\IEventDispatcher; use OCP\IL10N; use OCP\L10N\IFactory as IL10NFactory; use OCP\Security\ISecureRandom; @@ -27,6 +28,7 @@ class SetupTest extends \Test\TestCase { protected LoggerInterface $logger; protected ISecureRandom $random; protected Installer $installer; + protected IEventDispatcher $eventDispatcher; protected function setUp(): void { parent::setUp(); @@ -41,9 +43,10 @@ protected function setUp(): void { $this->logger = $this->createMock(LoggerInterface::class); $this->random = $this->createMock(ISecureRandom::class); $this->installer = $this->createMock(Installer::class); + $this->eventDispatcher = $this->createMock(IEventDispatcher::class); $this->setupClass = $this->getMockBuilder(Setup::class) ->setMethods(['class_exists', 'is_callable', 'getAvailableDbDriversForPdo']) - ->setConstructorArgs([$this->config, $this->iniWrapper, $this->l10nFactory, $this->defaults, $this->logger, $this->random, $this->installer]) + ->setConstructorArgs([$this->config, $this->iniWrapper, $this->l10nFactory, $this->defaults, $this->logger, $this->random, $this->installer, $this->eventDispatcher]) ->getMock(); }