From c1c6088c5d30feeb31277654963150ffcce87d2f Mon Sep 17 00:00:00 2001 From: Bernd Storath <999999bst@gmail.com> Date: Tue, 7 Jan 2025 16:11:51 +0100 Subject: [PATCH] handle form submit using js avoid weird behavior with FormData --- src/app/components/form/ActionField.vue | 4 --- src/app/components/form/Element.vue | 6 +--- src/app/pages/clients/[id].vue | 8 +++-- src/i18n/locales/en.json | 2 ++ src/package.json | 3 +- src/pnpm-lock.yaml | 12 ------- .../api/client/[clientId]/index.post.ts | 2 +- src/server/utils/apiHelper.ts | 31 ------------------- src/server/utils/types.ts | 29 +++++++---------- 9 files changed, 22 insertions(+), 75 deletions(-) delete mode 100644 src/server/utils/apiHelper.ts diff --git a/src/app/components/form/ActionField.vue b/src/app/components/form/ActionField.vue index af03e176..46cefd80 100644 --- a/src/app/components/form/ActionField.vue +++ b/src/app/components/form/ActionField.vue @@ -2,8 +2,6 @@ @@ -12,7 +10,5 @@ defineProps<{ label: string; type?: string; - formaction?: string; - formmethod?: string; }>(); diff --git a/src/app/components/form/Element.vue b/src/app/components/form/Element.vue index c0771931..20d8b517 100644 --- a/src/app/components/form/Element.vue +++ b/src/app/components/form/Element.vue @@ -1,9 +1,5 @@ - - diff --git a/src/app/pages/clients/[id].vue b/src/app/pages/clients/[id].vue index 9e1139a3..0caa25f2 100644 --- a/src/app/pages/clients/[id].vue +++ b/src/app/pages/clients/[id].vue @@ -5,7 +5,7 @@ - + {{ $t('me.sectionGeneral') }} @@ -74,13 +74,15 @@ authStore.update(); const route = useRoute(); const id = route.params.id as string; -const submitAction = computed(() => `/api/client/${id}`); - const { data: _data, refresh } = await useFetch(`/api/client/${id}`, { method: 'get', }); const data = toRef(_data.value); +function submit() { + console.log(data.value); +} + async function revert() { await refresh(); data.value = toRef(_data.value).value; diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json index 93e17436..370c1d07 100644 --- a/src/i18n/locales/en.json +++ b/src/i18n/locales/en.json @@ -52,6 +52,8 @@ "serverAllowedIPs": "Allowed IPs must be a valid array of strings", "name": "Name must be a valid string", "nameMin": "Name must be at least 1 Character", + "mtu": "MTU must be a valid number", + "persistentKeepalive": "Persistent Keepalive must be a valid number", "file": "File must be a valid string", "username": "Username must be a valid string", "usernameMin": "Username must be at least 8 Characters", diff --git a/src/package.json b/src/package.json index 07f73bc3..9abf671d 100644 --- a/src/package.json +++ b/src/package.json @@ -41,8 +41,7 @@ "timeago.js": "^4.0.2", "vue": "latest", "vue3-apexcharts": "^1.8.0", - "zod": "^3.24.1", - "zod-form-data": "^2.0.5" + "zod": "^3.24.1" }, "devDependencies": { "@nuxt/eslint-config": "^0.7.3", diff --git a/src/pnpm-lock.yaml b/src/pnpm-lock.yaml index b20435f5..1ec25ac0 100644 --- a/src/pnpm-lock.yaml +++ b/src/pnpm-lock.yaml @@ -83,9 +83,6 @@ importers: zod: specifier: ^3.24.1 version: 3.24.1 - zod-form-data: - specifier: ^2.0.5 - version: 2.0.5(zod@3.24.1) devDependencies: '@nuxt/eslint-config': specifier: ^0.7.3 @@ -4541,11 +4538,6 @@ packages: resolution: {integrity: sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==} engines: {node: '>= 14'} - zod-form-data@2.0.5: - resolution: {integrity: sha512-T7dV6lTBCwkd8PyvJVCnjXKpgXomU8gEm/TcvEZY7qNdRhIo9T17HrdlHIK68PzTAYaV2HxR9rgwpTSWv0L+QQ==} - peerDependencies: - zod: '>= 3.11.0' - zod@3.24.1: resolution: {integrity: sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==} @@ -9426,8 +9418,4 @@ snapshots: compress-commons: 6.0.2 readable-stream: 4.5.2 - zod-form-data@2.0.5(zod@3.24.1): - dependencies: - zod: 3.24.1 - zod@3.24.1: {} diff --git a/src/server/api/client/[clientId]/index.post.ts b/src/server/api/client/[clientId]/index.post.ts index da5584a1..5568957f 100644 --- a/src/server/api/client/[clientId]/index.post.ts +++ b/src/server/api/client/[clientId]/index.post.ts @@ -3,7 +3,7 @@ export default defineEventHandler(async (event) => { event, validateZod(clientIdType) ); - const data = await readValidatedFormData( + const data = await readValidatedBody( event, validateZod(clientUpdateType, event) ); diff --git a/src/server/utils/apiHelper.ts b/src/server/utils/apiHelper.ts deleted file mode 100644 index f0a816b2..00000000 --- a/src/server/utils/apiHelper.ts +++ /dev/null @@ -1,31 +0,0 @@ -import type { H3Event, InferEventInput } from 'h3'; - -export async function readValidatedFormData< - Event extends H3Event = H3Event, - T = InferEventInput<'body', Event, null>, ->(event: Event, validate: (data: FormData) => T) { - const _form = await readFormData(event); - return validateData(_form, validate); -} - -async function validateData(data: T, fn: (data: T) => K) { - try { - const res = await fn(data); - if (res === false) { - throw createValidationError(); - } - return res; - } catch (error) { - throw createValidationError(error); - } -} - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -function createValidationError(validateError?: any) { - throw createError({ - status: 400, - statusMessage: 'Validation Error', - message: validateError?.message || 'Validation Error', - data: validateError, - }); -} diff --git a/src/server/utils/types.ts b/src/server/utils/types.ts index 5b145ff4..c7ddec52 100644 --- a/src/server/utils/types.ts +++ b/src/server/utils/types.ts @@ -2,7 +2,6 @@ import type { ZodSchema, ZodTypeDef } from 'zod'; import { z, ZodError } from 'zod'; import type { H3Event, EventHandlerRequest } from 'h3'; import { LOCALES } from '#shared/locales'; -import { zfd } from 'zod-form-data'; // TODO: make objects strict @@ -155,22 +154,18 @@ const address6 = z .pipe(safeStringRefine); /** expects formdata, strict */ -export const clientUpdateType = zfd.formData({ - name: zfd.text(name), - enabled: zfd.checkbox(), - expiresAt: zfd.text(expireDate.optional()), - address4: zfd.text(address4), - address6: zfd.text(address6), - allowedIPs: zfd.repeatable( - z - .array(zfd.text(address), { message: 'zod.allowedIPs' }) - .min(1, { message: 'zod.allowedIPsMin' }) - ), - serverAllowedIPs: zfd.repeatable( - z.array(zfd.text(address), { message: 'zod.serverAllowedIPs' }) - ), - mtu: zfd.numeric(), - persistentKeepalive: zfd.numeric(), +export const clientUpdateType = z.strictObject({ + name: name, + enabled: z.boolean(), + expiresAt: expireDate, + address4: address4, + address6: address6, + allowedIPs: z + .array(address, { message: 'zod.allowedIPs' }) + .min(1, { message: 'zod.allowedIPsMin' }), + serverAllowedIPs: z.array(address, { message: 'zod.serverAllowedIPs' }), + mtu: z.number({ message: 'zod.mtu' }), + persistentKeepalive: z.number({ message: 'zod.persistentKeepalive' }), }); // from https://github.com/airjp73/rvf/blob/7e7c35d98015ea5ecff5affaf89f78296e84e8b9/packages/zod-form-data/src/helpers.ts#L117