From c32e38bac74bdc1fa8adbfc9a6c33cd583a4a452 Mon Sep 17 00:00:00 2001 From: sai80082 Date: Fri, 24 Apr 2026 15:48:34 +0530 Subject: [PATCH] feat: implement permissions management with new Permission interface and refactor API key handlers --- src/config/permissions.ts | 26 +++++++++++++++++++ .../api/settings/generate-import-api-key.ts | 11 ++------ .../api/settings/generate-workflow-api-key.ts | 11 ++------ src/pages/api/settings/validate-api-key.ts | 11 ++------ src/pages/assets/import-shared.tsx | 9 +------ src/pages/settings/index.tsx | 7 ++--- src/pages/workflows/[id].tsx | 9 +------ 7 files changed, 38 insertions(+), 46 deletions(-) create mode 100644 src/config/permissions.ts diff --git a/src/config/permissions.ts b/src/config/permissions.ts new file mode 100644 index 0000000..482f5f1 --- /dev/null +++ b/src/config/permissions.ts @@ -0,0 +1,26 @@ +export interface Permission { + name: string; + description: string; +} + +export const IMPORT_PERMISSIONS: Permission[] = [ + { name: "asset.read", description: "Check for existing assets" }, + { name: "asset.upload", description: "Upload new assets" }, + { name: "album.read", description: "Read album data" }, + { name: "album.create", description: "Create new albums" }, + { name: "album.update", description: "Add assets to albums" }, + { name: "tag.create", description: "Tag imported assets" }, + { name: "tag.asset", description: "Assign tags to assets" }, +]; + +export const WORKFLOW_PERMISSIONS: Permission[] = [ + { name: "asset.read", description: "Query and filter assets" }, + { name: "asset.update", description: "Favorite, archive, update metadata" }, + { name: "album.read", description: "Read album data" }, + { name: "album.create", description: "Create new albums" }, + { name: "album.update", description: "Add/remove assets from albums" }, + { name: "tag.create", description: "Create and assign tags" }, +]; + +export const getPermissionNames = (permissions: Permission[]): string[] => + permissions.map((p) => p.name); diff --git a/src/pages/api/settings/generate-import-api-key.ts b/src/pages/api/settings/generate-import-api-key.ts index df97ea5..24f46cc 100644 --- a/src/pages/api/settings/generate-import-api-key.ts +++ b/src/pages/api/settings/generate-import-api-key.ts @@ -5,17 +5,10 @@ import { getCurrentUser } from "@/handlers/serverUtils/user.utils"; import { getUserHeaders } from "@/helpers/user.helper"; import { and, eq } from "drizzle-orm"; import { NextApiRequest, NextApiResponse } from "next"; +import { IMPORT_PERMISSIONS, getPermissionNames } from "@/config/permissions"; export const IMPORT_API_KEY_SETTING = "import_api_key"; const IMPORT_KEY_NAME = "Power Tools Import Key"; -const IMPORT_PERMISSIONS = [ - "asset.read", - "asset.upload", - "album.read", - "album.create", - "album.update", - "tag.create", -]; export default async function handler(req: NextApiRequest, res: NextApiResponse) { if (req.method !== "POST") return res.status(405).json({ message: "Method not allowed" }); @@ -26,7 +19,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) const immichRes = await fetch(`${ENV.IMMICH_URL}/api/api-keys`, { method: "POST", headers: getUserHeaders(currentUser, { "Content-Type": "application/json" }), - body: JSON.stringify({ name: IMPORT_KEY_NAME, permissions: IMPORT_PERMISSIONS }), + body: JSON.stringify({ name: IMPORT_KEY_NAME, permissions: getPermissionNames(IMPORT_PERMISSIONS) }), }); if (!immichRes.ok) { diff --git a/src/pages/api/settings/generate-workflow-api-key.ts b/src/pages/api/settings/generate-workflow-api-key.ts index e5cdd8f..7053631 100644 --- a/src/pages/api/settings/generate-workflow-api-key.ts +++ b/src/pages/api/settings/generate-workflow-api-key.ts @@ -5,17 +5,10 @@ import { getCurrentUser } from "@/handlers/serverUtils/user.utils"; import { getUserHeaders } from "@/helpers/user.helper"; import { and, eq } from "drizzle-orm"; import { NextApiRequest, NextApiResponse } from "next"; +import { WORKFLOW_PERMISSIONS, getPermissionNames } from "@/config/permissions"; const WORKFLOW_API_KEY_SETTING = "workflow_api_key"; const WORKFLOW_KEY_NAME = "Power Tools Workflow Key"; -const WORKFLOW_PERMISSIONS = [ - "asset.read", - "asset.update", - "album.read", - "album.create", - "album.update", - "tag.create", -]; export default async function handler(req: NextApiRequest, res: NextApiResponse) { if (req.method !== "POST") return res.status(405).json({ message: "Method not allowed" }); @@ -27,7 +20,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) const immichRes = await fetch(`${ENV.IMMICH_URL}/api/api-keys`, { method: "POST", headers: getUserHeaders(currentUser, { "Content-Type": "application/json" }), - body: JSON.stringify({ name: WORKFLOW_KEY_NAME, permissions: WORKFLOW_PERMISSIONS }), + body: JSON.stringify({ name: WORKFLOW_KEY_NAME, permissions: getPermissionNames(WORKFLOW_PERMISSIONS) }), }); if (!immichRes.ok) { diff --git a/src/pages/api/settings/validate-api-key.ts b/src/pages/api/settings/validate-api-key.ts index ff49774..61b9491 100644 --- a/src/pages/api/settings/validate-api-key.ts +++ b/src/pages/api/settings/validate-api-key.ts @@ -1,14 +1,7 @@ import { ENV } from "@/config/environment"; import { getCurrentUser } from "@/handlers/serverUtils/user.utils"; import { NextApiRequest, NextApiResponse } from "next"; - -const WORKFLOW_PERMISSIONS = [ - "asset.read", - "asset.update", - "album.create", - "album.update", - "tag.create", -]; +import { WORKFLOW_PERMISSIONS, getPermissionNames } from "@/config/permissions"; export default async function handler(req: NextApiRequest, res: NextApiResponse) { if (req.method !== "POST") return res.status(405).json({ message: "Method not allowed" }); @@ -19,7 +12,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) const { apiKey, requiredPermissions } = req.body; if (!apiKey) return res.status(400).json({ message: "apiKey is required" }); - const REQUIRED_PERMISSIONS: string[] = Array.isArray(requiredPermissions) ? requiredPermissions : WORKFLOW_PERMISSIONS; + const REQUIRED_PERMISSIONS: string[] = Array.isArray(requiredPermissions) ? requiredPermissions : getPermissionNames(WORKFLOW_PERMISSIONS); try { const keyRes = await fetch(`${ENV.IMMICH_URL}/api/api-keys/me`, { diff --git a/src/pages/assets/import-shared.tsx b/src/pages/assets/import-shared.tsx index 14c4301..97e7ec0 100644 --- a/src/pages/assets/import-shared.tsx +++ b/src/pages/assets/import-shared.tsx @@ -22,14 +22,7 @@ import PageLayout from "@/components/layouts/PageLayout"; import Header from "@/components/shared/Header"; import ApiKeyGate from "@/components/shared/ApiKeyGate"; -const IMPORT_PERMISSIONS = [ - { name: "asset.read", description: "Check for existing assets" }, - { name: "asset.upload", description: "Upload new assets" }, - { name: "album.read", description: "Read album data" }, - { name: "album.create", description: "Create new albums" }, - { name: "album.update", description: "Add assets to albums" }, - { name: "tag.create", description: "Tag imported assets" }, -]; +import { IMPORT_PERMISSIONS } from "@/config/permissions"; import { Button } from "@/components/ui/button"; import { Checkbox } from "@/components/ui/checkbox"; import { Input } from "@/components/ui/input"; diff --git a/src/pages/settings/index.tsx b/src/pages/settings/index.tsx index 0616f2e..a19eccf 100644 --- a/src/pages/settings/index.tsx +++ b/src/pages/settings/index.tsx @@ -12,6 +12,7 @@ import toast from "react-hot-toast"; import API from "@/lib/api"; import { useConfig } from "@/contexts/ConfigContext"; import Link from "next/link"; +import { WORKFLOW_PERMISSIONS } from "@/config/permissions"; function ConnectionStatus({ label, url, icon: Icon }: { label: string; url: string; icon: any }) { return ( @@ -74,7 +75,7 @@ export default function SettingsPage() { } }; - const IMPORT_REQUIRED_PERMISSIONS = ["asset.read", "asset.upload", "album.read", "album.create", "album.update", "tag.create"]; + const IMPORT_REQUIRED_PERMISSIONS = ["asset.read", "asset.upload", "album.read", "album.create", "album.update", "tag.create", "tag.asset"]; const saveImportApiKey = async () => { if (!importApiKey.trim()) { @@ -269,8 +270,8 @@ export default function SettingsPage() { )} {!validationResult && (
- {["asset.read", "asset.update", "album.create", "album.update", "tag.create"].map((p) => ( - {p} + {WORKFLOW_PERMISSIONS.map((p) => ( + {p.name} ))}
)} diff --git a/src/pages/workflows/[id].tsx b/src/pages/workflows/[id].tsx index 24ce4e7..3cd991c 100644 --- a/src/pages/workflows/[id].tsx +++ b/src/pages/workflows/[id].tsx @@ -39,14 +39,7 @@ import Loader from "@/components/ui/loader"; import API from "@/lib/api"; import ApiKeyGate from "@/components/shared/ApiKeyGate"; -const WORKFLOW_PERMISSIONS = [ - { name: "asset.read", description: "Query and filter assets" }, - { name: "asset.update", description: "Favorite, archive, update metadata" }, - { name: "album.read", description: "Read album data" }, - { name: "album.create", description: "Create new albums" }, - { name: "album.update", description: "Add/remove assets from albums" }, - { name: "tag.create", description: "Create and assign tags" }, -]; +import { WORKFLOW_PERMISSIONS } from "@/config/permissions"; function generateId() { return Math.random().toString(36).substring(2, 15);