diff options
author | Louis Chemineau <louis@chmn.me> | 2022-09-22 17:35:00 +0300 |
---|---|---|
committer | Louis Chemineau <louis@chmn.me> | 2022-10-20 12:54:09 +0300 |
commit | 37e94bcacad19fe4240f48661be84ee649c47735 (patch) | |
tree | 8bdbf7f81d6aa882e8e50cf45d53797e7c6f40bb | |
parent | e721cd51df526e1f33cd9e5a22969b26d926d229 (diff) |
Display album's name instead of token
Signed-off-by: Louis Chemineau <louis@chmn.me>
-rw-r--r-- | appinfo/routes.php | 4 | ||||
-rw-r--r-- | lib/Album/AlbumMapper.php | 2 | ||||
-rw-r--r-- | lib/Controller/PublicAlbumController.php | 29 | ||||
-rw-r--r-- | lib/Sabre/Album/PropFindPlugin.php | 16 | ||||
-rw-r--r-- | lib/Sabre/Album/PublicAlbumsHome.php | 12 | ||||
-rw-r--r-- | lib/Sabre/PhotosHome.php | 8 | ||||
-rw-r--r-- | lib/Sabre/RootCollection.php | 8 | ||||
-rw-r--r-- | src/components/Albums/CollaboratorsSelectionForm.vue | 2 | ||||
-rw-r--r-- | src/router/index.js | 5 | ||||
-rw-r--r-- | src/services/Albums.js | 40 | ||||
-rw-r--r-- | src/views/PublicAlbumContent.vue | 29 |
11 files changed, 81 insertions, 74 deletions
diff --git a/appinfo/routes.php b/appinfo/routes.php index 2389fc2d..3ba966d5 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -46,12 +46,12 @@ return [ 'path' => '', ] ], - [ 'name' => 'publicAlbum#get', 'url' => '/public/{ownerId}/{token}', 'verb' => 'GET', + [ 'name' => 'publicAlbum#get', 'url' => '/public/{ownerId}/{path}', 'verb' => 'GET', 'requirements' => [ 'ownerId' => '.*', ], 'requirements' => [ - 'token' => '.*', + 'path' => '.*', ], ], ['name' => 'page#index', 'url' => '/folders/{path}', 'verb' => 'GET', 'postfix' => 'folders', diff --git a/lib/Album/AlbumMapper.php b/lib/Album/AlbumMapper.php index 577e0064..2b92c3b8 100644 --- a/lib/Album/AlbumMapper.php +++ b/lib/Album/AlbumMapper.php @@ -309,7 +309,7 @@ class AlbumMapper { $displayName = $this->groupManager->get($row['collaborator_id'])->getDisplayName(); break; case self::TYPE_LINK: - $displayName = $this->l->t('Public link');; + $displayName = $this->l->t('Public link'); break; default: throw new \Exception('Invalid collaborator type: ' . $row['collaborator_type']); diff --git a/lib/Controller/PublicAlbumController.php b/lib/Controller/PublicAlbumController.php index b9a9364e..c7143363 100644 --- a/lib/Controller/PublicAlbumController.php +++ b/lib/Controller/PublicAlbumController.php @@ -24,7 +24,7 @@ namespace OCA\Photos\Controller; -use OCP\AppFramework\PublicShareController; +use OCP\AppFramework\Controller; use OCA\Files\Event\LoadSidebar; use OCA\Photos\AppInfo\Application; use OCA\Photos\Service\UserConfigService; @@ -38,8 +38,7 @@ use OCP\IRequest; use OCP\ISession; use OCP\Util; - -class PublicAlbumController extends PublicShareController { +class PublicAlbumController extends Controller { private IAppManager $appManager; private IEventDispatcher $eventDispatcher; private UserConfigService $userConfig; @@ -62,28 +61,6 @@ class PublicAlbumController extends PublicShareController { } /** - * Validate the token of this share. If the token is invalid this controller - * will return a 404. - */ - public function isValidToken(): bool { - // TODO: uncomment - // $album = $this->albumMapper->getAlbumForToken($this->getToken); - // return $album !== null; - return true; - } - - public function getPasswordHash(): string { - return ''; - } - - /** - * Allows you to specify if this share is password protected - */ - protected function isPasswordProtected(): bool { - return false; - } - - /** * Your normal controller function. The following annotation will allow guests * to open the page as well * @@ -120,4 +97,4 @@ class PublicAlbumController extends PublicShareController { return $response; } -}
\ No newline at end of file +} diff --git a/lib/Sabre/Album/PropFindPlugin.php b/lib/Sabre/Album/PropFindPlugin.php index 00fb8017..3311b43e 100644 --- a/lib/Sabre/Album/PropFindPlugin.php +++ b/lib/Sabre/Album/PropFindPlugin.php @@ -87,10 +87,10 @@ class PropFindPlugin extends ServerPlugin { } $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::FAVORITE_PROPERTYNAME, fn () => $node->isFavorite() ? 1 : 0); - $propFind->handle(FilesPlugin::HAS_PREVIEW_PROPERTYNAME, fn () => json_encode($this->previewManager->isAvailable($fileInfo))); + $propFind->handle(FilesPlugin::GETETAG_PROPERTYNAME, fn () => $node->getETag()); + $propFind->handle(self::FILE_NAME_PROPERTYNAME, fn () => $node->getFile()->getName()); + $propFind->handle(self::FAVORITE_PROPERTYNAME, fn () => $node->isFavorite() ? 1 : 0); + $propFind->handle(FilesPlugin::HAS_PREVIEW_PROPERTYNAME, fn () => json_encode($this->previewManager->isAvailable($fileInfo))); if ($this->metadataEnabled) { $propFind->handle(FilesPlugin::FILE_METADATA_SIZE, function () use ($node) { @@ -110,10 +110,10 @@ class PropFindPlugin extends ServerPlugin { } if ($node instanceof AlbumRoot) { - $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())); + $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())); $propFind->handle(self::COLLABORATORS_PROPERTYNAME, fn () => $node->getCollaborators()); // TODO detect dynamically which metadata groups are requested and diff --git a/lib/Sabre/Album/PublicAlbumsHome.php b/lib/Sabre/Album/PublicAlbumsHome.php index 9d7d7362..f7d7e033 100644 --- a/lib/Sabre/Album/PublicAlbumsHome.php +++ b/lib/Sabre/Album/PublicAlbumsHome.php @@ -25,19 +25,22 @@ namespace OCA\Photos\Sabre\Album; use Sabre\DAV\Exception\Forbidden; use Sabre\DAV\Exception\NotFound; +use Sabre\DAV\Server; use OCP\Files\IRootFolder; use OCP\IUser; -use OCA\Photos\Sabre\Album\PublicAlbumRoot; use OCA\Photos\Service\UserConfigService; use OCA\Photos\Album\AlbumMapper; class PublicAlbumsHome extends AlbumsHome { + private Server $server; + public function __construct( array $principalInfo, AlbumMapper $albumMapper, IUser $user, IRootFolder $rootFolder, UserConfigService $userConfigService, + Server $server ) { parent::__construct( $principalInfo, @@ -46,6 +49,8 @@ class PublicAlbumsHome extends AlbumsHome { $rootFolder, $userConfigService, ); + + $this->server = $server; } public function getName(): string { @@ -60,7 +65,10 @@ class PublicAlbumsHome extends AlbumsHome { } public function getChild($name) { - $albums = $this->albumMapper->getSharedAlbumsForCollaboratorWithFiles($name, AlbumMapper::TYPE_LINK); + $basicAuth = $this->server->httpRequest->getHeader('Authorization'); + [, $base64Token] = explode('Basic ', $basicAuth); + $token = \base64_decode($base64Token); + $albums = $this->albumMapper->getSharedAlbumsForCollaboratorWithFiles($token, AlbumMapper::TYPE_LINK); array_filter($albums, fn ($album) => $album->getAlbum()->getUserId() === $this->user->getUid()); diff --git a/lib/Sabre/PhotosHome.php b/lib/Sabre/PhotosHome.php index ba4d266e..7e69e991 100644 --- a/lib/Sabre/PhotosHome.php +++ b/lib/Sabre/PhotosHome.php @@ -34,6 +34,7 @@ use OCP\IGroupManager; use Sabre\DAV\Exception\Forbidden; use Sabre\DAV\Exception\NotFound; use Sabre\DAV\ICollection; +use Sabre\DAV\Server; class PhotosHome implements ICollection { private AlbumMapper $albumMapper; @@ -42,6 +43,7 @@ class PhotosHome implements ICollection { private IRootFolder $rootFolder; private IGroupManager $groupManager; private UserConfigService $userConfigService; + private Server $server; public function __construct( array $principalInfo, @@ -49,7 +51,8 @@ class PhotosHome implements ICollection { IUser $user, IRootFolder $rootFolder, IGroupManager $groupManager, - UserConfigService $userConfigService + UserConfigService $userConfigService, + Server $server ) { $this->principalInfo = $principalInfo; $this->albumMapper = $albumMapper; @@ -57,6 +60,7 @@ class PhotosHome implements ICollection { $this->rootFolder = $rootFolder; $this->groupManager = $groupManager; $this->userConfigService = $userConfigService; + $this->server = $server; } /** @@ -95,7 +99,7 @@ class PhotosHome implements ICollection { } elseif ($name === 'sharedalbums') { return new SharedAlbumsHome($this->principalInfo, $this->albumMapper, $this->user, $this->rootFolder, $this->groupManager, $this->userConfigService); } elseif ($name === 'public') { - return new PublicAlbumsHome($this->principalInfo, $this->albumMapper, $this->user, $this->rootFolder, $this->userConfigService); + return new PublicAlbumsHome($this->principalInfo, $this->albumMapper, $this->user, $this->rootFolder, $this->userConfigService, $this->server); } throw new NotFound(); diff --git a/lib/Sabre/RootCollection.php b/lib/Sabre/RootCollection.php index 2e879f9d..96350927 100644 --- a/lib/Sabre/RootCollection.php +++ b/lib/Sabre/RootCollection.php @@ -29,6 +29,7 @@ use OCP\Files\IRootFolder; use OCP\IUserSession; use Sabre\DAVACL\AbstractPrincipalCollection; use Sabre\DAVACL\PrincipalBackend; +use Sabre\DAV\Server; use OCP\IGroupManager; class RootCollection extends AbstractPrincipalCollection { @@ -37,6 +38,7 @@ class RootCollection extends AbstractPrincipalCollection { private IRootFolder $rootFolder; private IGroupManager $groupManager; private UserConfigService $userConfigService; + private Server $server; public function __construct( AlbumMapper $folderMapper, @@ -44,7 +46,8 @@ class RootCollection extends AbstractPrincipalCollection { IRootFolder $rootFolder, PrincipalBackend\BackendInterface $principalBackend, IGroupManager $groupManager, - UserConfigService $userConfigService + UserConfigService $userConfigService, + Server $server ) { parent::__construct($principalBackend, 'principals/users'); @@ -53,6 +56,7 @@ class RootCollection extends AbstractPrincipalCollection { $this->rootFolder = $rootFolder; $this->groupManager = $groupManager; $this->userConfigService = $userConfigService; + $this->server = $server; } /** @@ -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, $user, $this->rootFolder, $this->groupManager, $this->userConfigService, $this->server); } public function getName(): string { diff --git a/src/components/Albums/CollaboratorsSelectionForm.vue b/src/components/Albums/CollaboratorsSelectionForm.vue index d55a3a83..04bbc7f4 100644 --- a/src/components/Albums/CollaboratorsSelectionForm.vue +++ b/src/components/Albums/CollaboratorsSelectionForm.vue @@ -348,7 +348,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/${getCurrentUser().uid}/${this.albumName}?token=${this.publicLink.id}`)}`) this.publicLinkCopied = true setTimeout(() => { this.publicLinkCopied = false diff --git a/src/router/index.js b/src/router/index.js index b9a96bc9..d22e28ac 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -120,12 +120,13 @@ const router = new Router({ }), }, { - path: '/public/:userId/:token', + path: '/public/:userId/:path*', component: PublicAlbumContent, name: 'publicAlbums', props: route => ({ userId: route.params.userId, - token: route.params.token, + albumName: route.params.path, + token: route.query.token, }), }, { diff --git a/src/services/Albums.js b/src/services/Albums.js index 3dc33297..5d5c6a87 100644 --- a/src/services/Albums.js +++ b/src/services/Albums.js @@ -21,7 +21,6 @@ */ import moment from '@nextcloud/moment' -import { showError } from '@nextcloud/dialogs' import { translate } from '@nextcloud/l10n' import client from '../services/DavClient.js' @@ -43,12 +42,13 @@ import { genFileInfo } from '../utils/fileUtils.js' /** * * @param {string} path - Albums' root path. - * @param {AbortSignal} signal - Abort signal to cancel the request. + * @param {import('webdav').StatOptions} options - Options to forward to the webdav client. + * @param {import('webdav').WebDAVClient} customClient * @return {Promise<Album|null>} */ -export async function fetchAlbum(path, signal) { +export async function fetchAlbum(path, options, customClient) { try { - const response = await client.stat(path, { + const response = await (customClient || client).stat(path, { data: `<?xml version="1.0"?> <d:propfind xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns" @@ -62,8 +62,8 @@ export async function fetchAlbum(path, signal) { <nc:collaborators /> </d:prop> </d:propfind>`, - signal, details: true, + ...options, }) logger.debug('[Albums] Fetched an album: ', response.data) @@ -81,12 +81,13 @@ export async function fetchAlbum(path, signal) { /** * * @param {string} path - Albums' root path. - * @param {AbortSignal} signal - Abort signal to cancel the request. + * @param {import('webdav').StatOptions} options - Options to forward to the webdav client. + * @param {import('webdav').WebDAVClient} customClient * @return {Promise<Album[]>} */ -export async function fetchAlbums(path, signal) { +export async function fetchAlbums(path, options, customClient) { try { - const response = await client.getDirectoryContents(path, { + const response = await (customClient || client).getDirectoryContents(path, { data: `<?xml version="1.0"?> <d:propfind xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns" @@ -101,7 +102,7 @@ export async function fetchAlbums(path, signal) { </d:prop> </d:propfind>`, details: true, - signal, + ...options, }) logger.debug(`[Albums] Fetched ${response.data.length} albums: `, response.data) @@ -144,14 +145,14 @@ function formatAlbum(album) { dateRange.start = moment().unix() dateRange.end = moment().unix() } - const dateRangeFormated = { + const dateRangeFormatted = { startDate: moment.unix(dateRange.start).format('MMMM YYYY'), endDate: moment.unix(dateRange.end).format('MMMM YYYY'), } - if (dateRangeFormated.startDate === dateRangeFormated.endDate) { - album.date = dateRangeFormated.startDate + if (dateRangeFormatted.startDate === dateRangeFormatted.endDate) { + album.date = dateRangeFormatted.startDate } else { - album.date = translate('photos', '{startDate} to {endDate}', dateRangeFormated) + album.date = translate('photos', '{startDate} to {endDate}', dateRangeFormatted) } return album @@ -160,15 +161,16 @@ function formatAlbum(album) { /** * * @param {string} path - Albums' root path. - * @param {AbortSignal} signal - Abort signal to cancel the request. - * @return {Promise<[]>} + * @param {import('webdav').StatOptions} options - Options to forward to the webdav client. + * @param {import('webdav').WebDAVClient} customClient + * @return {Promise<Array>} */ -export async function fetchAlbumContent(path, signal) { +export async function fetchAlbumContent(path, options, customClient) { try { - const response = await client.getDirectoryContents(path, { + const response = await (customClient || client).getDirectoryContents(path, { data: DavRequest, details: true, - signal, + ...options, }) const fetchedFiles = response.data @@ -188,4 +190,4 @@ export async function fetchAlbumContent(path, signal) { throw error } -}
\ No newline at end of file +} diff --git a/src/views/PublicAlbumContent.vue b/src/views/PublicAlbumContent.vue index 941bcd60..4a8056a9 100644 --- a/src/views/PublicAlbumContent.vue +++ b/src/views/PublicAlbumContent.vue @@ -103,6 +103,7 @@ <script> import { mapActions, mapGetters } from 'vuex' + import MapMarker from 'vue-material-design-icons/MapMarker' import Plus from 'vue-material-design-icons/Plus' import ImagePlus from 'vue-material-design-icons/ImagePlus' @@ -154,6 +155,10 @@ export default { type: String, required: true, }, + albumName: { + type: String, + required: true, + }, token: { type: String, required: true, @@ -167,7 +172,7 @@ export default { errorFetchingAlbum: null, loadingCount: 0, loadingAddFilesToAlbum: false, - albumName: '', + publicClient: null, } }, @@ -215,9 +220,13 @@ export default { this.loadingAlbum = true this.errorFetchingAlbum = null - const album = await fetchAlbum(`/photos/${this.userId}/public/${this.token}`, this.abortController.signal) + const album = await fetchAlbum(`/photos/${this.userId}/public/${this.albumName}`, { + signal: this.abortController.signal, + headers: { + Authorization: `Basic ${btoa(this.token)}`, + }, + }) this.addPublicAlbums({ collections: [album] }) - this.albumName = album.basename } catch (error) { if (error.response?.status === 404) { this.errorFetchingAlbum = 404 @@ -245,10 +254,12 @@ export default { this.loadingFiles = true this.semaphoreSymbol = semaphoreSymbol - const fetchedFiles = await fetchAlbumContent( - `/photos/${this.userId}/public/${this.token}`, - this.abortController.signal, - ) + const fetchedFiles = await fetchAlbumContent(`/photos/${this.userId}/public/${this.albumName}`, { + signal: this.abortController.signal, + headers: { + Authorization: `Basic ${btoa(this.token)}`, + }, + }) const fileIds = fetchedFiles .map(file => file.fileid.toString()) @@ -281,14 +292,14 @@ export default { async handleFilesPicked(fileIds) { this.showAddPhotosModal = false - await this.addFilesToPublicAlbum({ collectionName: this.albumName, fileIdsToAdd: fileIds }) + await this.addFilesToPublicAlbum({ collectionId: this.albumName, fileIdsToAdd: fileIds }) // Re-fetch album content to have the proper filenames. await this.fetchAlbumContent() }, async handleRemoveFilesFromAlbum(fileIds) { this.$refs.collectionContent.onUncheckFiles(fileIds) - await this.removeFilesFromPublicAlbum({ collectionName: this.albumName, fileIdsToRemove: fileIds }) + await this.removeFilesFromPublicAlbum({ collectionId: this.albumName, fileIdsToRemove: fileIds }) }, }, } |