diff --git a/frontend/components/admin/AdminClientTicketTab.vue b/frontend/components/admin/AdminClientTicketTab.vue index 64401a5..a9b3b63 100644 --- a/frontend/components/admin/AdminClientTicketTab.vue +++ b/frontend/components/admin/AdminClientTicketTab.vue @@ -274,25 +274,22 @@ const availableStatusTransitions = computed(() => { }) function getProjectName(iri: string): string { - const match = iri.match(/\/api\/projects\/(\d+)/) - if (!match) return '' - const id = Number(match[1]) + const id = extractIdFromIri(iri) + if (!id) return '' return projects.value.find(p => p.id === id)?.name ?? '' } function getSubmitterName(iri: string | null): string { if (!iri) return '-' - const match = iri.match(/\/api\/users\/(\d+)/) - if (!match) return '' - const id = Number(match[1]) + const id = extractIdFromIri(iri) + if (!id) return '' return users.value.find(u => u.id === id)?.username ?? '' } function getSubmitterUser(iri: string | null): UserData | undefined { if (!iri) return undefined - const match = iri.match(/\/api\/users\/(\d+)/) - if (!match) return undefined - const id = Number(match[1]) + const id = extractIdFromIri(iri) + if (!id) return undefined return users.value.find(u => u.id === id) } diff --git a/frontend/composables/useApi.ts b/frontend/composables/useApi.ts index 760df5b..bac2544 100644 --- a/frontend/composables/useApi.ts +++ b/frontend/composables/useApi.ts @@ -177,13 +177,16 @@ export function useApi(): ApiClient { ) { const needsJsonBody = method === 'POST' || method === 'PUT' const needsMergePatch = method === 'PATCH' + const isFormData = typeof FormData !== 'undefined' && options.body instanceof FormData const headers = new Headers(options.headers as HeadersInit | undefined) - if (needsMergePatch && !headers.has('Content-Type')) { - headers.set('Content-Type', 'application/merge-patch+json') - } else if (needsJsonBody && !headers.has('Content-Type')) { - headers.set('Content-Type', 'application/json') + if (!isFormData) { + if (needsMergePatch && !headers.has('Content-Type')) { + headers.set('Content-Type', 'application/merge-patch+json') + } else if (needsJsonBody && !headers.has('Content-Type')) { + headers.set('Content-Type', 'application/json') + } } return client(url, { ...options, method, headers }) diff --git a/frontend/composables/useAvatarService.ts b/frontend/composables/useAvatarService.ts index 010aad2..1b3072d 100644 --- a/frontend/composables/useAvatarService.ts +++ b/frontend/composables/useAvatarService.ts @@ -5,11 +5,13 @@ export function useAvatarService() { const formData = new FormData() formData.append('file', file, 'avatar.png') - return $fetch(`/api/users/${userId}/avatar`, { - method: 'POST', - body: formData, - credentials: 'include', - }) + return api.post<{ avatarUrl: string }>( + `/users/${userId}/avatar`, + formData as unknown as Record, + { + toastSuccessKey: 'profile.avatarUpdated', + } + ) } async function remove(userId: number): Promise { diff --git a/frontend/middleware/admin.ts b/frontend/middleware/admin.ts new file mode 100644 index 0000000..b464389 --- /dev/null +++ b/frontend/middleware/admin.ts @@ -0,0 +1,7 @@ +export default defineNuxtRouteMiddleware(() => { + const auth = useAuthStore() + + if (!auth.isAuthenticated || !auth.user?.roles?.includes('ROLE_ADMIN')) { + return navigateTo('/') + } +}) diff --git a/frontend/nuxt.config.ts b/frontend/nuxt.config.ts index ebec92b..fb3003e 100644 --- a/frontend/nuxt.config.ts +++ b/frontend/nuxt.config.ts @@ -23,14 +23,6 @@ export default defineNuxtConfig({ devServer: { port: 3002, }, - nitro: { - devProxy: { - '/api': { - target: 'http://nginx', - changeOrigin: true, - }, - }, - }, components: [ {path: '~/components', pathPrefix: false}, ], diff --git a/frontend/pages/admin.vue b/frontend/pages/admin.vue index fdc9854..0f8f91e 100644 --- a/frontend/pages/admin.vue +++ b/frontend/pages/admin.vue @@ -35,6 +35,7 @@