Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions server/prisma/executeTriggers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import pg from "pg";
import fs from "fs";
import path from "path";
import { fileURLToPath } from "url";
import dotenv from "dotenv";

dotenv.config();

const { Client } = pg;

// Fix __dirname for ES Modules
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

// Path to triggers.sql
const filePath = path.join(__dirname, "scripts", "triggers.sql");

const client = new Client({
connectionString: process.env.DATABASE_URL,
});

async function executeTriggers() {
try {
await client.connect();
console.log(" Connected to the database.");

// Ensure triggers.sql exists
if (!fs.existsSync(filePath)) {
throw new Error(` triggers.sql file not found at: ${filePath}`);
}

const sql = fs.readFileSync(filePath, "utf8");

console.log(" Executing triggers.sql...");
await client.query(sql);
console.log(" Triggers executed successfully.");
} catch (error) {
console.error(" Error executing triggers.sql:", error);
} finally {
await client.end();
console.log(" Database connection closed.");
}
}

executeTriggers();
40 changes: 26 additions & 14 deletions server/prisma/schema.prisma
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
generator client {
provider = "prisma-client-js"
binaryTargets = ["native", "linux-musl"]

provider = "prisma-client-js"
binaryTargets = ["native", "linux-musl"]
}

datasource db {
Expand All @@ -21,15 +20,16 @@ model User {
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
activities Activity[]
mentorActivities MentorActivity[] @relation("UserMentorActivities")
mentorFeedback MentorFeedback[]
mentorReports Report[] @relation(name: "mentorReports")
mentorRoles Mentorship[] @relation(name: "mentorRole")
studentRoles Mentorship[] @relation(name: "studentRole")
mentorActivities MentorActivity[] @relation(name: "UserMentorActivities")
mentorRoles Mentorship[] @relation("mentorRole")
studentRoles Mentorship[] @relation("studentRole")
mentorReports Report[] @relation("mentorReports")

@@map("users")
}


model Activity {
id String @id @default(uuid())
studentId String
Expand Down Expand Up @@ -59,12 +59,12 @@ model MentorFeedback {
}

model Report {
id String @id @default(uuid())
id String @id @default(uuid())
mentorId String
reportData Json
status ProcessStatus @default(pending)
generatedAt DateTime @default(now())
mentor User @relation(fields: [mentorId], references: [id], name: "mentorReports")
generatedAt DateTime @default(now())
mentor User @relation("mentorReports", fields: [mentorId], references: [id])

@@map("reports")
}
Expand All @@ -73,8 +73,8 @@ model Mentorship {
id String @id @default(uuid())
mentorId String
studentId String
mentor User @relation(fields: [mentorId], references: [id], name: "mentorRole")
student User @relation(fields: [studentId], references: [id], name: "studentRole")
mentor User @relation("mentorRole", fields: [mentorId], references: [id])
student User @relation("studentRole", fields: [studentId], references: [id])

@@map("mentorship")
}
Expand All @@ -87,11 +87,23 @@ model MentorActivity {
activities String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
mentor User @relation(fields: [mentorId], references: [id], name: "UserMentorActivities")
mentor User @relation("UserMentorActivities", fields: [mentorId], references: [id])

@@map("mentoractivities")
}

model AuditLog {
id String @id @default(uuid())
action String
tableName String
recordId String
oldData Json?
timestamp DateTime @default(now())
@@map("audit_logs")
}



enum Role {
student
mentor
Expand All @@ -109,4 +121,4 @@ enum ProcessStatus {
error
completed
wip
}
}
52 changes: 52 additions & 0 deletions server/prisma/scripts/triggers.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
-- Drop existing function if it exists
DROP FUNCTION IF EXISTS audit_all_tables CASCADE;

-- Create the audit function without current_user_id
CREATE OR REPLACE FUNCTION audit_all_tables() RETURNS TRIGGER AS $$
BEGIN
-- Insert into audit_logs (without current_user_id)
INSERT INTO audit_logs ("id", "action", "tableName", "recordId", "oldData", "timestamp")
VALUES (
gen_random_uuid(),
TG_OP,
TG_TABLE_NAME,
CASE WHEN TG_OP = 'DELETE' THEN OLD.id ELSE NEW.id END,
CASE WHEN TG_OP IN ('UPDATE', 'DELETE') THEN row_to_json(OLD) ELSE NULL END,
now()
);

RETURN NEW;
END;
$$ LANGUAGE plpgsql;

-- Create triggers for all tracked tables

-- Activities table trigger
DROP TRIGGER IF EXISTS audit_trigger_activities ON activities;
CREATE TRIGGER audit_trigger_activities
AFTER INSERT OR UPDATE OR DELETE ON activities
FOR EACH ROW EXECUTE FUNCTION audit_all_tables();

-- Mentor Feedback table trigger
DROP TRIGGER IF EXISTS audit_trigger_mentorfeedback ON mentorfeedback;
CREATE TRIGGER audit_trigger_mentorfeedback
AFTER INSERT OR UPDATE OR DELETE ON mentorfeedback
FOR EACH ROW EXECUTE FUNCTION audit_all_tables();

-- Mentorship table trigger
DROP TRIGGER IF EXISTS audit_trigger_mentorship ON mentorship;
CREATE TRIGGER audit_trigger_mentorship
AFTER INSERT OR UPDATE OR DELETE ON mentorship
FOR EACH ROW EXECUTE FUNCTION audit_all_tables();

-- Users table trigger
DROP TRIGGER IF EXISTS audit_trigger_users ON users;
CREATE TRIGGER audit_trigger_users
AFTER INSERT OR UPDATE OR DELETE ON users
FOR EACH ROW EXECUTE FUNCTION audit_all_tables();

-- Mentor Activity table trigger
DROP TRIGGER IF EXISTS audit_trigger_mentoractivities ON mentoractivities;
CREATE TRIGGER audit_trigger_mentoractivities
AFTER INSERT OR UPDATE OR DELETE ON mentoractivities
FOR EACH ROW EXECUTE FUNCTION audit_all_tables();