Skip to content

Commit 2b3d925

Browse files
authored
Merge pull request #3752 from nextcloud/feat/prevent-duplicate-mounts
2 parents 406f0b2 + a41aaa5 commit 2b3d925

File tree

6 files changed

+263
-37
lines changed

6 files changed

+263
-37
lines changed

lib/Command/Create.php

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,29 @@ protected function configure(): void {
2525
$this
2626
->setName('groupfolders:create')
2727
->setDescription('Create a new Team folder')
28-
->addArgument('name', InputArgument::REQUIRED, 'Name of the new folder');
28+
->addArgument('name', InputArgument::REQUIRED, 'Name or mount point of the new folder');
2929
parent::configure();
3030
}
3131

3232
protected function execute(InputInterface $input, OutputInterface $output): int {
33-
$id = $this->folderManager->createFolder($input->getArgument('name'));
33+
$name = trim($input->getArgument('name'));
34+
35+
// Check if the folder name is valid
36+
if (empty($name)) {
37+
$output->writeln('<error>Folder name cannot be empty</error>');
38+
return 1;
39+
}
40+
41+
// Check if mount point already exists
42+
$folders = $this->folderManager->getAllFolders();
43+
foreach ($folders as $folder) {
44+
if ($folder['mount_point'] === $name) {
45+
$output->writeln('<error>A Folder with the name ' . $name . ' already exists</error>');
46+
return 1;
47+
}
48+
}
49+
50+
$id = $this->folderManager->createFolder($name);
3451
$output->writeln((string)$id);
3552

3653
return 0;

lib/Command/Rename.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,28 @@ protected function execute(InputInterface $input, OutputInterface $output): int
2828
return -1;
2929
}
3030

31+
// Check if the new name is valid
32+
$name = trim($input->getArgument('name'));
33+
if (empty($name)) {
34+
$output->writeln('<error>Folder name cannot be empty</error>');
35+
return 1;
36+
}
37+
38+
// Check if the name actually changed
39+
if ($folder['mount_point'] === $name) {
40+
$output->writeln('The name is already set to ' . $name);
41+
return 0;
42+
}
43+
44+
// Check if mount point already exists
45+
$folders = $this->folderManager->getAllFolders();
46+
foreach ($folders as $existingFolder) {
47+
if ($existingFolder['mount_point'] === $name) {
48+
$output->writeln('<error>A Folder with the name ' . $name . ' already exists</error>');
49+
return 1;
50+
}
51+
}
52+
3153
$this->folderManager->renameFolder($folder['id'], $input->getArgument('name'));
3254

3355
return 0;

lib/Controller/FolderController.php

Lines changed: 53 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
2020
use OCP\AppFramework\Http\Attribute\PasswordConfirmationRequired;
2121
use OCP\AppFramework\Http\DataResponse;
22+
use OCP\AppFramework\OCS\OCSBadRequestException;
2223
use OCP\AppFramework\OCS\OCSForbiddenException;
2324
use OCP\AppFramework\OCS\OCSNotFoundException;
2425
use OCP\AppFramework\OCSController;
@@ -164,12 +165,28 @@ public function getFolder(int $id): DataResponse {
164165
private function checkFolderExists(int $id): ?DataResponse {
165166
$storageId = $this->getRootFolderStorageId();
166167
if ($storageId === null) {
167-
return new DataResponse([], Http::STATUS_NOT_FOUND);
168+
throw new OCSNotFoundException('Groupfolder not found');
168169
}
169170

170171
$folder = $this->manager->getFolder($id, $storageId);
171172
if ($folder === null) {
172-
return new DataResponse([], Http::STATUS_NOT_FOUND);
173+
throw new OCSNotFoundException('Groupfolder not found');
174+
}
175+
176+
return null;
177+
}
178+
179+
private function checkMountPointExists(string $mountpoint): ?DataResponse {
180+
$storageId = $this->getRootFolderStorageId();
181+
if ($storageId === null) {
182+
throw new OCSNotFoundException('Groupfolder not found');
183+
}
184+
185+
$folders = $this->manager->getAllFolders();
186+
foreach ($folders as $folder) {
187+
if ($folder['mount_point'] === $mountpoint) {
188+
throw new OCSBadRequestException('Mount point already exists');
189+
}
173190
}
174191

175192
return null;
@@ -185,6 +202,7 @@ private function getRootFolderStorageId(): ?int {
185202
* @param string $mountpoint Mountpoint of the new Groupfolder
186203
* @return DataResponse<Http::STATUS_OK, GroupFoldersFolder, array{}>
187204
* @throws OCSNotFoundException Groupfolder not found
205+
* @throws OCSBadRequestException Folder already exists
188206
*
189207
* 200: Groupfolder added successfully
190208
*/
@@ -193,12 +211,13 @@ private function getRootFolderStorageId(): ?int {
193211
#[NoAdminRequired]
194212
#[FrontpageRoute(verb: 'POST', url: '/folders')]
195213
public function addFolder(string $mountpoint): DataResponse {
196-
197214
$storageId = $this->rootFolder->getMountPoint()->getNumericStorageId();
198215
if ($storageId === null) {
199216
throw new OCSNotFoundException();
200217
}
201218

219+
$this->checkMountPointExists(trim($mountpoint));
220+
202221
$id = $this->manager->createFolder(trim($mountpoint));
203222
$folder = $this->manager->getFolder($id, $storageId);
204223
if ($folder === null) {
@@ -223,10 +242,7 @@ public function addFolder(string $mountpoint): DataResponse {
223242
#[NoAdminRequired]
224243
#[FrontpageRoute(verb: 'DELETE', url: '/folders/{id}')]
225244
public function removeFolder(int $id): DataResponse {
226-
$response = $this->checkFolderExists($id);
227-
if ($response) {
228-
return $response;
229-
}
245+
$this->checkFolderExists($id);
230246

231247
$folder = $this->mountProvider->getFolder($id);
232248
if ($folder === null) {
@@ -245,6 +261,8 @@ public function removeFolder(int $id): DataResponse {
245261
* @param int $id ID of the Groupfolder
246262
* @param string $mountPoint New mount point path
247263
* @return DataResponse<Http::STATUS_OK, array{success: true, folder: GroupFoldersFolder}, array{}>
264+
* @throws OCSNotFoundException Groupfolder not found
265+
* @throws OCSBadRequestException Mount point already exists
248266
*
249267
* 200: Mount point changed successfully
250268
*/
@@ -255,6 +273,9 @@ public function removeFolder(int $id): DataResponse {
255273
public function setMountPoint(int $id, string $mountPoint): DataResponse {
256274
$this->manager->renameFolder($id, trim($mountPoint));
257275

276+
$this->checkFolderExists($id);
277+
$this->checkMountPointExists(trim($mountPoint));
278+
258279
$folder = $this->manager->getFolder($id);
259280
if ($folder === null) {
260281
throw new OCSNotFoundException();
@@ -278,10 +299,7 @@ public function setMountPoint(int $id, string $mountPoint): DataResponse {
278299
#[NoAdminRequired]
279300
#[FrontpageRoute(verb: 'POST', url: '/folders/{id}/groups')]
280301
public function addGroup(int $id, string $group): DataResponse {
281-
$response = $this->checkFolderExists($id);
282-
if ($response) {
283-
return $response;
284-
}
302+
$this->checkFolderExists($id);
285303

286304
$this->manager->addApplicableGroup($id, $group);
287305

@@ -308,10 +326,7 @@ public function addGroup(int $id, string $group): DataResponse {
308326
#[NoAdminRequired]
309327
#[FrontpageRoute(verb: 'DELETE', url: '/folders/{id}/groups/{group}', requirements: ['group' => '.+'])]
310328
public function removeGroup(int $id, string $group): DataResponse {
311-
$response = $this->checkFolderExists($id);
312-
if ($response) {
313-
return $response;
314-
}
329+
$this->checkFolderExists($id);
315330

316331
$this->manager->removeApplicableGroup($id, $group);
317332

@@ -339,10 +354,7 @@ public function removeGroup(int $id, string $group): DataResponse {
339354
#[NoAdminRequired]
340355
#[FrontpageRoute(verb: 'POST', url: '/folders/{id}/groups/{group}', requirements: ['group' => '.+'])]
341356
public function setPermissions(int $id, string $group, int $permissions): DataResponse {
342-
$response = $this->checkFolderExists($id);
343-
if ($response) {
344-
return $response;
345-
}
357+
$this->checkFolderExists($id);
346358

347359
$this->manager->setGroupPermissions($id, $group, $permissions);
348360

@@ -371,10 +383,7 @@ public function setPermissions(int $id, string $group, int $permissions): DataRe
371383
#[NoAdminRequired]
372384
#[FrontpageRoute(verb: 'POST', url: '/folders/{id}/manageACL')]
373385
public function setManageACL(int $id, string $mappingType, string $mappingId, bool $manageAcl): DataResponse {
374-
$response = $this->checkFolderExists($id);
375-
if ($response) {
376-
return $response;
377-
}
386+
$this->checkFolderExists($id);
378387

379388
$this->manager->setManageACL($id, $mappingType, $mappingId, $manageAcl);
380389

@@ -401,10 +410,7 @@ public function setManageACL(int $id, string $mappingType, string $mappingId, bo
401410
#[NoAdminRequired]
402411
#[FrontpageRoute(verb: 'POST', url: '/folders/{id}/quota')]
403412
public function setQuota(int $id, int $quota): DataResponse {
404-
$response = $this->checkFolderExists($id);
405-
if ($response) {
406-
return $response;
407-
}
413+
$this->checkFolderExists($id);
408414

409415
$this->manager->setFolderQuota($id, $quota);
410416

@@ -431,10 +437,7 @@ public function setQuota(int $id, int $quota): DataResponse {
431437
#[NoAdminRequired]
432438
#[FrontpageRoute(verb: 'POST', url: '/folders/{id}/acl')]
433439
public function setACL(int $id, bool $acl): DataResponse {
434-
$response = $this->checkFolderExists($id);
435-
if ($response) {
436-
return $response;
437-
}
440+
$this->checkFolderExists($id);
438441

439442
$this->manager->setFolderACL($id, $acl);
440443

@@ -452,6 +455,8 @@ public function setACL(int $id, bool $acl): DataResponse {
452455
* @param int $id ID of the Groupfolder
453456
* @param string $mountpoint New Mountpoint of the Groupfolder
454457
* @return DataResponse<Http::STATUS_OK, array{success: true, folder: GroupFoldersFolder}, array{}>|DataResponse<Http::STATUS_NOT_FOUND, list<empty>, array{}>
458+
* @throws OCSNotFoundException Groupfolder not found
459+
* @throws OCSBadRequestException Mount point already exists or invalid mount point provided
455460
*
456461
* 200: Groupfolder renamed successfully
457462
* 404: Groupfolder not found
@@ -461,13 +466,27 @@ public function setACL(int $id, bool $acl): DataResponse {
461466
#[NoAdminRequired]
462467
#[FrontpageRoute(verb: 'POST', url: '/folders/{id}/mountpoint')]
463468
public function renameFolder(int $id, string $mountpoint): DataResponse {
464-
$response = $this->checkFolderExists($id);
465-
if ($response) {
466-
return $response;
469+
$this->checkFolderExists($id);
470+
471+
// Check if the new mountpoint is valid
472+
if (empty($mountpoint)) {
473+
throw new OCSBadRequestException('Mount point cannot be empty');
474+
}
475+
476+
// Check if we actually need to do anything
477+
$folder = $this->manager->getFolder($id);
478+
if ($folder === null) {
479+
throw new OCSNotFoundException();
480+
}
481+
482+
if ($folder['mount_point'] === trim($mountpoint)) {
483+
return new DataResponse(['success' => true, 'folder' => $this->formatFolder($folder)]);
467484
}
468485

486+
$this->checkMountPointExists(trim($mountpoint));
469487
$this->manager->renameFolder($id, trim($mountpoint));
470488

489+
// Get the new folder data
471490
$folder = $this->manager->getFolder($id);
472491
if ($folder === null) {
473492
throw new OCSNotFoundException();

openapi.json

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -651,6 +651,34 @@
651651
}
652652
}
653653
}
654+
},
655+
"400": {
656+
"description": "Folder already exists",
657+
"content": {
658+
"application/json": {
659+
"schema": {
660+
"type": "object",
661+
"required": [
662+
"ocs"
663+
],
664+
"properties": {
665+
"ocs": {
666+
"type": "object",
667+
"required": [
668+
"meta",
669+
"data"
670+
],
671+
"properties": {
672+
"meta": {
673+
"$ref": "#/components/schemas/OCSMeta"
674+
},
675+
"data": {}
676+
}
677+
}
678+
}
679+
}
680+
}
681+
}
654682
}
655683
}
656684
}
@@ -963,6 +991,62 @@
963991
}
964992
}
965993
}
994+
},
995+
"404": {
996+
"description": "Groupfolder not found",
997+
"content": {
998+
"application/json": {
999+
"schema": {
1000+
"type": "object",
1001+
"required": [
1002+
"ocs"
1003+
],
1004+
"properties": {
1005+
"ocs": {
1006+
"type": "object",
1007+
"required": [
1008+
"meta",
1009+
"data"
1010+
],
1011+
"properties": {
1012+
"meta": {
1013+
"$ref": "#/components/schemas/OCSMeta"
1014+
},
1015+
"data": {}
1016+
}
1017+
}
1018+
}
1019+
}
1020+
}
1021+
}
1022+
},
1023+
"400": {
1024+
"description": "Mount point already exists",
1025+
"content": {
1026+
"application/json": {
1027+
"schema": {
1028+
"type": "object",
1029+
"required": [
1030+
"ocs"
1031+
],
1032+
"properties": {
1033+
"ocs": {
1034+
"type": "object",
1035+
"required": [
1036+
"meta",
1037+
"data"
1038+
],
1039+
"properties": {
1040+
"meta": {
1041+
"$ref": "#/components/schemas/OCSMeta"
1042+
},
1043+
"data": {}
1044+
}
1045+
}
1046+
}
1047+
}
1048+
}
1049+
}
9661050
}
9671051
}
9681052
}
@@ -1912,6 +1996,34 @@
19121996
}
19131997
}
19141998
}
1999+
},
2000+
"400": {
2001+
"description": "Mount point already exists or invalid mount point provided",
2002+
"content": {
2003+
"application/json": {
2004+
"schema": {
2005+
"type": "object",
2006+
"required": [
2007+
"ocs"
2008+
],
2009+
"properties": {
2010+
"ocs": {
2011+
"type": "object",
2012+
"required": [
2013+
"meta",
2014+
"data"
2015+
],
2016+
"properties": {
2017+
"meta": {
2018+
"$ref": "#/components/schemas/OCSMeta"
2019+
},
2020+
"data": {}
2021+
}
2022+
}
2023+
}
2024+
}
2025+
}
2026+
}
19152027
}
19162028
}
19172029
}

0 commit comments

Comments
 (0)