mian commit

This commit is contained in:
2026-03-01 18:32:49 +00:00
parent c7e1203187
commit 3754ea4c28
135 changed files with 18211 additions and 0 deletions
+283
View File
@@ -0,0 +1,283 @@
-- CreateEnum
CREATE TYPE "UserSex" AS ENUM ('MALE', 'FEMALE');
-- CreateEnum
CREATE TYPE "Day" AS ENUM ('MONDAY', 'TUESDAY', 'WEDNESDAY', 'THURSDAY', 'FRIDAY');
-- CreateTable
CREATE TABLE "Admin" (
"id" TEXT NOT NULL,
"username" TEXT NOT NULL,
CONSTRAINT "Admin_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "Student" (
"id" TEXT NOT NULL,
"username" TEXT NOT NULL,
"name" TEXT NOT NULL,
"surname" TEXT NOT NULL,
"email" TEXT,
"phone" TEXT,
"address" TEXT NOT NULL,
"img" TEXT,
"bloodType" TEXT NOT NULL,
"sex" "UserSex" NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"parentId" TEXT NOT NULL,
"classId" INTEGER NOT NULL,
"gradeId" INTEGER NOT NULL,
"birthday" TIMESTAMP(3) NOT NULL,
CONSTRAINT "Student_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "Teacher" (
"id" TEXT NOT NULL,
"username" TEXT NOT NULL,
"name" TEXT NOT NULL,
"surname" TEXT NOT NULL,
"email" TEXT,
"phone" TEXT,
"address" TEXT NOT NULL,
"img" TEXT,
"bloodType" TEXT NOT NULL,
"sex" "UserSex" NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"birthday" TIMESTAMP(3) NOT NULL,
CONSTRAINT "Teacher_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "Parent" (
"id" TEXT NOT NULL,
"username" TEXT NOT NULL,
"name" TEXT NOT NULL,
"surname" TEXT NOT NULL,
"email" TEXT,
"phone" TEXT NOT NULL,
"address" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "Parent_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "Grade" (
"id" SERIAL NOT NULL,
"level" INTEGER NOT NULL,
CONSTRAINT "Grade_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "Class" (
"id" SERIAL NOT NULL,
"name" TEXT NOT NULL,
"capacity" INTEGER NOT NULL,
"supervisorId" TEXT,
"gradeId" INTEGER NOT NULL,
CONSTRAINT "Class_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "Subject" (
"id" SERIAL NOT NULL,
"name" TEXT NOT NULL,
CONSTRAINT "Subject_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "Lesson" (
"id" SERIAL NOT NULL,
"name" TEXT NOT NULL,
"day" "Day" NOT NULL,
"startTime" TIMESTAMP(3) NOT NULL,
"endTime" TIMESTAMP(3) NOT NULL,
"subjectId" INTEGER NOT NULL,
"classId" INTEGER NOT NULL,
"teacherId" TEXT NOT NULL,
CONSTRAINT "Lesson_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "Exam" (
"id" SERIAL NOT NULL,
"title" TEXT NOT NULL,
"startTime" TIMESTAMP(3) NOT NULL,
"endTime" TIMESTAMP(3) NOT NULL,
"lessonId" INTEGER NOT NULL,
CONSTRAINT "Exam_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "Assignment" (
"id" SERIAL NOT NULL,
"title" TEXT NOT NULL,
"startDate" TIMESTAMP(3) NOT NULL,
"dueDate" TIMESTAMP(3) NOT NULL,
"lessonId" INTEGER NOT NULL,
CONSTRAINT "Assignment_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "Result" (
"id" SERIAL NOT NULL,
"score" INTEGER NOT NULL,
"examId" INTEGER,
"assignmentId" INTEGER,
"studentId" TEXT NOT NULL,
CONSTRAINT "Result_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "Attendance" (
"id" SERIAL NOT NULL,
"date" TIMESTAMP(3) NOT NULL,
"present" BOOLEAN NOT NULL,
"studentId" TEXT NOT NULL,
"lessonId" INTEGER NOT NULL,
CONSTRAINT "Attendance_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "Event" (
"id" SERIAL NOT NULL,
"title" TEXT NOT NULL,
"description" TEXT NOT NULL,
"startTime" TIMESTAMP(3) NOT NULL,
"endTime" TIMESTAMP(3) NOT NULL,
"classId" INTEGER,
CONSTRAINT "Event_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "Announcement" (
"id" SERIAL NOT NULL,
"title" TEXT NOT NULL,
"description" TEXT NOT NULL,
"date" TIMESTAMP(3) NOT NULL,
"classId" INTEGER,
CONSTRAINT "Announcement_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "_SubjectToTeacher" (
"A" INTEGER NOT NULL,
"B" TEXT NOT NULL
);
-- CreateIndex
CREATE UNIQUE INDEX "Admin_username_key" ON "Admin"("username");
-- CreateIndex
CREATE UNIQUE INDEX "Student_username_key" ON "Student"("username");
-- CreateIndex
CREATE UNIQUE INDEX "Student_email_key" ON "Student"("email");
-- CreateIndex
CREATE UNIQUE INDEX "Student_phone_key" ON "Student"("phone");
-- CreateIndex
CREATE UNIQUE INDEX "Teacher_username_key" ON "Teacher"("username");
-- CreateIndex
CREATE UNIQUE INDEX "Teacher_email_key" ON "Teacher"("email");
-- CreateIndex
CREATE UNIQUE INDEX "Teacher_phone_key" ON "Teacher"("phone");
-- CreateIndex
CREATE UNIQUE INDEX "Parent_username_key" ON "Parent"("username");
-- CreateIndex
CREATE UNIQUE INDEX "Parent_email_key" ON "Parent"("email");
-- CreateIndex
CREATE UNIQUE INDEX "Parent_phone_key" ON "Parent"("phone");
-- CreateIndex
CREATE UNIQUE INDEX "Grade_level_key" ON "Grade"("level");
-- CreateIndex
CREATE UNIQUE INDEX "Class_name_key" ON "Class"("name");
-- CreateIndex
CREATE UNIQUE INDEX "Subject_name_key" ON "Subject"("name");
-- CreateIndex
CREATE UNIQUE INDEX "_SubjectToTeacher_AB_unique" ON "_SubjectToTeacher"("A", "B");
-- CreateIndex
CREATE INDEX "_SubjectToTeacher_B_index" ON "_SubjectToTeacher"("B");
-- AddForeignKey
ALTER TABLE "Student" ADD CONSTRAINT "Student_parentId_fkey" FOREIGN KEY ("parentId") REFERENCES "Parent"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Student" ADD CONSTRAINT "Student_classId_fkey" FOREIGN KEY ("classId") REFERENCES "Class"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Student" ADD CONSTRAINT "Student_gradeId_fkey" FOREIGN KEY ("gradeId") REFERENCES "Grade"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Class" ADD CONSTRAINT "Class_supervisorId_fkey" FOREIGN KEY ("supervisorId") REFERENCES "Teacher"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Class" ADD CONSTRAINT "Class_gradeId_fkey" FOREIGN KEY ("gradeId") REFERENCES "Grade"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Lesson" ADD CONSTRAINT "Lesson_subjectId_fkey" FOREIGN KEY ("subjectId") REFERENCES "Subject"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Lesson" ADD CONSTRAINT "Lesson_classId_fkey" FOREIGN KEY ("classId") REFERENCES "Class"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Lesson" ADD CONSTRAINT "Lesson_teacherId_fkey" FOREIGN KEY ("teacherId") REFERENCES "Teacher"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Exam" ADD CONSTRAINT "Exam_lessonId_fkey" FOREIGN KEY ("lessonId") REFERENCES "Lesson"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Assignment" ADD CONSTRAINT "Assignment_lessonId_fkey" FOREIGN KEY ("lessonId") REFERENCES "Lesson"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Result" ADD CONSTRAINT "Result_examId_fkey" FOREIGN KEY ("examId") REFERENCES "Exam"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Result" ADD CONSTRAINT "Result_assignmentId_fkey" FOREIGN KEY ("assignmentId") REFERENCES "Assignment"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Result" ADD CONSTRAINT "Result_studentId_fkey" FOREIGN KEY ("studentId") REFERENCES "Student"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Attendance" ADD CONSTRAINT "Attendance_studentId_fkey" FOREIGN KEY ("studentId") REFERENCES "Student"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Attendance" ADD CONSTRAINT "Attendance_lessonId_fkey" FOREIGN KEY ("lessonId") REFERENCES "Lesson"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Event" ADD CONSTRAINT "Event_classId_fkey" FOREIGN KEY ("classId") REFERENCES "Class"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Announcement" ADD CONSTRAINT "Announcement_classId_fkey" FOREIGN KEY ("classId") REFERENCES "Class"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "_SubjectToTeacher" ADD CONSTRAINT "_SubjectToTeacher_A_fkey" FOREIGN KEY ("A") REFERENCES "Subject"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "_SubjectToTeacher" ADD CONSTRAINT "_SubjectToTeacher_B_fkey" FOREIGN KEY ("B") REFERENCES "Teacher"("id") ON DELETE CASCADE ON UPDATE CASCADE;
@@ -0,0 +1,32 @@
-- Create roles that Clerk passes in the JWT `role` claim
-- PostgREST attempts to assume these roles when making requests.
-- We create them and grant them the standard authenticated role permissions.
DO $$
BEGIN
IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'admin') THEN
CREATE ROLE admin NOLOGIN;
GRANT authenticated TO admin;
END IF;
IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'teacher') THEN
CREATE ROLE teacher NOLOGIN;
GRANT authenticated TO teacher;
END IF;
IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'student') THEN
CREATE ROLE student NOLOGIN;
GRANT authenticated TO student;
END IF;
IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'parent') THEN
CREATE ROLE parent NOLOGIN;
GRANT authenticated TO parent;
END IF;
END $$;
-- Grant the roles to the authenticator role so PostgREST can switch to them
GRANT admin TO authenticator;
GRANT teacher TO authenticator;
GRANT student TO authenticator;
GRANT parent TO authenticator;
@@ -0,0 +1,201 @@
-- 1. Enable RLS on all tables
DO $$ BEGIN
ALTER TABLE "Admin" ENABLE ROW LEVEL SECURITY;
ALTER TABLE "Student" ENABLE ROW LEVEL SECURITY;
ALTER TABLE "Teacher" ENABLE ROW LEVEL SECURITY;
ALTER TABLE "Parent" ENABLE ROW LEVEL SECURITY;
ALTER TABLE "Grade" ENABLE ROW LEVEL SECURITY;
ALTER TABLE "Class" ENABLE ROW LEVEL SECURITY;
ALTER TABLE "Subject" ENABLE ROW LEVEL SECURITY;
ALTER TABLE "Lesson" ENABLE ROW LEVEL SECURITY;
ALTER TABLE "Exam" ENABLE ROW LEVEL SECURITY;
ALTER TABLE "Assignment" ENABLE ROW LEVEL SECURITY;
ALTER TABLE "Result" ENABLE ROW LEVEL SECURITY;
ALTER TABLE "Attendance" ENABLE ROW LEVEL SECURITY;
ALTER TABLE "Event" ENABLE ROW LEVEL SECURITY;
ALTER TABLE "Announcement" ENABLE ROW LEVEL SECURITY;
ALTER TABLE "_SubjectToTeacher" ENABLE ROW LEVEL SECURITY;
EXCEPTION
WHEN undefined_table THEN
NULL;
END $$;
-- 2. Utility helper functions connecting to Clerk JWT
CREATE OR REPLACE FUNCTION requesting_user_id()
RETURNS text
LANGUAGE sql STABLE
AS $$
SELECT NULLIF(current_setting('request.jwt.claims', true)::json->>'sub', '')::text;
$$;
CREATE OR REPLACE FUNCTION requesting_user_role()
RETURNS text
LANGUAGE sql STABLE
AS $$
SELECT current_setting('request.jwt.claims', true)::json->>'role';
$$;
CREATE OR REPLACE FUNCTION is_admin() RETURNS boolean LANGUAGE sql STABLE AS $$
SELECT requesting_user_role() = 'admin';
$$;
-- 3. Bypass-RLS Helper Functions for finding accessible IDs
-- We use SECURITY DEFINER SET search_path = public to execute these queries as the database owner,
-- which prevents infinite recursion errors (stack depth limit exceeded) when querying tables that have RLS enabled.
-- Transaction-local variables like `request.jwt.claims` perfectly persist through SECURITY DEFINER calls.
CREATE OR REPLACE FUNCTION auth_user_classes() RETURNS SETOF integer LANGUAGE plpgsql SECURITY DEFINER SET search_path = public STABLE AS $$
BEGIN
RETURN QUERY
SELECT "classId" FROM "Student" WHERE id = requesting_user_id() AND requesting_user_role() = 'student'
UNION
SELECT "classId" FROM "Student" WHERE "parentId" = requesting_user_id() AND requesting_user_role() = 'parent'
UNION
SELECT "classId" FROM "Lesson" WHERE "teacherId" = requesting_user_id() AND requesting_user_role() = 'teacher'
UNION
SELECT id FROM "Class" WHERE "supervisorId" = requesting_user_id() AND requesting_user_role() = 'teacher';
END;
$$;
CREATE OR REPLACE FUNCTION auth_user_students() RETURNS SETOF text LANGUAGE plpgsql SECURITY DEFINER SET search_path = public STABLE AS $$
BEGIN
RETURN QUERY
SELECT id FROM "Student" WHERE id = requesting_user_id() AND requesting_user_role() = 'student'
UNION
SELECT id FROM "Student" WHERE "parentId" = requesting_user_id() AND requesting_user_role() = 'parent'
UNION
SELECT id FROM "Student" WHERE "classId" IN (
SELECT "classId" FROM "Lesson" WHERE "teacherId" = requesting_user_id()
) AND requesting_user_role() = 'teacher';
END;
$$;
CREATE OR REPLACE FUNCTION auth_user_lessons() RETURNS SETOF integer LANGUAGE plpgsql SECURITY DEFINER SET search_path = public STABLE AS $$
BEGIN
RETURN QUERY
SELECT id FROM "Lesson" WHERE "teacherId" = requesting_user_id() AND requesting_user_role() = 'teacher'
UNION
SELECT id FROM "Lesson" WHERE "classId" IN (
SELECT "classId" FROM "Student" WHERE id = requesting_user_id() AND requesting_user_role() = 'student'
)
UNION
SELECT id FROM "Lesson" WHERE "classId" IN (
SELECT "classId" FROM "Student" WHERE "parentId" = requesting_user_id() AND requesting_user_role() = 'parent'
);
END;
$$;
CREATE OR REPLACE FUNCTION auth_user_subjects() RETURNS SETOF integer LANGUAGE plpgsql SECURITY DEFINER SET search_path = public STABLE AS $$
BEGIN
RETURN QUERY
SELECT "A" FROM "_SubjectToTeacher" WHERE "B" = requesting_user_id() AND requesting_user_role() = 'teacher'
UNION
SELECT "subjectId" FROM "Lesson" WHERE "classId" IN (
SELECT "classId" FROM "Student" WHERE id = requesting_user_id() AND requesting_user_role() = 'student'
)
UNION
SELECT "subjectId" FROM "Lesson" WHERE "classId" IN (
SELECT "classId" FROM "Student" WHERE "parentId" = requesting_user_id() AND requesting_user_role() = 'parent'
);
END;
$$;
CREATE OR REPLACE FUNCTION auth_user_teachers() RETURNS SETOF text LANGUAGE plpgsql SECURITY DEFINER SET search_path = public STABLE AS $$
BEGIN
RETURN QUERY
SELECT id FROM "Teacher" WHERE id = requesting_user_id() AND requesting_user_role() = 'teacher'
UNION
SELECT "teacherId" FROM "Lesson" WHERE "classId" IN (
SELECT "classId" FROM "Student" WHERE id = requesting_user_id() AND requesting_user_role() = 'student'
)
UNION
SELECT "teacherId" FROM "Lesson" WHERE "classId" IN (
SELECT "classId" FROM "Student" WHERE "parentId" = requesting_user_id() AND requesting_user_role() = 'parent'
);
END;
$$;
CREATE OR REPLACE FUNCTION auth_user_parents() RETURNS SETOF text LANGUAGE plpgsql SECURITY DEFINER SET search_path = public STABLE AS $$
BEGIN
RETURN QUERY
SELECT id FROM "Parent" WHERE id = requesting_user_id() AND requesting_user_role() = 'parent'
UNION
SELECT "parentId" FROM "Student" WHERE id = requesting_user_id() AND requesting_user_role() = 'student';
END;
$$;
-- 4. Define Table Policies using Helpers
CREATE POLICY "Admin has full access" ON "Admin" FOR ALL USING (is_admin());
CREATE POLICY "Admins have full access" ON "Student" FOR ALL USING (is_admin());
CREATE POLICY "Admins have full access" ON "Teacher" FOR ALL USING (is_admin());
CREATE POLICY "Admins have full access" ON "Parent" FOR ALL USING (is_admin());
CREATE POLICY "Admins have full access" ON "Grade" FOR ALL USING (is_admin());
CREATE POLICY "Admins have full access" ON "Class" FOR ALL USING (is_admin());
CREATE POLICY "Admins have full access" ON "Subject" FOR ALL USING (is_admin());
CREATE POLICY "Admins have full access" ON "Lesson" FOR ALL USING (is_admin());
CREATE POLICY "Admins have full access" ON "Exam" FOR ALL USING (is_admin());
CREATE POLICY "Admins have full access" ON "Assignment" FOR ALL USING (is_admin());
CREATE POLICY "Admins have full access" ON "Result" FOR ALL USING (is_admin());
CREATE POLICY "Admins have full access" ON "Attendance" FOR ALL USING (is_admin());
CREATE POLICY "Admins have full access" ON "Event" FOR ALL USING (is_admin());
CREATE POLICY "Admins have full access" ON "Announcement" FOR ALL USING (is_admin());
CREATE POLICY "Admins have full access" ON "_SubjectToTeacher" FOR ALL USING (is_admin());
CREATE POLICY "Anyone can view grades" ON "Grade" FOR SELECT TO authenticated USING (true);
CREATE POLICY "Anyone can view subject-teacher" ON "_SubjectToTeacher" FOR SELECT TO authenticated USING (true);
CREATE POLICY "Users can view permitted students" ON "Student" FOR SELECT USING (
is_admin() OR id IN (SELECT auth_user_students())
);
CREATE POLICY "Users can view permitted teachers" ON "Teacher" FOR SELECT USING (
is_admin() OR id IN (SELECT auth_user_teachers())
);
CREATE POLICY "Users can view permitted parents" ON "Parent" FOR SELECT USING (
is_admin() OR id IN (SELECT auth_user_parents())
);
CREATE POLICY "Users can view permitted subjects" ON "Subject" FOR SELECT USING (
is_admin() OR id IN (SELECT auth_user_subjects())
);
CREATE POLICY "Users can view permitted classes" ON "Class" FOR SELECT USING (
is_admin() OR id IN (SELECT auth_user_classes())
);
CREATE POLICY "Users can view permitted lessons" ON "Lesson" FOR SELECT USING (
is_admin() OR id IN (SELECT auth_user_lessons())
);
CREATE POLICY "Users can view permitted exams" ON "Exam" FOR SELECT USING (
is_admin() OR "lessonId" IN (SELECT auth_user_lessons())
);
CREATE POLICY "Users can view permitted assignments" ON "Assignment" FOR SELECT USING (
is_admin() OR "lessonId" IN (SELECT auth_user_lessons())
);
CREATE POLICY "Users can view permitted results" ON "Result" FOR SELECT USING (
is_admin() OR "studentId" IN (SELECT auth_user_students()) OR (
requesting_user_role() = 'teacher' AND (
"examId" IN (SELECT id FROM "Exam" WHERE "lessonId" IN (SELECT auth_user_lessons())) OR
"assignmentId" IN (SELECT id FROM "Assignment" WHERE "lessonId" IN (SELECT auth_user_lessons()))
)
)
);
CREATE POLICY "Users can view permitted attendance" ON "Attendance" FOR SELECT USING (
is_admin() OR "studentId" IN (SELECT auth_user_students())
);
CREATE POLICY "Users can view permitted events" ON "Event" FOR SELECT USING (
is_admin() OR "classId" IS NULL OR "classId" IN (SELECT auth_user_classes())
);
CREATE POLICY "Users can view permitted announcements" ON "Announcement" FOR SELECT USING (
is_admin() OR "classId" IS NULL OR "classId" IN (SELECT auth_user_classes())
);
@@ -0,0 +1,41 @@
-- Migration: Drop implicit _SubjectToTeacher and replace with explicit TeacherSubject
-- 1. Create the new explicit mapping table
CREATE TABLE "TeacherSubject" (
"id" SERIAL PRIMARY KEY,
"teacherId" TEXT NOT NULL REFERENCES "Teacher"("id") ON DELETE CASCADE,
"subjectId" INTEGER NOT NULL REFERENCES "Subject"("id") ON DELETE CASCADE,
"isPrimary" BOOLEAN DEFAULT false,
"assignedAt" TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 2. Migrate existing data (Optional, but good practice if not resetting)
INSERT INTO "TeacherSubject" ("teacherId", "subjectId")
SELECT "B", "A" FROM "_SubjectToTeacher";
-- 3. Drop the old implicit mapping table
DROP TABLE "_SubjectToTeacher";
-- 4. Enable RLS on the new table
ALTER TABLE "TeacherSubject" ENABLE ROW LEVEL SECURITY;
-- 5. Define RLS Policies for the new table
CREATE POLICY "Admins have full access" ON "TeacherSubject" FOR ALL USING (is_admin());
CREATE POLICY "Anyone can view teacher-subjects" ON "TeacherSubject" FOR SELECT TO authenticated USING (true);
-- 6. Update the auth_user_subjects RLS Helper Function to use explicitly named mapping table
CREATE OR REPLACE FUNCTION auth_user_subjects() RETURNS SETOF integer LANGUAGE plpgsql SECURITY DEFINER SET search_path = public STABLE AS $$
BEGIN
RETURN QUERY
SELECT "subjectId" FROM "TeacherSubject" WHERE "teacherId" = requesting_user_id() AND requesting_user_role() = 'teacher'
UNION
SELECT "subjectId" FROM "Lesson" WHERE "classId" IN (
SELECT "classId" FROM "Student" WHERE id = requesting_user_id() AND requesting_user_role() = 'student'
)
UNION
SELECT "subjectId" FROM "Lesson" WHERE "classId" IN (
SELECT "classId" FROM "Student" WHERE "parentId" = requesting_user_id() AND requesting_user_role() = 'parent'
);
END;
$$;