Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/photos.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorLouis Chemineau <louis@chmn.me>2022-07-27 12:47:27 +0300
committerLouis Chemineau <louis@chmn.me>2022-08-22 21:04:58 +0300
commitc8bf3a52d6affb175b17ed3380a6f39746e1c28a (patch)
treedb04fc10248c33dc05f42c760880c008b31ddb0d /lib
parent0f2bcdaab726739e16930e73e9e00b6079374e78 (diff)
Add Albums viewfeat/album_frontend
Signed-off-by: Louis Chemineau <louis@chmn.me>
Diffstat (limited to 'lib')
-rw-r--r--lib/Album/AlbumFile.php4
-rw-r--r--lib/Album/AlbumWithFiles.php2
-rw-r--r--lib/Exception/AlreadyInAlbumException.php1
-rw-r--r--lib/Migration/Version20000Date20220727125801.php3
-rw-r--r--lib/Sabre/Album/AlbumPhoto.php34
-rw-r--r--lib/Sabre/Album/AlbumRoot.php40
-rw-r--r--lib/Sabre/Album/AlbumsHome.php26
-rw-r--r--lib/Sabre/Album/PropFindPlugin.php44
-rw-r--r--lib/Sabre/PhotosHome.php9
-rw-r--r--lib/Sabre/RootCollection.php2
10 files changed, 136 insertions, 29 deletions
diff --git a/lib/Album/AlbumFile.php b/lib/Album/AlbumFile.php
index 86863e09..8eb2482f 100644
--- a/lib/Album/AlbumFile.php
+++ b/lib/Album/AlbumFile.php
@@ -33,7 +33,7 @@ class AlbumFile {
private int $mtime;
private string $etag;
private int $added;
- /** @var array<int, FileMetadata> */
+ /** @var array<string, FileMetadata> */
private array $metaData = [];
public function __construct(
@@ -74,7 +74,7 @@ class AlbumFile {
return $this->mtime;
}
- public function getEtag() {
+ public function getEtag(): string {
return $this->etag;
}
diff --git a/lib/Album/AlbumWithFiles.php b/lib/Album/AlbumWithFiles.php
index cc6d0d1a..0bb630d6 100644
--- a/lib/Album/AlbumWithFiles.php
+++ b/lib/Album/AlbumWithFiles.php
@@ -48,7 +48,7 @@ class AlbumWithFiles {
* @return int[]
*/
public function getFileIds(): array {
- return array_map(function(AlbumFile $file) {
+ return array_map(function (AlbumFile $file) {
return $file->getFileId();
}, $this->files);
}
diff --git a/lib/Exception/AlreadyInAlbumException.php b/lib/Exception/AlreadyInAlbumException.php
index 9c7d7fe3..a8a89b05 100644
--- a/lib/Exception/AlreadyInAlbumException.php
+++ b/lib/Exception/AlreadyInAlbumException.php
@@ -24,5 +24,4 @@ declare(strict_types=1);
namespace OCA\Photos\Exception;
class AlreadyInAlbumException extends \Exception {
-
}
diff --git a/lib/Migration/Version20000Date20220727125801.php b/lib/Migration/Version20000Date20220727125801.php
index 81284e35..5641a540 100644
--- a/lib/Migration/Version20000Date20220727125801.php
+++ b/lib/Migration/Version20000Date20220727125801.php
@@ -25,7 +25,6 @@ namespace OCA\Photos\Migration;
use Closure;
use Doctrine\DBAL\Types\Types;
-use OC\DB\SchemaWrapper;
use OCP\DB\ISchemaWrapper;
use OCP\Migration\IOutput;
use OCP\Migration\SimpleMigrationStep;
@@ -35,7 +34,7 @@ use OCP\Migration\SimpleMigrationStep;
*/
class Version20000Date20220727125801 extends SimpleMigrationStep {
public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper {
- /** @var SchemaWrapper $schema */
+ /** @var ISchemaWrapper $schema */
$schema = $schemaClosure();
if (!$schema->hasTable("photos_albums")) {
diff --git a/lib/Sabre/Album/AlbumPhoto.php b/lib/Sabre/Album/AlbumPhoto.php
index 01532725..0c208574 100644
--- a/lib/Sabre/Album/AlbumPhoto.php
+++ b/lib/Sabre/Album/AlbumPhoto.php
@@ -39,6 +39,8 @@ class AlbumPhoto implements IFile {
private AlbumFile $file;
private Folder $userFolder;
+ public const TAG_FAVORITE = '_$!<Favorite>!$_';
+
public function __construct(AlbumMapper $albumMapper, AlbumInfo $album, AlbumFile $file, Folder $userFolder) {
$this->albumMapper = $albumMapper;
$this->album = $album;
@@ -46,6 +48,9 @@ class AlbumPhoto implements IFile {
$this->userFolder = $userFolder;
}
+ /**
+ * @return void
+ */
public function delete() {
$this->albumMapper->removeFile($this->album->getId(), $this->file->getFileId());
}
@@ -54,6 +59,9 @@ class AlbumPhoto implements IFile {
return $this->file->getFileId() . "-" . $this->file->getName();
}
+ /**
+ * @return never
+ */
public function setName($name) {
throw new Forbidden('Can\'t rename photos trough the album api');
}
@@ -81,6 +89,20 @@ class AlbumPhoto implements IFile {
}
}
+ public function getFileId(): int {
+ return $this->file->getFileId();
+ }
+
+ public function getFileInfo(): Node {
+ $nodes = $this->userFolder->getById($this->file->getFileId());
+ $node = current($nodes);
+ if ($node) {
+ return $node;
+ } else {
+ throw new NotFoundException("Photo not found for user");
+ }
+ }
+
public function getContentType() {
return $this->file->getMimeType();
}
@@ -96,4 +118,16 @@ class AlbumPhoto implements IFile {
public function getFile(): AlbumFile {
return $this->file;
}
+
+ public function isFavorite(): bool {
+ $tagManager = \OCP\Server::get(\OCP\ITagManager::class);
+ $tagger = $tagManager->load('files');
+ $tags = $tagger->getTagsForObjects([$this->getFileId()]);
+
+ if ($tags === false || empty($tags)) {
+ return false;
+ }
+
+ return array_search(self::TAG_FAVORITE, current($tags)) !== false;
+ }
}
diff --git a/lib/Sabre/Album/AlbumRoot.php b/lib/Sabre/Album/AlbumRoot.php
index 4cb132c0..ffe5d2a2 100644
--- a/lib/Sabre/Album/AlbumRoot.php
+++ b/lib/Sabre/Album/AlbumRoot.php
@@ -52,6 +52,9 @@ class AlbumRoot implements ICollection, ICopyTarget {
$this->user = $user;
}
+ /**
+ * @return void
+ */
public function delete() {
$this->albumMapper->delete($this->album->getAlbum()->getId());
}
@@ -60,6 +63,9 @@ class AlbumRoot implements ICollection, ICopyTarget {
return basename($this->album->getAlbum()->getTitle());
}
+ /**
+ * @return void
+ */
public function setName($name) {
$this->albumMapper->rename($this->album->getAlbum()->getId(), $name);
}
@@ -68,6 +74,9 @@ class AlbumRoot implements ICollection, ICopyTarget {
throw new Forbidden('Not allowed to create files in this folder, copy files into this folder instead');
}
+ /**
+ * @return never
+ */
public function createDirectory($name) {
throw new Forbidden('Not allowed to create directories in this folder');
}
@@ -118,4 +127,35 @@ class AlbumRoot implements ICollection, ICopyTarget {
public function getAlbum(): AlbumWithFiles {
return $this->album;
}
+
+ public function getDateRange(): array {
+ $earliestDate = null;
+ $latestDate = null;
+
+ foreach ($this->getChildren() as $child) {
+ $childCreationDate = $child->getFileInfo()->getMtime();
+ if ($childCreationDate < $earliestDate || $earliestDate === null) {
+ $earliestDate = $childCreationDate;
+ }
+
+ if ($childCreationDate > $earliestDate || $latestDate === null) {
+ $latestDate = $childCreationDate;
+ }
+ }
+
+ return ['start' => $earliestDate, 'end' => $latestDate];
+ }
+
+ /**
+ * @return int|null
+ */
+ public function getCover() {
+ $children = $this->getChildren();
+
+ if (count($children) > 0) {
+ return $children[0]->getFileId();
+ } else {
+ return null;
+ }
+ }
}
diff --git a/lib/Sabre/Album/AlbumsHome.php b/lib/Sabre/Album/AlbumsHome.php
index 1c070b59..a2bc2fe7 100644
--- a/lib/Sabre/Album/AlbumsHome.php
+++ b/lib/Sabre/Album/AlbumsHome.php
@@ -39,6 +39,11 @@ class AlbumsHome implements ICollection {
private IRootFolder $rootFolder;
private Folder $userFolder;
+ /**
+ * @var AlbumRoot[]
+ */
+ private ?array $children = null;
+
public function __construct(
array $principalInfo,
AlbumMapper $albumMapper,
@@ -52,6 +57,9 @@ class AlbumsHome implements ICollection {
$this->userFolder = $rootFolder->getUserFolder($user->getUID());
}
+ /**
+ * @return never
+ */
public function delete() {
throw new Forbidden();
}
@@ -60,6 +68,9 @@ class AlbumsHome implements ICollection {
return 'albums';
}
+ /**
+ * @return never
+ */
public function setName($name) {
throw new Forbidden('Permission denied to rename this folder');
}
@@ -68,6 +79,9 @@ class AlbumsHome implements ICollection {
throw new Forbidden('Not allowed to create files in this folder');
}
+ /**
+ * @return void
+ */
public function createDirectory($name) {
$uid = $this->user->getUID();
$this->albumMapper->create($uid, $name);
@@ -87,10 +101,14 @@ class AlbumsHome implements ICollection {
* @return AlbumRoot[]
*/
public function getChildren(): array {
- $folders = $this->albumMapper->getForUserWithFiles($this->user->getUID());
- return array_map(function (AlbumWithFiles $folder) {
- return new AlbumRoot($this->albumMapper, $folder, $this->rootFolder, $this->userFolder, $this->user);
- }, $folders);
+ 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);
+ }, $folders);
+ }
+
+ return $this->children;
}
public function childExists($name): bool {
diff --git a/lib/Sabre/Album/PropFindPlugin.php b/lib/Sabre/Album/PropFindPlugin.php
index ce7f0eff..040ef5ac 100644
--- a/lib/Sabre/Album/PropFindPlugin.php
+++ b/lib/Sabre/Album/PropFindPlugin.php
@@ -27,6 +27,7 @@ use OC\Metadata\IMetadataManager;
use OCA\DAV\Connector\Sabre\FilesPlugin;
use OCA\Photos\Album\AlbumMapper;
use OCP\IConfig;
+use OCP\IPreview;
use Sabre\DAV\INode;
use Sabre\DAV\PropFind;
use Sabre\DAV\PropPatch;
@@ -36,11 +37,18 @@ use Sabre\DAV\Tree;
class PropFindPlugin extends ServerPlugin {
public const FILE_NAME_PROPERTYNAME = '{http://nextcloud.org/ns}file-name';
+ public const REALPATH_PROPERTYNAME = '{http://nextcloud.org/ns}realpath';
+ public const FAVORITE_PROPERTYNAME = '{http://owncloud.org/ns}favorite';
+ public const DATE_RANGE_PROPERTYNAME = '{http://nextcloud.org/ns}dateRange';
public const LOCATION_PROPERTYNAME = '{http://nextcloud.org/ns}location';
public const LAST_PHOTO_PROPERTYNAME = '{http://nextcloud.org/ns}last-photo';
+ public const NBITEMS_PROPERTYNAME = '{http://nextcloud.org/ns}nbItems';
+
+ public const TAG_FAVORITE = '_$!<Favorite>!$_';
private IConfig $config;
private IMetadataManager $metadataManager;
+ private IPreview $previewManager;
private bool $metadataEnabled;
private ?Tree $tree;
private AlbumMapper $albumMapper;
@@ -48,31 +56,35 @@ class PropFindPlugin extends ServerPlugin {
public function __construct(
IConfig $config,
IMetadataManager $metadataManager,
+ IPreview $previewManager,
AlbumMapper $albumMapper
) {
$this->config = $config;
$this->metadataManager = $metadataManager;
+ $this->previewManager = $previewManager;
$this->albumMapper = $albumMapper;
$this->metadataEnabled = $this->config->getSystemValueBool('enable_file_metadata', true);
}
-
+ /**
+ * @return void
+ */
public function initialize(Server $server) {
$this->tree = $server->tree;
$server->on('propFind', [$this, 'propFind']);
$server->on('propPatch', [$this, 'handleUpdateProperties']);
}
- public function propFind(PropFind $propFind, INode $node) {
+ public function propFind(PropFind $propFind, INode $node): void {
if ($node instanceof AlbumPhoto) {
- $propFind->handle(self::FILE_NAME_PROPERTYNAME, function () use ($node) {
- return $node->getFile()->getName();
- });
- $propFind->handle(FilesPlugin::INTERNAL_FILEID_PROPERTYNAME, function () use ($node) {
- return $node->getFile()->getFileId();
- });
- $propFind->handle(FilesPlugin::GETETAG_PROPERTYNAME, function () use ($node): string {
- return $node->getETag();
+ $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::FAVORITE_PROPERTYNAME, fn () => $node->isFavorite() ? 1 : 0);
+
+ $propFind->handle(FilesPlugin::HAS_PREVIEW_PROPERTYNAME, function () use ($node) {
+ return json_encode($this->previewManager->isAvailable($node->getFileInfo()));
});
if ($this->metadataEnabled) {
@@ -93,12 +105,10 @@ class PropFindPlugin extends ServerPlugin {
}
if ($node instanceof AlbumRoot) {
- $propFind->handle(self::LOCATION_PROPERTYNAME, function () use ($node) {
- return $node->getAlbum()->getAlbum()->getLocation();
- });
- $propFind->handle(self::LAST_PHOTO_PROPERTYNAME, function () use ($node) {
- return $node->getAlbum()->getAlbum()->getLastAddedPhoto();
- });
+ $propFind->handle(self::LAST_PHOTO_PROPERTYNAME, fn () => $node->getAlbum()->getAlbum()->getLastAddedPhoto());
+ $propFind->handle(self::NBITEMS_PROPERTYNAME, fn () => count($node->getChildren()));
+ $propFind->handle(self::LOCATION_PROPERTYNAME, fn () => $node->getAlbum()->getAlbum()->getLocation());
+ $propFind->handle(self::DATE_RANGE_PROPERTYNAME, fn () => json_encode($node->getDateRange()));
// TODO detect dynamically which metadata groups are requested and
// preload all of them and not just size
@@ -115,7 +125,7 @@ class PropFindPlugin extends ServerPlugin {
}
}
- public function handleUpdateProperties($path, PropPatch $propPatch) {
+ public function handleUpdateProperties($path, PropPatch $propPatch): void {
$node = $this->tree->getNodeForPath($path);
if ($node instanceof AlbumRoot) {
$propPatch->handle(self::LOCATION_PROPERTYNAME, function ($location) use ($node) {
diff --git a/lib/Sabre/PhotosHome.php b/lib/Sabre/PhotosHome.php
index d37c8a11..d3cd1c94 100644
--- a/lib/Sabre/PhotosHome.php
+++ b/lib/Sabre/PhotosHome.php
@@ -52,6 +52,9 @@ class PhotosHome implements ICollection {
$this->userFolder = $rootFolder->getUserFolder($user->getUID());
}
+ /**
+ * @return never
+ */
public function delete() {
throw new Forbidden();
}
@@ -61,6 +64,9 @@ class PhotosHome implements ICollection {
return $name;
}
+ /**
+ * @return never
+ */
public function setName($name) {
throw new Forbidden('Permission denied to rename this folder');
}
@@ -69,6 +75,9 @@ class PhotosHome implements ICollection {
throw new Forbidden('Not allowed to create files in this folder');
}
+ /**
+ * @return never
+ */
public function createDirectory($name) {
throw new Forbidden('Permission denied to create folders in this folder');
}
diff --git a/lib/Sabre/RootCollection.php b/lib/Sabre/RootCollection.php
index d2478991..c5cc1e82 100644
--- a/lib/Sabre/RootCollection.php
+++ b/lib/Sabre/RootCollection.php
@@ -26,7 +26,6 @@ namespace OCA\Photos\Sabre;
use OCA\Photos\Album\AlbumMapper;
use OCP\Files\IRootFolder;
use OCP\IUserSession;
-use Sabre\DAV\INode;
use Sabre\DAVACL\AbstractPrincipalCollection;
use Sabre\DAVACL\PrincipalBackend;
@@ -56,7 +55,6 @@ class RootCollection extends AbstractPrincipalCollection {
* supplied by the authentication backend.
*
* @param array $principalInfo
- * @return INode
*/
public function getChildForPrincipal(array $principalInfo): PhotosHome {
[, $name] = \Sabre\Uri\split($principalInfo['uri']);