diff --git a/supabase/migrations/20260719201049_student_photo.sql b/supabase/migrations/20260719201049_student_photo.sql new file mode 100644 index 0000000..473645a --- /dev/null +++ b/supabase/migrations/20260719201049_student_photo.sql @@ -0,0 +1,26 @@ +-- Student photo: a column for the stored path + a private storage bucket. + +ALTER TABLE public.students ADD COLUMN IF NOT EXISTS photo_path TEXT; + +INSERT INTO storage.buckets (id, name, public) +VALUES ('student-photos', 'student-photos', false) +ON CONFLICT (id) DO NOTHING; + +-- Admins upload/replace/remove photos. +CREATE POLICY "student photos admin write" ON storage.objects FOR INSERT TO authenticated + WITH CHECK (bucket_id = 'student-photos' AND public.current_user_has_role('admin')); +CREATE POLICY "student photos admin update" ON storage.objects FOR UPDATE TO authenticated + USING (bucket_id = 'student-photos' AND public.current_user_has_role('admin')); +CREATE POLICY "student photos admin delete" ON storage.objects FOR DELETE TO authenticated + USING (bucket_id = 'student-photos' AND public.current_user_has_role('admin')); + +-- Read: admins, the student's teacher, or the student's parent. +-- Path convention is "/", so folder[1] is the student id. +CREATE POLICY "student photos read" ON storage.objects FOR SELECT TO authenticated + USING ( + bucket_id = 'student-photos' AND ( + public.current_user_has_role('admin') + OR public.is_parent_of(((storage.foldername(name))[1])::uuid) + OR public.teaches_student(((storage.foldername(name))[1])::uuid) + ) + );