diff --git a/apps/files_sharing/lib/External/Manager.php b/apps/files_sharing/lib/External/Manager.php index f18d8346dc4..77f5c6bd172 100644 --- a/apps/files_sharing/lib/External/Manager.php +++ b/apps/files_sharing/lib/External/Manager.php @@ -599,7 +599,18 @@ class Manager { return $result; } - public function removeShare($mountPoint): bool { + /** + * Remove a share based on its mountpoint. + * + * User shares are always fully removed; group shares by default are just + * marked again as pending for the current user, unless explicitly forced + * to be fully removed (parent group share and all its sub-shares). + * + * @param bool $force True to fully removed a group share, false to mark it + * as pending for the current user + * @return bool True if the share could be removed, false otherwise + */ + public function removeShare(string $mountPoint, bool $force = false): bool { try { $mountPointObj = $this->mountManager->find($mountPoint); } catch (NotFoundException $e) { @@ -617,7 +628,7 @@ class Manager { try { $getShare = $this->connection->prepare(' - SELECT `remote`, `share_token`, `remote_id`, `share_type`, `id` + SELECT `remote`, `share_token`, `remote_id`, `share_type`, `id`, `parent` FROM `*PREFIX*share_external` WHERE `mountpoint_hash` = ? AND `user` = ?'); $result = $getShare->execute([$hash, $this->uid]); @@ -638,7 +649,22 @@ class Manager { $deleteResult = $query->execute([(int)$share['id']]); $deleteResult->closeCursor(); } elseif ($share !== false && (int)$share['share_type'] === IShare::TYPE_GROUP) { - $this->updateAccepted((int)$share['id'], false); + if ($force) { + $qb = $this->connection->getQueryBuilder(); + // delete group share entry and matching sub-entries + $qb->delete('share_external') + ->where( + $qb->expr()->orX( + $qb->expr()->eq('id', $qb->createParameter('share_parent_id')), + $qb->expr()->eq('parent', $qb->createParameter('share_parent_id')) + ) + ); + + $qb->setParameter('share_parent_id', $share['parent']); + $qb->executeStatement(); + } else { + $this->updateAccepted((int)$share['id'], false); + } } $this->removeReShares($id); diff --git a/apps/files_sharing/lib/External/Storage.php b/apps/files_sharing/lib/External/Storage.php index 7b64690d53e..425cf178c9b 100644 --- a/apps/files_sharing/lib/External/Storage.php +++ b/apps/files_sharing/lib/External/Storage.php @@ -239,7 +239,7 @@ class Storage extends DAV implements ISharedStorage, IDisableEncryptionStorage, // valid Nextcloud instance means that the public share no longer exists // since this is permanent (re-sharing the file will create a new token) // we remove the invalid storage - $this->manager->removeShare($this->mountPoint); + $this->manager->removeShare($this->mountPoint, true); $this->manager->getMountManager()->removeMount($this->mountPoint); throw new StorageInvalidException("Remote share not found", 0, $e); } else { @@ -248,7 +248,7 @@ class Storage extends DAV implements ISharedStorage, IDisableEncryptionStorage, } } catch (ForbiddenException $e) { // auth error, remove share for now (provide a dialog in the future) - $this->manager->removeShare($this->mountPoint); + $this->manager->removeShare($this->mountPoint, true); $this->manager->getMountManager()->removeMount($this->mountPoint); throw new StorageInvalidException("Auth error when getting remote share"); } catch (\GuzzleHttp\Exception\ConnectException $e) {