Skip to content
Merged
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
!/apps-external/user_oidc
!/apps-external/serverinfo
!/apps-external/groupquota
!/apps-external/files_downloadlimit
!/apps-custom/*

# apps modules
Expand Down
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -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
2 changes: 1 addition & 1 deletion IONOS
Submodule IONOS updated from ec73e0 to a92d32
1 change: 1 addition & 0 deletions apps-external/files_downloadlimit
Submodule files_downloadlimit added at ae2064
11 changes: 11 additions & 0 deletions apps/files_sharing/lib/Listener/LoadAdditionalListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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);
}
}
14 changes: 14 additions & 0 deletions apps/files_sharing/src/views/shares.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand All @@ -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({
Expand Down Expand Up @@ -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'),
Expand Down
140 changes: 140 additions & 0 deletions apps/files_sharing/tests/Listener/LoadAdditionalListenerTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
<?php

declare(strict_types=1);

/**
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\Files_Sharing\Tests\Listener;

use OC\InitialStateService;
use OCA\Files\Event\LoadAdditionalScriptsEvent;
use OCA\Files_Sharing\Listener\LoadAdditionalListener;
use OCP\EventDispatcher\Event;
use OCP\IConfig;
use OCP\L10N\IFactory;
use OCP\Share\IManager;
use PHPUnit\Framework\MockObject\MockObject;
use Psr\Log\LoggerInterface;
use Test\TestCase;

class LoadAdditionalListenerTest extends TestCase {
protected LoggerInterface&MockObject $logger;
protected LoadAdditionalScriptsEvent&MockObject $event;
protected IManager&MockObject $shareManager;
protected IFactory&MockObject $factory;
protected InitialStateService&MockObject $initialStateService;
protected IConfig&MockObject $config;

protected function setUp(): void {
parent::setUp();

$this->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);
}
}
Loading