mirror of
https://github.com/soconnor0919/hristudio.git
synced 2025-12-11 22:54:45 -05:00
- 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.
75 lines
2.0 KiB
TypeScript
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 };
|
|
}
|