diff --git a/app/auth/backend/admin.py b/app/auth/backend/admin.py index 0a53cef..796653d 100644 --- a/app/auth/backend/admin.py +++ b/app/auth/backend/admin.py @@ -22,23 +22,49 @@ class UserPasswordResetRequest(BaseModel): new_password: str = Field(..., min_length=8, max_length=128) +def _users_column_exists(column_name: str) -> bool: + result = execute_query_single( + """ + SELECT 1 + FROM information_schema.columns + WHERE table_schema = 'public' + AND table_name = 'users' + AND column_name = %s + LIMIT 1 + """, + (column_name,) + ) + return bool(result) + + @router.get("/admin/users", dependencies=[Depends(require_permission("users.manage"))]) async def list_users(): - users = execute_query( - """ - SELECT u.user_id, u.username, u.email, u.full_name, - u.is_active, u.is_superadmin, u.is_2fa_enabled, - u.telefoni_extension, u.telefoni_aktiv, u.telefoni_phone_ip, u.telefoni_phone_username, - u.created_at, u.last_login_at, - COALESCE(array_remove(array_agg(g.name), NULL), ARRAY[]::varchar[]) AS groups - FROM users u - LEFT JOIN user_groups ug ON u.user_id = ug.user_id - LEFT JOIN groups g ON ug.group_id = g.id - GROUP BY u.user_id - ORDER BY u.user_id - """ - ) - return users + is_2fa_expr = "u.is_2fa_enabled" if _users_column_exists("is_2fa_enabled") else "FALSE AS is_2fa_enabled" + telefoni_extension_expr = "u.telefoni_extension" if _users_column_exists("telefoni_extension") else "NULL::varchar AS telefoni_extension" + telefoni_active_expr = "u.telefoni_aktiv" if _users_column_exists("telefoni_aktiv") else "FALSE AS telefoni_aktiv" + telefoni_ip_expr = "u.telefoni_phone_ip" if _users_column_exists("telefoni_phone_ip") else "NULL::varchar AS telefoni_phone_ip" + telefoni_username_expr = "u.telefoni_phone_username" if _users_column_exists("telefoni_phone_username") else "NULL::varchar AS telefoni_phone_username" + last_login_expr = "u.last_login_at" if _users_column_exists("last_login_at") else "NULL::timestamp AS last_login_at" + + try: + users = execute_query( + f""" + SELECT u.user_id, u.username, u.email, u.full_name, + u.is_active, u.is_superadmin, {is_2fa_expr}, + {telefoni_extension_expr}, {telefoni_active_expr}, {telefoni_ip_expr}, {telefoni_username_expr}, + u.created_at, {last_login_expr}, + COALESCE(array_remove(array_agg(g.name), NULL), ARRAY[]::varchar[]) AS groups + FROM users u + LEFT JOIN user_groups ug ON u.user_id = ug.user_id + LEFT JOIN groups g ON ug.group_id = g.id + GROUP BY u.user_id + ORDER BY u.user_id + """ + ) + return users + except Exception as exc: + logger.error("❌ Failed to load admin users: %s", exc) + raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Could not load users") from exc @router.post("/admin/users", status_code=status.HTTP_201_CREATED, dependencies=[Depends(require_permission("users.manage"))]) diff --git a/app/settings/frontend/settings.html b/app/settings/frontend/settings.html index 3042139..e65ef7e 100644 --- a/app/settings/frontend/settings.html +++ b/app/settings/frontend/settings.html @@ -2241,14 +2241,16 @@ async function loadUsers() { async function loadAdminUsers() { try { const response = await fetch('/api/v1/admin/users'); - if (!response.ok) throw new Error('Failed to load users'); + if (!response.ok) { + throw new Error(await getErrorMessage(response, 'Kunne ikke indlaese brugere')); + } usersCache = await response.json(); displayUsers(usersCache); populateTelefoniTestUsers(usersCache); } catch (error) { console.error('Error loading users:', error); const tbody = document.getElementById('usersTableBody'); - tbody.innerHTML = '