Fix Super admins being blocked from editing proclamations
This commit is contained in:
@@ -13,8 +13,16 @@ const ProclamationSchema = z.object({
|
|||||||
content: z.string().optional().default('')
|
content: z.string().optional().default('')
|
||||||
});
|
});
|
||||||
|
|
||||||
function isSuper(locals: App.Locals): boolean {
|
async function isSuper(locals: App.Locals): Promise<boolean> {
|
||||||
return ((locals.user as { roleId?: number } | null)?.roleId ?? 4) <= 1;
|
if (!locals.user?.id) return false;
|
||||||
|
|
||||||
|
// The Better Auth session user does not include `roleId`, so read the
|
||||||
|
// current role from the database.
|
||||||
|
const user = await prisma.user.findUnique({
|
||||||
|
where: { id: locals.user.id },
|
||||||
|
select: { roleId: true }
|
||||||
|
});
|
||||||
|
return (user?.roleId ?? 4) <= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const load: PageServerLoad = async ({ locals }) => {
|
export const load: PageServerLoad = async ({ locals }) => {
|
||||||
@@ -40,7 +48,7 @@ export const load: PageServerLoad = async ({ locals }) => {
|
|||||||
const records = proclamations as unknown as Record<string, unknown>[];
|
const records = proclamations as unknown as Record<string, unknown>[];
|
||||||
|
|
||||||
// Strip content from non-Super users
|
// Strip content from non-Super users
|
||||||
if (!isSuper(locals)) {
|
if (!(await isSuper(locals))) {
|
||||||
for (const record of records) {
|
for (const record of records) {
|
||||||
delete record.content;
|
delete record.content;
|
||||||
}
|
}
|
||||||
@@ -55,7 +63,7 @@ export const actions = {
|
|||||||
return { success: false, action: 'upsert', error: 'Unauthorized' };
|
return { success: false, action: 'upsert', error: 'Unauthorized' };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isSuper(locals)) {
|
if (!(await isSuper(locals))) {
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
action: 'upsert',
|
action: 'upsert',
|
||||||
@@ -98,7 +106,7 @@ export const actions = {
|
|||||||
return { success: true, action: 'upsert' };
|
return { success: true, action: 'upsert' };
|
||||||
},
|
},
|
||||||
delete: async ({ request, locals }) => {
|
delete: async ({ request, locals }) => {
|
||||||
if (!isSuper(locals)) {
|
if (!(await isSuper(locals))) {
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
action: 'delete',
|
action: 'delete',
|
||||||
|
|||||||
@@ -18,6 +18,9 @@ vi.mock('$lib/db', () => ({
|
|||||||
},
|
},
|
||||||
proclamationGroup: {
|
proclamationGroup: {
|
||||||
findMany: vi.fn()
|
findMany: vi.fn()
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
findUnique: vi.fn()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
@@ -33,6 +36,7 @@ const mockProclamationDelete = prisma.proclamation.delete as ReturnType<typeof v
|
|||||||
const mockFreqFindMany = prisma.solfeggioFrequency.findMany as ReturnType<typeof vi.fn>;
|
const mockFreqFindMany = prisma.solfeggioFrequency.findMany as ReturnType<typeof vi.fn>;
|
||||||
const mockCatFindMany = prisma.proclamationCategory.findMany as ReturnType<typeof vi.fn>;
|
const mockCatFindMany = prisma.proclamationCategory.findMany as ReturnType<typeof vi.fn>;
|
||||||
const mockGroupFindMany = prisma.proclamationGroup.findMany as ReturnType<typeof vi.fn>;
|
const mockGroupFindMany = prisma.proclamationGroup.findMany as ReturnType<typeof vi.fn>;
|
||||||
|
const mockUserFindUnique = prisma.user.findUnique as ReturnType<typeof vi.fn>;
|
||||||
|
|
||||||
const frequencies = [{ id: 1, name: 'UT', value: 396 }];
|
const frequencies = [{ id: 1, name: 'UT', value: 396 }];
|
||||||
const categories = [{ id: 1, name: 'Healing' }];
|
const categories = [{ id: 1, name: 'Healing' }];
|
||||||
@@ -52,6 +56,8 @@ function validRequest(overrides: Record<string, string> = {}) {
|
|||||||
describe('proclamations admin page server', () => {
|
describe('proclamations admin page server', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
vi.clearAllMocks();
|
vi.clearAllMocks();
|
||||||
|
// Default the caller to SUPER (1); override per test as needed.
|
||||||
|
mockUserFindUnique.mockResolvedValue({ roleId: 1 });
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('load', () => {
|
describe('load', () => {
|
||||||
@@ -68,6 +74,7 @@ describe('proclamations admin page server', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('strips content for non-Super users', async () => {
|
it('strips content for non-Super users', async () => {
|
||||||
|
mockUserFindUnique.mockResolvedValue({ roleId: 4 });
|
||||||
const locals = createLocals(mockUser({ roleId: 4 }) as any);
|
const locals = createLocals(mockUser({ roleId: 4 }) as any);
|
||||||
const result = await load({ locals } as any);
|
const result = await load({ locals } as any);
|
||||||
|
|
||||||
@@ -109,6 +116,7 @@ describe('proclamations admin page server', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('rejects non-Super users', async () => {
|
it('rejects non-Super users', async () => {
|
||||||
|
mockUserFindUnique.mockResolvedValue({ roleId: 4 });
|
||||||
const locals = createLocals(mockUser({ roleId: 4 }) as any);
|
const locals = createLocals(mockUser({ roleId: 4 }) as any);
|
||||||
const req = createFormRequest({ name: 'test' });
|
const req = createFormRequest({ name: 'test' });
|
||||||
|
|
||||||
@@ -149,6 +157,21 @@ describe('proclamations admin page server', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('allows a Super user whose session user has no roleId', async () => {
|
||||||
|
mockProclamationCreate.mockResolvedValue({ id: 'p1' });
|
||||||
|
|
||||||
|
// The real Better Auth session user does not carry `roleId`; the
|
||||||
|
// action must look the role up in the database instead.
|
||||||
|
const locals = createLocals(mockUser({ roleId: null }) as any);
|
||||||
|
const result = await actions.upsert({ request: validRequest(), locals } as any);
|
||||||
|
|
||||||
|
expect(result).toEqual({ success: true, action: 'upsert' });
|
||||||
|
expect(mockUserFindUnique).toHaveBeenCalledWith({
|
||||||
|
where: { id: 'user-1' },
|
||||||
|
select: { roleId: true }
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('updates an existing proclamation for a Super user', async () => {
|
it('updates an existing proclamation for a Super user', async () => {
|
||||||
mockProclamationFindUnique.mockResolvedValue(mockProclamation());
|
mockProclamationFindUnique.mockResolvedValue(mockProclamation());
|
||||||
mockProclamationUpdate.mockResolvedValue({});
|
mockProclamationUpdate.mockResolvedValue({});
|
||||||
@@ -200,6 +223,7 @@ describe('proclamations admin page server', () => {
|
|||||||
|
|
||||||
describe('delete action', () => {
|
describe('delete action', () => {
|
||||||
it('rejects non-Super users', async () => {
|
it('rejects non-Super users', async () => {
|
||||||
|
mockUserFindUnique.mockResolvedValue({ roleId: 4 });
|
||||||
const locals = createLocals(mockUser({ roleId: 4 }) as any);
|
const locals = createLocals(mockUser({ roleId: 4 }) as any);
|
||||||
const req = createFormRequest({ id: '1' });
|
const req = createFormRequest({ id: '1' });
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user