Skip to content

Commit ab770e1

Browse files
committed
feat: improve VerifyMountPointEvent event
Signed-off-by: Robin Appelman <robin@icewind.nl>
1 parent 3425395 commit ab770e1

File tree

3 files changed

+148
-17
lines changed

3 files changed

+148
-17
lines changed

apps/files_sharing/lib/ShareTargetValidator.php

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public function verifyMountPoint(
6060
$parent = dirname($share->getTarget());
6161

6262
$recipientView = $this->getViewForUser($user);
63-
$event = new VerifyMountPointEvent($share, $recipientView, $parent);
63+
$event = new VerifyMountPointEvent($share, $recipientView, $parent, $user);
6464
$this->eventDispatcher->dispatchTyped($event);
6565
$parent = $event->getParent();
6666

@@ -78,9 +78,15 @@ public function verifyMountPoint(
7878
$this->folderExistsCache->set($parent, $parentExists);
7979
}
8080
if (!$parentExists) {
81-
$parent = Helper::getShareFolder($recipientView, $user->getUID());
82-
/** @psalm-suppress InternalMethod */
83-
$absoluteParent = $recipientView->getAbsolutePath($parent);
81+
if ($event->createParent()) {
82+
$internalPath = $parentMount->getInternalPath($absoluteParent);
83+
$parentMount->getStorage()->mkdir($internalPath);
84+
$parentMount->getStorage()->getUpdater()->update($internalPath);
85+
} else {
86+
$parent = Helper::getShareFolder($recipientView, $user->getUID());
87+
/** @psalm-suppress InternalMethod */
88+
$absoluteParent = $recipientView->getAbsolutePath($parent);
89+
}
8490
}
8591

8692
$newAbsoluteMountPoint = $this->generateUniqueTarget(
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
/**
5+
* SPDX-FileCopyrightText: 2025 Robin Appelman <robin@icewind.nl>
6+
* SPDX-License-Identifier: AGPL-3.0-or-later
7+
*/
8+
9+
namespace OCA\Files_Sharing\Tests;
10+
11+
use OC\EventDispatcher\EventDispatcher;
12+
use OC\Files\SetupManager;
13+
use OCA\Files_Sharing\ShareTargetValidator;
14+
use OCP\Constants;
15+
use OCP\EventDispatcher\IEventDispatcher;
16+
use OCP\Files\Config\ICachedMountInfo;
17+
use OCP\Files\Mount\IMountManager;
18+
use OCP\IUser;
19+
use OCP\Server;
20+
use OCP\Share\Events\VerifyMountPointEvent;
21+
use OCP\Share\IManager;
22+
use OCP\Share\IShare;
23+
use Psr\Container\ContainerInterface;
24+
use Psr\Log\LoggerInterface;
25+
use Symfony\Component\EventDispatcher\EventDispatcher as SymfonyEventDispatcher;
26+
27+
#[\PHPUnit\Framework\Attributes\Group('DB')]
28+
class ShareTargetValidatorTest extends TestCase {
29+
private IEventDispatcher $eventDispatcher;
30+
private ShareTargetValidator $targetValidator;
31+
32+
private IUser $user2;
33+
protected string $folder2;
34+
35+
protected function setUp(): void {
36+
parent::setUp();
37+
38+
$this->folder = '/folder_share_storage_test';
39+
$this->folder2 = '/folder_share_storage_test2';
40+
41+
$this->filename = '/share-api-storage.txt';
42+
43+
44+
$this->view->mkdir($this->folder);
45+
$this->view->mkdir($this->folder2);
46+
47+
// save file with content
48+
$this->view->file_put_contents($this->filename, 'root file');
49+
$this->view->file_put_contents($this->folder . $this->filename, 'file in subfolder');
50+
$this->view->file_put_contents($this->folder2 . $this->filename, 'file in subfolder2');
51+
52+
$this->eventDispatcher = new EventDispatcher(
53+
new SymfonyEventDispatcher(),
54+
Server::get(ContainerInterface::class),
55+
$this->createMock(LoggerInterface::class),
56+
);
57+
$this->targetValidator = new ShareTargetValidator(
58+
Server::get(IManager::class),
59+
$this->eventDispatcher,
60+
Server::get(SetupManager::class),
61+
Server::get(IMountManager::class),
62+
);
63+
$this->user2 = $this->createMock(IUser::class);
64+
$this->user2->method('getUID')
65+
->willReturn(self::TEST_FILES_SHARING_API_USER2);
66+
}
67+
68+
/**
69+
* test if the parent folder is created if asked for
70+
*/
71+
public function testShareMountCreateParentFolder(): void {
72+
// share to user
73+
$share = $this->share(
74+
IShare::TYPE_USER,
75+
$this->folder,
76+
self::TEST_FILES_SHARING_API_USER1,
77+
self::TEST_FILES_SHARING_API_USER2,
78+
Constants::PERMISSION_ALL);
79+
$this->shareManager->acceptShare($share, self::TEST_FILES_SHARING_API_USER2);
80+
81+
$share->setTarget('/foo/bar' . $this->folder);
82+
$this->shareManager->moveShare($share, self::TEST_FILES_SHARING_API_USER2);
83+
84+
$share = $this->shareManager->getShareById($share->getFullId());
85+
$this->assertSame('/foo/bar' . $this->folder, $share->getTarget());
86+
87+
$this->eventDispatcher->addListener(VerifyMountPointEvent::class, function (VerifyMountPointEvent $event) {
88+
$event->setCreateParent(true);
89+
});
90+
$this->targetValidator->verifyMountPoint($this->user2, $share, [], [$share]);
91+
92+
$share = $this->shareManager->getShareById($share->getFullId());
93+
$this->assertSame('/foo/bar' . $this->folder, $share->getTarget());
94+
$userFolder = $this->rootFolder->getUserFolder(self::TEST_FILES_SHARING_API_USER2);
95+
$this->assertTrue($userFolder->nodeExists('/foo/bar'));
96+
97+
//cleanup
98+
self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
99+
$this->shareManager->deleteShare($share);
100+
$this->view->unlink($this->folder);
101+
}
102+
}

lib/public/Share/Events/VerifyMountPointEvent.php

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,30 +10,25 @@
1010

1111
use OC\Files\View;
1212
use OCP\EventDispatcher\Event;
13+
use OCP\IUser;
1314
use OCP\Share\IShare;
1415

1516
/**
1617
* @since 19.0.0
1718
*/
1819
class VerifyMountPointEvent extends Event {
19-
/** @var IShare */
20-
private $share;
21-
/** @var View */
22-
private $view;
23-
/** @var string */
24-
private $parent;
20+
private bool $createParent = false;
2521

2622
/**
2723
* @since 19.0.0
2824
*/
29-
public function __construct(IShare $share,
30-
View $view,
31-
string $parent) {
25+
public function __construct(
26+
private readonly IShare $share,
27+
private readonly View $view,
28+
private string $parent,
29+
private readonly IUser $user,
30+
) {
3231
parent::__construct();
33-
34-
$this->share = $share;
35-
$this->view = $view;
36-
$this->parent = $parent;
3732
}
3833

3934
/**
@@ -51,6 +46,8 @@ public function getView(): View {
5146
}
5247

5348
/**
49+
* The parent folder where the share is placed, as relative path to the users home directory.
50+
*
5451
* @since 19.0.0
5552
*/
5653
public function getParent(): string {
@@ -63,4 +60,30 @@ public function getParent(): string {
6360
public function setParent(string $parent): void {
6461
$this->parent = $parent;
6562
}
63+
64+
/**
65+
* @since 33.0.3
66+
*/
67+
public function setCreateParent(bool $create): void {
68+
$this->createParent = $create;
69+
}
70+
71+
/**
72+
* Whether the parent folder should be created if missing.
73+
*
74+
* If set for `false` (the default), and the parent folder doesn't exist already,
75+
* the share will be moved to the default share folder instead.
76+
*
77+
* @since 33.0.3
78+
*/
79+
public function createParent(): bool {
80+
return $this->createParent;
81+
}
82+
83+
/**
84+
* @since 33.0.3
85+
*/
86+
public function getUser(): IUser {
87+
return $this->user;
88+
}
6689
}

0 commit comments

Comments
 (0)