Skip to content

Allow non-authenticated users to star photo (by admin option)#4082

Open
tkulev wants to merge 12 commits intoLycheeOrg:masterfrom
tkulev:photo_start_anonymous
Open

Allow non-authenticated users to star photo (by admin option)#4082
tkulev wants to merge 12 commits intoLycheeOrg:masterfrom
tkulev:photo_start_anonymous

Conversation

@tkulev
Copy link
Contributor

@tkulev tkulev commented Feb 11, 2026

  • Added implementation for pro feature - allowing of use of star flag for photos selection. Added migration for config option to keep current behaviour or enable anonymous starring of photos.
  • Added functionality to copy to clipboard names of selected images.

Summary by CodeRabbit

  • New Features

    • Star/unstar photos from headers and context menus; toggle album view to show only starred photos; copy starred photo names to clipboard; show starred state in thumbnails.
  • Permissions

    • Star-related rights (can_star) surfaced and enforced across albums, photos, and requests; visibility setting controls who can see/use star flags.
  • Documentation

    • Added translations and UI labels for starring, the filter, and the clipboard message in many languages.

tkulev-ss and others added 4 commits February 11, 2026 09:56
Added translations for Bulgarian language.
… for photos selection. Added migration for config.

- Added functionality to copy to clipboard names of selected images.
@tkulev tkulev requested a review from a team as a code owner February 11, 2026 21:14
@coderabbitai
Copy link

coderabbitai bot commented Feb 11, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds photo "star" support: new PhotoVisibilityType enum and config migration; album/photo policies and authorization trait; request update; rights and config exposed via API; middleware update; frontend UI/events/state for starring, filtering and copying names; photos store filtering; many i18n additions; minor date-format change.

Changes

Cohort / File(s) Summary
Enum & Config Migration
app/Enum/PhotoVisibilityType.php, database/migrations/2026_02_11_170000_add_star_photo_visibility_config.php
Adds PhotoVisibilityType enum and migration inserting photos_star_visibility config entry.
Policies
app/Policies/AlbumPolicy.php, app/Policies/PhotoPolicy.php
Adds CAN_STAR constants and canStar methods to evaluate star permissions at album and photo levels.
Request Authorization
app/Http/Requests/Traits/Authorize/AuthorizeCanStarPhotosTrait.php, app/Http/Requests/Photo/SetPhotosStarredRequest.php
New trait that checks per-photo CAN_STAR via Gate; request now uses this trait.
API Resources & Middleware
app/Http/Resources/GalleryConfigs/InitConfig.php, app/Http/Resources/Rights/AlbumRightsResource.php, app/Http/Resources/Rights/PhotoRightsResource.php, app/Http/Middleware/ConfigIntegrity.php
Expose photos_star_visibility in InitConfig; add can_star to rights resources; add photos_star_visibility to PRO_FIELDS.
Frontend Headers & Panels
resources/js/components/headers/AlbumHeader.vue, resources/js/components/headers/PhotoHeader.vue, resources/js/components/gallery/photoModule/PhotoPanel.vue, resources/js/components/gallery/albumModule/AlbumPanel.vue
Adds header buttons/events (showStarredImages, showSelected, toggleStar), album callbacks to toggle filter and copy starred names, wiring and toasts.
Thumb & Photo UI
resources/js/components/gallery/albumModule/thumbs/PhotoThumb.vue, resources/js/components/headers/PhotoHeader.vue
Badge rendering now respects photos_star_visibility and login; PhotoHeader gains toggleStar emit and star button UI.
Stores & Types
resources/js/stores/LycheeState.ts, resources/js/stores/AlbumState.ts, resources/js/stores/PhotosState.ts, resources/js/lychee.d.ts
Adds photos_star_visibility to global state and types; album store showStarredOnly; photos store allPhotos, activeFilter, filterPhotos, performFilter, and starredPhotosCount.
Context Menus & Actions
resources/js/composables/contextMenus/contextMenu.ts, resources/js/composables/album/photoActions.ts
Menu permission checks now use can_star; toggling star triggers photosStore.performFilter() to refresh filters.
Photo Data Formatting
app/Http/Resources/Models/Utils/PreFormattedAlbumData.php
Date formatting switched from format() to translatedFormat() for locale-aware output.
Translations
lang/*/gallery.php, lang/*/all_settings.php, lang/*/dialogs.php (many locales)
Adds photos_star_visibility docs/details keys, show_starred and copy_starred_names gallery strings, and selected_images.names_copied dialog texts across locales.
Misc / Minor
composer.json, small request/trait/import updates, other minor wiring files
Type/manifest updates and small wiring changes (imports, emits, storeToRefs additions, minor UI hooks).

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40 minutes

Poem

I’m a rabbit in the repo, quick and spry,
I found an enum and taught the stars to fly,
I toggle, filter, copy names with glee,
Permissions checked — translations sing with me,
Hop hop — the gallery sparkles, bright as sky. 🐇✨

🚥 Pre-merge checks | ✅ 1 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Merge Conflict Detection ⚠️ Warning ❌ Merge conflicts detected (96 files):

⚔️ .ai/embeds/demo.html (content)
⚔️ Dockerfile (content)
⚔️ Dockerfile-legacy (content)
⚔️ app/Http/Controllers/Gallery/EmbedController.php (content)
⚔️ app/Http/Middleware/ConfigIntegrity.php (content)
⚔️ app/Http/Requests/Embed/EmbededRequest.php (content)
⚔️ app/Http/Requests/Photo/SetPhotosStarredRequest.php (content)
⚔️ app/Http/Resources/GalleryConfigs/InitConfig.php (content)
⚔️ app/Http/Resources/Models/Utils/PreFormattedAlbumData.php (content)
⚔️ app/Http/Resources/Rights/AlbumRightsResource.php (content)
⚔️ app/Http/Resources/Rights/PhotoRightsResource.php (content)
⚔️ app/Policies/AlbumPolicy.php (content)
⚔️ app/Policies/PhotoPolicy.php (content)
⚔️ lang/ar/all_settings.php (content)
⚔️ lang/ar/dialogs.php (content)
⚔️ lang/ar/gallery.php (content)
⚔️ lang/bg/all_settings.php (content)
⚔️ lang/bg/dialogs.php (content)
⚔️ lang/bg/gallery.php (content)
⚔️ lang/cz/all_settings.php (content)
⚔️ lang/cz/dialogs.php (content)
⚔️ lang/cz/gallery.php (content)
⚔️ lang/de/all_settings.php (content)
⚔️ lang/de/dialogs.php (content)
⚔️ lang/de/gallery.php (content)
⚔️ lang/el/all_settings.php (content)
⚔️ lang/el/dialogs.php (content)
⚔️ lang/el/gallery.php (content)
⚔️ lang/en/all_settings.php (content)
⚔️ lang/en/dialogs.php (content)
⚔️ lang/en/gallery.php (content)
⚔️ lang/es/all_settings.php (content)
⚔️ lang/es/dialogs.php (content)
⚔️ lang/es/gallery.php (content)
⚔️ lang/fa/all_settings.php (content)
⚔️ lang/fa/dialogs.php (content)
⚔️ lang/fa/gallery.php (content)
⚔️ lang/fr/all_settings.php (content)
⚔️ lang/fr/dialogs.php (content)
⚔️ lang/fr/gallery.php (content)
⚔️ lang/hu/all_settings.php (content)
⚔️ lang/hu/dialogs.php (content)
⚔️ lang/hu/gallery.php (content)
⚔️ lang/it/all_settings.php (content)
⚔️ lang/it/dialogs.php (content)
⚔️ lang/it/gallery.php (content)
⚔️ lang/ja/all_settings.php (content)
⚔️ lang/ja/dialogs.php (content)
⚔️ lang/ja/gallery.php (content)
⚔️ lang/nl/all_settings.php (content)
⚔️ lang/nl/dialogs.php (content)
⚔️ lang/nl/gallery.php (content)
⚔️ lang/no/all_settings.php (content)
⚔️ lang/no/dialogs.php (content)
⚔️ lang/no/gallery.php (content)
⚔️ lang/pl/all_settings.php (content)
⚔️ lang/pl/dialogs.php (content)
⚔️ lang/pl/gallery.php (content)
⚔️ lang/pt/all_settings.php (content)
⚔️ lang/pt/dialogs.php (content)
⚔️ lang/pt/gallery.php (content)
⚔️ lang/ru/all_settings.php (content)
⚔️ lang/ru/dialogs.php (content)
⚔️ lang/ru/gallery.php (content)
⚔️ lang/sk/all_settings.php (content)
⚔️ lang/sk/dialogs.php (content)
⚔️ lang/sk/gallery.php (content)
⚔️ lang/sv/all_settings.php (content)
⚔️ lang/sv/dialogs.php (content)
⚔️ lang/sv/gallery.php (content)
⚔️ lang/vi/all_settings.php (content)
⚔️ lang/vi/dialogs.php (content)
⚔️ lang/vi/gallery.php (content)
⚔️ lang/zh_CN/all_settings.php (content)
⚔️ lang/zh_CN/dialogs.php (content)
⚔️ lang/zh_CN/gallery.php (content)
⚔️ lang/zh_TW/all_settings.php (content)
⚔️ lang/zh_TW/dialogs.php (content)
⚔️ lang/zh_TW/gallery.php (content)
⚔️ resources/js/components/gallery/albumModule/AlbumPanel.vue (content)
⚔️ resources/js/components/gallery/albumModule/thumbs/PhotoThumb.vue (content)
⚔️ resources/js/components/gallery/photoModule/PhotoPanel.vue (content)
⚔️ resources/js/components/headers/AlbumHeader.vue (content)
⚔️ resources/js/components/headers/PhotoHeader.vue (content)
⚔️ resources/js/composables/album/photoActions.ts (content)
⚔️ resources/js/composables/contextMenus/contextMenu.ts (content)
⚔️ resources/js/embed/api.ts (content)
⚔️ resources/js/embed/components/EmbedWidget.vue (content)
⚔️ resources/js/embed/config.ts (content)
⚔️ resources/js/embed/types.ts (content)
⚔️ resources/js/lychee.d.ts (content)
⚔️ resources/js/stores/AlbumState.ts (content)
⚔️ resources/js/stores/LycheeState.ts (content)
⚔️ resources/js/stores/PhotosState.ts (content)
⚔️ tests/Feature_v2/Embed/EmbedAlbumTest.php (content)
⚔️ tests/Feature_v2/Embed/EmbedStreamTest.php (content)

These conflicts must be resolved before merging into master.
Resolve conflicts locally and push changes to this branch.
✅ Passed checks (1 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 84.62% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

Tip

Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
resources/js/stores/PhotosState.ts (2)

18-22: ⚠️ Potential issue | 🟡 Minor

reset() doesn't clear allPhotos or starredPhotosCount.

After reset(), allPhotos and starredPhotosCount become stale. They should be reset alongside photos.

Suggested fix
 		reset() {
 			this.photos = [];
+			this.allPhotos = [];
 			this.photosTimeline = undefined;
 			this.photoRatingFilter = null;
+			this.starredPhotosCount = 0;
 		},

67-109: ⚠️ Potential issue | 🟠 Major

appendPhotos doesn't update allPhotos or starredPhotosCount.

When additional pages of photos are loaded via appendPhotos, the allPhotos cache and starredPhotosCount are not updated. This means:

  • Toggling the starred filter after paginating will lose the newly appended photos.
  • The starred count in the header badge will be wrong.
Suggested fix (add at the end of `appendPhotos`)
 		appendPhotos(photos: App.Http.Resources.Models.PhotoResource[], isTimeline: boolean) {
 			// ... existing code ...
+			this.allPhotos = this.photos;
+			this.starredPhotosCount = this.photos.filter((p) => p.is_starred).length;
 		},
🧹 Nitpick comments (5)
lang/cz/all_settings.php (1)

17-17: Minor grammar nit in translation string.

"set star flag to photo" reads more naturally as "set the star flag on a photo". This likely affects all locale files that share the same English fallback.

Suggested wording
-        'photos_star_visibility' => 'Who can see and set star flag to photo',
+        'photos_star_visibility' => 'Who can see and set the star flag on a photo',
lang/cz/dialogs.php (1)

253-255: Array keys use camelCase, inconsistent with the rest of the file.

Every other top-level key in this file uses snake_case (e.g., share_album, move_photo, photo_delete), but the new group uses camelCase (selectedImagesnamesCopied). To stay consistent:

Proposed fix
-    'selectedImages' => [
-        'namesCopied' => 'The names of the selected images have been copied!',
+    'selected_images' => [
+        'names_copied' => 'The names of the selected images have been copied!',
     ],

Ensure all references to these keys (in Blade/Vue templates) are updated accordingly.

#!/bin/bash
# Find all references to the camelCase keys in the codebase
rg -rn 'selectedImages' --type-add 'vue:*.vue' --type-add 'blade:*.blade.php' -g '!lang/'
rg -rn 'namesCopied' --type-add 'vue:*.vue' --type-add 'blade:*.blade.php' -g '!lang/'
# Also check other lang files for consistency
rg -rn 'selectedImages' lang/
lang/en/dialogs.php (1)

256-258: Inconsistent key naming: camelCase vs snake_case.

All other keys in this file use snake_case (e.g., share_album, url_copied, move_album, photo_delete). These new keys use camelCase, which breaks the established convention. Consider renaming to selected_images and names_copied for consistency across all locale files.

♻️ Suggested fix
-    'selectedImages' => [
-        'namesCopied' => 'The names of the selected images have been copied!',
+    'selected_images' => [
+        'names_copied' => 'The names of the selected images have been copied!',
     ],
resources/js/components/headers/AlbumHeader.vue (1)

29-36: "Copy starred names" button semantics are unclear.

The pi-clone icon and can_edit guard don't clearly convey that this button copies starred photo names to clipboard. Consider:

  • Using pi-copy or pi-clipboard icon instead.
  • Adding a :title tooltip explaining the action.
  • Reviewing whether can_edit is the right permission gate (the action reads data, it doesn't edit anything).
database/migrations/2026_02_11_170000_add_star_photo_visibility_config.php (1)

9-10: Missing use import for the DB facade.

DB is referenced on lines 44 and 55 but is not explicitly imported. While Laravel's global alias typically resolves this, adding the import is consistent with PSR-4 and avoids surprises if aliases are ever disabled.

Proposed fix
 use Illuminate\Database\Migrations\Migration;
+use Illuminate\Support\Facades\DB;

Comment on lines 282 to 297
/**
* Checks whether the photo can be starred by the current user.
*
* A photo is called _starred_ if the current user is allowed to star
* the photo.
* A photo is _starred_ if any of the following conditions hold
* (OR-clause)
*
* - the user is an admin
* - the user is the owner of the photo
*
* @param User|null $user
* @param Photo $photo
*
* @return bool
*/
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Docblock is inaccurate — it omits the album-level visibility conditions.

The PHPDoc states only "the user is an admin" and "the user is the owner" as conditions, but the implementation also delegates to AlbumPolicy::canStar which grants access based on photos_star_visibility config for authenticated and anonymous users. Update the docblock to reflect the full set of conditions.

Suggested docblock update
 	/**
 	 * Checks whether the photo can be starred by the current user.
 	 *
-	 * A photo is called _starred_ if the current user is allowed to star
-	 * the photo.
-	 * A photo is _starred_ if any of the following conditions hold
+	 * A photo can be starred if any of the following conditions hold
 	 * (OR-clause)
 	 *
 	 *  - the user is an admin
 	 *  - the user is the owner of the photo
+	 *  - the photo belongs to an album where starring is allowed per the album policy
+	 *    (based on photos_star_visibility config)
 	 *
 	 * `@param` User|null $user
 	 * `@param` Photo     $photo
 	 *
 	 * `@return` bool
 	 */

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

- Fix for update of starred photos.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
resources/js/stores/PhotosState.ts (1)

43-111: ⚠️ Potential issue | 🟠 Major

Preserve allPhotos when a filter is active.

When activeFilter is set, setPhotos/appendPhotos overwrite allPhotos with this.photos, which may already be filtered. This collapses the full list and makes the filter non-reversible (e.g., pagination in starred-only view permanently drops unstarred photos). Consider updating allPhotos from the unfiltered dataset and re-running performFilter so filtering stays view-only.

💡 Suggested fix (keep full list intact when filter is active)
	setPhotos(photos: App.Http.Resources.Models.PhotoResource[], isTimeline: boolean) {
		if (isTimeline) {
			this.photosTimeline = spliter(
				photos,
				(p: App.Http.Resources.Models.PhotoResource) => p.timeline?.time_date ?? "",
				(p: App.Http.Resources.Models.PhotoResource) => p.timeline?.format ?? "Others",
			);
			this.photos = merge(this.photosTimeline);
			// Rebuild navigation links after timeline merge since photos were reordered
			this.rebuildNavigationLinks();
		} else {
			// We are not using the timeline, so we can just use the photos as is.
			this.photos = photos;
			this.photosTimeline = undefined;
		}
		this.allPhotos = this.photos;
+		if (this.activeFilter !== null) {
+			this.performFilter();
+		}
	},
	/**
	 * Append new photos to the existing collection.
	 * Handles both timeline and non-timeline modes.
	 *
	 * Critical: Fixes navigation links (next_photo_id/previous_photo_id) between
	 * the last photo of the existing collection and the first photo of the new batch.
	 * Without this fix, navigating between photos would break at page boundaries.
	 */
	appendPhotos(photos: App.Http.Resources.Models.PhotoResource[], isTimeline: boolean) {
+		if (this.activeFilter !== null) {
+			this.allPhotos = [...this.allPhotos, ...photos];
+			this.performFilter();
+			return;
+		}
		if (isTimeline) {
			// Append new photos to timeline and re-merge
			const newTimelinePhotos = spliter(
				photos,
				(p: App.Http.Resources.Models.PhotoResource) => p.timeline?.time_date ?? "",
				(p: App.Http.Resources.Models.PhotoResource) => p.timeline?.format ?? "Others",
			);
			// Merge existing timeline with new timeline data
			if (this.photosTimeline) {
				// Append new timeline groups or merge into existing ones
				for (const newGroup of newTimelinePhotos) {
					const existingGroup = this.photosTimeline.find((g) => g.header === newGroup.header);
					if (existingGroup) {
						existingGroup.data = [...existingGroup.data, ...newGroup.data];
					} else {
						this.photosTimeline.push(newGroup);
					}
				}
			} else {
				this.photosTimeline = newTimelinePhotos;
			}
			this.photos = merge(this.photosTimeline);
			// Rebuild all navigation links after timeline merge since photos were reordered
			this.rebuildNavigationLinks();
		} else {
			// Remember where the old photos end so we can fix the boundary link
			const oldPhotoCount = this.photos.length;
			// Simply append photos to the existing array
			this.photos = [...this.photos, ...photos];

			// Fix navigation links at the boundary between old and new photos
			if (oldPhotoCount > 0 && oldPhotoCount < this.photos.length) {
				const lastOldPhoto = this.photos[oldPhotoCount - 1];
				const firstNewPhoto = this.photos[oldPhotoCount];

				// Connect the last old photo to the first new photo
				lastOldPhoto.next_photo_id = firstNewPhoto.id;
				// Connect the first new photo back to the last old photo
				firstNewPhoto.previous_photo_id = lastOldPhoto.id;
			}
		}
		this.allPhotos = this.photos;
	},
🧹 Nitpick comments (13)
lang/no/dialogs.php (1)

253-255: New translation string is in English, not Norwegian.

The names_copied value is not translated to Norwegian. Based on learnings, the maintainer does not prioritize strict localization consistency for new entries in language files, so this is a minor nit.

lang/pt/gallery.php (1)

99-100: New translation strings are in English, not Portuguese.

Both show_starred and copy_starred_names remain untranslated. Based on learnings, the maintainer does not prioritize strict localization consistency for new entries in language files.

lang/pl/dialogs.php (1)

254-256: New translation string is in English, not Polish.

The names_copied value is not translated to Polish. Based on learnings, the maintainer does not prioritize strict localization consistency for new entries in language files.

lang/vi/dialogs.php (1)

253-255: New translation string is in English, not Vietnamese.

The names_copied value is not translated to Vietnamese. Based on learnings, the maintainer does not prioritize strict localization consistency for new entries in language files.

lang/zh_TW/gallery.php (1)

99-100: New translation strings are in English, not Traditional Chinese.

Both show_starred and copy_starred_names remain untranslated. Based on learnings, the maintainer does not prioritize strict localization consistency for new entries in language files.

lang/de/gallery.php (1)

98-99: New translation strings are in English, not German.

Both show_starred and copy_starred_names remain untranslated. Based on learnings, the maintainer does not prioritize strict localization consistency for new entries in language files.

lang/fr/gallery.php (1)

98-99: New translation strings are in English, not French.

Both show_starred and copy_starred_names remain untranslated. Based on learnings, the maintainer does not prioritize strict localization consistency for new entries in language files.

lang/ja/gallery.php (1)

99-100: New translation strings are in English, not Japanese.

Both show_starred and copy_starred_names remain untranslated. Based on learnings, the maintainer does not prioritize strict localization consistency for new entries in language files.

lang/es/gallery.php (1)

99-100: New strings are not translated to Spanish.

Both show_starred and copy_starred_names contain English text instead of Spanish translations. This is consistent with some other untranslated strings in this file, but flagging for awareness.

Based on learnings, the maintainer does not prioritize strict localization consistency for new items in language files.

lang/ru/dialogs.php (1)

252-254: New string is not translated to Russian.

The names_copied value remains in English while the rest of this file is in Russian.

Based on learnings, the maintainer does not prioritize strict localization consistency for new items in language files.

lang/de/dialogs.php (1)

255-257: New string is not translated to German.

The names_copied value remains in English while the rest of this file is in German.

Based on learnings, the maintainer does not prioritize strict localization consistency for new items in language files.

lang/pt/dialogs.php (1)

253-255: New string is not translated to Portuguese.

Based on learnings, the maintainer does not prioritize strict localization consistency for new items in language files.

lang/ja/dialogs.php (1)

253-255: New string is not translated to Japanese.

Based on learnings, the maintainer does not prioritize strict localization consistency for new items in language files.

Comment on lines +359 to +371
toast.add({
severity: "info",
summary: "Info",
detail: trans("dialogs.selected_images.names_copied") + ". " + selectedNames,
life: 3000,
}),
)
.catch(() =>
toast.add({
severity: "error",
summary: "Error",
detail: "Failed to copy to clipboard",
life: 3000,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Localize toast summary/error strings.

The success/error toasts use hard-coded English ("Info", "Error", "Failed to copy to clipboard"). Please route these through i18n so the UI respects the user’s locale.

💡 Example update (add corresponding translation keys as needed)
			.then(() =>
				toast.add({
					severity: "info",
-					summary: "Info",
-					detail: trans("dialogs.selected_images.names_copied") + ". " + selectedNames,
+					summary: trans("toasts.info"),
+					detail: `${trans("dialogs.selected_images.names_copied")} ${selectedNames}`,
					life: 3000,
				}),
			)
			.catch(() =>
				toast.add({
					severity: "error",
-					summary: "Error",
-					detail: "Failed to copy to clipboard",
+					summary: trans("toasts.error"),
+					detail: trans("dialogs.selected_images.copy_failed"),
					life: 3000,
				}),
			);

Fixed images links after filtering.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
resources/js/stores/PhotosState.ts (1)

11-14: Consider stronger typing for activeFilter and filterPhotos parameter.

Record<string, unknown> allows arbitrary keys that may not exist on PhotoResource, and the cast at Line 132 bypasses compile-time checks. Using Partial<App.Http.Resources.Models.PhotoResource> would constrain the filter to valid photo properties and eliminate the need for the Record<string, unknown> cast inside the loop.

Proposed diff
-		activeFilter: null as Record<string, unknown> | null,
+		activeFilter: null as Partial<App.Http.Resources.Models.PhotoResource> | null,
-	filterPhotos(filter: Record<string, unknown> | null) {
+	filterPhotos(filter: Partial<App.Http.Resources.Models.PhotoResource> | null) {
-			if ((photo as Record<string, unknown>)[key] !== filter[key]) {
+			if (photo[key as keyof App.Http.Resources.Models.PhotoResource] !== filter[key as keyof App.Http.Resources.Models.PhotoResource]) {

Also applies to: 120-123

$this->can_pasword_protect = !request()->configs()->getValueAsBool('cache_enabled');
$this->can_import_from_server = Gate::check(AlbumPolicy::CAN_IMPORT_FROM_SERVER, [AbstractAlbum::class]);
$this->can_make_purchasable = $this->canMakePurchasable($abstract_album);
$this->can_star = Gate::check(AlbumPolicy::CAN_STAR, [AbstractAlbum::class, $abstract_album]);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As this is set in InitConfig, this is not needed here. It does not depend of the specific of the album. Unless you plan to add this later?

$this->can_edit = Gate::check(AlbumPolicy::CAN_EDIT, [AbstractAlbum::class, $album]);
$this->can_download = Gate::check(AlbumPolicy::CAN_DOWNLOAD, [AbstractAlbum::class, $album]);
$this->can_access_full_photo = Gate::check(AlbumPolicy::CAN_ACCESS_FULL_PHOTO, [AbstractAlbum::class, $album]);
$this->can_star = Gate::check(AlbumPolicy::CAN_STAR, [AbstractAlbum::class, $album]);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar question.

*/
public function canSee(?User $user, BaseSmartAlbum $smart_album): bool
{
// We do not require upload rights for all albums
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this removed ?

if ($user !== null && $visibility === PhotoVisibilityType::AUTHENTICATED) {
return true;
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are missing the condition where the album is shared with another user and PhotoVisibilityType is set to Annonymous. this should also return true.

use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;

return new class() extends Migration {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use App\Models\Extensions\BaseConfigMigration;

return new class() extends BaseConfigMigration {

takes care of the boiler plate, you just to define need getConfigs()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

Comments