mirror of
https://github.com/soconnor0919/hristudio.git
synced 2025-12-12 07:04:44 -05:00
feat(api): Enhance study creation and user management with improved error handling and logging
- Updated the study creation endpoint to return JSON responses for errors and success. - Added user existence verification before creating a study. - Enhanced error logging for better debugging. - Refactored user creation in webhooks to use transactions for atomicity. - Improved response structure for webhook processing. - Updated the seed script to streamline role and permission insertion. - Added new permissions for editing studies and participants.
This commit is contained in:
222
src/db/seed.ts
222
src/db/seed.ts
@@ -1,135 +1,105 @@
|
||||
import { db } from "~/db";
|
||||
import {
|
||||
permissionsTable,
|
||||
rolesTable,
|
||||
rolePermissionsTable,
|
||||
} from "~/db/schema";
|
||||
import { config } from "dotenv";
|
||||
import { db } from "./index";
|
||||
import { PERMISSIONS } from "~/lib/permissions";
|
||||
import { ROLES, ROLE_PERMISSIONS } from "~/lib/roles";
|
||||
import { permissionsTable, rolesTable, rolePermissionsTable } from "./schema";
|
||||
|
||||
// Load environment variables from .env.local
|
||||
config({ path: ".env.local" });
|
||||
|
||||
async function seed() {
|
||||
try {
|
||||
console.log("Starting seed...");
|
||||
console.log("🌱 Seeding database...");
|
||||
|
||||
// Create permissions
|
||||
const createdPermissions = await db
|
||||
.insert(permissionsTable)
|
||||
.values([
|
||||
{
|
||||
name: "View Participant Names",
|
||||
code: "view_participant_names",
|
||||
description: "Can view participant names",
|
||||
},
|
||||
{
|
||||
name: "Create Participant",
|
||||
code: "create_participant",
|
||||
description: "Can create new participants",
|
||||
},
|
||||
{
|
||||
name: "Delete Participant",
|
||||
code: "delete_participant",
|
||||
description: "Can delete participants",
|
||||
},
|
||||
{
|
||||
name: "Create Study",
|
||||
code: "create_study",
|
||||
description: "Can create new studies",
|
||||
},
|
||||
{
|
||||
name: "Delete Study",
|
||||
code: "delete_study",
|
||||
description: "Can delete studies",
|
||||
},
|
||||
{
|
||||
name: "Manage Roles",
|
||||
code: "manage_roles",
|
||||
description: "Can manage user roles",
|
||||
},
|
||||
])
|
||||
.returning();
|
||||
|
||||
console.log("Created permissions:", createdPermissions);
|
||||
|
||||
// Create roles
|
||||
const createdRoles = await db
|
||||
.insert(rolesTable)
|
||||
.values([
|
||||
{
|
||||
name: "Admin",
|
||||
description: "Full system access",
|
||||
},
|
||||
{
|
||||
name: "Researcher",
|
||||
description: "Can manage studies and participants",
|
||||
},
|
||||
{
|
||||
name: "Observer",
|
||||
description: "Can view participant names only",
|
||||
},
|
||||
])
|
||||
.returning();
|
||||
|
||||
console.log("Created roles:", createdRoles);
|
||||
|
||||
// Find roles by name
|
||||
const adminRole = createdRoles.find((r) => r.name === "Admin");
|
||||
const researcherRole = createdRoles.find((r) => r.name === "Researcher");
|
||||
const observerRole = createdRoles.find((r) => r.name === "Observer");
|
||||
|
||||
// Assign permissions to roles
|
||||
if (adminRole) {
|
||||
// Admin gets all permissions
|
||||
await db.insert(rolePermissionsTable).values(
|
||||
createdPermissions.map((p) => ({
|
||||
roleId: adminRole.id,
|
||||
permissionId: p.id,
|
||||
}))
|
||||
);
|
||||
console.log("Assigned all permissions to Admin role");
|
||||
}
|
||||
|
||||
if (researcherRole) {
|
||||
// Researcher gets specific permissions
|
||||
const researcherPermissions = createdPermissions.filter((p) =>
|
||||
[
|
||||
"view_participant_names",
|
||||
"create_participant",
|
||||
"create_study",
|
||||
].includes(p.code)
|
||||
);
|
||||
|
||||
await db.insert(rolePermissionsTable).values(
|
||||
researcherPermissions.map((p) => ({
|
||||
roleId: researcherRole.id,
|
||||
permissionId: p.id,
|
||||
}))
|
||||
);
|
||||
console.log("Assigned permissions to Researcher role");
|
||||
}
|
||||
|
||||
if (observerRole) {
|
||||
// Observer gets view-only permissions
|
||||
const observerPermissions = createdPermissions.filter((p) =>
|
||||
["view_participant_names"].includes(p.code)
|
||||
);
|
||||
|
||||
await db.insert(rolePermissionsTable).values(
|
||||
observerPermissions.map((p) => ({
|
||||
roleId: observerRole.id,
|
||||
permissionId: p.id,
|
||||
}))
|
||||
);
|
||||
console.log("Assigned permissions to Observer role");
|
||||
}
|
||||
|
||||
console.log("Seeding completed successfully");
|
||||
} catch (error) {
|
||||
console.error("Error seeding database:", error);
|
||||
throw error;
|
||||
// Insert roles
|
||||
console.log("Inserting roles...");
|
||||
for (const [roleKey, roleName] of Object.entries(ROLES)) {
|
||||
await db.insert(rolesTable)
|
||||
.values({
|
||||
name: roleName,
|
||||
description: getRoleDescription(roleKey),
|
||||
})
|
||||
.onConflictDoNothing();
|
||||
}
|
||||
|
||||
// Insert permissions
|
||||
console.log("Inserting permissions...");
|
||||
for (const [permKey, permCode] of Object.entries(PERMISSIONS)) {
|
||||
await db.insert(permissionsTable)
|
||||
.values({
|
||||
name: formatPermissionName(permKey),
|
||||
code: permCode,
|
||||
description: getPermissionDescription(permKey),
|
||||
})
|
||||
.onConflictDoNothing();
|
||||
}
|
||||
|
||||
// Get role and permission IDs
|
||||
const roles = await db.select().from(rolesTable);
|
||||
const permissions = await db.select().from(permissionsTable);
|
||||
|
||||
// Insert role permissions
|
||||
console.log("Inserting role permissions...");
|
||||
for (const [roleKey, permissionCodes] of Object.entries(ROLE_PERMISSIONS)) {
|
||||
const role = roles.find(r => r.name === ROLES[roleKey as keyof typeof ROLES]);
|
||||
if (!role) continue;
|
||||
|
||||
for (const permissionCode of permissionCodes) {
|
||||
const permission = permissions.find(p => p.code === PERMISSIONS[permissionCode]);
|
||||
if (!permission) continue;
|
||||
|
||||
await db.insert(rolePermissionsTable)
|
||||
.values({
|
||||
roleId: role.id,
|
||||
permissionId: permission.id,
|
||||
})
|
||||
.onConflictDoNothing();
|
||||
}
|
||||
}
|
||||
|
||||
console.log("✅ Seeding complete!");
|
||||
}
|
||||
|
||||
seed()
|
||||
.catch(console.error)
|
||||
.finally(() => process.exit());
|
||||
function getRoleDescription(roleKey: string): string {
|
||||
const descriptions: Record<string, string> = {
|
||||
ADMIN: "Full system administrator with all permissions",
|
||||
PRINCIPAL_INVESTIGATOR: "Lead researcher responsible for study design and oversight",
|
||||
RESEARCHER: "Study team member with data collection and analysis capabilities",
|
||||
WIZARD: "Operator controlling robot behavior during experiments",
|
||||
OBSERVER: "Team member observing and annotating experiments",
|
||||
ASSISTANT: "Support staff with limited view access",
|
||||
};
|
||||
return descriptions[roleKey] || "";
|
||||
}
|
||||
|
||||
function getPermissionDescription(permKey: string): string {
|
||||
const descriptions: Record<string, string> = {
|
||||
CREATE_STUDY: "Create new research studies",
|
||||
EDIT_STUDY: "Modify existing study parameters",
|
||||
DELETE_STUDY: "Remove studies from the system",
|
||||
VIEW_STUDY: "View study details and progress",
|
||||
VIEW_PARTICIPANT_NAMES: "Access participant identifying information",
|
||||
CREATE_PARTICIPANT: "Add new participants to studies",
|
||||
EDIT_PARTICIPANT: "Update participant information",
|
||||
DELETE_PARTICIPANT: "Remove participants from studies",
|
||||
CONTROL_ROBOT: "Operate robot during experiments",
|
||||
VIEW_ROBOT_STATUS: "Monitor robot state and sensors",
|
||||
RECORD_EXPERIMENT: "Start/stop experiment recording",
|
||||
VIEW_EXPERIMENT: "View experiment progress and details",
|
||||
VIEW_EXPERIMENT_DATA: "Access collected experiment data",
|
||||
EXPORT_EXPERIMENT_DATA: "Download experiment data",
|
||||
ANNOTATE_EXPERIMENT: "Add notes and annotations to experiments",
|
||||
MANAGE_ROLES: "Assign and modify user roles",
|
||||
MANAGE_USERS: "Add and remove system users",
|
||||
MANAGE_SYSTEM_SETTINGS: "Configure system-wide settings",
|
||||
};
|
||||
return descriptions[permKey] || "";
|
||||
}
|
||||
|
||||
function formatPermissionName(permKey: string): string {
|
||||
return permKey.toLowerCase()
|
||||
.split('_')
|
||||
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
|
||||
.join(' ');
|
||||
}
|
||||
|
||||
seed().catch(console.error);
|
||||
|
||||
Reference in New Issue
Block a user