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
diff options
context:
space:
mode:
authorLouis Chemineau <louis@chmn.me>2022-09-29 00:20:53 +0300
committerLouis Chemineau <louis@chmn.me>2022-10-20 13:03:41 +0300
commitdefdb69026e9ef700bda4b4bba14f05e8eab5b8b (patch)
tree832ad9afd6de0f7f07d10e409c98a47d9473c752
parent01f33ad7b5a3235369a39744c6a33c06dec40f0f (diff)
Make public pages work
Signed-off-by: Louis Chemineau <louis@chmn.me>
-rw-r--r--appinfo/info.xml24
-rw-r--r--appinfo/routes.php14
-rw-r--r--lib/Album/AlbumMapper.php12
-rw-r--r--lib/AppInfo/Application.php3
-rw-r--r--lib/Controller/PreviewController.php60
-rw-r--r--lib/Controller/PublicAlbumController.php17
-rw-r--r--lib/Controller/PublicPreviewController.php67
-rw-r--r--lib/Listener/SabrePluginAuthInitListener.php49
-rw-r--r--lib/Sabre/Album/AlbumPhoto.php3
-rw-r--r--lib/Sabre/Album/AlbumRoot.php19
-rw-r--r--lib/Sabre/Album/AlbumsHome.php17
-rw-r--r--lib/Sabre/Album/PropFindPlugin.php15
-rw-r--r--lib/Sabre/Album/PublicAlbumRoot.php2
-rw-r--r--lib/Sabre/Album/PublicAlbumsHome.php51
-rw-r--r--lib/Sabre/Album/SharedAlbumRoot.php5
-rw-r--r--lib/Sabre/Album/SharedAlbumsHome.php18
-rw-r--r--lib/Sabre/PhotosHome.php25
-rw-r--r--lib/Sabre/PublicAlbumAuthBackend.php80
-rw-r--r--lib/Sabre/PublicRootCollection.php87
-rw-r--r--lib/Sabre/RootCollection.php6
-rw-r--r--psalm.xml13
-rw-r--r--src/components/Albums/CollaboratorsSelectionForm.vue6
-rw-r--r--src/components/File.vue7
-rw-r--r--src/mixins/UserConfig.js4
-rw-r--r--src/router/index.js3
-rw-r--r--src/services/Albums.js14
-rw-r--r--src/views/PublicAlbumContent.vue32
-rw-r--r--templates/public.php26
-rw-r--r--tests/psalm-baseline.xml8
29 files changed, 507 insertions, 180 deletions
diff --git a/appinfo/info.xml b/appinfo/info.xml
index 277e83c5..dd334458 100644
--- a/appinfo/info.xml
+++ b/appinfo/info.xml
@@ -10,9 +10,10 @@
<author mail="skjnldsv@protonmail.com">John Molakvoæ</author>
<namespace>Photos</namespace>
<category>multimedia</category>
- <types>
- <dav/>
- </types>
+ <types>
+ <dav />
+ <authentication />
+ </types>
<website>https://github.com/nextcloud/photos</website>
<bugs>https://github.com/nextcloud/photos/issues</bugs>
@@ -29,12 +30,13 @@
</navigation>
</navigations>
- <sabre>
- <collections>
- <collection>OCA\Photos\Sabre\RootCollection</collection>
- </collections>
- <plugins>
- <plugin>OCA\Photos\Sabre\Album\PropFindPlugin</plugin>
- </plugins>
- </sabre>
+ <sabre>
+ <collections>
+ <collection>OCA\Photos\Sabre\RootCollection</collection>
+ <collection>OCA\Photos\Sabre\PublicRootCollection</collection>
+ </collections>
+ <plugins>
+ <plugin>OCA\Photos\Sabre\Album\PropFindPlugin</plugin>
+ </plugins>
+ </sabre>
</info>
diff --git a/appinfo/routes.php b/appinfo/routes.php
index 5ae06249..db37ad4c 100644
--- a/appinfo/routes.php
+++ b/appinfo/routes.php
@@ -46,10 +46,7 @@ return [
'path' => '',
]
],
- [ 'name' => 'publicAlbum#get', 'url' => '/public/{ownerId}/{token}', 'verb' => 'GET',
- 'requirements' => [
- 'ownerId' => '.*',
- ],
+ [ 'name' => 'publicAlbum#get', 'url' => '/public/{token}', 'verb' => 'GET',
'requirements' => [
'token' => '.*',
],
@@ -132,5 +129,14 @@ return [
'fileId' => '.*',
]
],
+
+ [
+ 'name' => 'publicPreview#index',
+ 'url' => '/api/v1/publicPreview/{fileId}',
+ 'verb' => 'GET',
+ 'requirements' => [
+ 'fileId' => '.*',
+ ]
+ ],
]
];
diff --git a/lib/Album/AlbumMapper.php b/lib/Album/AlbumMapper.php
index baf1a728..5514d869 100644
--- a/lib/Album/AlbumMapper.php
+++ b/lib/Album/AlbumMapper.php
@@ -362,7 +362,7 @@ class AlbumMapper {
}
break;
case self::TYPE_LINK:
- $collaborator['id'] = $this->random->generate(15, ISecureRandom::CHAR_UPPER . ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_DIGITS);
+ $collaborator['id'] = $this->random->generate(32, ISecureRandom::CHAR_UPPER . ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_DIGITS);
break;
default:
throw new \Exception('Invalid collaborator type: ' . $collaborator['type']);
@@ -420,7 +420,13 @@ class AlbumMapper {
}
if (!isset($albumsById[$albumId])) {
- $albumsById[$albumId] = new AlbumInfo($albumId, $row['album_user'], $row['album_name'].' ('.$row['album_user'].')', $row['location'], (int)$row['created'], (int)$row['last_added_photo']);
+ $albumName = $row['album_name'];
+ // Suffix album name with the album owner to prevent duplicates.
+ // Not done for public link as it would like owner's uid.
+ if ($collaboratorType !== self::TYPE_LINK) {
+ $row['album_name'].' ('.$row['album_user'].')';
+ }
+ $albumsById[$albumId] = new AlbumInfo($albumId, $row['album_user'], $albumName, $row['location'], (int)$row['created'], (int)$row['last_added_photo']);
}
}
@@ -452,7 +458,7 @@ class AlbumMapper {
* @param int $fileId
* @return AlbumInfo[]
*/
- public function getAlbumForCollaboratorIdAndFileId(string $collaboratorId, int $collaboratorType, int $fileId): array {
+ public function getAlbumsForCollaboratorIdAndFileId(string $collaboratorId, int $collaboratorType, int $fileId): array {
$query = $this->connection->getQueryBuilder();
$rows = $query
->select("a.album_id", "name", "user", "location", "created", "last_added_photo")
diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php
index 608c0f23..4a1dc328 100644
--- a/lib/AppInfo/Application.php
+++ b/lib/AppInfo/Application.php
@@ -25,6 +25,8 @@ declare(strict_types=1);
namespace OCA\Photos\AppInfo;
+use OCA\DAV\Events\SabrePluginAuthInitEvent;
+use OCA\Photos\Listener\SabrePluginAuthInitListener;
use OCA\DAV\Connector\Sabre\Principal;
use OCA\Photos\Listener\CacheEntryRemovedListener;
use OCP\AppFramework\App;
@@ -64,6 +66,7 @@ class Application extends App implements IBootstrap {
/** Register $principalBackend for the DAV collection */
$context->registerServiceAlias('principalBackend', Principal::class);
$context->registerEventListener(CacheEntryRemovedEvent::class, CacheEntryRemovedListener::class);
+ $context->registerEventListener(SabrePluginAuthInitEvent::class, SabrePluginAuthInitListener::class);
}
public function boot(IBootContext $context): void {
diff --git a/lib/Controller/PreviewController.php b/lib/Controller/PreviewController.php
index 48f79e2d..d84ea879 100644
--- a/lib/Controller/PreviewController.php
+++ b/lib/Controller/PreviewController.php
@@ -43,16 +43,16 @@ use OCP\IUserSession;
class PreviewController extends Controller {
private IUserSession $userSession;
- private Folder $userFolder;
+ private ?Folder $userFolder;
private IRootFolder $rootFolder;
- private AlbumMapper $albumMapper;
+ protected AlbumMapper $albumMapper;
private IPreview $preview;
private IGroupManager $groupManager;
public function __construct(
IRequest $request,
IUserSession $userSession,
- Folder $userFolder,
+ ?Folder $userFolder,
IRootFolder $rootFolder,
AlbumMapper $albumMapper,
IPreview $preview,
@@ -67,7 +67,6 @@ class PreviewController extends Controller {
$this->preview = $preview;
$this->groupManager = $groupManager;
}
-
/**
* @NoAdminRequired
* @NoCSRFRequired
@@ -85,25 +84,35 @@ class PreviewController extends Controller {
}
$user = $this->userSession->getUser();
+
+ if ($user === null || $this->userFolder === null) {
+ return new DataResponse([], Http::STATUS_FORBIDDEN);
+ }
+
$nodes = $this->userFolder->getById($fileId);
+ /** @var \OCA\Photos\Album\AlbumInfo[] */
+ $checkedAlbums = [];
if (\count($nodes) === 0) {
- $albums = $this->albumMapper->getForUserAndFile($user->getUID(), $fileId);
- $receivedAlbums = $this->albumMapper->getAlbumForCollaboratorIdAndFileId($user->getUID(), AlbumMapper::TYPE_USER, $fileId);
- $albums = array_merge($albums, $receivedAlbums);
+ $albumsOfCurrentUser = $this->albumMapper->getForUserAndFile($user->getUID(), $fileId);
+ $nodes = $this->getFileIdForAlbums($fileId, $albumsOfCurrentUser);
+ $checkedAlbums = $albumsOfCurrentUser;
+ }
+
+ if (\count($nodes) === 0) {
+ $receivedAlbums = $this->albumMapper->getAlbumsForCollaboratorIdAndFileId($user->getUID(), AlbumMapper::TYPE_USER, $fileId);
+ $receivedAlbums = array_udiff($checkedAlbums, $receivedAlbums, fn ($a, $b) => strcmp($a->getId(), $b->getId()));
+ $nodes = $this->getFileIdForAlbums($fileId, $receivedAlbums);
+ $checkedAlbums = array_merge($checkedAlbums, $receivedAlbums);
+ }
+ if (\count($nodes) === 0) {
$userGroups = $this->groupManager->getUserGroupIds($user);
foreach ($userGroups as $groupId) {
- $albumsForGroup = $this->albumMapper->getAlbumForCollaboratorIdAndFileId($groupId, AlbumMapper::TYPE_GROUP, $fileId);
- $albumsForGroup = array_udiff($albumsForGroup, $albums, fn ($a, $b) => $a->getId() - $b->getId());
- $albums = array_merge($albums, $albumsForGroup);
- }
-
- foreach ($albums as $album) {
- $albumFile = $this->albumMapper->getForAlbumIdAndFileId($album->getId(), $fileId);
- $nodes = $this->rootFolder
- ->getUserFolder($albumFile->getOwner())
- ->getById($fileId);
+ $albumsForGroup = $this->albumMapper->getAlbumsForCollaboratorIdAndFileId($groupId, AlbumMapper::TYPE_GROUP, $fileId);
+ $albumsForGroup = array_udiff($checkedAlbums, $albumsForGroup, fn ($a, $b) => strcmp($a->getId(), $b->getId()));
+ $nodes = $this->getFileIdForAlbums($fileId, $albumsForGroup);
+ $checkedAlbums = array_merge($checkedAlbums, $receivedAlbums);
if (\count($nodes) !== 0) {
break;
}
@@ -119,10 +128,25 @@ class PreviewController extends Controller {
return $this->fetchPreview($node, $x, $y);
}
+
+ protected function getFileIdForAlbums($fileId, $albums) {
+ foreach ($albums as $album) {
+ $albumFile = $this->albumMapper->getForAlbumIdAndFileId($album->getId(), $fileId);
+ $nodes = $this->rootFolder
+ ->getUserFolder($albumFile->getOwner())
+ ->getById($fileId);
+ if (\count($nodes) !== 0) {
+ return $nodes;
+ }
+ }
+
+ return [];
+ }
+
/**
* @return DataResponse|FileDisplayResponse
*/
- private function fetchPreview(
+ protected function fetchPreview(
Node $node,
int $x,
int $y
diff --git a/lib/Controller/PublicAlbumController.php b/lib/Controller/PublicAlbumController.php
index d5ccd3cc..6477c1f3 100644
--- a/lib/Controller/PublicAlbumController.php
+++ b/lib/Controller/PublicAlbumController.php
@@ -25,36 +25,27 @@
namespace OCA\Photos\Controller;
use OCP\AppFramework\Controller;
-use OCA\Files\Event\LoadSidebar;
use OCA\Photos\AppInfo\Application;
-use OCA\Photos\Service\UserConfigService;
use OCA\Viewer\Event\LoadViewer;
-use OCP\App\IAppManager;
use OCP\AppFramework\Http\ContentSecurityPolicy;
-use OCP\AppFramework\Http\TemplateResponse;
+use OCP\AppFramework\Http\Template\PublicTemplateResponse;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\AppFramework\Services\IInitialState;
use OCP\IRequest;
use OCP\Util;
class PublicAlbumController extends Controller {
- private IAppManager $appManager;
private IEventDispatcher $eventDispatcher;
- private UserConfigService $userConfig;
private IInitialState $initialState;
public function __construct(
IRequest $request,
- IAppManager $appManager,
IEventDispatcher $eventDispatcher,
- UserConfigService $userConfig,
- IInitialState $initialState,
+ IInitialState $initialState
) {
parent::__construct(Application::APP_ID, $request);
- $this->appManager = $appManager;
$this->eventDispatcher = $eventDispatcher;
- $this->userConfig = $userConfig;
$this->initialState = $initialState;
}
@@ -62,7 +53,7 @@ class PublicAlbumController extends Controller {
* @PublicPage
* @NoCSRFRequired
*/
- public function get(): TemplateResponse {
+ public function get(): PublicTemplateResponse {
$this->eventDispatcher->dispatch(LoadViewer::class, new LoadViewer());
$this->initialState->provideInitialState('image-mimes', Application::IMAGE_MIMES);
@@ -74,7 +65,7 @@ class PublicAlbumController extends Controller {
Util::addScript(Application::APP_ID, 'photos-public');
Util::addStyle(Application::APP_ID, 'icons');
- $response = new TemplateResponse(Application::APP_ID, 'main');
+ $response = new PublicTemplateResponse(Application::APP_ID, 'public');
$policy = new ContentSecurityPolicy();
$policy->addAllowedWorkerSrcDomain("'self'");
diff --git a/lib/Controller/PublicPreviewController.php b/lib/Controller/PublicPreviewController.php
new file mode 100644
index 00000000..f18811dd
--- /dev/null
+++ b/lib/Controller/PublicPreviewController.php
@@ -0,0 +1,67 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * @copyright Copyright (c) 2022, Louis Chmn <louis@chmn.me>
+ *
+ * @author Louis Chmn <louis@chmn.me>
+ *
+ * @license AGPL-3.0-or-later
+ *
+ * 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\Controller;
+
+use OCA\Photos\Album\AlbumMapper;
+use OCP\AppFramework\Http;
+use OCP\AppFramework\Http\DataResponse;
+use OCP\AppFramework\Http\FileDisplayResponse;
+
+class PublicPreviewController extends PreviewController {
+ /**
+ * @NoAdminRequired
+ * @NoCSRFRequired
+ * @PublicPage
+ * Render default index template
+ *
+ * @return DataResponse|FileDisplayResponse
+ */
+ public function index(
+ int $fileId = -1,
+ int $x = 32,
+ int $y = 32,
+ string $token = null
+ ) {
+ if ($fileId === -1 || $x === 0 || $y === 0) {
+ return new DataResponse([], Http::STATUS_BAD_REQUEST);
+ }
+
+ if ($token === null) {
+ return new DataResponse([], Http::STATUS_FORBIDDEN);
+ }
+
+ $publicAlbums = $this->albumMapper->getAlbumsForCollaboratorIdAndFileId($token, AlbumMapper::TYPE_LINK, $fileId);
+ $nodes = $this->getFileIdForAlbums($fileId, $publicAlbums);
+
+ if (\count($nodes) === 0) {
+ return new DataResponse([], Http::STATUS_NOT_FOUND);
+ }
+
+ $node = array_pop($nodes);
+
+ return $this->fetchPreview($node, $x, $y);
+ }
+}
diff --git a/lib/Listener/SabrePluginAuthInitListener.php b/lib/Listener/SabrePluginAuthInitListener.php
new file mode 100644
index 00000000..ec6a3784
--- /dev/null
+++ b/lib/Listener/SabrePluginAuthInitListener.php
@@ -0,0 +1,49 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2022, Louis Chmn <louis@chmn.me>
+ *
+ * @author Louis Chmn <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\Listener;
+
+use OCA\DAV\Events\SabrePluginAuthInitEvent;
+use OCA\Photos\Sabre\PublicAlbumAuthBackend;
+use OCP\EventDispatcher\Event;
+use OCP\EventDispatcher\IEventListener;
+
+class SabrePluginAuthInitListener implements IEventListener {
+ private PublicAlbumAuthBackend $publicAlbumAuthBackend;
+
+ public function __construct(PublicAlbumAuthBackend $publicAlbumAuthBackend) {
+ $this->publicAlbumAuthBackend = $publicAlbumAuthBackend;
+ }
+
+ public function handle(Event $event): void {
+ if (!($event instanceof SabrePluginAuthInitEvent)) {
+ return;
+ }
+
+ $server = $event->getServer();
+ $authPlugin = $server->getPlugin('auth');
+ $authPlugin->addBackend($this->publicAlbumAuthBackend);
+ }
+}
diff --git a/lib/Sabre/Album/AlbumPhoto.php b/lib/Sabre/Album/AlbumPhoto.php
index a5e51bff..832bcb97 100644
--- a/lib/Sabre/Album/AlbumPhoto.php
+++ b/lib/Sabre/Album/AlbumPhoto.php
@@ -137,6 +137,9 @@ class AlbumPhoto implements IFile {
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)) {
diff --git a/lib/Sabre/Album/AlbumRoot.php b/lib/Sabre/Album/AlbumRoot.php
index 0406a8c3..0a10157b 100644
--- a/lib/Sabre/Album/AlbumRoot.php
+++ b/lib/Sabre/Album/AlbumRoot.php
@@ -31,7 +31,6 @@ use OCA\Photos\Service\UserConfigService;
use OCP\Files\Folder;
use OCP\Files\IRootFolder;
use OCP\Files\NotFoundException;
-use OCP\IUser;
use Sabre\DAV\Exception\Conflict;
use Sabre\DAV\Exception\Forbidden;
use Sabre\DAV\Exception\NotFound;
@@ -43,22 +42,19 @@ class AlbumRoot implements ICollection, ICopyTarget {
protected AlbumMapper $albumMapper;
protected AlbumWithFiles $album;
protected IRootFolder $rootFolder;
- protected Folder $userFolder;
- protected IUser $user;
+ protected string $userId;
public function __construct(
AlbumMapper $albumMapper,
AlbumWithFiles $album,
IRootFolder $rootFolder,
- Folder $userFolder,
- IUser $user,
+ string $userId,
UserConfigService $userConfigService
) {
$this->albumMapper = $albumMapper;
$this->album = $album;
$this->rootFolder = $rootFolder;
- $this->userFolder = $userFolder;
- $this->user = $user;
+ $this->userId = $userId;
$this->userConfigService = $userConfigService;
}
@@ -82,7 +78,7 @@ class AlbumRoot implements ICollection, ICopyTarget {
protected function getPhotosLocationInfo() {
$photosLocation = $this->userConfigService->getUserConfig('photosLocation');
- $userFolder = $this->rootFolder->getUserFolder($this->user->getUID());
+ $userFolder = $this->rootFolder->getUserFolder($this->userId);
return [$photosLocation, $userFolder];
}
@@ -160,23 +156,22 @@ class AlbumRoot implements ICollection, ICopyTarget {
}
public function copyInto($targetName, $sourcePath, INode $sourceNode): bool {
- $uid = $this->user->getUID();
if ($sourceNode instanceof File) {
$sourceId = $sourceNode->getId();
$ownerUID = $sourceNode->getFileInfo()->getOwner()->getUID();
return $this->addFile($sourceId, $ownerUID);
}
+ $uid = $this->userId;
throw new \Exception("Can't add file to album, only files from $uid can be added");
}
protected 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) {
+ if ($ownerUID === $this->userId) {
$this->albumMapper->addFile($this->album->getAlbum()->getId(), $sourceId, $ownerUID);
- $node = current($this->userFolder->getById($sourceId));
+ $node = current($this->rootFolder->getUserFolder($ownerUID)->getById($sourceId));
$this->album->addFile(new AlbumFile($sourceId, $node->getName(), $node->getMimetype(), $node->getSize(), $node->getMTime(), $node->getEtag(), $node->getCreationTime(), $ownerUID));
return true;
}
diff --git a/lib/Sabre/Album/AlbumsHome.php b/lib/Sabre/Album/AlbumsHome.php
index c077eacd..d73e6da3 100644
--- a/lib/Sabre/Album/AlbumsHome.php
+++ b/lib/Sabre/Album/AlbumsHome.php
@@ -27,9 +27,7 @@ use OCA\Photos\Album\AlbumInfo;
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;
use Sabre\DAV\Exception\Forbidden;
use Sabre\DAV\Exception\NotFound;
use Sabre\DAV\ICollection;
@@ -37,9 +35,8 @@ use Sabre\DAV\ICollection;
class AlbumsHome implements ICollection {
protected AlbumMapper $albumMapper;
protected array $principalInfo;
- protected IUser $user;
+ protected string $userId;
protected IRootFolder $rootFolder;
- protected Folder $userFolder;
protected UserConfigService $userConfigService;
public const NAME = 'albums';
@@ -52,15 +49,14 @@ class AlbumsHome implements ICollection {
public function __construct(
array $principalInfo,
AlbumMapper $albumMapper,
- IUser $user,
+ string $userId,
IRootFolder $rootFolder,
UserConfigService $userConfigService
) {
$this->principalInfo = $principalInfo;
$this->albumMapper = $albumMapper;
- $this->user = $user;
+ $this->userId = $userId;
$this->rootFolder = $rootFolder;
- $this->userFolder = $rootFolder->getUserFolder($user->getUID());
$this->userConfigService = $userConfigService;
}
@@ -90,8 +86,7 @@ class AlbumsHome implements ICollection {
* @return void
*/
public function createDirectory($name) {
- $uid = $this->user->getUID();
- $this->albumMapper->create($uid, $name);
+ $this->albumMapper->create($this->userId, $name);
}
public function getChild($name) {
@@ -109,9 +104,9 @@ class AlbumsHome implements ICollection {
*/
public function getChildren(): array {
if ($this->children === null) {
- $albumInfos = $this->albumMapper->getForUser($this->user->getUID());
+ $albumInfos = $this->albumMapper->getForUser($this->userId);
$this->children = array_map(function (AlbumInfo $albumInfo) {
- return new AlbumRoot($this->albumMapper, new AlbumWithFiles($albumInfo, $this->albumMapper), $this->rootFolder, $this->userFolder, $this->user, $this->userConfigService);
+ return new AlbumRoot($this->albumMapper, new AlbumWithFiles($albumInfo, $this->albumMapper), $this->rootFolder, $this->userId, $this->userConfigService);
}, $albumInfos);
}
diff --git a/lib/Sabre/Album/PropFindPlugin.php b/lib/Sabre/Album/PropFindPlugin.php
index b716ca34..9f3572ce 100644
--- a/lib/Sabre/Album/PropFindPlugin.php
+++ b/lib/Sabre/Album/PropFindPlugin.php
@@ -28,13 +28,13 @@ use OCA\DAV\Connector\Sabre\FilesPlugin;
use OCA\Photos\Album\AlbumMapper;
use OCP\IConfig;
use OCP\IPreview;
+use OCP\Files\NotFoundException;
use Sabre\DAV\INode;
use Sabre\DAV\PropFind;
use Sabre\DAV\PropPatch;
use Sabre\DAV\Server;
use Sabre\DAV\ServerPlugin;
use Sabre\DAV\Tree;
-use OCP\Files\NotFoundException;
class PropFindPlugin extends ServerPlugin {
public const ORIGINAL_NAME_PROPERTYNAME = '{http://nextcloud.org/ns}original-name';
@@ -69,6 +69,19 @@ class PropFindPlugin extends ServerPlugin {
}
/**
+ * Returns a plugin name.
+ *
+ * Using this name other plugins will be able to access other plugins
+ * using DAV\Server::getPlugin
+ *
+ * @return string
+ */
+ public function getPluginName() {
+ return 'photosDavPlugin';
+ }
+
+
+ /**
* @return void
*/
public function initialize(Server $server) {
diff --git a/lib/Sabre/Album/PublicAlbumRoot.php b/lib/Sabre/Album/PublicAlbumRoot.php
index ab4e6fc4..54ccaa87 100644
--- a/lib/Sabre/Album/PublicAlbumRoot.php
+++ b/lib/Sabre/Album/PublicAlbumRoot.php
@@ -24,8 +24,6 @@ declare(strict_types=1);
namespace OCA\Photos\Sabre\Album;
use Sabre\DAV\Exception\Forbidden;
-use Sabre\DAV\Exception\Conflict;
-use OCP\Files\Folder;
use Sabre\DAV\INode;
class PublicAlbumRoot extends AlbumRoot {
diff --git a/lib/Sabre/Album/PublicAlbumsHome.php b/lib/Sabre/Album/PublicAlbumsHome.php
deleted file mode 100644
index a97597bd..00000000
--- a/lib/Sabre/Album/PublicAlbumsHome.php
+++ /dev/null
@@ -1,51 +0,0 @@
-<?php
-
-declare(strict_types=1);
-/**
- * @copyright Copyright (c) 2022 Robin Appelman <robin@icewind.nl>
- *
- * @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 Sabre\DAV\Exception\Forbidden;
-use Sabre\DAV\Exception\NotFound;
-use OCA\Photos\Album\AlbumMapper;
-
-class PublicAlbumsHome extends AlbumsHome {
- public const NAME = 'public';
-
- /**
- * @return never
- */
- public function createDirectory($name) {
- throw new Forbidden('Not allowed to create folders in this folder');
- }
-
- public function getChild($name) {
- $albums = $this->albumMapper->getSharedAlbumsForCollaboratorWithFiles($name, AlbumMapper::TYPE_LINK);
-
- $albums = array_filter($albums, fn ($album) => $album->getAlbum()->getUserId() === $this->user->getUid());
-
- if (count($albums) !== 1) {
- throw new NotFound();
- }
-
- return new PublicAlbumRoot($this->albumMapper, $albums[0], $this->rootFolder, $this->userFolder, $this->user, $this->userConfigService);
- }
-}
diff --git a/lib/Sabre/Album/SharedAlbumRoot.php b/lib/Sabre/Album/SharedAlbumRoot.php
index 25caf87a..d5dc9909 100644
--- a/lib/Sabre/Album/SharedAlbumRoot.php
+++ b/lib/Sabre/Album/SharedAlbumRoot.php
@@ -32,7 +32,7 @@ class SharedAlbumRoot extends AlbumRoot {
* @return void
*/
public function delete() {
- $this->albumMapper->deleteUserFromAlbumCollaboratorsList($this->user->getUID(), $this->album->getAlbum()->getId());
+ $this->albumMapper->deleteUserFromAlbumCollaboratorsList($this->userId, $this->album->getAlbum()->getId());
}
/**
@@ -51,8 +51,7 @@ class SharedAlbumRoot extends AlbumRoot {
fn ($collaborator) => $collaborator['type'].':'.$collaborator['id'],
$this->albumMapper->getCollaborators($this->album->getAlbum()->getId()),
);
- $uid = $this->user->getUID();
- if (!in_array(AlbumMapper::TYPE_USER.':'.$uid, $collaboratorIds)) {
+ if (!in_array(AlbumMapper::TYPE_USER.':'.$this->userId, $collaboratorIds)) {
return false;
}
diff --git a/lib/Sabre/Album/SharedAlbumsHome.php b/lib/Sabre/Album/SharedAlbumsHome.php
index c4665a17..136ae66b 100644
--- a/lib/Sabre/Album/SharedAlbumsHome.php
+++ b/lib/Sabre/Album/SharedAlbumsHome.php
@@ -26,12 +26,13 @@ namespace OCA\Photos\Sabre\Album;
use OCA\Photos\Album\AlbumWithFiles;
use OCA\Photos\Service\UserConfigService;
use Sabre\DAV\Exception\Forbidden;
+use OCP\IUserManager;
use OCP\IGroupManager;
use OCA\Photos\Album\AlbumMapper;
use OCP\Files\IRootFolder;
-use OCP\IUser;
class SharedAlbumsHome extends AlbumsHome {
+ private IUserManager $userManager;
private IGroupManager $groupManager;
public const NAME = 'sharedalbums';
@@ -39,19 +40,21 @@ class SharedAlbumsHome extends AlbumsHome {
public function __construct(
array $principalInfo,
AlbumMapper $albumMapper,
- IUser $user,
+ string $userId,
IRootFolder $rootFolder,
+ IUserManager $userManager,
IGroupManager $groupManager,
UserConfigService $userConfigService
) {
parent::__construct(
$principalInfo,
$albumMapper,
- $user,
+ $userId,
$rootFolder,
$userConfigService
);
+ $this->userManager = $userManager;
$this->groupManager = $groupManager;
}
@@ -67,17 +70,18 @@ class SharedAlbumsHome extends AlbumsHome {
*/
public function getChildren(): array {
if ($this->children === null) {
- $albums = $this->albumMapper->getSharedAlbumsForCollaboratorWithFiles($this->user->getUID(), AlbumMapper::TYPE_USER);
+ $albums = $this->albumMapper->getSharedAlbumsForCollaboratorWithFiles($this->userId, AlbumMapper::TYPE_USER);
- $userGroups = $this->groupManager->getUserGroupIds($this->user);
+ $user = $this->userManager->get($this->userId);
+ $userGroups = $this->groupManager->getUserGroupIds($user);
foreach ($userGroups as $groupId) {
$albumsForGroup = $this->albumMapper->getSharedAlbumsForCollaboratorWithFiles($groupId, AlbumMapper::TYPE_GROUP);
$albumsForGroup = array_udiff($albumsForGroup, $albums, fn ($a, $b) => $a->getAlbum()->getId() - $b->getAlbum()->getId());
$albums = array_merge($albums, $albumsForGroup);
}
- $this->children = array_map(function (AlbumWithFiles $folder) {
- return new SharedAlbumRoot($this->albumMapper, $folder, $this->rootFolder, $this->userFolder, $this->user, $this->userConfigService);
+ $this->children = array_map(function (AlbumWithFiles $album) {
+ return new SharedAlbumRoot($this->albumMapper, $album, $this->rootFolder, $this->userId, $this->userConfigService);
}, $albums);
}
diff --git a/lib/Sabre/PhotosHome.php b/lib/Sabre/PhotosHome.php
index 97106c44..fc2e6b4c 100644
--- a/lib/Sabre/PhotosHome.php
+++ b/lib/Sabre/PhotosHome.php
@@ -26,10 +26,9 @@ namespace OCA\Photos\Sabre;
use OCA\Photos\Album\AlbumMapper;
use OCA\Photos\Sabre\Album\AlbumsHome;
use OCA\Photos\Sabre\Album\SharedAlbumsHome;
-use OCA\Photos\Sabre\Album\PublicAlbumsHome;
use OCA\Photos\Service\UserConfigService;
use OCP\Files\IRootFolder;
-use OCP\IUser;
+use OCP\IUserManager;
use OCP\IGroupManager;
use Sabre\DAV\Exception\Forbidden;
use Sabre\DAV\Exception\NotFound;
@@ -38,23 +37,26 @@ use Sabre\DAV\ICollection;
class PhotosHome implements ICollection {
private AlbumMapper $albumMapper;
private array $principalInfo;
- private IUser $user;
+ private string $userId;
private IRootFolder $rootFolder;
+ private IUserManager $userManager;
private IGroupManager $groupManager;
private UserConfigService $userConfigService;
public function __construct(
array $principalInfo,
AlbumMapper $albumMapper,
- IUser $user,
+ string $userId,
IRootFolder $rootFolder,
+ IUserManager $userManager,
IGroupManager $groupManager,
UserConfigService $userConfigService
) {
$this->principalInfo = $principalInfo;
$this->albumMapper = $albumMapper;
- $this->user = $user;
+ $this->userId = $userId;
$this->rootFolder = $rootFolder;
+ $this->userManager = $userManager;
$this->groupManager = $groupManager;
$this->userConfigService = $userConfigService;
}
@@ -92,11 +94,9 @@ class PhotosHome implements ICollection {
public function getChild($name) {
switch ($name) {
case AlbumsHome::NAME:
- return new AlbumsHome($this->principalInfo, $this->albumMapper, $this->user, $this->rootFolder, $this->userConfigService);
+ return new AlbumsHome($this->principalInfo, $this->albumMapper, $this->userId, $this->rootFolder, $this->userConfigService);
case SharedAlbumsHome::NAME:
- return new SharedAlbumsHome($this->principalInfo, $this->albumMapper, $this->user, $this->rootFolder, $this->groupManager, $this->userConfigService);
- case PublicAlbumsHome::NAME:
- return new PublicAlbumsHome($this->principalInfo, $this->albumMapper, $this->user, $this->rootFolder, $this->userConfigService);
+ return new SharedAlbumsHome($this->principalInfo, $this->albumMapper, $this->userId, $this->rootFolder, $this->userManager, $this->groupManager, $this->userConfigService);
}
throw new NotFound();
@@ -107,14 +107,13 @@ class PhotosHome implements ICollection {
*/
public function getChildren(): array {
return [
- new AlbumsHome($this->principalInfo, $this->albumMapper, $this->user, $this->rootFolder, $this->userConfigService),
- new SharedAlbumsHome($this->principalInfo, $this->albumMapper, $this->user, $this->rootFolder, $this->groupManager, $this->userConfigService),
- new PublicAlbumsHome($this->principalInfo, $this->albumMapper, $this->user, $this->rootFolder, $this->userConfigService),
+ new AlbumsHome($this->principalInfo, $this->albumMapper, $this->userId, $this->rootFolder, $this->userConfigService),
+ new SharedAlbumsHome($this->principalInfo, $this->albumMapper, $this->userId, $this->rootFolder, $this->userManager, $this->groupManager, $this->userConfigService),
];
}
public function childExists($name): bool {
- return $name === AlbumsHome::NAME || $name === SharedAlbumsHome::NAME || $name === PublicAlbumsHome::NAME;
+ return $name === AlbumsHome::NAME || $name === SharedAlbumsHome::NAME;
}
public function getLastModified(): int {
diff --git a/lib/Sabre/PublicAlbumAuthBackend.php b/lib/Sabre/PublicAlbumAuthBackend.php
new file mode 100644
index 00000000..bbf84f50
--- /dev/null
+++ b/lib/Sabre/PublicAlbumAuthBackend.php
@@ -0,0 +1,80 @@
+<?php
+/**
+ * @copyright Copyright (c) 2022 Louis Chmn <louis@chmn.me>
+ *
+ * @author Louis Chmn <louis@chmn.me>
+ *
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * 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, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OCA\Photos\Sabre;
+
+use OC\Security\Bruteforce\Throttler;
+use OCA\Photos\Album\AlbumMapper;
+use OCA\Photos\Album\AlbumWithFiles;
+use OCP\IRequest;
+use Sabre\DAV\Auth\Backend\AbstractBasic;
+
+class PublicAlbumAuthBackend extends AbstractBasic {
+ private const BRUTEFORCE_ACTION = 'public_webdav_auth';
+ private ?AlbumWithFiles $album = null;
+ private IRequest $request;
+ private AlbumMapper $albumMapper;
+ private Throttler $throttler;
+
+ public function __construct(
+ IRequest $request,
+ AlbumMapper $albumMapper,
+ Throttler $throttler
+ ) {
+ $this->request = $request;
+ $this->albumMapper = $albumMapper;
+ $this->throttler = $throttler;
+
+ // setup realm
+ $defaults = new \OCP\Defaults();
+ $this->realm = $defaults->getName();
+ }
+
+ /**
+ * Validates the token.
+ *
+ * @param string $username
+ * @return bool
+ * @throws \Sabre\DAV\Exception\NotAuthenticated
+ */
+ protected function validateUserPass($username, $password) {
+ $this->throttler->sleepDelayOrThrowOnMax($this->request->getRemoteAddress(), self::BRUTEFORCE_ACTION);
+
+ $albums = $this->albumMapper->getSharedAlbumsForCollaboratorWithFiles($username, AlbumMapper::TYPE_LINK);
+
+
+ if (count($albums) !== 1) {
+ $this->throttler->registerAttempt(self::BRUTEFORCE_ACTION, $this->request->getRemoteAddress());
+ return false;
+ }
+
+ $this->album = $albums[0];
+
+ \OC_User::setIncognitoMode(true);
+
+ return true;
+ }
+
+ public function getShare(): AlbumWithFiles {
+ assert($this->album !== null);
+ return $this->album;
+ }
+}
diff --git a/lib/Sabre/PublicRootCollection.php b/lib/Sabre/PublicRootCollection.php
new file mode 100644
index 00000000..e8b6bf50
--- /dev/null
+++ b/lib/Sabre/PublicRootCollection.php
@@ -0,0 +1,87 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * @copyright Copyright (c) 2022 Robin Appelman <robin@icewind.nl>
+ *
+ * @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;
+
+use OCA\Photos\Album\AlbumMapper;
+use OCA\Photos\Sabre\Album\PublicAlbumRoot;
+use OCA\Photos\Service\UserConfigService;
+use OCP\Files\IRootFolder;
+use Sabre\DAVACL\AbstractPrincipalCollection;
+use Sabre\DAVACL\PrincipalBackend;
+use Sabre\DAV\Exception\NotFound;
+
+class PublicRootCollection extends AbstractPrincipalCollection {
+ private AlbumMapper $albumMapper;
+ private IRootFolder $rootFolder;
+ private UserConfigService $userConfigService;
+
+ public function __construct(
+ AlbumMapper $albumMapper,
+ IRootFolder $rootFolder,
+ PrincipalBackend\BackendInterface $principalBackend,
+ UserConfigService $userConfigService
+ ) {
+ parent::__construct($principalBackend, 'principals/token');
+
+ $this->albumMapper = $albumMapper;
+ $this->rootFolder = $rootFolder;
+ $this->userConfigService = $userConfigService;
+ }
+
+ public function getName(): string {
+ return 'photospublic';
+ }
+
+ /**
+ * Child are retrieved directly by getChild.
+ * This should never be called.
+ * @param array $principalInfo
+ */
+ public function getChildForPrincipal(array $principalInfo): PublicAlbumRoot {
+ throw new \Sabre\DAV\Exception\Forbidden();
+ }
+
+ /**
+ * Returns a child object, by its token.
+ *
+ * @param string $token
+ *
+ * @throws NotFound
+ *
+ * @return DAV\INode
+ */
+ public function getChild($token) {
+ if (is_null($token)) {
+ throw new \Sabre\DAV\Exception\Forbidden();
+ }
+
+ $albums = $this->albumMapper->getSharedAlbumsForCollaboratorWithFiles($token, AlbumMapper::TYPE_LINK);
+
+ if (count($albums) !== 1) {
+ throw new NotFound("Unable to find public album");
+ }
+
+ return new PublicAlbumRoot($this->albumMapper, $albums[0], $this->rootFolder, $albums[0]->getAlbum()->getUserId(), $this->userConfigService);
+ }
+}
diff --git a/lib/Sabre/RootCollection.php b/lib/Sabre/RootCollection.php
index 2e879f9d..8bcb42c7 100644
--- a/lib/Sabre/RootCollection.php
+++ b/lib/Sabre/RootCollection.php
@@ -29,12 +29,14 @@ use OCP\Files\IRootFolder;
use OCP\IUserSession;
use Sabre\DAVACL\AbstractPrincipalCollection;
use Sabre\DAVACL\PrincipalBackend;
+use OCP\IUserManager;
use OCP\IGroupManager;
class RootCollection extends AbstractPrincipalCollection {
private AlbumMapper $folderMapper;
private IUserSession $userSession;
private IRootFolder $rootFolder;
+ private IUserManager $userManager;
private IGroupManager $groupManager;
private UserConfigService $userConfigService;
@@ -43,6 +45,7 @@ class RootCollection extends AbstractPrincipalCollection {
IUserSession $userSession,
IRootFolder $rootFolder,
PrincipalBackend\BackendInterface $principalBackend,
+ IUserManager $userManager,
IGroupManager $groupManager,
UserConfigService $userConfigService
) {
@@ -51,6 +54,7 @@ class RootCollection extends AbstractPrincipalCollection {
$this->folderMapper = $folderMapper;
$this->userSession = $userSession;
$this->rootFolder = $rootFolder;
+ $this->userManager = $userManager;
$this->groupManager = $groupManager;
$this->userConfigService = $userConfigService;
}
@@ -70,7 +74,7 @@ class RootCollection extends AbstractPrincipalCollection {
if (is_null($user) || $name !== $user->getUID()) {
throw new \Sabre\DAV\Exception\Forbidden();
}
- return new PhotosHome($principalInfo, $this->folderMapper, $user, $this->rootFolder, $this->groupManager, $this->userConfigService);
+ return new PhotosHome($principalInfo, $this->folderMapper, $name, $this->rootFolder, $this->userManager, $this->groupManager, $this->userConfigService);
}
public function getName(): string {
diff --git a/psalm.xml b/psalm.xml
index 06b4e4ed..83a9bb9f 100644
--- a/psalm.xml
+++ b/psalm.xml
@@ -1,13 +1,7 @@
<?xml version="1.0"?>
-<psalm
- errorLevel="4"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns="https://getpsalm.org/schema/config"
- xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
- errorBaseline="tests/psalm-baseline.xml"
->
+<psalm errorLevel="4" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="https://getpsalm.org/schema/config" xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd" errorBaseline="tests/psalm-baseline.xml">
<stubs>
- <file name="tests/stub.phpstub" preloadClasses="true"/>
+ <file name="tests/stub.phpstub" preloadClasses="true" />
</stubs>
<projectFiles>
<directory name="lib" />
@@ -28,6 +22,9 @@
<referencedClass name="OCA\DAV\Connector\Sabre\Principal" />
<referencedClass name="OCA\DAV\Connector\Sabre\File" />
<referencedClass name="OCA\DAV\Connector\Sabre\FilesPlugin" />
+ <referencedClass name="OCA\DAV\Events\SabrePluginAuthInitEvent" />
+ <referencedClass name="OC\Security\Bruteforce\Throttler" />
+ <referencedClass name="OC_User" />
</errorLevel>
</UndefinedClass>
<UndefinedDocblockClass>
diff --git a/src/components/Albums/CollaboratorsSelectionForm.vue b/src/components/Albums/CollaboratorsSelectionForm.vue
index 6e1cd921..89aae866 100644
--- a/src/components/Albums/CollaboratorsSelectionForm.vue
+++ b/src/components/Albums/CollaboratorsSelectionForm.vue
@@ -358,7 +358,7 @@ export default {
this.errorFetchingAlbum = error
}
- logger.error('[PublicAlbumContent] Error fetching album', {error})
+ logger.error('[PublicAlbumContent] Error fetching album', { error })
showError(this.t('photos', 'Failed to fetch album.'))
} finally {
this.loadingAlbum = false
@@ -385,7 +385,7 @@ export default {
},
})
} catch (error) {
- logger.error('[PublicAlbumContent] Error updating album', {error})
+ logger.error('[PublicAlbumContent] Error updating album', { error })
showError(this.t('photos', 'Failed to update album.'))
} finally {
this.loadingAlbum = false
@@ -393,7 +393,7 @@ export default {
},
async copyPublicLink() {
- await navigator.clipboard.writeText(`${window.location.protocol}//${window.location.host}${generateUrl(`apps/photos/public/${getCurrentUser().uid}/${this.publicLink.id}`)}`)
+ await navigator.clipboard.writeText(`${window.location.protocol}//${window.location.host}${generateUrl(`apps/photos/public/${this.publicLink.id}`)}`)
this.publicLinkCopied = true
setTimeout(() => {
this.publicLinkCopied = false
diff --git a/src/components/File.vue b/src/components/File.vue
index ca1d11c9..9e414701 100644
--- a/src/components/File.vue
+++ b/src/components/File.vue
@@ -201,7 +201,12 @@ export default {
},
getItemURL(size) {
- return generateUrl(`/apps/photos/api/v1/preview/${this.file.fileid}?x=${size}&y=${size}`)
+ const token = this.$route.params.token
+ if (token) {
+ return generateUrl(`/apps/photos/api/v1/publicPreview/${this.file.fileid}?x=${size}&y=${size}&token=${token}`)
+ } else {
+ return generateUrl(`/apps/photos/api/v1/preview/${this.file.fileid}?x=${size}&y=${size}`)
+ }
},
diff --git a/src/mixins/UserConfig.js b/src/mixins/UserConfig.js
index 265aeb43..d6c6f0e8 100644
--- a/src/mixins/UserConfig.js
+++ b/src/mixins/UserConfig.js
@@ -34,8 +34,8 @@ export default {
return {
croppedLayout: croppedLayoutLocalStorage !== null
? croppedLayoutLocalStorage === 'true'
- : loadState('photos', 'croppedLayout') === 'true',
- photosLocation: loadState('photos', 'photosLocation'),
+ : loadState('photos', 'croppedLayout', 'false') === 'true',
+ photosLocation: loadState('photos', 'photosLocation', ''),
}
},
diff --git a/src/router/index.js b/src/router/index.js
index b9a96bc9..72cd1b5f 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -120,11 +120,10 @@ const router = new Router({
}),
},
{
- path: '/public/:userId/:token',
+ path: '/public/:token',
component: PublicAlbumContent,
name: 'publicAlbums',
props: route => ({
- userId: route.params.userId,
token: route.params.token,
}),
},
diff --git a/src/services/Albums.js b/src/services/Albums.js
index 741595ab..6dd3f1a9 100644
--- a/src/services/Albums.js
+++ b/src/services/Albums.js
@@ -23,7 +23,7 @@
import moment from '@nextcloud/moment'
import { translate } from '@nextcloud/l10n'
-import client from '../services/DavClient.js'
+import defaultClient from '../services/DavClient.js'
import logger from '../services/logger.js'
import DavRequest from '../services/DavRequest.js'
import { genFileInfo } from '../utils/fileUtils.js'
@@ -65,9 +65,10 @@ function getDavRequest(extraProps = '') {
* @param {string} path - Albums' root path.
* @param {import('webdav').StatOptions} options - Options to forward to the webdav client.
* @param {string} extraProps - Extra properties to add to the DAV request.
+ * @param {import('webdav').WebDAVClient} client - The DAV client to use.
* @return {Promise<Album|null>}
*/
-export async function fetchAlbum(path, options, extraProps = '') {
+export async function fetchAlbum(path, options, extraProps = '', client = defaultClient) {
try {
const response = await client.stat(path, {
data: getDavRequest(extraProps),
@@ -91,12 +92,14 @@ export async function fetchAlbum(path, options, extraProps = '') {
*
* @param {string} path - Albums' root path.
* @param {import('webdav').StatOptions} options - Options to forward to the webdav client.
+ * @param {string} extraProps - Extra properties to add to the DAV request.
+ * @param {import('webdav').WebDAVClient} client - The DAV client to use.
* @return {Promise<Album[]>}
*/
-export async function fetchAlbums(path, options) {
+export async function fetchAlbums(path, options, extraProps = '', client = defaultClient) {
try {
const response = await client.getDirectoryContents(path, {
- data: getDavRequest(),
+ data: getDavRequest(extraProps),
details: true,
...options,
})
@@ -158,9 +161,10 @@ function formatAlbum(album) {
*
* @param {string} path - Albums' root path.
* @param {import('webdav').StatOptions} options - Options to forward to the webdav client.
+ * @param {import('webdav').WebDAVClient} client - The DAV client to use.
* @return {Promise<Array>}
*/
-export async function fetchAlbumContent(path, options) {
+export async function fetchAlbumContent(path, options, client = defaultClient) {
try {
const response = await client.getDirectoryContents(path, {
data: DavRequest,
diff --git a/src/views/PublicAlbumContent.vue b/src/views/PublicAlbumContent.vue
index d0dae75a..6d263ad3 100644
--- a/src/views/PublicAlbumContent.vue
+++ b/src/views/PublicAlbumContent.vue
@@ -33,7 +33,7 @@
slot="header"
slot-scope="{selectedFileIds}"
:loading="loadingAlbum || loadingFiles"
- :params="{ userId, token }"
+ :params="{ token }"
path="/"
:root-title="albumOriginalName"
:title="albumOriginalName"
@@ -93,6 +93,8 @@
<script>
import { mapActions, mapGetters } from 'vuex'
+import { createClient, getPatcher } from 'webdav'
+
import MapMarker from 'vue-material-design-icons/MapMarker'
import Plus from 'vue-material-design-icons/Plus'
import ImagePlus from 'vue-material-design-icons/ImagePlus'
@@ -100,8 +102,10 @@ import Close from 'vue-material-design-icons/Close'
// import Download from 'vue-material-design-icons/Download'
// import DownloadMultiple from 'vue-material-design-icons/DownloadMultiple'
-import { NcActions, NcActionButton, NcButton, NcModal, NcEmptyContent, /** NcActionSeparator, */ isMobile } from '@nextcloud/vue'
+import { NcActions, NcActionButton, NcButton, NcEmptyContent, /** NcActionSeparator, */ isMobile } from '@nextcloud/vue'
import { showError } from '@nextcloud/dialogs'
+import axios from '@nextcloud/axios'
+import { generateRemoteUrl } from '@nextcloud/router'
import FetchFilesMixin from '../mixins/FetchFilesMixin.js'
import AbortControllerMixin from '../mixins/AbortControllerMixin.js'
@@ -111,6 +115,16 @@ import HeaderNavigation from '../components/HeaderNavigation.vue'
import { fetchAlbum, fetchAlbumContent } from '../services/Albums.js'
import logger from '../services/logger.js'
+const publicRootPath = 'dav'
+
+// force our axios
+const patcher = getPatcher()
+patcher.patch('request', axios)
+
+// init webdav client on default dav endpoint
+const remote = generateRemoteUrl(publicRootPath)
+const publicRemote = remote
+
export default {
name: 'PublicAlbumContent',
components: {
@@ -137,10 +151,6 @@ export default {
],
props: {
- userId: {
- type: String,
- required: true,
- },
token: {
type: String,
required: true,
@@ -155,6 +165,10 @@ export default {
loadingCount: 0,
loadingAddFilesToAlbum: false,
albumOriginalName: '',
+ publicClient: createClient(publicRemote, {
+ username: this.token,
+ password: null,
+ }),
}
},
@@ -210,9 +224,10 @@ export default {
this.errorFetchingAlbum = null
const album = await fetchAlbum(
- `/photos/${this.userId}/public/${this.token}`,
+ `/photospublic/${this.token}`,
this.abortController.signal,
'<nc:original-name />',
+ this.publicClient,
)
this.addPublicAlbums({ collections: [album] })
this.albumOriginalName = album.originalName
@@ -244,8 +259,9 @@ export default {
this.semaphoreSymbol = semaphoreSymbol
const fetchedFiles = await fetchAlbumContent(
- `/photos/${this.userId}/public/${this.token}`,
+ `/photospublic/${this.token}`,
this.abortController.signal,
+ this.publicClient,
)
const fileIds = fetchedFiles
diff --git a/templates/public.php b/templates/public.php
new file mode 100644
index 00000000..0f2fc271
--- /dev/null
+++ b/templates/public.php
@@ -0,0 +1,26 @@
+<?php
+/**
+ * @copyright Copyright (c) 2019 John Molakvoæ <skjnldsv@protonmail.com>
+ *
+ * @author John Molakvoæ <skjnldsv@protonmail.com>
+ *
+ * @license AGPL-3.0-or-later
+ *
+ * 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/>.
+ *
+ */
+?>
+
+<input type="hidden" id="isPublic" name="isPublic" value="1">
+<div id="content"></div>
diff --git a/tests/psalm-baseline.xml b/tests/psalm-baseline.xml
index 706d15f6..e3827420 100644
--- a/tests/psalm-baseline.xml
+++ b/tests/psalm-baseline.xml
@@ -20,4 +20,10 @@
<code>SearchQuery</code>
</UndefinedClass>
</file>
-</files>
+ <file src="lib/Controller/PublicAlbumController.php">
+ <UndefinedClass occurrences="10">
+ <code>LoadViewer</code>
+ <code>LoadViewer</code>
+ </UndefinedClass>
+ </file>
+</files> \ No newline at end of file