From 09f9a10d0b293b2b8873e4fdc07bb9156476b22c Mon Sep 17 00:00:00 2001 From: Silver Date: Thu, 20 Nov 2025 10:46:26 +0100 Subject: [PATCH 1/2] feat: Add expiry date support for collective shares in backend Add ability to view and manage expiration dates on collective shares. Shares now inherit and respect Nextcloud's default expiry date policy for file shares. - Add expirationDate field to CollectiveShare entity (transient) - Extract expiry dates from underlying IShare objects in service layer - Add helper methods for expiry configuration (hasDefaultExpireDate, isExpireDateEnforced, getDefaultExpireDays) - Update API endpoints to accept and return expiry date information - Support setting, updating, and removing expiry dates via updateShare - Return both share data and global expiry config in getCollectiveShares Signed-off-by: Silver --- lib/Controller/ShareController.php | 24 ++++++++---- lib/Db/CollectiveShare.php | 10 +++++ lib/ResponseDefinitions.php | 1 + lib/Service/CollectiveShareService.php | 51 +++++++++++++++++++++++++- 4 files changed, 78 insertions(+), 8 deletions(-) diff --git a/lib/Controller/ShareController.php b/lib/Controller/ShareController.php index d6619c08b..955ef6a52 100644 --- a/lib/Controller/ShareController.php +++ b/lib/Controller/ShareController.php @@ -58,8 +58,18 @@ public function __construct( public function getCollectiveShares(int $collectiveId): DataResponse { $share = $this->handleErrorResponse(function () use ($collectiveId): array { $userId = $this->userId; - $collective = $this->collectiveService->getCollective($collectiveId, $userId); - return $this->shareService->getSharesByCollectiveAndUser($userId, $collective->getId()); + $this->collectiveService->getCollective($collectiveId, $userId); + $shares = $this->shareService->getSharesByCollectiveAndUser($userId, $collectiveId); + + // Get global expiry configuration + return [ + 'shares' => $shares, + 'expiryConfig' => [ + 'hasDefaultExpireDate' => $this->shareService->hasDefaultExpireDate(), + 'isExpireDateEnforced' => $this->shareService->isExpireDateEnforced(), + 'defaultExpireDays' => $this->shareService->getDefaultExpireDays(), + ], + ]; }, $this->logger); return new DataResponse($share); } @@ -96,8 +106,8 @@ public function createCollectiveShare(int $collectiveId, string $password = ''): * 200: Share updated */ #[NoAdminRequired] - public function updateCollectiveShare(int $collectiveId, string $token, bool $editable, string $password = ''): DataResponse { - return $this->updatePageShare($collectiveId, 0, $token, $editable, $password); + public function updateCollectiveShare(int $collectiveId, string $token, bool $editable, string $password = '', ?string $expiryDate = null): DataResponse { + return $this->updatePageShare($collectiveId, 0, $token, $editable, $password, $expiryDate); } /** @@ -159,15 +169,15 @@ public function createPageShare(int $collectiveId, int $pageId = 0, string $pass * 200: Share updated */ #[NoAdminRequired] - public function updatePageShare(int $collectiveId, int $pageId, string $token, bool $editable, ?string $password = null): DataResponse { - $share = $this->handleErrorResponse(function () use ($collectiveId, $pageId, $token, $editable, $password): CollectiveShare { + public function updatePageShare(int $collectiveId, int $pageId, string $token, bool $editable, ?string $password = null, ?string $expiryDate = null): DataResponse { + $share = $this->handleErrorResponse(function () use ($collectiveId, $pageId, $token, $editable, $password, $expiryDate): CollectiveShare { $userId = $this->userId; $collective = $this->collectiveService->getCollective($collectiveId, $userId); $pageInfo = null; if ($pageId !== 0) { $pageInfo = $this->pageService->findByFileId($collectiveId, $pageId, $userId); } - return $this->shareService->updateShare($userId, $collective, $pageInfo, $token, $editable, $password); + return $this->shareService->updateShare($userId, $collective, $pageInfo, $token, $editable, $password, $expiryDate); }, $this->logger); return new DataResponse($share); } diff --git a/lib/Db/CollectiveShare.php b/lib/Db/CollectiveShare.php index 80c87dae3..44e89d42e 100644 --- a/lib/Db/CollectiveShare.php +++ b/lib/Db/CollectiveShare.php @@ -34,6 +34,7 @@ class CollectiveShare extends Entity implements JsonSerializable { /** transient attributes, not persisted in database */ protected bool $editable = false; protected string $password = ''; + protected ?\DateTime $expirationDate = null; public function getEditable(): bool { return $this->editable; @@ -51,6 +52,14 @@ public function setPassword(string $password): void { $this->password = $password; } + public function getExpirationDate(): ?\DateTime { + return $this->expirationDate; + } + + public function setExpirationDate(?\DateTime $expirationDate): void { + $this->expirationDate = $expirationDate; + } + public function jsonSerialize(): array { return [ 'id' => $this->id, @@ -60,6 +69,7 @@ public function jsonSerialize(): array { 'owner' => $this->owner, 'editable' => $this->editable, 'password' => $this->password, + 'expirationDate' => $this->expirationDate?->format(\DateTime::ATOM), ]; } } diff --git a/lib/ResponseDefinitions.php b/lib/ResponseDefinitions.php index b43621fb2..617d3203f 100644 --- a/lib/ResponseDefinitions.php +++ b/lib/ResponseDefinitions.php @@ -41,6 +41,7 @@ * owner: string, * editable: bool, * password: string, + * expirationDate: string|null, * } * * @psalm-type CollectivesPageInfo = array{ diff --git a/lib/Service/CollectiveShareService.php b/lib/Service/CollectiveShareService.php index 746593c8a..d4afa544c 100644 --- a/lib/Service/CollectiveShareService.php +++ b/lib/Service/CollectiveShareService.php @@ -124,6 +124,12 @@ public function findShare(string $userId, int $collectiveId, int $pageId): ?Coll if ($folderShare->getPassword()) { $collectiveShare->setPassword($folderShare->getPassword()); } + + if ($folderShare->getExpirationDate()) { + $collectiveShare->setExpirationDate($folderShare->getExpirationDate()); + } else { + $collectiveShare->setExpirationDate(null); + } return $collectiveShare; } @@ -150,6 +156,12 @@ public function findShareByToken(string $token, bool $getPermissionInfo = true): if ($folderShare->getPassword()) { $collectiveShare->setPassword($folderShare->getPassword()); } + + if ($folderShare->getExpirationDate()) { + $collectiveShare->setExpirationDate($folderShare->getExpirationDate()); + } else { + $collectiveShare->setExpirationDate(null); + } return $collectiveShare; } @@ -168,6 +180,13 @@ public function getSharesByCollectiveAndUser(string $userId, int $collectiveId): if ($folderShare->getPassword()) { $share->setPassword($folderShare->getPassword()); } + + $expirationDate = $folderShare->getExpirationDate(); + if ($expirationDate) { + $share->setExpirationDate($expirationDate); + } else { + $share->setExpirationDate(null); + } $shares[] = $share; } @@ -179,6 +198,18 @@ private function isShareEditable(IShare $folderShare): bool { return ($folderShare->getPermissions() & Collective::editPermissions) === Collective::editPermissions; } + public function isExpireDateEnforced(): bool { + return $this->shareManager->shareApiLinkDefaultExpireDateEnforced(); + } + + public function getDefaultExpireDays(): int { + return $this->shareManager->shareApiLinkDefaultExpireDays(); + } + + public function hasDefaultExpireDate(): bool { + return $this->shareManager->shareApiLinkDefaultExpireDate(); + } + /** * @throws NotFoundException * @throws NotPermittedException @@ -217,7 +248,7 @@ public function createShare(string $userId, Collective $collective, ?PageInfo $p * @throws NotFoundException * @throws NotPermittedException */ - public function updateShare(string $userId, Collective $collective, ?PageInfo $pageInfo, string $token, bool $editable, ?string $password): CollectiveShare { + public function updateShare(string $userId, Collective $collective, ?PageInfo $pageInfo, string $token, bool $editable, ?string $password, ?string $expiryDate = null): CollectiveShare { if (!$collective->canShare()) { throw new NotPermittedException($this->l10n->t('You are not allowed to share %s', $collective->getName())); } @@ -250,10 +281,28 @@ public function updateShare(string $userId, Collective $collective, ?PageInfo $p $password = null; } $folderShare->setPassword($password); + + if ($expiryDate !== null) { + if ($expiryDate === '') { + // Empty string means remove expiration date + $folderShare->setExpirationDate(null); + } else { + $folderShare->setExpirationDate(new \DateTime($expiryDate)); + } + } + // If $expiryDate === null, don't change existing expiry date + $this->shareManager->updateShare($folderShare); $share->setEditable($this->isShareEditable($folderShare)); $share->setPassword($folderShare->getPassword() ?? ''); + + if ($folderShare->getExpirationDate()) { + $share->setExpirationDate($folderShare->getExpirationDate()); + } else { + $share->setExpirationDate(null); + } + return $share; } From f8e0a4a00afdeaf7573cd57c73ed4895e00e5a46 Mon Sep 17 00:00:00 2001 From: Silver Date: Wed, 17 Dec 2025 09:21:36 +0100 Subject: [PATCH 2/2] refactor: simplify expiration date handling in share methods - Remove redundant if/else checks since getExpirationDate() returns null - Add setExpirationDate() in createShare() to reflect auto-applied expiry dates Signed-off-by: Silver --- lib/Service/CollectiveShareService.php | 26 +++++--------------------- 1 file changed, 5 insertions(+), 21 deletions(-) diff --git a/lib/Service/CollectiveShareService.php b/lib/Service/CollectiveShareService.php index d4afa544c..0752762a5 100644 --- a/lib/Service/CollectiveShareService.php +++ b/lib/Service/CollectiveShareService.php @@ -125,11 +125,7 @@ public function findShare(string $userId, int $collectiveId, int $pageId): ?Coll $collectiveShare->setPassword($folderShare->getPassword()); } - if ($folderShare->getExpirationDate()) { - $collectiveShare->setExpirationDate($folderShare->getExpirationDate()); - } else { - $collectiveShare->setExpirationDate(null); - } + $collectiveShare->setExpirationDate($folderShare->getExpirationDate()); return $collectiveShare; } @@ -157,11 +153,7 @@ public function findShareByToken(string $token, bool $getPermissionInfo = true): $collectiveShare->setPassword($folderShare->getPassword()); } - if ($folderShare->getExpirationDate()) { - $collectiveShare->setExpirationDate($folderShare->getExpirationDate()); - } else { - $collectiveShare->setExpirationDate(null); - } + $collectiveShare->setExpirationDate($folderShare->getExpirationDate()); return $collectiveShare; } @@ -181,12 +173,7 @@ public function getSharesByCollectiveAndUser(string $userId, int $collectiveId): $share->setPassword($folderShare->getPassword()); } - $expirationDate = $folderShare->getExpirationDate(); - if ($expirationDate) { - $share->setExpirationDate($expirationDate); - } else { - $share->setExpirationDate(null); - } + $share->setExpirationDate($folderShare->getExpirationDate()); $shares[] = $share; } @@ -238,6 +225,7 @@ public function createShare(string $userId, Collective $collective, ?PageInfo $p if ($password != '') { $collectiveShare->setPassword($folderShare->getPassword()); } + $collectiveShare->setExpirationDate($folderShare->getExpirationDate()); return $collectiveShare; } @@ -297,11 +285,7 @@ public function updateShare(string $userId, Collective $collective, ?PageInfo $p $share->setEditable($this->isShareEditable($folderShare)); $share->setPassword($folderShare->getPassword() ?? ''); - if ($folderShare->getExpirationDate()) { - $share->setExpirationDate($folderShare->getExpirationDate()); - } else { - $share->setExpirationDate(null); - } + $share->setExpirationDate($folderShare->getExpirationDate()); return $share; }