Files
hristudio/src/lib/permissions-server.ts
Sean O'Connor 95b106d9e9 chore(deps): Update dependencies and enhance API error handling
- Added '@vercel/analytics' to package.json for improved analytics tracking.
- Updated 'next' version from 15.0.2 to 15.0.3 to incorporate the latest features and fixes.
- Refactored API routes for invitations and studies to improve error handling and response structure.
- Enhanced permission checks in the invitations and studies API to ensure proper access control.
- Removed the participants dashboard page as part of a restructuring effort.
- Updated the database schema to include environment settings for users and studies.
- Improved the dashboard components to handle loading states and display statistics more effectively.
2024-12-04 12:32:54 -05:00

75 lines
2.0 KiB
TypeScript

import { eq, and, or } from "drizzle-orm";
import { db } from "~/db";
import { userRolesTable, rolePermissionsTable, permissionsTable } from "~/db/schema";
import { ApiError } from "./api-utils";
import { auth } from "@clerk/nextjs/server";
import { PERMISSIONS } from "./permissions-client";
export { PERMISSIONS };
export async function hasStudyAccess(userId: string, studyId: number): Promise<boolean> {
const userRoles = await db
.select()
.from(userRolesTable)
.where(
and(
eq(userRolesTable.userId, userId),
eq(userRolesTable.studyId, studyId)
)
);
return userRoles.length > 0;
}
export async function hasPermission(
userId: string,
permissionCode: string,
studyId: number
): Promise<boolean> {
const permissions = await db
.selectDistinct({
permissionCode: permissionsTable.code,
})
.from(userRolesTable)
.innerJoin(rolePermissionsTable, eq(rolePermissionsTable.roleId, userRolesTable.roleId))
.innerJoin(permissionsTable, eq(permissionsTable.id, rolePermissionsTable.permissionId))
.where(
and(
eq(userRolesTable.userId, userId),
eq(userRolesTable.studyId, studyId)
)
);
return permissions.some(p => p.permissionCode === permissionCode);
}
export type PermissionCheck = {
studyId: number;
permission?: string;
requireStudyAccess?: boolean;
};
export async function checkPermissions(check: PermissionCheck) {
const { userId } = await auth();
if (!userId) {
return { error: ApiError.Unauthorized() };
}
const { studyId, permission, requireStudyAccess = true } = check;
if (requireStudyAccess) {
const hasAccess = await hasStudyAccess(userId, studyId);
if (!hasAccess) {
return { error: ApiError.NotFound("Study") };
}
}
if (permission) {
const hasRequiredPermission = await hasPermission(userId, permission, studyId);
if (!hasRequiredPermission) {
return { error: ApiError.Forbidden() };
}
}
return { userId };
}