From 768a4391cf144c46d2a42a3344af37d4dc659bcb Mon Sep 17 00:00:00 2001 From: Leo Vasanko Date: Wed, 3 Dec 2025 01:03:25 +0000 Subject: [PATCH] Improved profile view layout. --- frontend/auth/admin/AdminApp.vue | 42 +++++++++++++------------- frontend/src/admin/AdminUserDetail.vue | 8 ++--- passkey/fastapi/mainapp.py | 7 +---- 3 files changed, 26 insertions(+), 31 deletions(-) diff --git a/frontend/auth/admin/AdminApp.vue b/frontend/auth/admin/AdminApp.vue index 71341b4..f80babf 100644 --- a/frontend/auth/admin/AdminApp.vue +++ b/frontend/auth/admin/AdminApp.vue @@ -114,7 +114,7 @@ async function attachPermissionToOrg(pid, orgUuid) { if (!orgUuid) return try { const params = new URLSearchParams({ permission_id: pid }) - const res = await fetch(`/auth/admin/orgs/${orgUuid}/permission?${params.toString()}`, { method: 'POST' }) + const res = await fetch(`/auth/api/admin/orgs/${orgUuid}/permission?${params.toString()}`, { method: 'POST' }) const data = await res.json() if (data.detail) throw new Error(data.detail) await loadOrgs() @@ -127,7 +127,7 @@ async function detachPermissionFromOrg(pid, orgUuid) { openDialog('confirm', { message: 'Remove permission from this org?', action: async () => { try { const params = new URLSearchParams({ permission_id: pid }) - const res = await fetch(`/auth/admin/orgs/${orgUuid}/permission?${params.toString()}`, { method: 'DELETE' }) + const res = await fetch(`/auth/api/admin/orgs/${orgUuid}/permission?${params.toString()}`, { method: 'DELETE' }) const data = await res.json() if (data.detail) throw new Error(data.detail) await loadOrgs() @@ -149,7 +149,7 @@ function parseHash() { } async function loadOrgs() { - const res = await fetch('/auth/admin/orgs') + const res = await fetch('/auth/api/admin/orgs') if (res.status === 401) { authStore.authRequired = true throw new Error('Authentication required') @@ -167,7 +167,7 @@ async function loadOrgs() { } async function loadPermissions() { - const res = await fetch('/auth/admin/permissions') + const res = await fetch('/auth/api/admin/permissions') if (res.status === 401) { authStore.authRequired = true throw new Error('Authentication required') @@ -230,7 +230,7 @@ function editUserName(user) { openDialog('user-update-name', { user, name: user. function deleteOrg(org) { if (!info.value?.is_global_admin) { authStore.showMessage('Global admin only'); return } openDialog('confirm', { message: `Delete organization ${org.display_name}?`, action: async () => { - const res = await fetch(`/auth/admin/orgs/${org.uuid}`, { method: 'DELETE' }) + const res = await fetch(`/auth/api/admin/orgs/${org.uuid}`, { method: 'DELETE' }) const data = await res.json(); if (data.detail) throw new Error(data.detail) await Promise.all([loadOrgs(), loadPermissions()]) } }) @@ -240,7 +240,7 @@ function createUserInRole(org, role) { openDialog('user-create', { org, role }) async function moveUserToRole(org, user, targetRoleDisplayName) { if (user.role === targetRoleDisplayName) return - const res = await fetch(`/auth/admin/orgs/${org.uuid}/users/${user.uuid}/role`, { + const res = await fetch(`/auth/api/admin/orgs/${org.uuid}/users/${user.uuid}/role`, { method: 'PUT', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ role: targetRoleDisplayName }) @@ -282,7 +282,7 @@ function updateRole(role) { openDialog('role-update', { role, name: role.display function deleteRole(role) { openDialog('confirm', { message: `Delete role ${role.display_name}?`, action: async () => { - const res = await fetch(`/auth/admin/orgs/${role.org_uuid}/roles/${role.uuid}`, { method: 'DELETE' }) + const res = await fetch(`/auth/api/admin/orgs/${role.org_uuid}/roles/${role.uuid}`, { method: 'DELETE' }) const data = await res.json(); if (data.detail) throw new Error(data.detail) await loadOrgs() } }) @@ -299,7 +299,7 @@ async function toggleRolePermission(role, pid, checked) { role.permissions = newPermissions try { - const res = await fetch(`/auth/admin/orgs/${role.org_uuid}/roles/${role.uuid}`, { + const res = await fetch(`/auth/api/admin/orgs/${role.org_uuid}/roles/${role.uuid}`, { method: 'PUT', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ display_name: role.display_name, permissions: newPermissions }) @@ -319,7 +319,7 @@ function updatePermission(p) { openDialog('perm-display', { permission: p }) } function deletePermission(p) { openDialog('confirm', { message: `Delete permission ${p.id}?`, action: async () => { const params = new URLSearchParams({ permission_id: p.id }) - const res = await fetch(`/auth/admin/permission?${params.toString()}`, { method: 'DELETE' }) + const res = await fetch(`/auth/api/admin/permission?${params.toString()}`, { method: 'DELETE' }) const data = await res.json(); if (data.detail) throw new Error(data.detail) await loadPermissions() } }) @@ -449,7 +449,7 @@ const breadcrumbEntries = computed(() => { watch(selectedUser, async (u) => { if (!u) { userDetail.value = null; return } try { - const res = await fetch(`/auth/admin/orgs/${u.org_uuid}/users/${u.uuid}`) + const res = await fetch(`/auth/api/admin/orgs/${u.org_uuid}/users/${u.uuid}`) const data = await res.json() if (data.detail) throw new Error(data.detail) userDetail.value = data @@ -488,7 +488,7 @@ async function toggleOrgPermission(org, permId, checked) { org.permissions = next try { const params = new URLSearchParams({ permission_id: permId }) - const res = await fetch(`/auth/admin/orgs/${org.uuid}/permission?${params.toString()}`, { method: checked ? 'POST' : 'DELETE' }) + const res = await fetch(`/auth/api/admin/orgs/${org.uuid}/permission?${params.toString()}`, { method: checked ? 'POST' : 'DELETE' }) const data = await res.json() if (data.detail) throw new Error(data.detail) await loadOrgs() @@ -505,7 +505,7 @@ async function onUserNameSaved() { await loadOrgs() if (selectedUser.value) { try { - const r = await fetch(`/auth/admin/orgs/${selectedUser.value.org_uuid}/users/${selectedUser.value.uuid}`) + const r = await fetch(`/auth/api/admin/orgs/${selectedUser.value.org_uuid}/users/${selectedUser.value.uuid}`) const jd = await r.json() if (!r.ok || jd.detail) throw new Error(jd.detail || 'Reload failed') userDetail.value = jd @@ -521,27 +521,27 @@ async function submitDialog() { const t = dialog.value.type if (t === 'org-create') { const name = dialog.value.data.name?.trim(); if (!name) throw new Error('Name required') - const res = await fetch('/auth/admin/orgs', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ display_name: name, permissions: [] }) }) + const res = await fetch('/auth/api/admin/orgs', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ display_name: name, permissions: [] }) }) const d = await res.json(); if (d.detail) throw new Error(d.detail); await Promise.all([loadOrgs(), loadPermissions()]) } else if (t === 'org-update') { const { org } = dialog.value.data; const name = dialog.value.data.name?.trim(); if (!name) throw new Error('Name required') - const res = await fetch(`/auth/admin/orgs/${org.uuid}`, { method: 'PUT', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ display_name: name, permissions: org.permissions }) }) + const res = await fetch(`/auth/api/admin/orgs/${org.uuid}`, { method: 'PUT', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ display_name: name, permissions: org.permissions }) }) const d = await res.json(); if (d.detail) throw new Error(d.detail); await loadOrgs() } else if (t === 'role-create') { const { org } = dialog.value.data; const name = dialog.value.data.name?.trim(); if (!name) throw new Error('Name required') - const res = await fetch(`/auth/admin/orgs/${org.uuid}/roles`, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ display_name: name, permissions: [] }) }) + const res = await fetch(`/auth/api/admin/orgs/${org.uuid}/roles`, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ display_name: name, permissions: [] }) }) const d = await res.json(); if (d.detail) throw new Error(d.detail); await loadOrgs() } else if (t === 'role-update') { const { role } = dialog.value.data; const name = dialog.value.data.name?.trim(); if (!name) throw new Error('Name required') - const res = await fetch(`/auth/admin/orgs/${role.org_uuid}/roles/${role.uuid}`, { method: 'PUT', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ display_name: name, permissions: role.permissions }) }) + const res = await fetch(`/auth/api/admin/orgs/${role.org_uuid}/roles/${role.uuid}`, { method: 'PUT', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ display_name: name, permissions: role.permissions }) }) const d = await res.json(); if (d.detail) throw new Error(d.detail); await loadOrgs() } else if (t === 'user-create') { const { org, role } = dialog.value.data; const name = dialog.value.data.name?.trim(); if (!name) throw new Error('Name required') - const res = await fetch(`/auth/admin/orgs/${org.uuid}/users`, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ display_name: name, role: role.display_name }) }) + const res = await fetch(`/auth/api/admin/orgs/${org.uuid}/users`, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ display_name: name, role: role.display_name }) }) const d = await res.json(); if (d.detail) throw new Error(d.detail); await loadOrgs() } else if (t === 'user-update-name') { const { user } = dialog.value.data; const name = dialog.value.data.name?.trim(); if (!name) throw new Error('Name required') - const res = await fetch(`/auth/admin/orgs/${user.org_uuid}/users/${user.uuid}/display-name`, { method: 'PUT', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ display_name: name }) }) + const res = await fetch(`/auth/api/admin/orgs/${user.org_uuid}/users/${user.uuid}/display-name`, { method: 'PUT', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ display_name: name }) }) const d = await res.json(); if (d.detail) throw new Error(d.detail); await onUserNameSaved() } else if (t === 'perm-display') { const { permission } = dialog.value.data @@ -553,20 +553,20 @@ async function submitDialog() { if (newId !== permission.id) { // ID changed, use rename endpoint const body = { old_id: permission.id, new_id: newId, display_name: newDisplay } - const res = await fetch('/auth/admin/permission/rename', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body) }) + const res = await fetch('/auth/api/admin/permission/rename', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body) }) let data; try { data = await res.json() } catch(_) { data = {} } if (!res.ok || data.detail) throw new Error(data.detail || data.error || `Failed (${res.status})`) } else if (newDisplay !== permission.display_name) { // Only display name changed const params = new URLSearchParams({ permission_id: permission.id, display_name: newDisplay }) - const res = await fetch(`/auth/admin/permission?${params.toString()}`, { method: 'PUT' }) + const res = await fetch(`/auth/api/admin/permission?${params.toString()}`, { method: 'PUT' }) const d = await res.json(); if (d.detail) throw new Error(d.detail) } await loadPermissions() } else if (t === 'perm-create') { const id = dialog.value.data.id?.trim(); if (!id) throw new Error('ID required') const display_name = dialog.value.data.display_name?.trim(); if (!display_name) throw new Error('Display name required') - const res = await fetch('/auth/admin/permissions', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ id, display_name }) }) + const res = await fetch('/auth/api/admin/permissions', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ id, display_name }) }) const data = await res.json(); if (data.detail) throw new Error(data.detail) await loadPermissions(); dialog.value.data.display_name = ''; dialog.value.data.id = '' } else if (t === 'confirm') { diff --git a/frontend/src/admin/AdminUserDetail.vue b/frontend/src/admin/AdminUserDetail.vue index 4594467..a1a86bf 100644 --- a/frontend/src/admin/AdminUserDetail.vue +++ b/frontend/src/admin/AdminUserDetail.vue @@ -27,7 +27,7 @@ function handleEditName() { } function handleDelete(credential) { - fetch(`/auth/admin/orgs/${props.selectedUser.org_uuid}/users/${props.selectedUser.uuid}/credentials/${credential.credential_uuid}`, { method: 'DELETE' }) + fetch(`/auth/api/admin/orgs/${props.selectedUser.org_uuid}/users/${props.selectedUser.uuid}/credentials/${credential.credential_uuid}`, { method: 'DELETE' }) .then(res => res.json()) .then(data => { if (data.status === 'ok') { @@ -52,7 +52,7 @@ function handleDelete(credential) { :loading="loading" :org-display-name="userDetail.org.display_name" :role-name="userDetail.role" - :update-endpoint="`/auth/admin/orgs/${selectedUser.org_uuid}/users/${selectedUser.uuid}/display-name`" + :update-endpoint="`/auth/api/admin/orgs/${selectedUser.org_uuid}/users/${selectedUser.uuid}/display-name`" @saved="$emit('onUserNameSaved')" @edit-name="handleEditName" /> @@ -94,7 +94,7 @@ function handleDelete(credential) { \ No newline at end of file + diff --git a/passkey/fastapi/mainapp.py b/passkey/fastapi/mainapp.py index daa8469..0f2f97e 100644 --- a/passkey/fastapi/mainapp.py +++ b/passkey/fastapi/mainapp.py @@ -51,7 +51,7 @@ app = FastAPI(lifespan=lifespan) # Apply redirections to auth-host if configured (deny access to restricted endpoints, remove /auth/) app.middleware("http")(auth_host.redirect_middleware) -app.mount("/auth/admin/", admin.app) +app.mount("/auth/api/admin/", admin.app) app.mount("/auth/api/", api.app) app.mount("/auth/ws/", ws.app) app.mount( @@ -59,11 +59,6 @@ app.mount( StaticFiles(directory=frontend.file("auth", "assets")), name="assets", ) -app.mount( - "/int/", - StaticFiles(directory=frontend.file("int"), html=True), - name="int", -) @app.get("/auth/restricted/")