feat: support deleting photo folders with content

This commit is contained in:
2026-04-08 17:08:55 +03:00
parent 4384b291e5
commit a2d133386c
9 changed files with 149 additions and 27 deletions

View File

@@ -121,10 +121,12 @@ final class PhotoController extends OCSController {
/**
* Delete a photo folder
*
* Photos in this folder are moved to the board root.
* When deleteContents is false (default), photos are moved to the board root.
* When true, the folder and all its photos (including files) are permanently deleted.
*
* @param int $houseId House id.
* @param int $folderId Folder id.
* @param bool $deleteContents Whether to also delete photos inside the folder.
*
* @return DataResponse<Http::STATUS_OK, PantrySuccess, array{}>
*
@@ -132,12 +134,13 @@ final class PhotoController extends OCSController {
*/
#[ApiRoute(verb: 'DELETE', url: '/api/houses/{houseId}/photos/folders/{folderId}')]
#[NoAdminRequired]
public function deleteFolder(int $houseId, int $folderId): DataResponse {
return $this->runAction(function () use ($houseId, $folderId): DataResponse {
$this->auth->requireMember($houseId, $this->requireUid());
public function deleteFolder(int $houseId, int $folderId, bool $deleteContents = false): DataResponse {
return $this->runAction(function () use ($houseId, $folderId, $deleteContents): DataResponse {
$uid = $this->requireUid();
$this->auth->requireMember($houseId, $uid);
$existing = $this->photos->getFolder($folderId);
$this->assertInHouse($existing->getHouseId(), $houseId, 'Folder');
$this->photos->deleteFolder($folderId);
$this->photos->deleteFolder($folderId, $deleteContents, $uid);
return new DataResponse(['success' => true]);
});
}
@@ -287,10 +290,11 @@ final class PhotoController extends OCSController {
#[NoAdminRequired]
public function deletePhoto(int $houseId, int $photoId): DataResponse {
return $this->runAction(function () use ($houseId, $photoId): DataResponse {
$this->auth->requireMember($houseId, $this->requireUid());
$uid = $this->requireUid();
$this->auth->requireMember($houseId, $uid);
$existing = $this->photos->getPhoto($photoId);
$this->assertInHouse($existing->getHouseId(), $houseId, 'Photo');
$this->photos->deletePhoto($photoId);
$this->photos->deletePhoto($photoId, $uid);
return new DataResponse(['success' => true]);
});
}

View File

@@ -57,6 +57,24 @@ class ImageService {
return $file->getId();
}
/**
* Delete a file by its Nextcloud file id.
*
* Silently does nothing if the file does not exist or is not accessible.
*/
public function deleteFile(int $fileId, string $uid): void {
$userFolder = $this->rootFolder->getUserFolder($uid);
$nodes = $userFolder->getById($fileId);
foreach ($nodes as $node) {
try {
$node->delete();
} catch (\Throwable) {
// Best-effort — file may have been removed already.
}
break; // Only need to delete once.
}
}
private function resolvePhotoFolder(string $uid, int $houseId): Folder {
$base = $this->resolveBaseFolder($uid, $houseId);
return $this->getOrCreateSubFolder($base, self::PHOTOS_SUBDIR);

View File

@@ -18,6 +18,7 @@ class PhotoService {
public function __construct(
private PhotoMapper $photoMapper,
private PhotoFolderMapper $folderMapper,
private ImageService $images,
) {
}
@@ -72,10 +73,20 @@ class PhotoService {
return $folder;
}
public function deleteFolder(int $folderId): void {
public function deleteFolder(int $folderId, bool $deleteContents = false, ?string $uid = null): void {
$folder = $this->getFolder($folderId);
// Move all photos in this folder to the board root
$this->photoMapper->moveToRoot($folderId);
if ($deleteContents) {
$photos = $this->photoMapper->findByFolder($folderId);
foreach ($photos as $photo) {
if ($uid !== null) {
$this->images->deleteFile($photo->getFileId(), $uid);
}
$this->photoMapper->delete($photo);
}
} else {
// Move all photos in this folder to the board root
$this->photoMapper->moveToRoot($folderId);
}
$this->folderMapper->delete($folder);
}
@@ -163,8 +174,11 @@ class PhotoService {
return $photo;
}
public function deletePhoto(int $photoId): void {
public function deletePhoto(int $photoId, ?string $uid = null): void {
$photo = $this->getPhoto($photoId);
if ($uid !== null) {
$this->images->deleteFile($photo->getFileId(), $uid);
}
$this->photoMapper->delete($photo);
}