From 19f253f53e55d397beb69b6d0814f60503280ce2 Mon Sep 17 00:00:00 2001 From: Remi <73385395+itsrubberduck@users.noreply.github.com> Date: Tue, 16 Sep 2025 17:28:34 +0200 Subject: [PATCH] Implement authentication, waitlist, and logging upgrades --- app/composables/useApi.ts | 68 +++++++++ app/pages/pm.vue | 128 +++++++++++------ app/stores/auth.ts | 128 +++++++++++++++++ nuxt.config.ts | 10 +- server/api/atc/ptt.post.ts | 21 +++ server/api/atc/say.post.ts | 25 ++++ server/api/auth/logout.post.ts | 10 ++ server/api/auth/me.get.ts | 15 ++ server/middleware/auth.global.ts | 17 +++ server/models/TransmissionLog.ts | 30 ++++ server/utils/auth.ts | 206 +++++++++++++++++++++++++++ shared/utils/communicationsEngine.ts | 8 +- 12 files changed, 620 insertions(+), 46 deletions(-) create mode 100644 app/composables/useApi.ts create mode 100644 app/stores/auth.ts create mode 100644 server/api/auth/logout.post.ts create mode 100644 server/api/auth/me.get.ts create mode 100644 server/middleware/auth.global.ts create mode 100644 server/models/TransmissionLog.ts create mode 100644 server/utils/auth.ts diff --git a/app/composables/useApi.ts b/app/composables/useApi.ts new file mode 100644 index 0000000..8b78d0b --- /dev/null +++ b/app/composables/useApi.ts @@ -0,0 +1,68 @@ +import { useAuthStore } from '~/stores/auth' + +type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' + +interface ApiRequestOptions { + method?: HttpMethod + body?: T + query?: Record + headers?: HeadersInit + auth?: boolean +} + +export function useApi() { + const auth = useAuthStore() + + const execute = async (path: string, options: ApiRequestOptions = {}) => { + const { method = 'GET', body, query, headers = {}, auth: requiresAuth = true } = options + + const computedHeaders: Record = { + Accept: 'application/json', + ...(headers as Record), + } + + if (requiresAuth && auth.accessToken) { + computedHeaders.Authorization = `Bearer ${auth.accessToken}` + } + + const requestOptions: any = { + method, + headers: computedHeaders, + query, + body, + } + + if (body && !(body instanceof FormData)) { + computedHeaders['Content-Type'] = 'application/json' + requestOptions.body = body + } + + try { + return await $fetch(path, requestOptions) + } catch (error: any) { + const status = error?.status || error?.response?.status + if (status === 401 && requiresAuth) { + const refreshed = await auth.tryRefresh() + if (refreshed) { + if (auth.accessToken) { + computedHeaders.Authorization = `Bearer ${auth.accessToken}` + } + return await $fetch(path, requestOptions) + } + await auth.logout() + } + throw error + } + } + + return { + request: execute, + get: (path: string, options: ApiRequestOptions = {}) => execute(path, { ...options, method: 'GET' }), + post: (path: string, body?: any, options: ApiRequestOptions = {}) => + execute(path, { ...options, method: 'POST', body }), + put: (path: string, body?: any, options: ApiRequestOptions = {}) => + execute(path, { ...options, method: 'PUT', body }), + del: (path: string, options: ApiRequestOptions = {}) => execute(path, { ...options, method: 'DELETE' }), + } +} + diff --git a/app/pages/pm.vue b/app/pages/pm.vue index ab985e8..f862d49 100644 --- a/app/pages/pm.vue +++ b/app/pages/pm.vue @@ -460,8 +460,20 @@
-

Communication Log

- {{ log.length }} +
+

Communication Log

+ {{ log.length }} +
+ + Leeren +
@@ -563,15 +575,22 @@