diff --git a/messages/en.json b/messages/en.json index cc9ea3b..6b0e882 100644 --- a/messages/en.json +++ b/messages/en.json @@ -21,5 +21,11 @@ "sms_label_phone": "Phone Number", "sms_label_message": "Message", "sms_button_submit": "Send Message", + "settings_title": "Settings", + "settings_category_twilio": "Twilio Config", + "settings_twilio_account_sid": "Account SID", + "settings_twilio_auth_token": "Auth Token", + "settings_twilio_phone_number": "Phone Number", + "settings_save": "Save Settings", "error_page_go_home": "Go Home" -} +} \ No newline at end of file diff --git a/src/routes/app/settings/+page.server.ts b/src/routes/app/settings/+page.server.ts new file mode 100644 index 0000000..2c60456 --- /dev/null +++ b/src/routes/app/settings/+page.server.ts @@ -0,0 +1,77 @@ +import { PhoneRegex } from '$lib/regex'; +import { encrypt } from '$lib/server/crypto/encryption.js'; +import { logger } from '$lib/server/logger'; +import { prisma } from '$lib/server/prisma'; +import { fail, type Actions } from '@sveltejs/kit'; +import zod from 'zod'; + +export const load = async (event) => { + const tenantId = event.locals.auth!.orgId!; + + const configs = await prisma.tenantConfig.findUnique({ + where: { tenantId: tenantId }, + select: { accountSID: true, authToken: true, phoneNumber: true }, + }); + + return { + configs: configs, + }; +}; + +export const actions = { + update: async (event) => { + const form = await event.request.formData(); + const tenantId = event.locals.auth!.orgId!; + + if (!form.has('accountSID')) { + return fail(400, { error: 'account_sid_missing' }); + } + if (!form.has('authToken')) { + return fail(400, { error: 'auth_token_missing' }); + } + if (!form.has('phoneNumber')) { + return fail(400, { error: 'phone_number_missing' }); + } + + const accountSID = form.get('accountSID'); + if (typeof accountSID !== 'string') { + return fail(400, { error: 'invalid_account_sid' }); + } + const authToken = form.get('authToken'); + if (typeof authToken !== 'string') { + return fail(400, { error: 'invalid_auth_token' }); + } + const { + success: phoneSuccess, + data: phoneNumber, + error: phoneError, + } = zod.string().regex(PhoneRegex).safeParse(form.get('phone')); + if (!phoneSuccess) { + logger.error(phoneError); + return fail(400, { error: 'invalid_phone_number' }); + } + + const configs = await prisma.tenantConfig.upsert({ + where: { + tenantId: tenantId, + }, + create: { + tenantId: tenantId, + accountSID: encrypt(accountSID), + authToken: encrypt(authToken), + phoneNumber: encrypt(phoneNumber), + }, + update: { + tenantId: tenantId, + accountSID: accountSID, + authToken: authToken, + phoneNumber: phoneNumber, + }, + select: { accountSID: true, authToken: true, phoneNumber: true }, + }); + + return { + configs: configs, + }; + }, +} satisfies Actions; diff --git a/src/routes/app/settings/+page.svelte b/src/routes/app/settings/+page.svelte index b637efa..e8759d6 100644 --- a/src/routes/app/settings/+page.svelte +++ b/src/routes/app/settings/+page.svelte @@ -1,4 +1,90 @@ -
+