diff --git a/README.md b/README.md index 4cd5585..be75cca 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,6 @@ CRUD layer has been removed; see `docs/ADMIN_OVERHAUL.md` for the migration note | -------------------------------- | ------------------------ | | `/admin/users` | Name, Email, Role | | `/admin/profiles` | Reference implementation | -| `/admin/user-roles` | | | `/admin/proclamations` | Super-only content edits | | `/admin/solfeggio-frequencies` | | | `/admin/proclamation-categories` | Draggable reorder | diff --git a/src/routes/(protected)/admin/role-guards.spec.ts b/src/routes/(protected)/admin/role-guards.spec.ts index 52fbc82..9f2f849 100644 --- a/src/routes/(protected)/admin/role-guards.spec.ts +++ b/src/routes/(protected)/admin/role-guards.spec.ts @@ -3,21 +3,17 @@ import { createLocals, createFormRequest, mockUser } from '$lib/test-utils'; vi.mock('$lib/db', () => ({ prisma: { - userRole: { create: vi.fn(), update: vi.fn(), delete: vi.fn() }, solfeggioFrequency: { create: vi.fn(), update: vi.fn(), delete: vi.fn() }, proclamationCategory: { findFirst: vi.fn(), create: vi.fn(), update: vi.fn(), delete: vi.fn() }, proclamationGroup: { findFirst: vi.fn(), create: vi.fn(), update: vi.fn(), delete: vi.fn() } } })); -import { prisma } from '$lib/db'; -import { actions as userRoles } from './user-roles/+page.server'; import { actions as frequencies } from './solfeggio-frequencies/+page.server'; import { actions as categories } from './proclamation-categories/+page.server'; import { actions as groups } from './proclamation-groups/+page.server'; const staff = () => createLocals(mockUser({ roleId: 3 }) as any); -const admin = () => createLocals(mockUser({ roleId: 2 }) as any); const user = () => createLocals(mockUser({ roleId: 4 }) as any); const anonymous = () => createLocals(); @@ -27,7 +23,6 @@ type CrudActions = { }; const pages: Array<[string, CrudActions]> = [ - ['user-roles', userRoles as unknown as CrudActions], ['solfeggio-frequencies', frequencies as unknown as CrudActions], ['proclamation-categories', categories as unknown as CrudActions], ['proclamation-groups', groups as unknown as CrudActions] @@ -60,25 +55,3 @@ describe('admin CRUD action role guards', () => { }); } }); - -describe('admin CRUD action role guards: authorized users still work', () => { - it('staff can create a user role', async () => { - (prisma.userRole.create as ReturnType).mockResolvedValue({ id: 5 }); - const result = await userRoles.upsert({ - request: createFormRequest({ name: 'New Role' }), - locals: staff() - } as any); - expect(result).toEqual({ success: true, action: 'upsert' }); - expect(prisma.userRole.create).toHaveBeenCalledWith({ data: { name: 'New Role' } }); - }); - - it('admin can delete a user role', async () => { - (prisma.userRole.delete as ReturnType).mockResolvedValue({}); - const result = await userRoles.delete({ - request: createFormRequest({ id: '5' }), - locals: admin() - } as any); - expect(result).toEqual({ success: true, action: 'delete' }); - expect(prisma.userRole.delete).toHaveBeenCalledWith({ where: { id: 5 } }); - }); -}); diff --git a/src/routes/(protected)/admin/user-roles/+page.server.ts b/src/routes/(protected)/admin/user-roles/+page.server.ts deleted file mode 100644 index 2519d02..0000000 --- a/src/routes/(protected)/admin/user-roles/+page.server.ts +++ /dev/null @@ -1,71 +0,0 @@ -import type { PageServerLoad } from './$types'; -import { prisma } from '$lib/db'; -import { isAdmin, isStaff } from '$lib/server/roles'; -import { superValidate } from 'sveltekit-superforms/server'; -import { zod4 } from 'sveltekit-superforms/adapters'; -import { z } from 'zod'; -import { superFormErrorsToFieldErrors } from '$lib/superform-errors'; - -const UserRoleSchema = z.object({ - name: z.string().min(1, 'Required').max(100, 'Too long') -}); - -export const load: PageServerLoad = async () => { - const records = await prisma.userRole.findMany({ orderBy: { id: 'asc' } }); - return { records: records as unknown as Record[] }; -}; - -export const actions = { - upsert: async ({ request, locals }) => { - if (!isStaff(locals)) { - return { success: false, action: 'upsert', error: 'Not authorized' }; - } - - const formData = await request.formData(); - const form = await superValidate(formData, zod4(UserRoleSchema)); - if (!form.valid) { - const { error: formError, fieldErrors } = superFormErrorsToFieldErrors( - form.errors as Record - ); - return { success: false, action: 'upsert', error: formError, fieldErrors }; - } - - const rawId = formData.get('id')?.toString(); - const data = { name: form.data.name }; - - try { - if (rawId) { - await prisma.userRole.update({ where: { id: Number(rawId) }, data }); - } else { - await prisma.userRole.create({ data }); - } - } catch (e: unknown) { - if (e && typeof e === 'object' && 'code' in e && (e as { code: string }).code === 'P2002') { - return { success: false, action: 'upsert', error: 'A role with that name already exists.' }; - } - throw e; - } - - return { success: true, action: 'upsert' }; - }, - delete: async ({ request, locals }) => { - if (!isAdmin(locals)) { - return { success: false, error: 'Not authorized' }; - } - - const formData = await request.formData(); - const rawId = formData.get('id')?.toString(); - if (!rawId) return { success: false, error: 'Missing id' }; - - try { - await prisma.userRole.delete({ where: { id: Number(rawId) } }); - } catch (e: unknown) { - if (e && typeof e === 'object' && 'code' in e && (e as { code: string }).code === 'P2003') { - return { success: false, error: 'Cannot delete: this role is assigned to users.' }; - } - throw e; - } - - return { success: true, action: 'delete' }; - } -}; diff --git a/src/routes/(protected)/admin/user-roles/+page.svelte b/src/routes/(protected)/admin/user-roles/+page.svelte deleted file mode 100644 index ccdbd6a..0000000 --- a/src/routes/(protected)/admin/user-roles/+page.svelte +++ /dev/null @@ -1,160 +0,0 @@ - - -
- -
- -{#if modalOpen} - - {#if successMessage} -
- {successMessage} -
- {/if} - {#if formError} -
- {formError} -
- {/if} - -
- {#if editingRecord} - - {/if} - -
- - - {#if fieldErrors.name} -

{fieldErrors.name}

- {/if} -
- -
- - -
-
-
-{/if} diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 5043627..862663f 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -17,7 +17,6 @@ const adminModels = [ { slug: 'users', href: '/admin/users', displayName: 'Users' }, { slug: 'profiles', href: '/admin/profiles', displayName: 'Profiles' }, - { slug: 'user-roles', href: '/admin/user-roles', displayName: 'User Roles' }, { slug: 'proclamations', href: '/admin/proclamations',