Skip to content

Commit 351a796

Browse files
committed
Add DAV endpoint for location grouping
Signed-off-by: Louis Chemineau <[email protected]>
1 parent c5c257d commit 351a796

File tree

5 files changed

+458
-5
lines changed

5 files changed

+458
-5
lines changed
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
/**
5+
* @copyright Copyright (c) 2022 Louis Chemineau <[email protected]>
6+
*
7+
* @author Louis Chemineau <[email protected]>
8+
*
9+
* @license GNU AGPL version 3 or any later version
10+
*
11+
* This program is free software: you can redistribute it and/or modify
12+
* it under the terms of the GNU Affero General Public License as
13+
* published by the Free Software Foundation, either version 3 of the
14+
* License, or (at your option) any later version.
15+
*
16+
* This program is distributed in the hope that it will be useful,
17+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
18+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19+
* GNU Affero General Public License for more details.
20+
*
21+
* You should have received a copy of the GNU Affero General Public License
22+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
23+
*
24+
*/
25+
26+
namespace OCA\Photos\Sabre\Location;
27+
28+
use OCA\Photos\DB\Location\LocationFile;
29+
use OCA\Photos\DB\Location\LocationInfo;
30+
use OCP\Files\IRootFolder;
31+
use OCP\Files\Node;
32+
use OCP\Files\File;
33+
use OCP\Files\NotFoundException;
34+
use Sabre\DAV\Exception\Forbidden;
35+
use Sabre\DAV\IFile;
36+
37+
class LocationPhoto implements IFile {
38+
private LocationInfo $locationInfo;
39+
private LocationFile $locationFile;
40+
private IRootFolder $rootFolder;
41+
42+
public const TAG_FAVORITE = '_$!<Favorite>!$_';
43+
44+
public function __construct(
45+
LocationInfo $locationInfo,
46+
LocationFile $locationFile,
47+
IRootFolder $rootFolder
48+
) {
49+
$this->locationInfo = $locationInfo;
50+
$this->locationFile = $locationFile;
51+
$this->rootFolder = $rootFolder;
52+
}
53+
54+
/**
55+
* @return void
56+
*/
57+
public function delete() {
58+
throw new Forbidden('Cannot remove from a location');
59+
}
60+
61+
public function getName() {
62+
return $this->locationFile->getFileId() . "-" . $this->locationFile->getName();
63+
}
64+
65+
/**
66+
* @return never
67+
*/
68+
public function setName($name) {
69+
throw new Forbidden('Cannot rename from a location');
70+
}
71+
72+
public function getLastModified() {
73+
return $this->locationFile->getMTime();
74+
}
75+
76+
public function put($data) {
77+
$nodes = $this->userFolder->getById($this->file->getFileId());
78+
$node = current($nodes);
79+
if ($node) {
80+
/** @var Node $node */
81+
if ($node instanceof File) {
82+
return $node->putContent($data);
83+
} else {
84+
throw new NotFoundException("Photo is a folder");
85+
}
86+
} else {
87+
throw new NotFoundException("Photo not found for user");
88+
}
89+
}
90+
91+
public function get() {
92+
$nodes = $this->rootFolder
93+
->getUserFolder($this->locationInfo->getUserId())
94+
->getById($this->locationFile->getFileId());
95+
$node = current($nodes);
96+
if ($node) {
97+
/** @var Node $node */
98+
if ($node instanceof File) {
99+
return $node->fopen('r');
100+
} else {
101+
throw new NotFoundException("Photo is a folder");
102+
}
103+
} else {
104+
throw new NotFoundException("Photo not found for user");
105+
}
106+
}
107+
108+
public function getFileId(): int {
109+
return $this->locationFile->getFileId();
110+
}
111+
112+
public function getFileInfo(): Node {
113+
$nodes = $this->rootFolder
114+
->getUserFolder($this->locationInfo->getUserId())
115+
->getById($this->locationFile->getFileId());
116+
$node = current($nodes);
117+
if ($node) {
118+
return $node->get;
119+
} else {
120+
throw new NotFoundException("Photo not found for user");
121+
}
122+
}
123+
124+
public function getContentType() {
125+
return $this->locationFile->getMimeType();
126+
}
127+
128+
public function getETag() {
129+
return $this->locationFile->getEtag();
130+
}
131+
132+
public function getSize() {
133+
return $this->locationFile->getSize();
134+
}
135+
136+
public function getFile(): LocationFile {
137+
return $this->locationFile;
138+
}
139+
140+
public function isFavorite(): bool {
141+
$tagManager = \OCP\Server::get(\OCP\ITagManager::class);
142+
$tagger = $tagManager->load('files');
143+
if ($tagger === null) {
144+
return false;
145+
}
146+
$tags = $tagger->getTagsForObjects([$this->getFileId()]);
147+
148+
if ($tags === false || empty($tags)) {
149+
return false;
150+
}
151+
152+
return array_search(self::TAG_FAVORITE, current($tags)) !== false;
153+
}
154+
155+
public function setFavoriteState($favoriteState): bool {
156+
$tagManager = \OCP\Server::get(\OCP\ITagManager::class);
157+
$tagger = $tagManager->load('files');
158+
159+
switch ($favoriteState) {
160+
case "0":
161+
return $tagger->removeFromFavorites($this->locationFile->getFileId());
162+
case "1":
163+
return $tagger->addToFavorites($this->locationFile->getFileId());
164+
default:
165+
new \Exception('Favorite state is invalide, should be 0 or 1.');
166+
}
167+
}
168+
}
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
/**
5+
* @copyright Copyright (c) 2022 Louis Chemineau <[email protected]>
6+
*
7+
* @author Louis Chemineau <[email protected]>
8+
*
9+
* @license GNU AGPL version 3 or any later version
10+
*
11+
* This program is free software: you can redistribute it and/or modify
12+
* it under the terms of the GNU Affero General Public License as
13+
* published by the Free Software Foundation, either version 3 of the
14+
* License, or (at your option) any later version.
15+
*
16+
* This program is distributed in the hope that it will be useful,
17+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
18+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19+
* GNU Affero General Public License for more details.
20+
*
21+
* You should have received a copy of the GNU Affero General Public License
22+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
23+
*
24+
*/
25+
26+
namespace OCA\Photos\Sabre\Location;
27+
28+
use OCA\Photos\DB\Location\LocationFile;
29+
use OCA\Photos\DB\Location\LocationInfo;
30+
use OCA\Photos\DB\Location\LocationMapper;
31+
use OCA\Photos\Service\ReverseGeoCoderService;
32+
use OCP\Files\IRootFolder;
33+
use Sabre\DAV\Exception\Forbidden;
34+
use Sabre\DAV\Exception\NotFound;
35+
use Sabre\DAV\ICollection;
36+
37+
class LocationRoot implements ICollection {
38+
protected LocationMapper $locationMapper;
39+
protected ReverseGeoCoderService $reverseGeoCoderService;
40+
protected LocationInfo $locationInfo;
41+
protected IRootFolder $rootFolder;
42+
/** @var LocationFile[] */
43+
protected ?array $children = null;
44+
45+
public function __construct(
46+
LocationMapper $locationMapper,
47+
ReverseGeoCoderService $reverseGeoCoderService,
48+
LocationInfo $locationInfo,
49+
IRootFolder $rootFolder,
50+
) {
51+
$this->locationMapper = $locationMapper;
52+
$this->reverseGeoCoderService = $reverseGeoCoderService;
53+
$this->locationInfo = $locationInfo;
54+
$this->rootFolder = $rootFolder;
55+
}
56+
57+
/**
58+
* @return never
59+
*/
60+
public function delete() {
61+
throw new Forbidden('Not allowed to delete a location collection');
62+
}
63+
64+
public function getName(): string {
65+
return $this->reverseGeoCoderService->getLocationNameForLocationId(
66+
$this->locationInfo->getLocationId()
67+
);
68+
}
69+
70+
/**
71+
* @return never
72+
*/
73+
public function setName($name) {
74+
throw new Forbidden('Cannot change the location collection name');
75+
}
76+
77+
/**
78+
* @param string $name
79+
* @param null|resource|string $data
80+
* @return never
81+
*/
82+
public function createFile($name, $data = null) {
83+
throw new Forbidden('Cannot create a file in a location collection');
84+
}
85+
86+
/**
87+
* @return never
88+
*/
89+
public function createDirectory($name) {
90+
throw new Forbidden('Not allowed to create directories in this folder');
91+
}
92+
93+
public function getChildren(): array {
94+
if ($this->children === null) {
95+
$this->children = array_map(
96+
fn (LocationFile $file) => new LocationPhoto($this->locationInfo, $file, $this->rootFolder),
97+
$this->locationMapper->findFilesForUserAndLocation($this->locationInfo->getUserId(), $this->locationInfo->getLocationId())
98+
);
99+
}
100+
101+
return $this->children;
102+
}
103+
104+
public function getChild($name): LocationPhoto {
105+
foreach ($this->getChildren() as $child) {
106+
if ($child->getName() === $name) {
107+
return $child;
108+
}
109+
}
110+
111+
throw new NotFound("$name not found");
112+
}
113+
114+
public function childExists($name): bool {
115+
try {
116+
$this->getChild($name);
117+
return true;
118+
} catch (NotFound $e) {
119+
return false;
120+
}
121+
}
122+
123+
public function getLastModified(): int {
124+
return 0;
125+
}
126+
127+
/**
128+
* @return int|null
129+
*/
130+
public function getCover() {
131+
$children = $this->getChildren();
132+
133+
if (count($children) > 0) {
134+
return $children[0]->getFileId();
135+
} else {
136+
return null;
137+
}
138+
}
139+
}

0 commit comments

Comments
 (0)