diff --git a/lib/Album/AlbumMapper.php b/lib/Album/AlbumMapper.php index f06f54d35..9b2209183 100644 --- a/lib/Album/AlbumMapper.php +++ b/lib/Album/AlbumMapper.php @@ -86,6 +86,22 @@ public function getForUser(string $userId): array { }, $rows); } + /** + * @param int $fileId + * @return AlbumInfo[] + */ + public function getForFile(int $fileId): array { + $query = $this->connection->getQueryBuilder(); + $query->select("a.album_id", "name", "user", "location", "created", "last_added_photo") + ->from("photos_albums", "a") + ->leftJoin("a", "photos_albums_files", "p", $query->expr()->eq("a.album_id", "p.album_id")) + ->where($query->expr()->eq('file_id', $query->createNamedParameter($fileId, IQueryBuilder::PARAM_INT))); + $rows = $query->executeQuery()->fetchAll(); + return array_map(function (array $row) { + return new AlbumInfo((int)$row['album_id'], $row['user'], $row['name'], $row['location'], (int)$row['created'], (int)$row['last_added_photo']); + }, $rows); + } + public function rename(int $id, string $newName): void { $query = $this->connection->getQueryBuilder(); $query->update("photos_albums") diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index 6a69d59ea..029fcc80c 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -30,6 +30,8 @@ use OCP\AppFramework\Bootstrap\IBootContext; use OCP\AppFramework\Bootstrap\IBootstrap; use OCP\AppFramework\Bootstrap\IRegistrationContext; +use OCP\Files\Events\Node\NodeDeletedEvent; +use OCA\Photos\Event\MoveToTrashListener; class Application extends App implements IBootstrap { public const APP_ID = 'photos'; @@ -61,6 +63,7 @@ public function __construct() { public function register(IRegistrationContext $context): void { /** Register $principalBackend for the DAV collection */ $context->registerServiceAlias('principalBackend', Principal::class); + $context->registerEventListener(NodeDeletedEvent::class, MoveToTrashListener::class); } public function boot(IBootContext $context): void { diff --git a/lib/Event/MoveToTrashListener.php b/lib/Event/MoveToTrashListener.php new file mode 100644 index 000000000..d5927f18d --- /dev/null +++ b/lib/Event/MoveToTrashListener.php @@ -0,0 +1,28 @@ +albumMapper = $albumMapper; + } + + public function handle(Event $event): void { + if (!($event instanceof NodeDeletedEvent)) { + return; + } + + // Remove node from all albums containing it. + $albums = $this->albumMapper->getForFile($event->getNode()->getId()); + foreach ($albums as $album) { + $this->albumMapper->removeFile($album->getId(), $event->getNode()->getId()); + } + } +} diff --git a/lib/Sabre/Album/PropFindPlugin.php b/lib/Sabre/Album/PropFindPlugin.php index 827649545..303cb7ed6 100644 --- a/lib/Sabre/Album/PropFindPlugin.php +++ b/lib/Sabre/Album/PropFindPlugin.php @@ -34,6 +34,7 @@ use Sabre\DAV\Server; use Sabre\DAV\ServerPlugin; use Sabre\DAV\Tree; +use OCP\Files\NotFoundException; class PropFindPlugin extends ServerPlugin { public const FILE_NAME_PROPERTYNAME = '{http://nextcloud.org/ns}file-name'; @@ -77,14 +78,22 @@ public function initialize(Server $server) { public function propFind(PropFind $propFind, INode $node): void { if ($node instanceof AlbumPhoto) { + // Checking if the node is trulely available and ignoring if not + // Should be pre-emptively handled by the NodeDeletedEvent + try { + $fileInfo = $node->getFileInfo(); + } catch (NotFoundException $e) { + return; + } + $propFind->handle(FilesPlugin::INTERNAL_FILEID_PROPERTYNAME, fn () => $node->getFile()->getFileId()); $propFind->handle(FilesPlugin::GETETAG_PROPERTYNAME, fn () => $node->getETag()); $propFind->handle(self::FILE_NAME_PROPERTYNAME, fn () => $node->getFile()->getName()); - $propFind->handle(self::REALPATH_PROPERTYNAME, fn () => $node->getFileInfo()->getPath()); + $propFind->handle(self::REALPATH_PROPERTYNAME, fn () => $fileInfo->getPath()); $propFind->handle(self::FAVORITE_PROPERTYNAME, fn () => $node->isFavorite() ? 1 : 0); - $propFind->handle(FilesPlugin::HAS_PREVIEW_PROPERTYNAME, function () use ($node) { - return json_encode($this->previewManager->isAvailable($node->getFileInfo())); + $propFind->handle(FilesPlugin::HAS_PREVIEW_PROPERTYNAME, function () use ($fileInfo) { + return json_encode($this->previewManager->isAvailable($fileInfo)); }); if ($this->metadataEnabled) {