Repository: LycheeOrg/Lychee (language: php)

Issue:
Sharing does not work

### Discussed in https://github.com/LycheeOrg/Lychee/discussions/3279

<div type='discussions-op-text'>

<sup>Originally posted by **tinohager** April 25, 2025</sup>
### Lychee version

v6.5.2

### Which PHP version are you using?

PHP 8.4

### Detailed description of the problem

I have logged in as a user. Then tried to share something. The button does not throw an error and nothing happens. But it throws errors in the browser console.

![image](https://github.com/user-attachments/assets/d4fe51da-9dca-428c-ad72-32aaf138baa3)

![image](https://github.com/user-attachments/assets/ca6bc25f-895b-4a6a-bc7c-480e7a66094d)



### Steps to reproduce the issue

_No response_

### Diagnostics [REQUIRED]

_No response_

### Browser & System [REQUIRED]

_No response_

### Please confirm (incomplete submissions will not be addressed)

- [X] I have provided easy and step-by-step instructions to reproduce the bug.
- [X] I understand my bug report will be removed if I haven't met the criteria above.</div>


Discussion / hints:
Found the problem. The list displayed is not the list of "sharable" albums (i.e. the list of albums that can be shared) but the full list of albums...

Fix patch:
diff --git a/app/Actions/Album/ListAlbums.php b/app/Actions/Album/ListAlbums.php
index 2f6b4dd5d23..4145f9c8fd8 100644
--- a/app/Actions/Album/ListAlbums.php
+++ b/app/Actions/Album/ListAlbums.php
@@ -27,13 +27,15 @@ class ListAlbums
 	/**
 	 * @return TAlbumSaved[]
 	 */
-	public function do(Collection $albums_filtering, ?string $parent_id): array
+	public function do(Collection $albums_filtering, ?string $parent_id, ?int $owner_id = null): array
 	{
 		$album_query_policy = resolve(AlbumQueryPolicy::class);
 		$unfiltered = $album_query_policy->applyReachabilityFilter(
 			// We remove all sub albums
 			// Otherwise it would create cyclic dependency
 			Album::query()
+				->when($owner_id !== null,
+					fn ($q) => $q->where('owner_id', '=', $owner_id))
 				->when($albums_filtering->count() > 0,
 					function ($q) use ($albums_filtering) {
 						$albums_filtering->each(
diff --git a/app/Http/Controllers/Gallery/AlbumController.php b/app/Http/Controllers/Gallery/AlbumController.php
index 3601ca6f190..9e7d385e55f 100644
--- a/app/Http/Controllers/Gallery/AlbumController.php
+++ b/app/Http/Controllers/Gallery/AlbumController.php
@@ -241,12 +241,12 @@ public function delete(DeleteAlbumsRequest $request, Delete $delete): void
 	 *
 	 * @return array<string|int,TargetAlbumResource>
 	 */
-	public function getTargetListAlbums(TargetListAlbumRequest $request, ListAlbums $list_albums)
+	public function getTargetListAlbums(TargetListAlbumRequest $request, ListAlbums $list_albums): array
 	{
 		$albums = $request->albums();
 		$parent_id = $albums->count() > 0 ? $albums->first()->parent_id : null;
 
-		return TargetAlbumResource::collect($list_albums->do($albums, $parent_id));
+		return TargetAlbumResource::collect($list_albums->do($albums, $parent_id, null));
 	}
 
 	/**
diff --git a/app/Http/Controllers/Gallery/SharingController.php b/app/Http/Controllers/Gallery/SharingController.php
index 6d45da54302..1e6d5e8bed0 100644
--- a/app/Http/Controllers/Gallery/SharingController.php
+++ b/app/Http/Controllers/Gallery/SharingController.php
@@ -8,10 +8,12 @@
 
 namespace App\Http\Controllers\Gallery;
 
+use App\Actions\Album\ListAlbums;
 use App\Actions\Sharing\Propagate;
 use App\Actions\Sharing\Share;
 use App\Constants\AccessPermissionConstants as APC;
 use App\Exceptions\Internal\LycheeLogicException;
+use App\Exceptions\UnauthenticatedException;
 use App\Http\Requests\Sharing\AddSharingRequest;
 use App\Http\Requests\Sharing\DeleteSharingRequest;
 use App\Http\Requests\Sharing\EditSharingRequest;
@@ -19,9 +21,11 @@
 use App\Http\Requests\Sharing\ListSharingRequest;
 use App\Http\Requests\Sharing\PropagateSharingRequest;
 use App\Http\Resources\Models\AccessPermissionResource;
+use App\Http\Resources\Models\TargetAlbumResource;
 use App\Models\AccessPermission;
 use App\Models\Album;
 use App\Models\BaseAlbumImpl;
+use App\Models\User;
 use Illuminate\Routing\Controller;
 use Illuminate\Support\Collection;
 use Illuminate\Support\Facades\Auth;
@@ -115,6 +119,28 @@ public function listAll(ListAllSharingRequest $request): Collection
 		return AccessPermissionResource::collect($query->get());
 	}
 
+	/**
+	 * Get the list of albums.
+	 *
+	 * @return array<string|int,TargetAlbumResource>
+	 */
+	public function listAlbums(ListAllSharingRequest $request, ListAlbums $list_albums): array
+	{
+		/** @var User $user */
+		$user = Auth::user() ?? throw new UnauthenticatedException();
+		if ($user->may_administrate) {
+			$owner_id = null;
+		} else {
+			$owner_id = $user->id;
+		}
+
+		return TargetAlbumResource::collect($list_albums->do(
+			albums_filtering: resolve(Collection::class),
+			parent_id: null,
+			owner_id: $owner_id)
+		);
+	}
+
 	/**
 	 * Delete sharing permissions.
 	 *
diff --git a/app/Metadata/Cache/RouteCacheManager.php b/app/Metadata/Cache/RouteCacheManager.php
index 96b3744a9b7..441e81b691c 100644
--- a/app/Metadata/Cache/RouteCacheManager.php
+++ b/app/Metadata/Cache/RouteCacheManager.php
@@ -91,6 +91,7 @@ public function __construct()
 			'api/v2/Settings::getLanguages' => new RouteCacheConfig(tag: CacheTag::SETTINGS),
 			'api/v2/Sharing' => new RouteCacheConfig(tag: CacheTag::GALLERY, user_dependant: true, extra: [RequestAttribute::ALBUM_ID_ATTRIBUTE]),
 			'api/v2/Sharing::all' => new RouteCacheConfig(tag: CacheTag::GALLERY, user_dependant: true),
+			'api/v2/Sharing::albums' => new RouteCacheConfig(tag: CacheTag::GALLERY, user_dependant: true),
 			'api/v2/Statistics::albumSpace' => new RouteCacheConfig(tag: CacheTag::STATISTICS, user_dependant: true),
 			'api/v2/Statistics::sizeVariantSpace' => new RouteCacheConfig(tag: CacheTag::STATISTICS, user_dependant: true),
 			'api/v2/Statistics::totalAlbumSpace' => new RouteCacheConfig(tag: CacheTag::STATISTICS, user_dependant: true),
diff --git a/app/Policies/AlbumPolicy.php b/app/Policies/AlbumPolicy.php
index 05b0e67eacc..139a0529c89 100644
--- a/app/Policies/AlbumPolicy.php
+++ b/app/Policies/AlbumPolicy.php
@@ -466,7 +466,8 @@ public function canShareWithUsers(User $user, AbstractAlbum|BaseAlbumImpl|null $
 
 		// If this is null, this means that we are looking at the list.
 		if ($abstract_album === null) {
-			return true;
+			// We need to be at least owner of an album to be able to share anything.
+			return BaseAlbumImpl::query()->where('owner_id', '=', $user->id)->toBase()->count() > 0;
 		}
 
 		if (!$abstract_album instanceof BaseAlbum && !$abstract_album instanceof BaseAlbumImpl) {
diff --git a/lang/cz/sharing.php b/lang/cz/sharing.php
index 8881813adee..e713202e73b 100644
--- a/lang/cz/sharing.php
+++ b/lang/cz/sharing.php
@@ -33,6 +33,10 @@
 	'permission_updated' => 'Propagation successful! Permission updated!',
 	'bluk_share' => 'Bulk share',
 	'bulk_share_instr' => 'Select multiple albums and users to share with.',
+	'albums' => 'Albums',
+	'users' => 'Users',
+	'no_users' => 'No selectable users.',
+	'no_albums' => 'No selectable albums.',
 
 	'grants' => [
 		'read' => 'Grants read access',
diff --git a/lang/de/sharing.php b/lang/de/sharing.php
index 8881813adee..e713202e73b 100644
--- a/lang/de/sharing.php
+++ b/lang/de/sharing.php
@@ -33,6 +33,10 @@
 	'permission_updated' => 'Propagation successful! Permission updated!',
 	'bluk_share' => 'Bulk share',
 	'bulk_share_instr' => 'Select multiple albums and users to share with.',
+	'albums' => 'Albums',
+	'users' => 'Users',
+	'no_users' => 'No selectable users.',
+	'no_albums' => 'No selectable albums.',
 
 	'grants' => [
 		'read' => 'Grants read access',
diff --git a/lang/el/sharing.php b/lang/el/sharing.php
index 8881813adee..e713202e73b 100644
--- a/lang/el/sharing.php
+++ b/lang/el/sharing.php
@@ -33,6 +33,10 @@
 	'permission_updated' => 'Propagation successful! Permission updated!',
 	'bluk_share' => 'Bulk share',
 	'bulk_share_instr' => 'Select multiple albums and users to share with.',
+	'albums' => 'Albums',
+	'users' => 'Users',
+	'no_users' => 'No selectable users.',
+	'no_albums' => 'No selectable albums.',
 
 	'grants' => [
 		'read' => 'Grants read access',
diff --git a/lang/en/sharing.php b/lang/en/sharing.php
index 1d32472a5e6..5c49567eda1 100644
--- a/lang/en/sharing.php
+++ b/lang/en/sharing.php
@@ -34,6 +34,10 @@
 
 	'bluk_share' => 'Bulk share',
 	'bulk_share_instr' => 'Select multiple albums and users to share with.',
+	'albums' => 'Albums',
+	'users' => 'Users',
+	'no_users' => 'No selectable users.',
+	'no_albums' => 'No selectable albums.',
 
 	'grants' => [
 		'read' => 'Grants read access',
diff --git a/lang/es/sharing.php b/lang/es/sharing.php
index 8881813adee..e713202e73b 100644
--- a/lang/es/sharing.php
+++ b/lang/es/sharing.php
@@ -33,6 +33,10 @@
 	'permission_updated' => 'Propagation successful! Permission updated!',
 	'bluk_share' => 'Bulk share',
 	'bulk_share_instr' => 'Select multiple albums and users to share with.',
+	'albums' => 'Albums',
+	'users' => 'Users',
+	'no_users' => 'No selectable users.',
+	'no_albums' => 'No selectable albums.',
 
 	'grants' => [
 		'read' => 'Grants read access',
diff --git a/lang/fr/sharing.php b/lang/fr/sharing.php
index 2abedf83457..0cf249ff1a0 100644
--- a/lang/fr/sharing.php
+++ b/lang/fr/sharing.php
@@ -33,6 +33,10 @@
 	'permission_updated' => 'Propagation réussie ! Autorisations mises à jour !',
 	'bluk_share' => 'Bulk share',
 	'bulk_share_instr' => 'Select multiple albums and users to share with.',
+	'albums' => 'Albums',
+	'users' => 'Users',
+	'no_users' => 'No selectable users.',
+	'no_albums' => 'No selectable albums.',
 
 	'grants' => [
 		'read' => 'Autorise la lecture',
diff --git a/lang/hu/sharing.php b/lang/hu/sharing.php
index 8881813adee..e713202e73b 100644
--- a/lang/hu/sharing.php
+++ b/lang/hu/sharing.php
@@ -33,6 +33,10 @@
 	'permission_updated' => 'Propagation successful! Permission updated!',
 	'bluk_share' => 'Bulk share',
 	'bulk_share_instr' => 'Select multiple albums and users to share with.',
+	'albums' => 'Albums',
+	'users' => 'Users',
+	'no_users' => 'No selectable users.',
+	'no_albums' => 'No selectable albums.',
 
 	'grants' => [
 		'read' => 'Grants read access',
diff --git a/lang/it/sharing.php b/lang/it/sharing.php
index 8881813adee..e713202e73b 100644
--- a/lang/it/sharing.php
+++ b/lang/it/sharing.php
@@ -33,6 +33,10 @@
 	'permission_updated' => 'Propagation successful! Permission updated!',
 	'bluk_share' => 'Bulk share',
 	'bulk_share_instr' => 'Select multiple albums and users to share with.',
+	'albums' => 'Albums',
+	'users' => 'Users',
+	'no_users' => 'No selectable users.',
+	'no_albums' => 'No selectable albums.',
 
 	'grants' => [
 		'read' => 'Grants read access',
diff --git a/lang/ja/sharing.php b/lang/ja/sharing.php
index 8881813adee..e713202e73b 100644
--- a/lang/ja/sharing.php
+++ b/lang/ja/sharing.php
@@ -33,6 +33,10 @@
 	'permission_updated' => 'Propagation successful! Permission updated!',
 	'bluk_share' => 'Bulk share',
 	'bulk_share_instr' => 'Select multiple albums and users to share with.',
+	'albums' => 'Albums',
+	'users' => 'Users',
+	'no_users' => 'No selectable users.',
+	'no_albums' => 'No selectable albums.',
 
 	'grants' => [
 		'read' => 'Grants read access',
diff --git a/lang/nl/sharing.php b/lang/nl/sharing.php
index 8881813adee..e713202e73b 100644
--- a/lang/nl/sharing.php
+++ b/lang/nl/sharing.php
@@ -33,6 +33,10 @@
 	'permission_updated' => 'Propagation successful! Permission updated!',
 	'bluk_share' => 'Bulk share',
 	'bulk_share_instr' => 'Select multiple albums and users to share with.',
+	'albums' => 'Albums',
+	'users' => 'Users',
+	'no_users' => 'No selectable users.',
+	'no_albums' => 'No selectable albums.',
 
 	'grants' => [
 		'read' => 'Grants read access',
diff --git a/lang/no/sharing.php b/lang/no/sharing.php
index 8881813adee..e713202e73b 100644
--- a/lang/no/sharing.php
+++ b/lang/no/sharing.php
@@ -33,6 +33,10 @@
 	'permission_updated' => 'Propagation successful! Permission updated!',
 	'bluk_share' => 'Bulk share',
 	'bulk_share_instr' => 'Select multiple albums and users to share with.',
+	'albums' => 'Albums',
+	'users' => 'Users',
+	'no_users' => 'No selectable users.',
+	'no_albums' => 'No selectable albums.',
 
 	'grants' => [
 		'read' => 'Grants read access',
diff --git a/lang/pl/sharing.php b/lang/pl/sharing.php
index 2bc8a895295..d92fe5bb06f 100644
--- a/lang/pl/sharing.php
+++ b/lang/pl/sharing.php
@@ -33,6 +33,10 @@
 	'permission_updated' => 'Propagacja zakończona sukcesem! Pozwolenie zaktualizowane!',
 	'bluk_share' => 'Bulk share',
 	'bulk_share_instr' => 'Select multiple albums and users to share with.',
+	'albums' => 'Albums',
+	'users' => 'Users',
+	'no_users' => 'No selectable users.',
+	'no_albums' => 'No selectable albums.',
 
 	'grants' => [
 		'read' => 'Przyznaje dostęp do odczytu',
diff --git a/lang/pt/sharing.php b/lang/pt/sharing.php
index 8881813adee..e713202e73b 100644
--- a/lang/pt/sharing.php
+++ b/lang/pt/sharing.php
@@ -33,6 +33,10 @@
 	'permission_updated' => 'Propagation successful! Permission updated!',
 	'bluk_share' => 'Bulk share',
 	'bulk_share_instr' => 'Select multiple albums and users to share with.',
+	'albums' => 'Albums',
+	'users' => 'Users',
+	'no_users' => 'No selectable users.',
+	'no_albums' => 'No selectable albums.',
 
 	'grants' => [
 		'read' => 'Grants read access',
diff --git a/lang/ru/sharing.php b/lang/ru/sharing.php
index f196fb34d9f..6a89f817a23 100644
--- a/lang/ru/sharing.php
+++ b/lang/ru/sharing.php
@@ -33,6 +33,10 @@
 	'permission_updated' => 'Распространение успешно! Разрешение обновлено!',
 	'bluk_share' => 'Bulk share',
 	'bulk_share_instr' => 'Select multiple albums and users to share with.',
+	'albums' => 'Albums',
+	'users' => 'Users',
+	'no_users' => 'No selectable users.',
+	'no_albums' => 'No selectable albums.',
 
 	'grants' => [
 		'read' => 'Предоставляет доступ для чтения',
diff --git a/lang/sk/sharing.php b/lang/sk/sharing.php
index 8881813adee..e713202e73b 100644
--- a/lang/sk/sharing.php
+++ b/lang/sk/sharing.php
@@ -33,6 +33,10 @@
 	'permission_updated' => 'Propagation successful! Permission updated!',
 	'bluk_share' => 'Bulk share',
 	'bulk_share_instr' => 'Select multiple albums and users to share with.',
+	'albums' => 'Albums',
+	'users' => 'Users',
+	'no_users' => 'No selectable users.',
+	'no_albums' => 'No selectable albums.',
 
 	'grants' => [
 		'read' => 'Grants read access',
diff --git a/lang/sv/sharing.php b/lang/sv/sharing.php
index 8881813adee..e713202e73b 100644
--- a/lang/sv/sharing.php
+++ b/lang/sv/sharing.php
@@ -33,6 +33,10 @@
 	'permission_updated' => 'Propagation successful! Permission updated!',
 	'bluk_share' => 'Bulk share',
 	'bulk_share_instr' => 'Select multiple albums and users to share with.',
+	'albums' => 'Albums',
+	'users' => 'Users',
+	'no_users' => 'No selectable users.',
+	'no_albums' => 'No selectable albums.',
 
 	'grants' => [
 		'read' => 'Grants read access',
diff --git a/lang/vi/sharing.php b/lang/vi/sharing.php
index 8881813adee..e713202e73b 100644
--- a/lang/vi/sharing.php
+++ b/lang/vi/sharing.php
@@ -33,6 +33,10 @@
 	'permission_updated' => 'Propagation successful! Permission updated!',
 	'bluk_share' => 'Bulk share',
 	'bulk_share_instr' => 'Select multiple albums and users to share with.',
+	'albums' => 'Albums',
+	'users' => 'Users',
+	'no_users' => 'No selectable users.',
+	'no_albums' => 'No selectable albums.',
 
 	'grants' => [
 		'read' => 'Grants read access',
diff --git a/lang/zh_CN/sharing.php b/lang/zh_CN/sharing.php
index 28d764b8307..64a8402cc26 100644
--- a/lang/zh_CN/sharing.php
+++ b/lang/zh_CN/sharing.php
@@ -33,6 +33,10 @@
 	'permission_updated' => '传播成功！权限已更新！',
 	'bluk_share' => 'Bulk share',
 	'bulk_share_instr' => 'Select multiple albums and users to share with.',
+	'albums' => 'Albums',
+	'users' => 'Users',
+	'no_users' => 'No selectable users.',
+	'no_albums' => 'No selectable albums.',
 
 	'grants' => [
 		'read' => '授予读取权限',
diff --git a/lang/zh_TW/sharing.php b/lang/zh_TW/sharing.php
index 8881813adee..e713202e73b 100644
--- a/lang/zh_TW/sharing.php
+++ b/lang/zh_TW/sharing.php
@@ -33,6 +33,10 @@
 	'permission_updated' => 'Propagation successful! Permission updated!',
 	'bluk_share' => 'Bulk share',
 	'bulk_share_instr' => 'Select multiple albums and users to share with.',
+	'albums' => 'Albums',
+	'users' => 'Users',
+	'no_users' => 'No selectable users.',
+	'no_albums' => 'No selectable albums.',
 
 	'grants' => [
 		'read' => 'Grants read access',
diff --git a/resources/js/components/forms/sharing/BulkSharingModal.vue b/resources/js/components/forms/sharing/BulkSharingModal.vue
index 543a7a25ca9..aae721f0b67 100644
--- a/resources/js/components/forms/sharing/BulkSharingModal.vue
+++ b/resources/js/components/forms/sharing/BulkSharingModal.vue
@@ -21,6 +21,12 @@
 						class="w-full"
 						:virtualScrollerOptions="{ itemSize: 28 }"
 					>
+						<template #header
+							><span class="text-muted-color-emphasis font-bold">{{ $t("sharing.albums") }}</span></template
+						>
+						<template #empty
+							><span class="text-muted-color">{{ $t("sharing.no_albums") }}</span></template
+						>
 						<template #option="slotProps">
 							<div class="flex items-center">
 								<div
@@ -45,7 +51,14 @@
 						:highlightOnSelect="false"
 						class="w-full"
 						:virtualScrollerOptions="{ itemSize: 28 }"
-					/>
+					>
+						<template #header
+							><span class="text-muted-color-emphasis font-bold">{{ $t("sharing.users") }}</span></template
+						>
+						<template #empty
+							><span class="text-muted-color">{{ $t("sharing.no_users") }}</span></template
+						>
+					</Listbox>
 				</div>
 
 				<div class="w-1/2 flex justify-around items-center">
@@ -85,7 +98,6 @@
 <script setup lang="ts">
 import Dialog from "primevue/dialog";
 import { ref } from "vue";
-import AlbumService from "@/services/album-service";
 import UsersService from "@/services/users-service";
 import { onMounted } from "vue";
 import Checkbox from "primevue/checkbox";
@@ -146,7 +158,7 @@ function closeCallback() {
 }
 
 function loadAlbums() {
-	AlbumService.getTargetListAlbums(null).then((response) => {
+	SharingService.listAlbums().then((response) => {
 		targetAlbums.value = response.data;
 	});
 }
diff --git a/resources/js/services/album-service.ts b/resources/js/services/album-service.ts
index 8b6cbbc6674..b60a07109dc 100644
--- a/resources/js/services/album-service.ts
+++ b/resources/js/services/album-service.ts
@@ -57,7 +57,7 @@ const AlbumService = {
 	clearCache(album_id: string | null = null): void {
 		const axiosWithCache = axios as unknown as AxiosCacheInstance;
 		if (!album_id) {
-			// @ts-expect-error
+			// @ts-expect-error  we now what we are doing here.
 			axiosWithCache.storage.clear();
 		} else {
 			axiosWithCache.storage.remove("album_" + album_id);
diff --git a/resources/js/services/sharing-service.ts b/resources/js/services/sharing-service.ts
index b7b251fa745..0ef036b1625 100644
--- a/resources/js/services/sharing-service.ts
+++ b/resources/js/services/sharing-service.ts
@@ -49,6 +49,10 @@ const SharingService = {
 	list(): Promise<AxiosResponse<App.Http.Resources.Models.AccessPermissionResource[]>> {
 		return axios.get(`${Constants.getApiUrl()}Sharing::all`, { data: {} });
 	},
+
+	listAlbums(): Promise<AxiosResponse<App.Http.Resources.Models.TargetAlbumResource[]>> {
+		return axios.get(`${Constants.getApiUrl()}Sharing::albums`, { data: {} });
+	},
 };
 
 export default SharingService;
diff --git a/resources/js/views/Sharing.vue b/resources/js/views/Sharing.vue
index 2b11d9b96fe..9cd89f5f984 100644
--- a/resources/js/views/Sharing.vue
+++ b/resources/js/views/Sharing.vue
@@ -36,7 +36,7 @@
 				<div class="w-1/6"></div>
 			</div>
 			<template v-if="perms?.length > 0">
-				<ShareLine v-for="perm in perms" :perm="perm" @delete="deletePermission" :with-album="true" />
+				<ShareLine v-for="(perm, idx) in perms" :perm="perm" @delete="deletePermission" :with-album="true" :key="'p' + (perm.id ?? idx)" />
 			</template>
 			<p v-else class="text-center">{{ $t("sharing.no_data") }}</p>
 		</div>
diff --git a/routes/api_v2.php b/routes/api_v2.php
index d342fc721b6..f57ca4d6806 100644
--- a/routes/api_v2.php
+++ b/routes/api_v2.php
@@ -78,6 +78,7 @@
 Route::patch('/Sharing', [Gallery\SharingController::class, 'edit']);
 Route::delete('/Sharing', [Gallery\SharingController::class, 'delete']);
 Route::get('/Sharing::all', [Gallery\SharingController::class, 'listAll']);
+Route::get('/Sharing::albums', [Gallery\SharingController::class, 'listAlbums']);
 
 /**
  * IMPORT.


Test patch:
diff --git a/tests/Feature_v2/Album/SharingTest.php b/tests/Feature_v2/Album/SharingTest.php
index 5f37f4da4b8..38acd37d98d 100644
--- a/tests/Feature_v2/Album/SharingTest.php
+++ b/tests/Feature_v2/Album/SharingTest.php
@@ -31,6 +31,21 @@ public function testGet(): void
 
 		$response = $this->getJsonWithData('Sharing', ['album_id' => $this->album1->id]);
 		$this->assertUnauthorized($response);
+
+		$response = $this->getJsonWithData('Sharing::albums');
+		$this->assertUnauthorized($response);
+	}
+
+	public function testUserForbidden(): void
+	{
+		$response = $this->actingAs($this->userNoUpload)->getJsonWithData('Sharing');
+		$this->assertUnprocessable($response);
+
+		$response = $this->actingAs($this->userNoUpload)->getJsonWithData('Sharing::all');
+		$this->assertForbidden($response);
+
+		$response = $this->actingAs($this->userNoUpload)->getJsonWithData('Sharing::albums');
+		$this->assertForbidden($response);
 	}
 
 	public function testUserGet(): void
@@ -44,6 +59,23 @@ public function testUserGet(): void
 		$response = $this->actingAs($this->userMayUpload1)->getJsonWithData('Sharing::all');
 		$this->assertOk($response);
 
+		$response = $this->actingAs($this->userMayUpload1)->getJsonWithData('Sharing::albums');
+		$this->assertOk($response);
+		$response->assertJson([
+			[
+				'id' => $this->album1->id,
+				'title' => $this->album1->title,
+				'original' => $this->album1->title,
+				'short_title' => $this->album1->title,
+			],
+			[
+				'id' => $this->subAlbum1->id,
+				'title' => $this->album1->title . '/' . $this->subAlbum1->title,
+				'original' => $this->subAlbum1->title,
+				'short_title' => $this->album1->title . '/' . $this->subAlbum1->title,
+			],
+		]);
+
 		$response = $this->actingAs($this->userMayUpload1)->patchJson('Sharing', [
 			'perm_id' => $this->perm1->id,
 			'grants_edit' => true,