mian commit
This commit is contained in:
@@ -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;
|
||||
$$;
|
||||
Reference in New Issue
Block a user