From ec92608024534027317e15a4a23605baea7a5095 Mon Sep 17 00:00:00 2001 From: martin <74269598+martabal@users.noreply.github.com> Date: Fri, 1 Dec 2023 21:58:24 +0100 Subject: [PATCH] fix(web): disable metadata edit if user is not owner (#5415) * fix(web): disable metadata edit if user is not owner * pr feedback * pr feedback * get data from page data * fix: better representation * feat: warn user if there's issues with the selected assets --------- Co-authored-by: Alex Tran --- .../components/album-page/album-viewer.svelte | 2 +- .../asset-viewer/asset-viewer.svelte | 11 +++-- .../asset-viewer/detail-panel.svelte | 42 ++++++++++++------- .../actions/change-date-action.svelte | 6 +-- .../actions/change-location-action.svelte | 6 +-- .../components/photos-page/asset-grid.svelte | 4 +- .../individual-shared-viewer.svelte | 5 +-- .../gallery-viewer/gallery-viewer.svelte | 4 +- web/src/lib/stores/user.store.ts | 4 ++ web/src/lib/utils/asset-utils.ts | 24 ++++++++++- .../(user)/albums/[albumId]/+page.svelte | 25 +++++------ web/src/routes/(user)/photos/+page.svelte | 3 ++ 12 files changed, 83 insertions(+), 53 deletions(-) create mode 100644 web/src/lib/stores/user.store.ts diff --git a/web/src/lib/components/album-page/album-viewer.svelte b/web/src/lib/components/album-page/album-viewer.svelte index ba71c396d..609a03e25 100644 --- a/web/src/lib/components/album-page/album-viewer.svelte +++ b/web/src/lib/components/album-page/album-viewer.svelte @@ -144,7 +144,7 @@
- +

{ - if (album && user) { + if (album && $user) { try { const { data } = await api.activityApi.getActivities({ - userId: user.id, + userId: $user.id, assetId: asset.id, albumId: album.id, type: ReactionType.Like, @@ -743,7 +742,7 @@ {/if} - {#if isShared && album && isShowActivity && user} + {#if isShared && album && isShowActivity && $user}

(isShowChangeDate = true)} - on:keydown={(event) => event.key === 'Enter' && (isShowChangeDate = true)} + class="flex justify-between place-items-start gap-4 py-4" tabindex="0" role="button" - title="Edit date" + on:click={() => (isOwner ? (isShowChangeDate = true) : null)} + on:keydown={(event) => (isOwner ? event.key === 'Enter' && (isShowChangeDate = true) : null)} + title={isOwner ? 'Edit date' : ''} + class:hover:dark:text-immich-dark-primary={isOwner} + class:hover:text-immich-primary={isOwner} >
@@ -276,11 +279,14 @@
- + + {#if isOwner} + + {/if} - {:else if !asset.exifInfo?.dateTimeOriginal && !asset.isReadOnly} + {:else if !asset.exifInfo?.dateTimeOriginal && !asset.isReadOnly && $user && asset.ownerId === $user.id}
@@ -410,12 +416,14 @@ {#if asset.exifInfo?.city && !asset.isReadOnly}
(isShowChangeLocation = true)} - on:keydown={(event) => event.key === 'Enter' && (isShowChangeLocation = true)} + class="flex justify-between place-items-start gap-4 py-4" + on:click={() => (isOwner ? (isShowChangeLocation = true) : null)} + on:keydown={(event) => (isOwner ? event.key === 'Enter' && (isShowChangeLocation = true) : null)} tabindex="0" + title={isOwner ? 'Edit location' : ''} role="button" - title="Edit location" + class:hover:dark:text-immich-dark-primary={isOwner} + class:hover:text-immich-primary={isOwner} >
@@ -435,11 +443,13 @@
-
- -
+ {#if isOwner} +
+ +
+ {/if}
- {:else if !asset.exifInfo?.city && !asset.isReadOnly} + {:else if !asset.exifInfo?.city && !asset.isReadOnly && $user && asset.ownerId === $user.id}
(isShowChangeLocation = true)} diff --git a/web/src/lib/components/photos-page/actions/change-date-action.svelte b/web/src/lib/components/photos-page/actions/change-date-action.svelte index b917a36fe..8f9748261 100644 --- a/web/src/lib/components/photos-page/actions/change-date-action.svelte +++ b/web/src/lib/components/photos-page/actions/change-date-action.svelte @@ -5,6 +5,8 @@ import { DateTime } from 'luxon'; import MenuOption from '../../shared-components/context-menu/menu-option.svelte'; import { getAssetControlContext } from '../asset-select-control-bar.svelte'; + import { user } from '$lib/stores/user.store'; + import { getSelectedAssets } from '$lib/utils/asset-utils'; export let menuItem = false; const { clearSelect, getOwnedAssets } = getAssetControlContext(); @@ -12,9 +14,7 @@ const handleConfirm = async (dateTimeOriginal: string) => { isShowChangeDate = false; - const ids = Array.from(getOwnedAssets()) - .filter((a) => !a.isExternal) - .map((a) => a.id); + const ids = getSelectedAssets(getOwnedAssets(), $user); try { await api.assetApi.updateAssets({ diff --git a/web/src/lib/components/photos-page/actions/change-location-action.svelte b/web/src/lib/components/photos-page/actions/change-location-action.svelte index b916d26c3..ac1e66d09 100644 --- a/web/src/lib/components/photos-page/actions/change-location-action.svelte +++ b/web/src/lib/components/photos-page/actions/change-location-action.svelte @@ -4,6 +4,8 @@ import { getAssetControlContext } from '../asset-select-control-bar.svelte'; import ChangeLocation from '$lib/components/shared-components/change-location.svelte'; import { handleError } from '../../../utils/handle-error'; + import { user } from '$lib/stores/user.store'; + import { getSelectedAssets } from '$lib/utils/asset-utils'; export let menuItem = false; const { clearSelect, getOwnedAssets } = getAssetControlContext(); @@ -12,9 +14,7 @@ async function handleConfirm(point: { lng: number; lat: number }) { isShowChangeLocation = false; - const ids = Array.from(getOwnedAssets()) - .filter((a) => !a.isExternal) - .map((a) => a.id); + const ids = getSelectedAssets(getOwnedAssets(), $user); try { await api.assetApi.updateAssets({ diff --git a/web/src/lib/components/photos-page/asset-grid.svelte b/web/src/lib/components/photos-page/asset-grid.svelte index 1e5304e8e..310b2d4de 100644 --- a/web/src/lib/components/photos-page/asset-grid.svelte +++ b/web/src/lib/components/photos-page/asset-grid.svelte @@ -8,7 +8,7 @@ import { locale } from '$lib/stores/preferences.store'; import { isSearchEnabled } from '$lib/stores/search.store'; import { formatGroupTitle, splitBucketIntoDateGroups } from '$lib/utils/timeline-util'; - import type { AlbumResponseDto, AssetResponseDto, UserResponseDto } from '@api'; + import type { AlbumResponseDto, AssetResponseDto } from '@api'; import { DateTime } from 'luxon'; import { createEventDispatcher, onDestroy, onMount } from 'svelte'; import AssetViewer from '../asset-viewer/asset-viewer.svelte'; @@ -27,7 +27,6 @@ export let removeAction: AssetAction | null = null; export let withStacked = false; export let isShared = false; - export let user: UserResponseDto | null = null; export let album: AlbumResponseDto | null = null; $: isTrashEnabled = $featureFlags.loaded && $featureFlags.trash; @@ -394,7 +393,6 @@ {#if $showAssetViewer} = new Set(); @@ -103,6 +102,6 @@ {/if}
- +
diff --git a/web/src/lib/components/shared-components/gallery-viewer/gallery-viewer.svelte b/web/src/lib/components/shared-components/gallery-viewer/gallery-viewer.svelte index dc62bc8da..0aa51dfa9 100644 --- a/web/src/lib/components/shared-components/gallery-viewer/gallery-viewer.svelte +++ b/web/src/lib/components/shared-components/gallery-viewer/gallery-viewer.svelte @@ -2,7 +2,7 @@ import { page } from '$app/stores'; import Thumbnail from '$lib/components/assets/thumbnail/thumbnail.svelte'; import { handleError } from '$lib/utils/handle-error'; - import { AssetResponseDto, ThumbnailFormat, UserResponseDto } from '@api'; + import { AssetResponseDto, ThumbnailFormat } from '@api'; import AssetViewer from '../../asset-viewer/asset-viewer.svelte'; import { flip } from 'svelte/animate'; import { getThumbnailSize } from '$lib/utils/thumbnail-util'; @@ -13,7 +13,6 @@ export let selectedAssets: Set = new Set(); export let disableAssetSelect = false; export let showArchiveIcon = false; - export let user: UserResponseDto | undefined = undefined; let { isViewing: showAssetViewer } = assetViewingStore; @@ -109,7 +108,6 @@ {#if $showAssetViewer} (null); diff --git a/web/src/lib/utils/asset-utils.ts b/web/src/lib/utils/asset-utils.ts index 94c12d140..b466e142c 100644 --- a/web/src/lib/utils/asset-utils.ts +++ b/web/src/lib/utils/asset-utils.ts @@ -1,6 +1,14 @@ import { notificationController, NotificationType } from '$lib/components/shared-components/notification/notification'; import { downloadManager } from '$lib/stores/download'; -import { api, BulkIdResponseDto, AssetResponseDto, DownloadResponseDto, DownloadInfoDto, AssetTypeEnum } from '@api'; +import { + api, + BulkIdResponseDto, + AssetResponseDto, + DownloadResponseDto, + DownloadInfoDto, + AssetTypeEnum, + UserResponseDto, +} from '@api'; import { handleError } from './handle-error'; export const addAssetsToAlbum = async (albumId: string, assetIds: Array): Promise => @@ -203,3 +211,17 @@ export const getAssetType = (type: AssetTypeEnum) => { return 'Asset'; } }; + +export const getSelectedAssets = (assets: Set, user: UserResponseDto | null): string[] => { + const ids = Array.from(assets) + .filter((a) => !a.isExternal && user && a.ownerId !== user.id) + .map((a) => a.id); + const numberOfIssues = Array.from(assets).filter((a) => a.isExternal || (user && a.ownerId === user.id)).length; + if (numberOfIssues > 0) { + notificationController.show({ + message: `Can't change metadata of ${numberOfIssues} asset${numberOfIssues > 1 ? 's' : ''}`, + type: NotificationType.Warning, + }); + } + return ids; +}; diff --git a/web/src/routes/(user)/albums/[albumId]/+page.svelte b/web/src/routes/(user)/albums/[albumId]/+page.svelte index a16216453..a88187713 100644 --- a/web/src/routes/(user)/albums/[albumId]/+page.svelte +++ b/web/src/routes/(user)/albums/[albumId]/+page.svelte @@ -59,6 +59,7 @@ import { numberOfComments, setNumberOfComments, updateNumberOfComments } from '$lib/stores/activity.store'; import AlbumOptions from '$lib/components/album-page/album-options.svelte'; import UpdatePanel from '$lib/components/shared-components/update-panel.svelte'; + import { user } from '$lib/stores/user.store'; export let data: PageData; @@ -66,6 +67,9 @@ let { slideshowState, slideshowShuffle } = slideshowStore; let album = data.album; + + $user = data.user; + $: album = data.album; $: { @@ -96,7 +100,6 @@ let isShowActivity = false; let isLiked: ActivityResponseDto | null = null; let reactions: ActivityResponseDto[] = []; - let user = data.user; let globalWidth: number; let assetGridWidth: number; @@ -179,10 +182,10 @@ }; const getFavorite = async () => { - if (user) { + if ($user) { try { const { data } = await api.activityApi.getActivities({ - userId: user.id, + userId: $user.id, albumId: album.id, type: ReactionType.Like, level: ReactionLevel.Album, @@ -549,16 +552,10 @@ style={`width:${assetGridWidth}px`} > {#if viewMode === ViewMode.SELECT_ASSETS} - + {:else} 0} @@ -679,7 +676,7 @@ {/if}
- {#if album.sharedUsers.length > 0 && album && isShowActivity && user && !$showAssetViewer} + {#if album.sharedUsers.length > 0 && album && isShowActivity && $user && !$showAssetViewer}
{/if} -{#if viewMode === ViewMode.OPTIONS} +{#if viewMode === ViewMode.OPTIONS && $user} (viewMode = ViewMode.VIEW)} on:toggleEnableActivity={handleToggleEnableActivity} on:showSelectSharedUser={() => (viewMode = ViewMode.SELECT_USERS)} diff --git a/web/src/routes/(user)/photos/+page.svelte b/web/src/routes/(user)/photos/+page.svelte index e74a109b9..6cf3bdd64 100644 --- a/web/src/routes/(user)/photos/+page.svelte +++ b/web/src/routes/(user)/photos/+page.svelte @@ -24,6 +24,7 @@ import { assetViewingStore } from '$lib/stores/asset-viewing.store'; import { mdiDotsVertical, mdiPlus } from '@mdi/js'; import UpdatePanel from '$lib/components/shared-components/update-panel.svelte'; + import { user } from '$lib/stores/user.store'; export let data: PageData; @@ -33,6 +34,8 @@ const assetInteractionStore = createAssetInteractionStore(); const { isMultiSelectState, selectedAssets } = assetInteractionStore; + $user = data.user; + $: isAllFavorite = Array.from($selectedAssets).every((asset) => asset.isFavorite); const handleEscape = () => {