API: Kategorie-Art und Kategorie für Webapp-Vorlagen
fetch_kategorien() liefert art, Kategorien lassen sich als App oder Richtlinie anlegen. Webapp-Vorlagen tragen optional eine App-Kategorie, die beim Aktivieren in den Workspace mitkopiert wird. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
845533a0a0
commit
8363d41dd3
1 file changed
+36
-24
@@ -15,6 +15,7 @@ import urllib.error
|
||||
import urllib.request
|
||||
from urllib.parse import urljoin, urlparse
|
||||
from uuid import UUID, uuid4
|
||||
from typing import Literal
|
||||
|
||||
import psycopg
|
||||
from psycopg.types.json import Jsonb
|
||||
@@ -210,6 +211,7 @@ class CreateKategorieRequest(BaseModel):
|
||||
name: str
|
||||
description: str | None = None
|
||||
sort_order: int = 0
|
||||
art: Literal["app", "richtlinie"] = "app"
|
||||
|
||||
|
||||
class CreateWorkspaceRequest(BaseModel):
|
||||
@@ -243,12 +245,14 @@ class CreateWebappTemplateRequest(BaseModel):
|
||||
name: str
|
||||
url: str
|
||||
description: str | None = None
|
||||
kategorie_id: str | None = None
|
||||
|
||||
|
||||
class UpdateWebappTemplateRequest(BaseModel):
|
||||
name: str
|
||||
url: str
|
||||
description: str | None = None
|
||||
kategorie_id: str | None = None
|
||||
|
||||
|
||||
class ExtraPartitionRequest(BaseModel):
|
||||
@@ -2862,7 +2866,7 @@ def fetch_kategorien():
|
||||
with get_database_connection() as conn:
|
||||
with conn.cursor() as cur:
|
||||
cur.execute(
|
||||
"SELECT id, key, name, description, sort_order FROM kategorien ORDER BY sort_order, name"
|
||||
"SELECT id, key, name, description, sort_order, art FROM kategorien ORDER BY sort_order, name"
|
||||
)
|
||||
return [
|
||||
{
|
||||
@@ -2871,24 +2875,25 @@ def fetch_kategorien():
|
||||
"name": name,
|
||||
"description": description,
|
||||
"sort_order": sort_order,
|
||||
"art": art,
|
||||
}
|
||||
for kid, key, name, description, sort_order in cur.fetchall()
|
||||
for kid, key, name, description, sort_order, art in cur.fetchall()
|
||||
]
|
||||
|
||||
def create_kategorie(key: str, name: str, description: str | None, sort_order: int):
|
||||
def create_kategorie(key: str, name: str, description: str | None, sort_order: int, art: str = "app"):
|
||||
kategorie_id = uuid4()
|
||||
|
||||
with get_database_connection() as conn:
|
||||
with conn.cursor() as cur:
|
||||
cur.execute(
|
||||
"""
|
||||
INSERT INTO kategorien (id, key, name, description, sort_order)
|
||||
VALUES (%s, %s, %s, %s, %s)
|
||||
INSERT INTO kategorien (id, key, name, description, sort_order, art)
|
||||
VALUES (%s, %s, %s, %s, %s, %s)
|
||||
""",
|
||||
(kategorie_id, key, name, description, sort_order),
|
||||
(kategorie_id, key, name, description, sort_order, art),
|
||||
)
|
||||
|
||||
return {"id": str(kategorie_id), "key": key, "name": name}
|
||||
return {"id": str(kategorie_id), "key": key, "name": name, "art": art}
|
||||
|
||||
def fetch_workspaces():
|
||||
with get_database_connection() as conn:
|
||||
@@ -3242,7 +3247,12 @@ def fetch_webapp_templates():
|
||||
with get_database_connection() as conn:
|
||||
with conn.cursor() as cur:
|
||||
cur.execute(
|
||||
"SELECT id, name, url, description, icon_filename FROM webapp_templates ORDER BY name"
|
||||
"""
|
||||
SELECT t.id, t.name, t.url, t.description, t.icon_filename, t.kategorie_id, k.name
|
||||
FROM webapp_templates t
|
||||
LEFT JOIN kategorien k ON k.id = t.kategorie_id
|
||||
ORDER BY t.name
|
||||
"""
|
||||
)
|
||||
return [
|
||||
{
|
||||
@@ -3251,8 +3261,10 @@ def fetch_webapp_templates():
|
||||
"url": url,
|
||||
"description": description,
|
||||
"icon_path": f"/webapp-icons/{icon_filename}" if icon_filename else None,
|
||||
"kategorie_id": str(kategorie_id) if kategorie_id else None,
|
||||
"kategorie_name": kategorie_name,
|
||||
}
|
||||
for template_id, name, url, description, icon_filename in cur.fetchall()
|
||||
for template_id, name, url, description, icon_filename, kategorie_id, kategorie_name in cur.fetchall()
|
||||
]
|
||||
|
||||
|
||||
@@ -3286,7 +3298,7 @@ def fetch_available_templates_for_workspace(workspace_id: str):
|
||||
]
|
||||
|
||||
|
||||
def create_webapp_template(name: str, url: str, description: str | None):
|
||||
def create_webapp_template(name: str, url: str, description: str | None, kategorie_id: str | None = None):
|
||||
template_id = uuid4()
|
||||
favicon = fetch_favicon(url)
|
||||
icon_filename = _write_webapp_icon(template_id, favicon[0], favicon[1]) if favicon else None
|
||||
@@ -3296,16 +3308,16 @@ def create_webapp_template(name: str, url: str, description: str | None):
|
||||
with conn.cursor() as cur:
|
||||
cur.execute(
|
||||
"""
|
||||
INSERT INTO webapp_templates (id, name, url, description, icon_filename, icon_content_type)
|
||||
VALUES (%s, %s, %s, %s, %s, %s)
|
||||
INSERT INTO webapp_templates (id, name, url, description, icon_filename, icon_content_type, kategorie_id)
|
||||
VALUES (%s, %s, %s, %s, %s, %s, %s)
|
||||
""",
|
||||
(template_id, name, url, description, icon_filename, icon_content_type),
|
||||
(template_id, name, url, description, icon_filename, icon_content_type, kategorie_id),
|
||||
)
|
||||
|
||||
return {"id": str(template_id), "name": name, "url": url, "description": description, "icon_path": f"/webapp-icons/{icon_filename}" if icon_filename else None}
|
||||
|
||||
|
||||
def update_webapp_template(template_id: str, name: str, url: str, description: str | None):
|
||||
def update_webapp_template(template_id: str, name: str, url: str, description: str | None, kategorie_id: str | None = None):
|
||||
favicon = fetch_favicon(url)
|
||||
icon_filename = _write_webapp_icon(template_id, favicon[0], favicon[1]) if favicon else None
|
||||
icon_content_type = favicon[1] if favicon else None
|
||||
@@ -3316,10 +3328,10 @@ def update_webapp_template(template_id: str, name: str, url: str, description: s
|
||||
"""
|
||||
UPDATE webapp_templates
|
||||
SET name = %s, url = %s, description = %s, icon_filename = %s,
|
||||
icon_content_type = %s, updated_at = now()
|
||||
icon_content_type = %s, kategorie_id = %s, updated_at = now()
|
||||
WHERE id = %s
|
||||
""",
|
||||
(name, url, description, icon_filename, icon_content_type, template_id),
|
||||
(name, url, description, icon_filename, icon_content_type, kategorie_id, template_id),
|
||||
)
|
||||
|
||||
return {"id": template_id, "name": name, "url": url, "description": description, "icon_path": f"/webapp-icons/{icon_filename}" if icon_filename else None}
|
||||
@@ -3350,7 +3362,7 @@ def activate_webapp_template(workspace_id: str, template_id: str):
|
||||
with get_database_connection() as conn:
|
||||
with conn.cursor() as cur:
|
||||
cur.execute(
|
||||
"SELECT name, url, icon_filename, icon_content_type FROM webapp_templates WHERE id = %s",
|
||||
"SELECT name, url, icon_filename, icon_content_type, kategorie_id FROM webapp_templates WHERE id = %s",
|
||||
(template_id,),
|
||||
)
|
||||
template = cur.fetchone()
|
||||
@@ -3358,7 +3370,7 @@ def activate_webapp_template(workspace_id: str, template_id: str):
|
||||
if template is None:
|
||||
return None
|
||||
|
||||
name, url, icon_filename, icon_content_type = template
|
||||
name, url, icon_filename, icon_content_type, kategorie_id = template
|
||||
|
||||
cur.execute(
|
||||
"SELECT 1 FROM workspace_webapps WHERE workspace_id = %s AND template_id = %s",
|
||||
@@ -3386,10 +3398,10 @@ def activate_webapp_template(workspace_id: str, template_id: str):
|
||||
|
||||
cur.execute(
|
||||
"""
|
||||
INSERT INTO workspace_webapps (id, workspace_id, name, url, icon_filename, icon_content_type, template_id)
|
||||
VALUES (%s, %s, %s, %s, %s, %s, %s)
|
||||
INSERT INTO workspace_webapps (id, workspace_id, name, url, icon_filename, icon_content_type, template_id, kategorie_id)
|
||||
VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
|
||||
""",
|
||||
(webapp_id, workspace_id, name, url, copied_icon_filename, icon_content_type, template_id),
|
||||
(webapp_id, workspace_id, name, url, copied_icon_filename, icon_content_type, template_id, kategorie_id),
|
||||
)
|
||||
|
||||
return {"id": str(webapp_id), "name": name, "url": url, "icon_path": f"/webapp-icons/{copied_icon_filename}" if copied_icon_filename else None}
|
||||
@@ -4806,7 +4818,7 @@ def create_kategorie_endpoint(payload: CreateKategorieRequest, authorization: st
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"kategorie": create_kategorie(payload.key, payload.name, payload.description, payload.sort_order),
|
||||
"kategorie": create_kategorie(payload.key, payload.name, payload.description, payload.sort_order, payload.art),
|
||||
}
|
||||
|
||||
|
||||
@@ -4936,7 +4948,7 @@ def create_webapp_template_endpoint(payload: CreateWebappTemplateRequest, author
|
||||
if not require_service_token(authorization):
|
||||
return {"success": False, "error": "unauthorized", "message": "Fehlendes oder ungültiges Service-Token."}
|
||||
|
||||
return {"success": True, "webapp_template": create_webapp_template(payload.name, payload.url, payload.description)}
|
||||
return {"success": True, "webapp_template": create_webapp_template(payload.name, payload.url, payload.description, payload.kategorie_id)}
|
||||
|
||||
|
||||
@app.put("/api/v1/webapp-templates/{template_id}")
|
||||
@@ -4944,7 +4956,7 @@ def update_webapp_template_endpoint(template_id: str, payload: UpdateWebappTempl
|
||||
if not require_service_token(authorization):
|
||||
return {"success": False, "error": "unauthorized", "message": "Fehlendes oder ungültiges Service-Token."}
|
||||
|
||||
return {"success": True, "webapp_template": update_webapp_template(template_id, payload.name, payload.url, payload.description)}
|
||||
return {"success": True, "webapp_template": update_webapp_template(template_id, payload.name, payload.url, payload.description, payload.kategorie_id)}
|
||||
|
||||
|
||||
@app.delete("/api/v1/webapp-templates/{template_id}")
|
||||
|
||||
Reference in new issue
Block a user