Skip to content

Commit

Permalink
Add DAV endpoint for location grouping
Browse files Browse the repository at this point in the history
Signed-off-by: Louis Chemineau <louis@chmn.me>
  • Loading branch information
artonge committed Oct 25, 2022
1 parent f294c88 commit dceccde
Show file tree
Hide file tree
Showing 5 changed files with 457 additions and 5 deletions.
126 changes: 126 additions & 0 deletions lib/Sabre/Location/LocationHome.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
<?php

declare(strict_types=1);
/**
* @copyright Copyright (c) 2022 Louis Chemineau <louis@chmn.me>
*
* @author Louis Chemineau <louis@chmn.me>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

namespace OCA\Photos\Sabre\Location;

use OCP\Files\IRootFolder;
use OCA\Photos\DB\Location\LocationInfo;
use OCA\Photos\DB\Location\LocationMapper;
use OCA\Photos\Service\MediaLocationManager;
use Sabre\DAV\Exception\Forbidden;
use Sabre\DAV\Exception\NotFound;
use Sabre\DAV\ICollection;

class LocationHome implements ICollection {
protected array $principalInfo;
protected string $userId;
protected IRootFolder $rootFolder;
protected MediaLocationManager $mediaLocationManager;
protected LocationMapper $locationMapper;

public const NAME = 'locations';

/**
* @var LocationRoot[]
*/
protected ?array $children = null;

public function __construct(
array $principalInfo,
string $userId,
IRootFolder $rootFolder,
MediaLocationManager $mediaLocationManager,
LocationMapper $locationMapper
) {
$this->principalInfo = $principalInfo;
$this->userId = $userId;
$this->rootFolder = $rootFolder;
$this->mediaLocationManager = $mediaLocationManager;
$this->locationMapper = $locationMapper;
}

/**
* @return never
*/
public function delete() {
throw new Forbidden();
}

public function getName(): string {
return self::NAME;
}

/**
* @return never
*/
public function setName($name) {
throw new Forbidden('Permission denied to rename this folder');
}

public function createFile($name, $data = null) {
throw new Forbidden('Not allowed to create files in this folder');
}

public function createDirectory($name) {
throw new Forbidden('Not allowed to create folder in this folder');
}

public function getChild($name) {
foreach ($this->getChildren() as $child) {
if ($child->getName() === $name) {
return $child;
}
}

throw new NotFound();
}

/**
* @return AlbumRoot[]
*/
public function getChildren(): array {
if ($this->children === null) {
$this->children = array_map(
fn (LocationInfo $locationInfo) => new LocationRoot($this->locationMapper, $this->mediaLocationManager, $locationInfo, $this->rootFolder),
$this->locationMapper->findLocationForUser($this->userId)
);
}

return $this->children;
}

public function childExists($name): bool {
try {
$this->getChild($name);
return true;
} catch (NotFound $e) {
return false;
}
}

public function getLastModified(): int {
return 0;
}
}
168 changes: 168 additions & 0 deletions lib/Sabre/Location/LocationPhoto.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
<?php

declare(strict_types=1);
/**
* @copyright Copyright (c) 2022 Louis Chemineau <louis@chmn.me>
*
* @author Louis Chemineau <louis@chmn.me>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

namespace OCA\Photos\Sabre\Location;

use OCA\Photos\DB\Location\LocationFile;
use OCA\Photos\DB\Location\LocationInfo;
use OCP\Files\IRootFolder;
use OCP\Files\Node;
use OCP\Files\File;
use OCP\Files\NotFoundException;
use Sabre\DAV\Exception\Forbidden;
use Sabre\DAV\IFile;

class LocationPhoto implements IFile {
private LocationInfo $locationInfo;
private LocationFile $locationFile;
private IRootFolder $rootFolder;

public const TAG_FAVORITE = '_$!<Favorite>!$_';

public function __construct(
LocationInfo $locationInfo,
LocationFile $locationFile,
IRootFolder $rootFolder
) {
$this->locationInfo = $locationInfo;
$this->locationFile = $locationFile;
$this->rootFolder = $rootFolder;
}

/**
* @return void
*/
public function delete() {
throw new Forbidden('Cannot remove from a location');
}

public function getName() {
return $this->locationFile->getFileId() . "-" . $this->locationFile->getName();
}

/**
* @return never
*/
public function setName($name) {
throw new Forbidden('Cannot rename from a location');
}

public function getLastModified() {
return $this->locationFile->getMTime();
}

public function put($data) {
$nodes = $this->userFolder->getById($this->file->getFileId());
$node = current($nodes);
if ($node) {
/** @var Node $node */
if ($node instanceof File) {
return $node->putContent($data);
} else {
throw new NotFoundException("Photo is a folder");
}
} else {
throw new NotFoundException("Photo not found for user");
}
}

public function get() {
$nodes = $this->rootFolder
->getUserFolder($this->locationInfo->getUserId())
->getById($this->locationFile->getFileId());
$node = current($nodes);
if ($node) {
/** @var Node $node */
if ($node instanceof File) {
return $node->fopen('r');
} else {
throw new NotFoundException("Photo is a folder");
}
} else {
throw new NotFoundException("Photo not found for user");
}
}

public function getFileId(): int {
return $this->locationFile->getFileId();
}

public function getFileInfo(): Node {
$nodes = $this->rootFolder
->getUserFolder($this->locationInfo->getUserId())
->getById($this->locationFile->getFileId());
$node = current($nodes);
if ($node) {
return $node->get;
} else {
throw new NotFoundException("Photo not found for user");
}
}

public function getContentType() {
return $this->locationFile->getMimeType();
}

public function getETag() {
return $this->locationFile->getEtag();
}

public function getSize() {
return $this->locationFile->getSize();
}

public function getFile(): LocationFile {
return $this->locationFile;
}

public function isFavorite(): bool {
$tagManager = \OCP\Server::get(\OCP\ITagManager::class);
$tagger = $tagManager->load('files');
if ($tagger === null) {
return false;
}
$tags = $tagger->getTagsForObjects([$this->getFileId()]);

if ($tags === false || empty($tags)) {
return false;
}

return array_search(self::TAG_FAVORITE, current($tags)) !== false;
}

public function setFavoriteState($favoriteState): bool {
$tagManager = \OCP\Server::get(\OCP\ITagManager::class);
$tagger = $tagManager->load('files');

switch ($favoriteState) {
case "0":
return $tagger->removeFromFavorites($this->locationFile->getFileId());
case "1":
return $tagger->addToFavorites($this->locationFile->getFileId());
default:
new \Exception('Favorite state is invalide, should be 0 or 1.');
}
}
}
Loading

0 comments on commit dceccde

Please sign in to comment.