From 912d332411db21bfcdeebb2106842688d313bcae Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Sun, 16 Mar 2025 01:02:59 +0000 Subject: [PATCH 1/6] Fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- l10n/uz.js | 1 + l10n/uz.json | 1 + 2 files changed, 2 insertions(+) diff --git a/l10n/uz.js b/l10n/uz.js index 84c25fd30..210909bf6 100644 --- a/l10n/uz.js +++ b/l10n/uz.js @@ -3,6 +3,7 @@ OC.L10N.register( { "Deny" : "Rad etish", "Delete" : "Delete", + "Share" : "Ulashish", "Folder name" : "Folder name", "Quota" : "kvota", "Unknown" : "Noma'lum", diff --git a/l10n/uz.json b/l10n/uz.json index 826a1a899..b7031009e 100644 --- a/l10n/uz.json +++ b/l10n/uz.json @@ -1,6 +1,7 @@ { "translations": { "Deny" : "Rad etish", "Delete" : "Delete", + "Share" : "Ulashish", "Folder name" : "Folder name", "Quota" : "kvota", "Unknown" : "Noma'lum", From 55af6cbceb0b4750d70b70aacba6dbd44e660fc5 Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Mon, 17 Mar 2025 01:02:59 +0000 Subject: [PATCH 2/6] Fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- l10n/de.js | 2 +- l10n/de.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/l10n/de.js b/l10n/de.js index 092c5ce7c..f5555eb7d 100644 --- a/l10n/de.js +++ b/l10n/de.js @@ -63,6 +63,6 @@ OC.L10N.register( "They will only have access to group folders for which they have advanced permissions." : "Sie haben nur Zugriff auf Gruppenordner, für die sie erweiterte Rechte haben.", "You can not remove your own read permission." : "Du kannst deine eigene Leseberechtigung nicht entfernen.", "Admin configured folders shared with everyone in a group.\n\nFolders can be configured from *Group folders* in the admin settings.\n\nAfter a folder is created, the admin can give access to the folder to one or more groups, control their write/sharing permissions and assign a quota for the folder." : "Von der Administration konfigurierte Ordner, die mit allen Mitgliedern einer Gruppe geteilt werden.\n\nOrdner können in den Administrationseinstellungen unter *Gruppenordner* konfiguriert werden.\n\nNachdem ein Ordner erstellt wurde, kann die Administration einer oder mehreren Gruppen Zugriff auf den Ordner gewähren, ihre Schreib-/Freigabeberechtigungen steuern und dem Ordner ein Kontingent zuweisen.", - "Admin configured folders shared with everyone in a team.\n\nFolders can be configured from *Team folders* in the admin settings.\n\nAfter a folder is created, the admin can give access to the folder to one or more teams, control their write/sharing permissions and assign a quota for the folder." : "Von der Administration konfigurierte Ordner, die mit allen Mitgliedern eines Teams geteilt werden.\n\nOrdner können in den Administrationseinstellungen unter *Team-Ordner* konfiguriert werden.\n\nNachdem ein Ordner erstellt wurde, kann die Administration einer oder mehreren Teams Zugriff auf den Ordner gewähren, ihre Schreib-/Freigabeberechtigungen steuern und dem Ordner ein Kontingent zuweisen." + "Admin configured folders shared with everyone in a team.\n\nFolders can be configured from *Team folders* in the admin settings.\n\nAfter a folder is created, the admin can give access to the folder to one or more teams, control their write/sharing permissions and assign a quota for the folder." : "Von der Administration konfigurierte Ordner, die mit allen Mitgliedern eines Teams geteilt werden.\n\nOrdner können in den Administrationseinstellungen unter *Team-Ordner* konfiguriert werden.\n\nNachdem ein Ordner erstellt wurde, kann die Administration einem oder mehreren Teams Zugriff auf den Ordner gewähren, ihre Schreib-/Freigabeberechtigungen steuern und dem Ordner ein Kontingent zuweisen." }, "nplurals=2; plural=(n != 1);"); diff --git a/l10n/de.json b/l10n/de.json index 27755188f..307ff9605 100644 --- a/l10n/de.json +++ b/l10n/de.json @@ -61,6 +61,6 @@ "They will only have access to group folders for which they have advanced permissions." : "Sie haben nur Zugriff auf Gruppenordner, für die sie erweiterte Rechte haben.", "You can not remove your own read permission." : "Du kannst deine eigene Leseberechtigung nicht entfernen.", "Admin configured folders shared with everyone in a group.\n\nFolders can be configured from *Group folders* in the admin settings.\n\nAfter a folder is created, the admin can give access to the folder to one or more groups, control their write/sharing permissions and assign a quota for the folder." : "Von der Administration konfigurierte Ordner, die mit allen Mitgliedern einer Gruppe geteilt werden.\n\nOrdner können in den Administrationseinstellungen unter *Gruppenordner* konfiguriert werden.\n\nNachdem ein Ordner erstellt wurde, kann die Administration einer oder mehreren Gruppen Zugriff auf den Ordner gewähren, ihre Schreib-/Freigabeberechtigungen steuern und dem Ordner ein Kontingent zuweisen.", - "Admin configured folders shared with everyone in a team.\n\nFolders can be configured from *Team folders* in the admin settings.\n\nAfter a folder is created, the admin can give access to the folder to one or more teams, control their write/sharing permissions and assign a quota for the folder." : "Von der Administration konfigurierte Ordner, die mit allen Mitgliedern eines Teams geteilt werden.\n\nOrdner können in den Administrationseinstellungen unter *Team-Ordner* konfiguriert werden.\n\nNachdem ein Ordner erstellt wurde, kann die Administration einer oder mehreren Teams Zugriff auf den Ordner gewähren, ihre Schreib-/Freigabeberechtigungen steuern und dem Ordner ein Kontingent zuweisen." + "Admin configured folders shared with everyone in a team.\n\nFolders can be configured from *Team folders* in the admin settings.\n\nAfter a folder is created, the admin can give access to the folder to one or more teams, control their write/sharing permissions and assign a quota for the folder." : "Von der Administration konfigurierte Ordner, die mit allen Mitgliedern eines Teams geteilt werden.\n\nOrdner können in den Administrationseinstellungen unter *Team-Ordner* konfiguriert werden.\n\nNachdem ein Ordner erstellt wurde, kann die Administration einem oder mehreren Teams Zugriff auf den Ordner gewähren, ihre Schreib-/Freigabeberechtigungen steuern und dem Ordner ein Kontingent zuweisen." },"pluralForm" :"nplurals=2; plural=(n != 1);" } \ No newline at end of file From c424e778785df0869e2bdadcec7d02741cf90fc6 Mon Sep 17 00:00:00 2001 From: Nextcloud bot Date: Tue, 18 Mar 2025 01:05:30 +0000 Subject: [PATCH 3/6] Fix(l10n): Update translations from Transifex Signed-off-by: Nextcloud bot --- l10n/uz.js | 1 + l10n/uz.json | 1 + 2 files changed, 2 insertions(+) diff --git a/l10n/uz.js b/l10n/uz.js index 210909bf6..3c975f458 100644 --- a/l10n/uz.js +++ b/l10n/uz.js @@ -2,6 +2,7 @@ OC.L10N.register( "groupfolders", { "Deny" : "Rad etish", + "Create" : "Yaratish", "Delete" : "Delete", "Share" : "Ulashish", "Folder name" : "Folder name", diff --git a/l10n/uz.json b/l10n/uz.json index b7031009e..7765689ee 100644 --- a/l10n/uz.json +++ b/l10n/uz.json @@ -1,5 +1,6 @@ { "translations": { "Deny" : "Rad etish", + "Create" : "Yaratish", "Delete" : "Delete", "Share" : "Ulashish", "Folder name" : "Folder name", From 13980df12e3e281fac9cf98e96feb3334e6c768f Mon Sep 17 00:00:00 2001 From: provokateurin Date: Tue, 18 Mar 2025 11:20:53 +0100 Subject: [PATCH 4/6] fix(ACLPlugin): Use correct path to test new permissions Signed-off-by: provokateurin --- lib/DAV/ACLPlugin.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/DAV/ACLPlugin.php b/lib/DAV/ACLPlugin.php index 4369bb26c..df1bd6ba5 100644 --- a/lib/DAV/ACLPlugin.php +++ b/lib/DAV/ACLPlugin.php @@ -227,7 +227,7 @@ public function propPatch(string $path, PropPatch $propPatch): void { } $aclManager = $this->aclManagerFactory->getACLManager($this->user); - $newPermissions = $aclManager->testACLPermissionsForPath($fileInfo->getPath(), $rules); + $newPermissions = $aclManager->testACLPermissionsForPath($path, $rules); if (!($newPermissions & Constants::PERMISSION_READ)) { throw new BadRequest($this->l10n->t('You cannot remove your own read permission.')); } From 87f5c98aa98112c057f6f22324ce9537257748d5 Mon Sep 17 00:00:00 2001 From: provokateurin Date: Tue, 18 Mar 2025 14:13:32 +0100 Subject: [PATCH 5/6] chore(release): v19.0.4 Signed-off-by: provokateurin --- appinfo/info.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appinfo/info.xml b/appinfo/info.xml index ffca1bcf2..20a98ea36 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -13,7 +13,7 @@ Folders can be configured from *Team folders* in the admin settings. After a folder is created, the admin can give access to the folder to one or more teams, control their write/sharing permissions and assign a quota for the folder. ]]> - 19.0.3 + 19.0.4 agpl Robin Appelman GroupFolders From 6f3b300dc6f9f6d932ce98d12e86a32eb7a4aa7d Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Thu, 6 Mar 2025 20:46:24 +0100 Subject: [PATCH 6/6] feat: only setup trash mount when required Signed-off-by: Robin Appelman --- lib/AppInfo/Application.php | 4 ++++ lib/Mount/GroupFolderStorage.php | 4 ++++ lib/Mount/MountProvider.php | 25 ++++---------------- lib/Trash/TrashBackend.php | 39 ++++++++++++++++++++++++-------- 4 files changed, 43 insertions(+), 29 deletions(-) diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index f21e66595..70ad302d2 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -47,7 +47,9 @@ use OCP\Files\Folder; use OCP\Files\IMimeTypeLoader; use OCP\Files\IRootFolder; +use OCP\Files\Mount\IMountManager; use OCP\Files\NotFoundException; +use OCP\Files\Storage\IStorageFactory; use OCP\Group\Events\GroupDeletedEvent; use OCP\IAppConfig; use OCP\ICacheFactory; @@ -131,6 +133,8 @@ public function register(IRegistrationContext $context): void { $c->get(LoggerInterface::class), $c->get(IUserManager::class), $c->get(IUserSession::class), + $c->get(IMountManager::class), + $c->get(IStorageFactory::class), ); $hasVersionApp = interface_exists(\OCA\Files_Versions\Versions\IVersionBackend::class); if ($hasVersionApp) { diff --git a/lib/Mount/GroupFolderStorage.php b/lib/Mount/GroupFolderStorage.php index c8ca119fb..5ab28bb6f 100644 --- a/lib/Mount/GroupFolderStorage.php +++ b/lib/Mount/GroupFolderStorage.php @@ -51,6 +51,10 @@ public function getOwner(string $path): string|false { return false; } + public function getUser(): ?IUser { + return $this->mountOwner; + } + /** * @inheritDoc */ diff --git a/lib/Mount/MountProvider.php b/lib/Mount/MountProvider.php index f5bc74acb..daa3ee1c4 100644 --- a/lib/Mount/MountProvider.php +++ b/lib/Mount/MountProvider.php @@ -83,7 +83,7 @@ public function getMountsForUser(IUser $user, IStorageFactory $loader): array { $aclManager = $this->aclManagerFactory->getACLManager($user, $this->getRootStorageId()); $rootRules = $aclManager->getRelevantRulesForPath($aclRootPaths); - return array_merge(...array_filter(array_map(function (array $folder) use ($user, $loader, $conflicts, $aclManager, $rootRules): ?array { + return array_filter(array_map(function (array $folder) use ($user, $loader, $conflicts, $aclManager, $rootRules): ?IMountPoint { // check for existing files in the user home and rename them if needed $originalFolderName = $folder['mount_point']; if (in_array($originalFolderName, $conflicts)) { @@ -102,7 +102,7 @@ public function getMountsForUser(IUser $user, IStorageFactory $loader): array { $userStorage->getPropagator()->propagateChange("files/$folderName", time()); } - $mount = $this->getMount( + return $this->getMount( $folder['folder_id'], '/' . $user->getUID() . '/files/' . $folder['mount_point'], $folder['permissions'], @@ -114,23 +114,7 @@ public function getMountsForUser(IUser $user, IStorageFactory $loader): array { $aclManager, $rootRules ); - if (!$mount) { - return null; - } - $trashMount = $this->getTrashMount( - $folder['folder_id'], - '/' . $user->getUID() . '/files_trashbin/groupfolders/' . $folder['folder_id'], - $folder['quota'], - $loader, - $user - ); - - return [ - $mount, - $trashMount, - ]; - - }, $folders))); + }, $folders)); } private function getCurrentUID(): ?string { @@ -225,6 +209,7 @@ public function getTrashMount( int $quota, IStorageFactory $loader, IUser $user, + ?ICacheEntry $cacheEntry = null, ): IMountPoint { $storage = $this->getRootFolder()->getStorage(); @@ -233,7 +218,7 @@ public function getTrashMount( $trashPath = $this->getRootFolder()->getInternalPath() . '/trash/' . $id; - $trashStorage = $this->getGroupFolderStorage($id, $storage, $user, $trashPath, $quota, null); + $trashStorage = $this->getGroupFolderStorage($id, $storage, $user, $trashPath, $quota, $cacheEntry); return new GroupMountPoint( $id, diff --git a/lib/Trash/TrashBackend.php b/lib/Trash/TrashBackend.php index 1d5090367..c0e912a79 100644 --- a/lib/Trash/TrashBackend.php +++ b/lib/Trash/TrashBackend.php @@ -19,13 +19,16 @@ use OCA\GroupFolders\Mount\MountProvider; use OCA\GroupFolders\Versions\VersionsBackend; use OCP\Constants; +use OCP\Files\FileInfo; use OCP\Files\Folder; use OCP\Files\IRootFolder; +use OCP\Files\Mount\IMountManager; use OCP\Files\Node; use OCP\Files\NotFoundException; use OCP\Files\NotPermittedException; use OCP\Files\Storage\ISharedStorage; use OCP\Files\Storage\IStorage; +use OCP\Files\Storage\IStorageFactory; use OCP\IUser; use OCP\IUserManager; use OCP\IUserSession; @@ -47,6 +50,8 @@ public function __construct( private LoggerInterface $logger, private IUserManager $userManager, private IUserSession $userSession, + private IMountManager $mountManager, + private IStorageFactory $storageFactory, ) { } @@ -235,16 +240,17 @@ public function removeItem(ITrashItem $item): void { public function moveToTrash(IStorage $storage, string $internalPath): bool { if ($storage->instanceOfStorage(GroupFolderStorage::class) && $storage->isDeletable($internalPath)) { + /** @var GroupFolderStorage $storage */ $name = basename($internalPath); $fileEntry = $storage->getCache()->get($internalPath); $folderId = $storage->getFolderId(); $user = $this->userSession->getUser(); - // ensure the folder exists - $this->getTrashFolder($folderId); + $owner = $storage->getUser(); - $owner = $storage->getOwner($internalPath); - $trashFolder = $this->rootFolder->get('/' . $owner . '/files_trashbin/groupfolders/' . $folderId); + $this->setupTrashFolder($folderId, $owner); + + $trashFolder = $this->rootFolder->get('/' . $owner->getUID() . '/files_trashbin/groupfolders/' . $folderId); $trashStorage = $trashFolder->getStorage(); $time = time(); $trashName = $name . '.d' . $time; @@ -371,7 +377,22 @@ private function getTrashRoot(): Folder { } } - private function getTrashFolder(int $folderId): Folder { + private function setupTrashFolder(int $folderId, ?IUser $user = null): Folder { + if ($user) { + $mountPoint = '/' . $user->getUID() . '/files_trashbin/groupfolders/' . $folderId; + $mount = $this->mountManager->find($mountPoint); + if ($mount->getMountPoint() !== $mountPoint) { + $trashMount = $this->mountProvider->getTrashMount( + $folderId, + $mountPoint, + FileInfo::SPACE_UNLIMITED, + $this->storageFactory, + $user, + ); + $this->mountManager->addMount($trashMount); + } + } + try { /** @var Folder $folder */ $folder = $this->appFolder->get('trash/' . $folderId); @@ -418,7 +439,7 @@ private function getTrashForFolders(IUser $user, array $folders): array { $mountPoint = $folder['mount_point']; // ensure the trash folder exists - $this->getTrashFolder($folderId); + $this->setupTrashFolder($folderId, $user); $trashFolder = $this->rootFolder->get('/' . $user->getUID() . '/files_trashbin/groupfolders/' . $folderId); $content = $trashFolder->getDirectoryListing(); @@ -513,7 +534,7 @@ public function getTrashNodeById(IUser $user, int $fileId): ?Node { } public function cleanTrashFolder(int $folderid): void { - $trashFolder = $this->getTrashFolder($folderid); + $trashFolder = $this->setupTrashFolder($folderid); foreach ($trashFolder->getDirectoryListing() as $node) { $node->delete(); @@ -532,7 +553,7 @@ public function expire(Expiration $expiration): array { // calculate size of trash items $sizeInTrash = 0; - $trashFolder = $this->getTrashFolder($folderId); + $trashFolder = $this->setupTrashFolder($folderId); $nodes = []; // cache foreach ($trashItems as $groupTrashItem) { $nodeName = $groupTrashItem['name'] . '.d' . $groupTrashItem['deleted_time']; @@ -593,7 +614,7 @@ private function cleanupDeletedFoldersTrash(array $existingFolders): void { $folderId = (int)$folderId; if (!isset($existingFolders[$folderId])) { $this->cleanTrashFolder($folderId); - $this->getTrashFolder($folderId)->delete(); + $this->setupTrashFolder($folderId)->delete(); } } }