From eed02c3bb9d447083415a95477e46677c7b026d3 Mon Sep 17 00:00:00 2001 From: ildyria Date: Wed, 26 Aug 2026 01:16:39 +0200 Subject: [PATCH 1/2] Clarify settings requirements --- app/Http/Resources/Models/ConfigResource.php | 4 + app/Models/Configs.php | 3 +- ..._08_25_000001_add_config_required_keys.php | 180 ++++++++++++++++++ resources/js/lychee.d.ts | 1 + .../js/v8/components/settings/ConfigGroup.vue | 10 +- resources/js/v8/views/admin/LandingConfig.vue | 1 + 6 files changed, 197 insertions(+), 2 deletions(-) create mode 100644 database/migrations/2026_08_25_000001_add_config_required_keys.php diff --git a/app/Http/Resources/Models/ConfigResource.php b/app/Http/Resources/Models/ConfigResource.php index ebe94408ce9..9fb84d7359d 100644 --- a/app/Http/Resources/Models/ConfigResource.php +++ b/app/Http/Resources/Models/ConfigResource.php @@ -25,6 +25,9 @@ class ConfigResource extends Data public bool $require_se; public int|null $order; + /** @var array */ + public array $required_keys; + public function __construct(Configs $c) { $this->key = $c->key; @@ -35,6 +38,7 @@ public function __construct(Configs $c) $this->require_se = $c->level > 0; $this->is_expert = $c->is_expert; $this->order = (config('app.env', 'dev') === 'dev') ? $c->order : null; + $this->required_keys = $c->required_keys !== null && $c->required_keys !== '' ? explode(',', $c->required_keys) : []; } public static function fromModel(Configs $c): ConfigResource diff --git a/app/Models/Configs.php b/app/Models/Configs.php index 2832c244bb9..75588e212f3 100644 --- a/app/Models/Configs.php +++ b/app/Models/Configs.php @@ -38,6 +38,7 @@ * @property bool $not_on_docker * @property int $order * @property bool $is_expert + * @property string|null $required_keys * * @method static ConfigsBuilder|Configs addSelect($column) * @method static ConfigsBuilder|Configs join(string $table, string $first, string $operator = null, string $second = null, string $type = 'inner', string $where = false) @@ -69,7 +70,7 @@ class Configs extends Model * * @var list */ - protected $fillable = ['key', 'value', 'cat', 'type_range', 'is_secret', 'description', 'level', 'not_on_docker', 'order']; + protected $fillable = ['key', 'value', 'cat', 'type_range', 'is_secret', 'description', 'level', 'not_on_docker', 'order', 'required_keys']; /** * this is a parameter for Laravel to indicate that there is no created_at, updated_at columns. diff --git a/database/migrations/2026_08_25_000001_add_config_required_keys.php b/database/migrations/2026_08_25_000001_add_config_required_keys.php new file mode 100644 index 00000000000..a38783d5c7c --- /dev/null +++ b/database/migrations/2026_08_25_000001_add_config_required_keys.php @@ -0,0 +1,180 @@ +string(self::COL)->nullable()->after('is_expert'); + }); + + // Landing page (cat: Mod Welcome), root: landing_page_enable + DB::table('configs')->whereIn('key', [ + 'landing_layout', + 'landing_intro_screen_enabled', + 'landing_hero_text_position', + 'landing_hero_text_color', + 'landing_hero_text_opacity', + 'landing_animation_preset', + 'landing_about_enabled', + 'landing_featured_items_enabled', + 'landing_cta_text', + 'landing_cta_position', + 'landing_cta_shift_type', + 'landing_cta_shift_x', + 'landing_cta_shift_x_direction', + 'landing_cta_shift_y', + 'landing_cta_shift_y_direction', + 'landing_meridian_explore_offset', + 'landing_meridian_contact_offset', + 'landing_meridian_explore_line_position', + 'landing_meridian_contact_line_position', + 'landing_login_position', + 'landing_backdrop_opacity', + ])->update([self::COL => 'landing_page_enable']); + DB::table('configs')->where('key', 'landing_about_text')->update([self::COL => 'landing_page_enable,landing_about_enabled']); + DB::table('configs')->whereIn('key', [ + 'landing_featured_items_mode', + 'landing_featured_items_count', + ])->update([self::COL => 'landing_page_enable,landing_featured_items_enabled']); + + // Timeline (cat: Mod Timeline), two independent roots + DB::table('configs')->whereIn('key', [ + 'timeline_photos_public', + 'timeline_photos_granularity', + 'timeline_photos_order', + 'timeline_photos_layout', + 'timeline_photos_pagination_limit', + 'timeline_photo_date_format_year', + 'timeline_photo_date_format_month', + 'timeline_photo_date_format_day', + 'timeline_photo_date_format_hour', + ])->update([self::COL => 'timeline_photos_enabled']); + DB::table('configs')->whereIn('key', [ + 'timeline_albums_public', + 'timeline_albums_granularity', + 'timeline_albums_root_enabled', + 'timeline_album_date_format_year', + 'timeline_album_date_format_month', + 'timeline_album_date_format_day', + ])->update([self::COL => 'timeline_albums_enabled']); + + // AI Vision (cat: AI Vision), root: ai_vision_enabled + DB::table('configs')->whereIn('key', [ + 'ai_vision_face_enabled', + 'ai_vision_nsfw_enabled', + ])->update([self::COL => 'ai_vision_enabled']); + DB::table('configs')->whereIn('key', [ + 'ai_vision_face_permission_mode', + 'ai_vision_face_selfie_confidence_threshold', + 'ai_vision_face_person_is_searchable_default', + 'ai_vision_face_allow_user_claim', + 'ai_vision_face_overlay_enabled', + 'ai_vision_face_recognition_warning', + ])->update([self::COL => 'ai_vision_enabled,ai_vision_face_enabled']); + DB::table('configs')->where('key', 'ai_vision_face_overlay_default_visibility') + ->update([self::COL => 'ai_vision_enabled,ai_vision_face_enabled,ai_vision_face_overlay_enabled']); + DB::table('configs')->whereIn('key', [ + 'ai_vision_nsfw_preset', + 'ai_vision_nsfw_check_block_action', + 'ai_vision_nsfw_monitor_block_action', + 'ai_vision_nsfw_trust_but_verify_block_action', + 'ai_vision_nsfw_trust_block_action', + 'ai_vision_nsfw_sensitive_album_action', + 'ai_vision_nsfw_sensitive_no_album_action', + 'ai_vision_nsfw_scan_trusted_users', + 'ai_vision_nsfw_monitor_hide_on_scan', + 'ai_vision_nsfw_trust_but_verify_hide_on_scan', + 'ai_vision_nsfw_trust_hide_on_scan', + ])->update([self::COL => 'ai_vision_enabled,ai_vision_nsfw_enabled']); + + // Watermarker (cat: Mod Watermarker), root: watermark_enabled + DB::table('configs')->whereIn('key', [ + 'watermark_photo_id', + 'watermark_random_path', + 'watermark_public', + 'watermark_logged_in_users_enabled', + 'watermark_original', + 'watermark_size', + 'watermark_opacity', + 'watermark_position', + 'watermark_shift_type', + 'watermark_shift_x', + 'watermark_shift_x_direction', + 'watermark_shift_y', + 'watermark_shift_y_direction', + 'watermark_optout_disabled', + ])->update([self::COL => 'watermark_enabled']); + + // Frame (cat: Mod Frame), root: mod_frame_enabled + DB::table('configs')->whereIn('key', [ + 'random_album_id', + 'mod_frame_refresh', + ])->update([self::COL => 'mod_frame_enabled']); + + // Map (cat: Mod Map), root: map_display + DB::table('configs')->whereIn('key', [ + 'map_provider', + 'map_include_subalbums', + 'map_display_direction', + 'map_display_public', + 'gps_coordinate_display', + 'gps_coordinate_display_public', + ])->update([self::COL => 'map_display']); + + // Flow (cat: Mod Flow), root: flow_enabled + DB::table('configs')->whereIn('key', [ + 'flow_public', + 'flow_base', + 'flow_max_items', + 'flow_strategy', + 'flow_include_sub_albums', + 'flow_include_photos_from_children', + 'flow_open_album_on_click', + 'flow_display_open_album_button', + 'flow_highlight_first_picture', + 'flow_min_max_enabled', + 'flow_display_statistics', + 'flow_compact_mode_enabled', + 'flow_image_header_enabled', + 'flow_carousel_enabled', + 'date_format_flow_published', + 'flow_blur_nsfw_enabled', + 'hide_nsfw_in_flow', + ])->update([self::COL => 'flow_enabled']); + DB::table('configs')->whereIn('key', [ + 'flow_min_max_order', + 'date_format_flow_min_max', + ])->update([self::COL => 'flow_enabled,flow_min_max_enabled']); + DB::table('configs')->whereIn('key', [ + 'flow_image_header_cover', + 'flow_image_header_height', + ])->update([self::COL => 'flow_enabled,flow_image_header_enabled']); + DB::table('configs')->where('key', 'flow_carousel_height')->update([self::COL => 'flow_enabled,flow_carousel_enabled']); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('configs', function (Blueprint $table) { + $table->dropColumn(self::COL); + }); + } +}; diff --git a/resources/js/lychee.d.ts b/resources/js/lychee.d.ts index 88a7f0661e3..b5259cf6a3f 100644 --- a/resources/js/lychee.d.ts +++ b/resources/js/lychee.d.ts @@ -896,6 +896,7 @@ declare namespace App { is_expert: boolean; require_se: boolean; order: number | null; + required_keys: string[]; }; export type ContactMessageResource = { id: number; diff --git a/resources/js/v8/components/settings/ConfigGroup.vue b/resources/js/v8/components/settings/ConfigGroup.vue index 077cb0dad5a..d54c1d9bfed 100644 --- a/resources/js/v8/components/settings/ConfigGroup.vue +++ b/resources/js/v8/components/settings/ConfigGroup.vue @@ -1,7 +1,7 @@