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.
This commit is contained in:
2024-12-04 12:32:54 -05:00
parent cb4c0f9c87
commit 95b106d9e9
22 changed files with 1160 additions and 771 deletions

View File

@@ -0,0 +1,75 @@
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 };
}