From 000b7de5945ff567d6bab4fac9ba4929f17f93cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20Molakvo=C3=A6?= Date: Tue, 13 Sep 2022 12:29:05 +0200 Subject: [PATCH 1/3] Catch invalid fileInfo in propFind MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: John Molakvoæ --- lib/Sabre/Album/PropFindPlugin.php | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) 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) { From b07696089ae3e574da2e6f5f26aa4f30161bd0e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20Molakvo=C3=A6?= Date: Thu, 8 Sep 2022 23:23:02 +0200 Subject: [PATCH 2/3] Allow to PUT files into an album MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: John Molakvoæ --- lib/Sabre/Album/AlbumRoot.php | 50 ++++++++++++++++++++++++++-------- lib/Sabre/Album/AlbumsHome.php | 9 ++++-- lib/Sabre/PhotosHome.php | 13 +++++---- lib/Sabre/RootCollection.php | 9 ++++-- 4 files changed, 58 insertions(+), 23 deletions(-) diff --git a/lib/Sabre/Album/AlbumRoot.php b/lib/Sabre/Album/AlbumRoot.php index ffe5d2a21..b41aa4879 100644 --- a/lib/Sabre/Album/AlbumRoot.php +++ b/lib/Sabre/Album/AlbumRoot.php @@ -27,6 +27,7 @@ use OCA\Photos\Album\AlbumFile; use OCA\Photos\Album\AlbumMapper; use OCA\Photos\Album\AlbumWithFiles; +use OCA\Photos\Service\UserConfigService; use OCP\Files\Folder; use OCP\Files\IRootFolder; use OCP\IUser; @@ -40,16 +41,22 @@ class AlbumRoot implements ICollection, ICopyTarget { private AlbumMapper $albumMapper; private AlbumWithFiles $album; - private IRootFolder $rootFolder; private Folder $userFolder; private IUser $user; - - public function __construct(AlbumMapper $albumMapper, AlbumWithFiles $album, IRootFolder $rootFolder, Folder $userFolder, IUser $user) { + private UserConfigService $userConfigService; + + public function __construct(AlbumMapper $albumMapper, + AlbumWithFiles $album, + IRootFolder $rootFolder, + Folder $userFolder, + IUser $user, + UserConfigService $userConfigService) { $this->albumMapper = $albumMapper; $this->album = $album; $this->rootFolder = $rootFolder; $this->userFolder = $userFolder; $this->user = $user; + $this->userConfigService = $userConfigService; } /** @@ -70,8 +77,23 @@ public function setName($name) { $this->albumMapper->rename($this->album->getAlbum()->getId(), $name); } + /** + * We cannot create files in an Album + * We add the file to the default Photos folder and then link it there. + * + * @param [type] $name + * @param [type] $data + * @return void + */ public function createFile($name, $data = null) { - throw new Forbidden('Not allowed to create files in this folder, copy files into this folder instead'); + try { + $photosLocation = $this->userConfigService->getUserConfig('photosLocation'); + $photosFolder = $this->userFolder->get($photosLocation); + $node = $photosFolder->newFile($name, $data); + return $this->addFile($node->getId(), $node->getOwner()->getUID()); + } catch (\Exception $e) { + throw new \Exception('The file could not be created'); + } } /** @@ -113,17 +135,23 @@ public function copyInto($targetName, $sourcePath, INode $sourceNode): bool { $uid = $this->user->getUID(); if ($sourceNode instanceof File) { $sourceId = $sourceNode->getId(); - if (in_array($sourceId, $this->album->getFileIds())) { - throw new Conflict("File $sourceId is already in the folder"); - } - if ($sourceNode->getFileInfo()->getOwner()->getUID() === $uid) { - $this->albumMapper->addFile($this->album->getAlbum()->getId(), $sourceId); - return true; - } + $ownerUID = $sourceNode->getFileInfo()->getOwner()->getUID(); + return $this->addFile($sourceId, $ownerUID); } throw new \Exception("Can't add file to album, only files from $uid can be added"); } + private function addFile(int $sourceId, string $ownerUID): bool { + $uid = $this->user->getUID(); + if (in_array($sourceId, $this->album->getFileIds())) { + throw new Conflict("File $sourceId is already in the folder"); + } + if ($ownerUID === $uid) { + $this->albumMapper->addFile($this->album->getAlbum()->getId(), $sourceId); + return true; + } + } + public function getAlbum(): AlbumWithFiles { return $this->album; } diff --git a/lib/Sabre/Album/AlbumsHome.php b/lib/Sabre/Album/AlbumsHome.php index a2bc2fe73..82912d28d 100644 --- a/lib/Sabre/Album/AlbumsHome.php +++ b/lib/Sabre/Album/AlbumsHome.php @@ -25,6 +25,7 @@ use OCA\Photos\Album\AlbumMapper; use OCA\Photos\Album\AlbumWithFiles; +use OCA\Photos\Service\UserConfigService; use OCP\Files\Folder; use OCP\Files\IRootFolder; use OCP\IUser; @@ -38,6 +39,7 @@ class AlbumsHome implements ICollection { private IUser $user; private IRootFolder $rootFolder; private Folder $userFolder; + private UserConfigService $userConfigService; /** * @var AlbumRoot[] @@ -48,13 +50,14 @@ public function __construct( array $principalInfo, AlbumMapper $albumMapper, IUser $user, - IRootFolder $rootFolder - ) { + IRootFolder $rootFolder, + UserConfigService $userConfigService) { $this->principalInfo = $principalInfo; $this->albumMapper = $albumMapper; $this->user = $user; $this->rootFolder = $rootFolder; $this->userFolder = $rootFolder->getUserFolder($user->getUID()); + $this->userConfigService = $userConfigService; } /** @@ -104,7 +107,7 @@ public function getChildren(): array { if ($this->children === null) { $folders = $this->albumMapper->getForUserWithFiles($this->user->getUID()); $this->children = array_map(function (AlbumWithFiles $folder) { - return new AlbumRoot($this->albumMapper, $folder, $this->rootFolder, $this->userFolder, $this->user); + return new AlbumRoot($this->albumMapper, $folder, $this->rootFolder, $this->userFolder, $this->user, $this->userConfigService); }, $folders); } diff --git a/lib/Sabre/PhotosHome.php b/lib/Sabre/PhotosHome.php index d3cd1c94e..c9498113b 100644 --- a/lib/Sabre/PhotosHome.php +++ b/lib/Sabre/PhotosHome.php @@ -25,7 +25,7 @@ use OCA\Photos\Album\AlbumMapper; use OCA\Photos\Sabre\Album\AlbumsHome; -use OCP\Files\Folder; +use OCA\Photos\Service\UserConfigService; use OCP\Files\IRootFolder; use OCP\IUser; use Sabre\DAV\Exception\Forbidden; @@ -37,19 +37,20 @@ class PhotosHome implements ICollection { private array $principalInfo; private IUser $user; private IRootFolder $rootFolder; - private Folder $userFolder; + private UserConfigService $userConfigService; public function __construct( array $principalInfo, AlbumMapper $albumMapper, IUser $user, - IRootFolder $rootFolder + IRootFolder $rootFolder, + UserConfigService $userConfigService ) { $this->principalInfo = $principalInfo; $this->albumMapper = $albumMapper; $this->user = $user; $this->rootFolder = $rootFolder; - $this->userFolder = $rootFolder->getUserFolder($user->getUID()); + $this->userConfigService = $userConfigService; } /** @@ -84,7 +85,7 @@ public function createDirectory($name) { public function getChild($name) { if ($name === 'albums') { - return new AlbumsHome($this->principalInfo, $this->albumMapper, $this->user, $this->rootFolder); + return new AlbumsHome($this->principalInfo, $this->albumMapper, $this->user, $this->rootFolder, $this->userConfigService); } throw new NotFound(); @@ -94,7 +95,7 @@ public function getChild($name) { * @return AlbumsHome[] */ public function getChildren(): array { - return [new AlbumsHome($this->principalInfo, $this->albumMapper, $this->user, $this->rootFolder)]; + return [new AlbumsHome($this->principalInfo, $this->albumMapper, $this->user, $this->rootFolder, $this->userConfigService)]; } public function childExists($name): bool { diff --git a/lib/Sabre/RootCollection.php b/lib/Sabre/RootCollection.php index c5cc1e82f..5684181f7 100644 --- a/lib/Sabre/RootCollection.php +++ b/lib/Sabre/RootCollection.php @@ -24,6 +24,7 @@ namespace OCA\Photos\Sabre; use OCA\Photos\Album\AlbumMapper; +use OCA\Photos\Service\UserConfigService; use OCP\Files\IRootFolder; use OCP\IUserSession; use Sabre\DAVACL\AbstractPrincipalCollection; @@ -33,18 +34,20 @@ class RootCollection extends AbstractPrincipalCollection { private AlbumMapper $folderMapper; private IUserSession $userSession; private IRootFolder $rootFolder; + private UserConfigService $userConfigService; public function __construct( AlbumMapper $folderMapper, IUserSession $userSession, IRootFolder $rootFolder, - PrincipalBackend\BackendInterface $principalBackend - ) { + PrincipalBackend\BackendInterface $principalBackend, + UserConfigService $userConfigService) { parent::__construct($principalBackend, 'principals/users'); $this->folderMapper = $folderMapper; $this->userSession = $userSession; $this->rootFolder = $rootFolder; + $this->userConfigService = $userConfigService; } /** @@ -62,7 +65,7 @@ public function getChildForPrincipal(array $principalInfo): PhotosHome { if (is_null($user) || $name !== $user->getUID()) { throw new \Sabre\DAV\Exception\Forbidden(); } - return new PhotosHome($principalInfo, $this->folderMapper, $user, $this->rootFolder); + return new PhotosHome($principalInfo, $this->folderMapper, $user, $this->rootFolder, $this->userConfigService); } public function getName(): string { From 8c4bc0d0ca1fd320b28c305e8c4603d36d6caa9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20Molakvo=C3=A6?= Date: Sat, 10 Sep 2022 08:39:56 +0200 Subject: [PATCH 3/3] Album upload MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: John Molakvoæ --- lib/Sabre/Album/AlbumRoot.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/Sabre/Album/AlbumRoot.php b/lib/Sabre/Album/AlbumRoot.php index b41aa4879..d9fcdb626 100644 --- a/lib/Sabre/Album/AlbumRoot.php +++ b/lib/Sabre/Album/AlbumRoot.php @@ -87,12 +87,18 @@ public function setName($name) { */ public function createFile($name, $data = null) { try { + // userConfigService->getUserConfig handle the path creation if missing $photosLocation = $this->userConfigService->getUserConfig('photosLocation'); + $photosFolder = $this->userFolder->get($photosLocation); + if (!($photosFolder instanceof Folder)) { + throw new Conflict('The destination exists and is not a folder'); + } + $node = $photosFolder->newFile($name, $data); return $this->addFile($node->getId(), $node->getOwner()->getUID()); } catch (\Exception $e) { - throw new \Exception('The file could not be created'); + throw new Forbidden('Could not create file'); } } @@ -150,6 +156,7 @@ private function addFile(int $sourceId, string $ownerUID): bool { $this->albumMapper->addFile($this->album->getAlbum()->getId(), $sourceId); return true; } + return false; } public function getAlbum(): AlbumWithFiles {