""" Feature Management Endpoints for Mitai Jinkendo Admin-only CRUD for features registry. """ from fastapi import APIRouter, HTTPException, Depends from db import get_db, get_cursor, r2d from auth import require_admin router = APIRouter(prefix="/api/features", tags=["features"]) @router.get("") def list_features(session: dict = Depends(require_admin)): """Admin: List all features.""" with get_db() as conn: cur = get_cursor(conn) cur.execute(""" SELECT * FROM features ORDER BY category, name """) return [r2d(r) for r in cur.fetchall()] @router.post("") def create_feature(data: dict, session: dict = Depends(require_admin)): """ Admin: Create new feature. Required fields: - id: Feature ID (e.g., 'new_data_source') - name: Display name - category: 'data', 'ai', 'export', 'integration' - limit_type: 'count' or 'boolean' - reset_period: 'never', 'daily', 'monthly' - default_limit: INT or NULL (unlimited) """ feature_id = data.get('id', '').strip() name = data.get('name', '').strip() description = data.get('description', '') category = data.get('category') limit_type = data.get('limit_type', 'count') reset_period = data.get('reset_period', 'never') default_limit = data.get('default_limit') if not feature_id or not name: raise HTTPException(400, "ID und Name fehlen") if category not in ['data', 'ai', 'export', 'integration']: raise HTTPException(400, "Ungültige Kategorie") if limit_type not in ['count', 'boolean']: raise HTTPException(400, "limit_type muss 'count' oder 'boolean' sein") if reset_period not in ['never', 'daily', 'monthly']: raise HTTPException(400, "Ungültiger reset_period") with get_db() as conn: cur = get_cursor(conn) # Check if ID already exists cur.execute("SELECT id FROM features WHERE id = %s", (feature_id,)) if cur.fetchone(): raise HTTPException(400, f"Feature '{feature_id}' existiert bereits") # Create feature cur.execute(""" INSERT INTO features ( id, name, description, category, limit_type, reset_period, default_limit ) VALUES (%s, %s, %s, %s, %s, %s, %s) """, (feature_id, name, description, category, limit_type, reset_period, default_limit)) conn.commit() return {"ok": True, "id": feature_id} @router.put("/{feature_id}") def update_feature(feature_id: str, data: dict, session: dict = Depends(require_admin)): """Admin: Update feature.""" with get_db() as conn: cur = get_cursor(conn) updates = [] values = [] if 'name' in data: updates.append('name = %s') values.append(data['name']) if 'description' in data: updates.append('description = %s') values.append(data['description']) if 'default_limit' in data: updates.append('default_limit = %s') values.append(data['default_limit']) if 'active' in data: updates.append('active = %s') values.append(data['active']) if not updates: return {"ok": True} updates.append('updated = CURRENT_TIMESTAMP') values.append(feature_id) cur.execute( f"UPDATE features SET {', '.join(updates)} WHERE id = %s", values ) conn.commit() return {"ok": True} @router.delete("/{feature_id}") def delete_feature(feature_id: str, session: dict = Depends(require_admin)): """Admin: Delete feature (soft-delete: set active=false).""" with get_db() as conn: cur = get_cursor(conn) cur.execute("UPDATE features SET active = false WHERE id = %s", (feature_id,)) conn.commit() return {"ok": True}