Skip to content
Prev Previous commit
Next Next commit
dav api
Signed-off-by: Louis Chemineau <[email protected]>
  • Loading branch information
icewind1991 authored and artonge committed Aug 22, 2022
commit 3cd7fede24e383072afbceb92be41125f2ebaa4b
9 changes: 9 additions & 0 deletions appinfo/info.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
<author mail="[email protected]">John Molakvoæ</author>
<namespace>Photos</namespace>
<category>multimedia</category>
<types>
<dav/>
</types>

<website>https://github.com/nextcloud/photos</website>
<bugs>https://github.com/nextcloud/photos/issues</bugs>
Expand All @@ -25,4 +28,10 @@
<order>1</order>
</navigation>
</navigations>

<sabre>
<collections>
<collection>OCA\Photos\Sabre\RootCollection</collection>
</collections>
</sabre>
</info>
3 changes: 3 additions & 0 deletions lib/AppInfo/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

namespace OCA\Photos\AppInfo;

use OCA\DAV\Connector\Sabre\Principal;
use OCP\AppFramework\App;
use OCP\AppFramework\Bootstrap\IBootContext;
use OCP\AppFramework\Bootstrap\IBootstrap;
Expand Down Expand Up @@ -58,6 +59,8 @@ public function __construct() {
}

public function register(IRegistrationContext $context): void {
/** Register $principalBackend for the DAV collection */
$context->registerServiceAlias('principalBackend', Principal::class);
}

public function boot(IBootContext $context): void {
Expand Down
95 changes: 95 additions & 0 deletions lib/Sabre/Album/AlbumPhoto.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
<?php

declare(strict_types=1);
/**
* @copyright Copyright (c) 2021 Robin Appelman <[email protected]>
*
* @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\Album;

use OCA\Photos\Album\AlbumFile;
use OCA\Photos\Album\AlbumInfo;
use OCA\Photos\Album\AlbumMapper;
use OCP\Files\Folder;
use OCP\Files\Node;
use OCP\Files\File;
use OCP\Files\NotFoundException;
use Sabre\DAV\Exception\Forbidden;
use Sabre\DAV\IFile;

class AlbumPhoto implements IFile {
private AlbumMapper $albumMapper;
private AlbumInfo $album;
private AlbumFile $file;
private Folder $userFolder;

public function __construct(AlbumMapper $albumMapper, AlbumInfo $album, AlbumFile $file, Folder $userFolder) {
$this->albumMapper = $albumMapper;
$this->album = $album;
$this->file = $file;
$this->userFolder = $userFolder;
}

public function delete() {
$this->albumMapper->removeFile($this->album->getId(), $this->file->getFileId());
}

public function getName() {
return $this->file->getName();
}

public function setName($name) {
throw new Forbidden('Can\'t rename photos trough the album api');
}

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

public function put($data) {
throw new Forbidden('Can\'t write to photos trough the album api');
}

public function get() {
$nodes = $this->userFolder->getById($this->file->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 getContentType() {
return $this->file->getMimeType();
}

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

public function getSize() {
return $this->file->getSize();
}
}
117 changes: 117 additions & 0 deletions lib/Sabre/Album/AlbumRoot.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
<?php

declare(strict_types=1);
/**
* @copyright Copyright (c) 2021 Robin Appelman <[email protected]>
*
* @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\Album;

use OCA\DAV\Connector\Sabre\File;
use OCA\Photos\Album\AlbumFile;
use OCA\Photos\Album\AlbumMapper;
use OCA\Photos\Album\AlbumWithFiles;
use OCP\Files\Folder;
use OCP\Files\IRootFolder;
use OCP\IUser;
use Sabre\DAV\Exception\Conflict;
use Sabre\DAV\Exception\Forbidden;
use Sabre\DAV\Exception\NotFound;
use Sabre\DAV\ICollection;
use Sabre\DAV\ICopyTarget;
use Sabre\DAV\INode;

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) {
$this->albumMapper = $albumMapper;
$this->album = $album;
$this->rootFolder = $rootFolder;
$this->userFolder = $userFolder;
$this->user = $user;
}

public function delete() {
$this->albumMapper->delete($this->album->getAlbum()->getId());
}

public function getName(): string {
return basename($this->album->getAlbum()->getTitle());
}

public function setName($name) {
$this->albumMapper->rename($this->album->getAlbum()->getId(), $name);
}

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

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

public function getChildren(): array {
return array_map(function (AlbumFile $file) {
return new AlbumPhoto($this->albumMapper, $this->album->getAlbum(), $file, $this->userFolder);
}, $this->album->getFiles());
}

public function getChild($name): AlbumPhoto {
foreach ($this->album->getFiles() as $file) {
if ($file->getName() === $name) {
return new AlbumPhoto($this->albumMapper, $this->album->getAlbum(), $file, $this->userFolder);
}
}
throw new NotFound("$name not found");
}

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

public function getLastModified(): int {
return 0;
}

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;
}
}
throw new \Exception("Can't add file to album, only files from $uid can be added");
}
}
107 changes: 107 additions & 0 deletions lib/Sabre/Album/AlbumsHome.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
<?php

declare(strict_types=1);
/**
* @copyright Copyright (c) 2021 Robin Appelman <[email protected]>
*
* @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\Album;

use OCA\Photos\Album\AlbumMapper;
use OCA\Photos\Album\AlbumWithFiles;
use OCP\Files\Folder;
use OCP\Files\IRootFolder;
use OCP\IUser;
use Sabre\DAV\Exception\Forbidden;
use Sabre\DAV\Exception\NotFound;
use Sabre\DAV\ICollection;

class AlbumsHome implements ICollection {
private AlbumMapper $albumMapper;
private array $principalInfo;
private IUser $user;
private IRootFolder $rootFolder;
private Folder $userFolder;

public function __construct(
array $principalInfo,
AlbumMapper $albumMapper,
IUser $user,
IRootFolder $rootFolder
) {
$this->principalInfo = $principalInfo;
$this->albumMapper = $albumMapper;
$this->user = $user;
$this->rootFolder = $rootFolder;
$this->userFolder = $rootFolder->getUserFolder($user->getUID());
}

public function delete() {
throw new Forbidden();
}

public function getName(): string {
return 'albums';
}

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) {
$uid = $this->user->getUID();
$this->albumMapper->create($uid, $name);
}

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

throw new NotFound();
}

/**
* @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);
}

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

public function getLastModified(): int {
return 0;
}
}
Loading