diff --git a/.gitignore b/.gitignore index c16fdcd4183cb..5d1efb1194491 100644 --- a/.gitignore +++ b/.gitignore @@ -58,6 +58,7 @@ !/apps-external/user_oidc !/apps-external/serverinfo !/apps-external/groupquota +!/apps-external/files_downloadlimit !/apps-custom/* # apps modules diff --git a/.gitmodules b/.gitmodules index 08bfe329ab61a..626ec3a9050c4 100644 --- a/.gitmodules +++ b/.gitmodules @@ -49,3 +49,6 @@ [submodule "apps-external/richdocuments"] path = apps-external/richdocuments url = git@github.com:IONOS-Productivity/nc-richdocuments.git +[submodule "apps-external/files_downloadlimit"] + path = apps-external/files_downloadlimit + url = git@github.com:nextcloud/files_downloadlimit.git diff --git a/IONOS b/IONOS index ec73e092134c8..a92d327f4ad75 160000 --- a/IONOS +++ b/IONOS @@ -1 +1 @@ -Subproject commit ec73e092134c82807036c1e92e1979f63ead9117 +Subproject commit a92d327f4ad752e71fdb84a7816d4b7a9767a20c diff --git a/apps-custom/nc_theming b/apps-custom/nc_theming index 9792e1e1f99fd..37001717a056a 160000 --- a/apps-custom/nc_theming +++ b/apps-custom/nc_theming @@ -1 +1 @@ -Subproject commit 9792e1e1f99fde8cbfdb39fa137aa222caec3bac +Subproject commit 37001717a056a9caf12b51103821a046bb1f6573 diff --git a/apps-custom/simplesettings b/apps-custom/simplesettings index e89547d3e9081..e2ec7c701fe96 160000 --- a/apps-custom/simplesettings +++ b/apps-custom/simplesettings @@ -1 +1 @@ -Subproject commit e89547d3e90814c9b40faa59453383ee34a4b2d9 +Subproject commit e2ec7c701fe969de7dac30fd4086f42361900aff diff --git a/apps-external/files_downloadlimit b/apps-external/files_downloadlimit new file mode 160000 index 0000000000000..ae20646b6a2d4 --- /dev/null +++ b/apps-external/files_downloadlimit @@ -0,0 +1 @@ +Subproject commit ae20646b6a2d40c92d8fd362f2268b54b370b0cf diff --git a/apps/files_sharing/lib/Listener/LoadAdditionalListener.php b/apps/files_sharing/lib/Listener/LoadAdditionalListener.php index fc6516a83e2c9..1c25941376eb2 100644 --- a/apps/files_sharing/lib/Listener/LoadAdditionalListener.php +++ b/apps/files_sharing/lib/Listener/LoadAdditionalListener.php @@ -8,10 +8,12 @@ */ namespace OCA\Files_Sharing\Listener; +use OC\InitialStateService; use OCA\Files\Event\LoadAdditionalScriptsEvent; use OCA\Files_Sharing\AppInfo\Application; use OCP\EventDispatcher\Event; use OCP\EventDispatcher\IEventListener; +use OCP\IConfig; use OCP\Share\IManager; use OCP\Util; @@ -30,5 +32,14 @@ public function handle(Event $event): void { if ($shareManager->shareApiEnabled() && class_exists('\OCA\Files\App')) { Util::addInitScript(Application::APP_ID, 'init'); } + + $this->provideInitialStates(); + } + + private function provideInitialStates(): void { + $initialState = \OC::$server->get(InitialStateService::class); + $config = \OC::$server->get(IConfig::class); + $defaultAcceptSystemConfig = $config->getSystemValueBool('sharing.enable_share_accept'); + $initialState->provideInitialState(Application::APP_ID, 'accept_default', $defaultAcceptSystemConfig); } } diff --git a/apps/files_sharing/src/views/shares.ts b/apps/files_sharing/src/views/shares.ts index 7aec0dbeafb70..fd2722d1bc698 100644 --- a/apps/files_sharing/src/views/shares.ts +++ b/apps/files_sharing/src/views/shares.ts @@ -14,6 +14,7 @@ import FileUploadSvg from '@mdi/svg/svg/file-upload.svg?raw' import LinkSvg from '@mdi/svg/svg/link.svg?raw' import { getContents, isFileRequest } from '../services/SharingService' +import { loadState } from '@nextcloud/initial-state' export const sharesViewId = 'shareoverview' export const sharedWithYouViewId = 'sharingin' @@ -23,6 +24,15 @@ export const deletedSharesViewId = 'deletedshares' export const pendingSharesViewId = 'pendingshares' export const fileRequestViewId = 'filerequest' +/** + * Checks if share accept approval required by nextcloud configuration. + * + * @returns {boolean} True if share accept approval is required, otherwise false. + */ +function isShareAcceptApprovalRequired(): boolean { + return loadState('files_sharing', 'accept_default', false) +} + export default () => { const Navigation = getNavigation() Navigation.register(new View({ @@ -132,6 +142,10 @@ export default () => { getContents: () => getContents(false, false, false, true), })) + if (!isShareAcceptApprovalRequired()) { + return + } + Navigation.register(new View({ id: pendingSharesViewId, name: t('files_sharing', 'Pending shares'), diff --git a/apps/files_sharing/tests/Listener/LoadAdditionalListenerTest.php b/apps/files_sharing/tests/Listener/LoadAdditionalListenerTest.php new file mode 100644 index 0000000000000..145dfad06a098 --- /dev/null +++ b/apps/files_sharing/tests/Listener/LoadAdditionalListenerTest.php @@ -0,0 +1,140 @@ +logger = $this->createMock(LoggerInterface::class); + $this->event = $this->createMock(LoadAdditionalScriptsEvent::class); + $this->shareManager = $this->createMock(IManager::class); + $this->factory = $this->createMock(IFactory::class); + $this->initialStateService = $this->createMock(InitialStateService::class); + $this->config = $this->createMock(IConfig::class); + } + + public function testHandleIgnoresNonMatchingEvent(): void { + $listener = new LoadAdditionalListener(); + $event = $this->createMock(Event::class); + + // Should not throw or call anything + $listener->handle($event); + + $this->assertTrue(true); // No exception means pass + } + + public function testHandleWithLoadAdditionalScriptsEvent(): void { + $listener = new LoadAdditionalListener(); + + $this->shareManager->method('shareApiEnabled')->willReturn(false); + $this->factory->method('findLanguage')->willReturn('language_mock'); + $this->config->method('getSystemValueBool')->willReturn(true); + + $this->overwriteService(IManager::class, $this->shareManager); + $this->overwriteService(IFactory::class, $this->factory); + $this->overwriteService(InitialStateService::class, $this->initialStateService); + $this->overwriteService(IConfig::class, $this->config); + + $scriptsBefore = \OCP\Util::getScripts(); + $this->assertNotContains('files_sharing/l10n/language_mock', $scriptsBefore); + $this->assertNotContains('files_sharing/js/additionalScripts', $scriptsBefore); + $this->assertNotContains('files_sharing/js/init', $scriptsBefore); + $this->assertNotContains('files_sharing/css/icons', \OC_Util::$styles); + + // Util static methods can't be easily mocked, so just ensure no exceptions + $listener->handle($this->event); + + // assert array $scripts contains the expected scripts + $scriptsAfter = \OCP\Util::getScripts(); + $this->assertContains('files_sharing/l10n/language_mock', $scriptsAfter); + $this->assertContains('files_sharing/js/additionalScripts', $scriptsAfter); + $this->assertNotContains('files_sharing/js/init', $scriptsAfter); + + $this->assertContains('files_sharing/css/icons', \OC_Util::$styles); + + $this->assertTrue(true); + } + + public function testHandleWithLoadAdditionalScriptsEventWithShareApiEnabled(): void { + $listener = new LoadAdditionalListener(); + + $this->shareManager->method('shareApiEnabled')->willReturn(true); + $this->config->method('getSystemValueBool')->willReturn(true); + + $this->overwriteService(IManager::class, $this->shareManager); + $this->overwriteService(InitialStateService::class, $this->initialStateService); + $this->overwriteService(IConfig::class, $this->config); + $this->overwriteService(IFactory::class, $this->factory); + + $scriptsBefore = \OCP\Util::getScripts(); + $this->assertNotContains('files_sharing/js/init', $scriptsBefore); + + // Util static methods can't be easily mocked, so just ensure no exceptions + $listener->handle($this->event); + + $scriptsAfter = \OCP\Util::getScripts(); + + // assert array $scripts contains the expected scripts + $this->assertContains('files_sharing/js/init', $scriptsAfter); + + $this->assertTrue(true); + } + + public function testProvideInitialStates(): void { + $listener = new LoadAdditionalListener(); + + // Expect config to be queried for 'sharing.enable_share_accept' + $this->config->expects($this->once()) + ->method('getSystemValueBool') + ->with('sharing.enable_share_accept') + ->willReturn(true); + + // Expect initial state to be provided with correct values + $this->initialStateService->expects($this->once()) + ->method('provideInitialState') + ->with( + 'files_sharing', + 'accept_default', + true + ); + + // Other dependencies required by the listener + $this->shareManager->method('shareApiEnabled')->willReturn(true); + + // Mock the server container to return the correct dependencies + $this->overwriteService(IManager::class, $this->shareManager); + $this->overwriteService(InitialStateService::class, $this->initialStateService); + $this->overwriteService(IConfig::class, $this->config); + $this->overwriteService(IFactory::class, $this->factory); + + $listener->handle($this->event); + + $this->assertTrue(true); + } +}