feat: add visual admin panel with page builder and settings editor
- Add /admin route with password-protected visual page builder
- Page Builder: manage hero images, standalone albums, subpages, and sections
- Album Picker: browse all shared Immich albums with search and filtering
- Settings Editor: theme, grid, footer, legal, SEO configuration
- YAML service with atomic writes and automatic backups (content/.backups/)
- HMAC-signed admin sessions (24h expiry, HttpOnly cookies)
- API endpoints: /api/admin/{auth,gallery,settings,albums,reload}
- Enable with ADMIN_PASSWORD env var; disabled by default
- invalidateConfigCache() export for hot-reload after saves
2026-05-29 17:04:37 +02:00
|
|
|
import { NextResponse } from 'next/server';
|
2026-09-22 14:12:13 +02:00
|
|
|
import { withAdmin } from '@/lib/admin/withAdmin';
|
feat: add visual admin panel with page builder and settings editor
- Add /admin route with password-protected visual page builder
- Page Builder: manage hero images, standalone albums, subpages, and sections
- Album Picker: browse all shared Immich albums with search and filtering
- Settings Editor: theme, grid, footer, legal, SEO configuration
- YAML service with atomic writes and automatic backups (content/.backups/)
- HMAC-signed admin sessions (24h expiry, HttpOnly cookies)
- API endpoints: /api/admin/{auth,gallery,settings,albums,reload}
- Enable with ADMIN_PASSWORD env var; disabled by default
- invalidateConfigCache() export for hot-reload after saves
2026-05-29 17:04:37 +02:00
|
|
|
import { getConfig } from '@/lib/config';
|
|
|
|
|
|
|
|
|
|
interface ImmichAlbumSummary {
|
|
|
|
|
id: string;
|
|
|
|
|
albumName: string;
|
2026-08-23 23:18:14 +02:00
|
|
|
/** Immich's own flag. Absent on older versions, which is not the same as false. */
|
|
|
|
|
shared?: boolean;
|
feat: add visual admin panel with page builder and settings editor
- Add /admin route with password-protected visual page builder
- Page Builder: manage hero images, standalone albums, subpages, and sections
- Album Picker: browse all shared Immich albums with search and filtering
- Settings Editor: theme, grid, footer, legal, SEO configuration
- YAML service with atomic writes and automatic backups (content/.backups/)
- HMAC-signed admin sessions (24h expiry, HttpOnly cookies)
- API endpoints: /api/admin/{auth,gallery,settings,albums,reload}
- Enable with ADMIN_PASSWORD env var; disabled by default
- invalidateConfigCache() export for hot-reload after saves
2026-05-29 17:04:37 +02:00
|
|
|
description: string;
|
|
|
|
|
albumThumbnailAssetId: string | null;
|
|
|
|
|
assetCount: number;
|
|
|
|
|
createdAt: string;
|
|
|
|
|
updatedAt: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** GET: List ALL shared Immich albums (not just allowlisted ones). */
|
2026-09-22 14:12:13 +02:00
|
|
|
export const GET = withAdmin(async () => {
|
feat: add visual admin panel with page builder and settings editor
- Add /admin route with password-protected visual page builder
- Page Builder: manage hero images, standalone albums, subpages, and sections
- Album Picker: browse all shared Immich albums with search and filtering
- Settings Editor: theme, grid, footer, legal, SEO configuration
- YAML service with atomic writes and automatic backups (content/.backups/)
- HMAC-signed admin sessions (24h expiry, HttpOnly cookies)
- API endpoints: /api/admin/{auth,gallery,settings,albums,reload}
- Enable with ADMIN_PASSWORD env var; disabled by default
- invalidateConfigCache() export for hot-reload after saves
2026-05-29 17:04:37 +02:00
|
|
|
const config = getConfig();
|
2026-08-23 23:18:14 +02:00
|
|
|
// Credentials, not `needsSetup`: this route is how the operator picks the
|
|
|
|
|
// albums that gallery.yaml is built from, so refusing to run until that file
|
|
|
|
|
// exists is a deadlock (#507).
|
|
|
|
|
if (config.needsCredentials) {
|
feat: add visual admin panel with page builder and settings editor
- Add /admin route with password-protected visual page builder
- Page Builder: manage hero images, standalone albums, subpages, and sections
- Album Picker: browse all shared Immich albums with search and filtering
- Settings Editor: theme, grid, footer, legal, SEO configuration
- YAML service with atomic writes and automatic backups (content/.backups/)
- HMAC-signed admin sessions (24h expiry, HttpOnly cookies)
- API endpoints: /api/admin/{auth,gallery,settings,albums,reload}
- Enable with ADMIN_PASSWORD env var; disabled by default
- invalidateConfigCache() export for hot-reload after saves
2026-05-29 17:04:37 +02:00
|
|
|
return NextResponse.json({ error: 'Immich not configured' }, { status: 503 });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const res = await fetch(`${config.immich.apiUrl}/albums?shared=true`, {
|
|
|
|
|
headers: {
|
|
|
|
|
'x-api-key': config.immich.apiKey,
|
|
|
|
|
Accept: 'application/json',
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (!res.ok) {
|
|
|
|
|
return NextResponse.json({ error: `Immich API returned ${res.status}` }, { status: 502 });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const albums = (await res.json()) as ImmichAlbumSummary[];
|
|
|
|
|
|
|
|
|
|
// Mark which albums are already configured
|
|
|
|
|
const configuredIds = new Set(config.albums);
|
|
|
|
|
const enriched = albums.map((album) => ({
|
|
|
|
|
id: album.id,
|
|
|
|
|
albumName: album.albumName,
|
|
|
|
|
description: album.description || '',
|
|
|
|
|
thumbnailAssetId: album.albumThumbnailAssetId,
|
|
|
|
|
assetCount: album.assetCount,
|
|
|
|
|
createdAt: album.createdAt,
|
|
|
|
|
updatedAt: album.updatedAt,
|
|
|
|
|
isConfigured: configuredIds.has(album.id),
|
2026-08-23 23:18:14 +02:00
|
|
|
// Immich ignores ?shared=true and returns everything, so this list is the
|
|
|
|
|
// whole library rather than the shared part of it (#515). Passing the flag
|
|
|
|
|
// through lets the picker say which albums Immich still considers private
|
|
|
|
|
// — the accident-prevention the filter was supposed to give, without
|
|
|
|
|
// taking away the ability to publish them.
|
|
|
|
|
shared: album.shared,
|
feat: add visual admin panel with page builder and settings editor
- Add /admin route with password-protected visual page builder
- Page Builder: manage hero images, standalone albums, subpages, and sections
- Album Picker: browse all shared Immich albums with search and filtering
- Settings Editor: theme, grid, footer, legal, SEO configuration
- YAML service with atomic writes and automatic backups (content/.backups/)
- HMAC-signed admin sessions (24h expiry, HttpOnly cookies)
- API endpoints: /api/admin/{auth,gallery,settings,albums,reload}
- Enable with ADMIN_PASSWORD env var; disabled by default
- invalidateConfigCache() export for hot-reload after saves
2026-05-29 17:04:37 +02:00
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
// Sort: configured first, then by name
|
|
|
|
|
enriched.sort((a, b) => {
|
|
|
|
|
if (a.isConfigured !== b.isConfigured) return a.isConfigured ? -1 : 1;
|
|
|
|
|
return a.albumName.localeCompare(b.albumName);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return NextResponse.json({ albums: enriched });
|
|
|
|
|
} catch (err) {
|
|
|
|
|
console.error('[Admin] Failed to fetch albums from Immich:', err);
|
|
|
|
|
return NextResponse.json({ error: 'Failed to connect to Immich' }, { status: 502 });
|
|
|
|
|
}
|
2026-09-22 14:12:13 +02:00
|
|
|
});
|