diff --git a/src/ambient.d.ts b/src/ambient.d.ts index 442cf55..05afb5e 100644 --- a/src/ambient.d.ts +++ b/src/ambient.d.ts @@ -63,6 +63,7 @@ type Config = { security: { passwordStrength: number; }; + defaultGroup?: string | null; }; type Option = { diff --git a/src/lib/components/admin/SettingsForm/DefaultGroup.svelte b/src/lib/components/admin/SettingsForm/DefaultGroup.svelte new file mode 100644 index 0000000..fe8f729 --- /dev/null +++ b/src/lib/components/admin/SettingsForm/DefaultGroup.svelte @@ -0,0 +1,24 @@ + + + + + diff --git a/src/lib/components/admin/SettingsForm/index.svelte b/src/lib/components/admin/SettingsForm/index.svelte index 9e9d847..6aaf1f5 100644 --- a/src/lib/components/admin/SettingsForm/index.svelte +++ b/src/lib/components/admin/SettingsForm/index.svelte @@ -3,19 +3,33 @@ import { ProgressRadial } from "@skeletonlabs/skeleton"; import PublicSignup from "./PublicSignup.svelte"; import Suggestions from "./Suggestions.svelte"; - import Smtp from "./SMTP.svelte"; import Claims from "./Claims.svelte"; import Security from "./Security.svelte"; + import DefaultGroup from "./DefaultGroup.svelte"; + import Smtp from "./SMTP.svelte"; + + type Group = { + id: string; + name: string; + }; interface Props { config: Config; + groups: Group[]; hideActions?: boolean; saved?: boolean; sending?: boolean; sent?: boolean; } - let { config = $bindable(), hideActions = false, saved = false, sending = false, sent = false }: Props = $props(); + let { + config = $bindable(), + groups = [], + hideActions = false, + saved = false, + sending = false, + sent = false + }: Props = $props(); let form = $derived($page.form); @@ -34,6 +48,9 @@
+
+ +
=> { @@ -79,7 +80,8 @@ export const getConfig = async (groupId?: string, includeSensitive = false): Pro listMode: (configMap[ConfigKey.LIST_MODE] as ListMode) || "standard", security: { passwordStrength: Number(configMap[ConfigKey.SECURITY_PASSWORD_STRENGTH] || 2) - } + }, + defaultGroup: configMap[ConfigKey.DEFAULT_GROUP]! }; return config; @@ -141,6 +143,7 @@ export const writeConfig = async (config: Partial, groupId = GLOBAL) => configMap[ConfigKey.CLAIMS_SHOW_NAME] = config?.claims?.showName.toString(); configMap[ConfigKey.LIST_MODE] = config?.listMode; configMap[ConfigKey.SECURITY_PASSWORD_STRENGTH] = config?.security?.passwordStrength.toString(); + configMap[ConfigKey.DEFAULT_GROUP] = config?.defaultGroup; for (const [key, value] of Object.entries(configMap)) { await client.systemConfig.upsert({ diff --git a/src/lib/validations.ts b/src/lib/validations.ts index f51d423..4b37218 100644 --- a/src/lib/validations.ts +++ b/src/lib/validations.ts @@ -52,7 +52,8 @@ export const settingSchema = z.object({ smtpFromName: z.string().optional(), claimsShowName: z.coerce.boolean().default(false), listMode: z.enum(["standard", "registry"]).default("standard"), - passwordStrength: z.coerce.number().min(-1).max(5).default(2) + passwordStrength: z.coerce.number().min(-1).max(5).default(2), + defaultGroup: z.string().optional() }); export const publicListCreateSchema = z.object({ diff --git a/src/routes/admin/groups/[groupId]/members/+page.svelte b/src/routes/admin/groups/[groupId]/members/+page.svelte index 27d8cbf..47afce0 100644 --- a/src/routes/admin/groups/[groupId]/members/+page.svelte +++ b/src/routes/admin/groups/[groupId]/members/+page.svelte @@ -65,6 +65,14 @@ }; const deleteGroup = () => { + if (data.config.defaultGroup === $page.params.groupId) { + modalStore.trigger({ + type: "alert", + title: "Cannot Delete Default Group", + body: "You cannot delete the default group. Please change the default group before deleting this group." + }); + return; + } modalStore.trigger({ type: "confirm", title: "Delete Group", diff --git a/src/routes/admin/settings/+page.server.ts b/src/routes/admin/settings/+page.server.ts index 0d29397..8152c59 100644 --- a/src/routes/admin/settings/+page.server.ts +++ b/src/routes/admin/settings/+page.server.ts @@ -1,4 +1,5 @@ import { Role } from "$lib/schema"; +import { client } from "$lib/server/prisma"; import { getConfig, writeConfig } from "$lib/server/config"; import { redirect, error, fail, type Actions } from "@sveltejs/kit"; import type { PageServerLoad } from "./$types"; @@ -16,8 +17,16 @@ export const load: PageServerLoad = async ({ locals }) => { const config = await getConfig(undefined, true); + const groups = await client.group.findMany({ + select: { + id: true, + name: true + } + }); + return { - config + config, + groups }; }; @@ -82,7 +91,8 @@ const generateConfig = (configData: z.infer) => { listMode: "standard", security: { passwordStrength: configData.passwordStrength - } + }, + defaultGroup: configData.defaultGroup }; return newConfig; diff --git a/src/routes/admin/settings/+page.svelte b/src/routes/admin/settings/+page.svelte index cfbf8f5..032d92d 100644 --- a/src/routes/admin/settings/+page.svelte +++ b/src/routes/admin/settings/+page.svelte @@ -11,6 +11,7 @@ let { data }: Props = $props(); let config = $state(data.config); + let groups = $state(data.groups); let sending = $state(false); let saved = $state(false); let sent = $state(false); @@ -36,5 +37,5 @@ }; }} > - + diff --git a/src/routes/setup-wizard/step/[step]/GlobalSettingsStep.svelte b/src/routes/setup-wizard/step/[step]/GlobalSettingsStep.svelte index 30eddf4..173dc22 100644 --- a/src/routes/setup-wizard/step/[step]/GlobalSettingsStep.svelte +++ b/src/routes/setup-wizard/step/[step]/GlobalSettingsStep.svelte @@ -5,10 +5,12 @@ import { getContext } from "svelte"; import type { Writable } from "svelte/store"; import type { Props } from "./steps"; + import type { Group } from "@prisma/client"; let { onSuccess }: Props = $props(); let config: Config = $state($page.data.config); + let groups: Group[] = $state($page.data.groups); let form: HTMLFormElement | undefined = $state(); let sending = $state(false); let saved = $state(false); @@ -51,7 +53,7 @@ }; }} > - +
diff --git a/src/routes/signup/+page.server.ts b/src/routes/signup/+page.server.ts index 8f6aa1f..8efda30 100644 --- a/src/routes/signup/+page.server.ts +++ b/src/routes/signup/+page.server.ts @@ -43,6 +43,7 @@ export const load: PageServerLoad = async ({ locals, request }) => { export const actions: Actions = { default: async ({ request, cookies }) => { + const config = await getConfig(); const formData = Object.fromEntries(await request.formData()); const signupSchema = await getSignupSchema(); const signupData = signupSchema.safeParse(formData); @@ -79,6 +80,8 @@ export const actions: Actions = { } }) )?.id; + } else if (config.defaultGroup) { + groupId = config.defaultGroup; } try {