Migrations
This commit is contained in:
@@ -0,0 +1,158 @@
|
||||
-- ───────────────────────────────────────────────────────────
|
||||
-- Profile: avatar + face enrollment
|
||||
-- ───────────────────────────────────────────────────────────
|
||||
-- avatar_url and face_photo_url may already exist; ADD IF NOT EXISTS
|
||||
-- Postgres 11+ doesn't have ADD COLUMN IF NOT EXISTS in a clean way,
|
||||
-- so we wrap each in a DO block.
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM information_schema.columns
|
||||
WHERE table_name = 'profiles' AND column_name = 'avatar_url'
|
||||
) THEN
|
||||
ALTER TABLE profiles ADD COLUMN avatar_url TEXT;
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM information_schema.columns
|
||||
WHERE table_name = 'profiles' AND column_name = 'face_photo_url'
|
||||
) THEN
|
||||
ALTER TABLE profiles ADD COLUMN face_photo_url TEXT;
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM information_schema.columns
|
||||
WHERE table_name = 'profiles' AND column_name = 'face_enrolled_at'
|
||||
) THEN
|
||||
ALTER TABLE profiles ADD COLUMN face_enrolled_at TIMESTAMPTZ;
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- ───────────────────────────────────────────────────────────
|
||||
-- Attendance logs: verification status + selfie
|
||||
-- ───────────────────────────────────────────────────────────
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'verification_status') THEN
|
||||
CREATE TYPE verification_status AS ENUM (
|
||||
'pending',
|
||||
'verified',
|
||||
'unverified',
|
||||
'skipped'
|
||||
);
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM information_schema.columns
|
||||
WHERE table_name = 'attendance_logs' AND column_name = 'verification_status'
|
||||
) THEN
|
||||
ALTER TABLE attendance_logs
|
||||
ADD COLUMN verification_status verification_status NOT NULL DEFAULT 'pending';
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM information_schema.columns
|
||||
WHERE table_name = 'attendance_logs' AND column_name = 'verification_photo_url'
|
||||
) THEN
|
||||
ALTER TABLE attendance_logs ADD COLUMN verification_photo_url TEXT;
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- ───────────────────────────────────────────────────────────
|
||||
-- Storage buckets (idempotent via INSERT ... ON CONFLICT)
|
||||
-- ───────────────────────────────────────────────────────────
|
||||
|
||||
INSERT INTO storage.buckets (id, name, public)
|
||||
VALUES ('avatars', 'avatars', true)
|
||||
ON CONFLICT (id) DO NOTHING;
|
||||
|
||||
INSERT INTO storage.buckets (id, name, public)
|
||||
VALUES ('face-enrollment', 'face-enrollment', false)
|
||||
ON CONFLICT (id) DO NOTHING;
|
||||
|
||||
INSERT INTO storage.buckets (id, name, public)
|
||||
VALUES ('attendance-verification', 'attendance-verification', false)
|
||||
ON CONFLICT (id) DO NOTHING;
|
||||
|
||||
-- Storage policies: avatars (public read, auth write own)
|
||||
DROP POLICY IF EXISTS "Public can view avatars" ON storage.objects;
|
||||
CREATE POLICY "Public can view avatars"
|
||||
ON storage.objects FOR SELECT
|
||||
USING (bucket_id = 'avatars');
|
||||
|
||||
DROP POLICY IF EXISTS "Users can upload own avatar" ON storage.objects;
|
||||
CREATE POLICY "Users can upload own avatar"
|
||||
ON storage.objects FOR INSERT
|
||||
WITH CHECK (
|
||||
bucket_id = 'avatars'
|
||||
AND (storage.foldername(name))[1] = auth.uid()::text
|
||||
);
|
||||
|
||||
DROP POLICY IF EXISTS "Users can update own avatar" ON storage.objects;
|
||||
CREATE POLICY "Users can update own avatar"
|
||||
ON storage.objects FOR UPDATE
|
||||
USING (
|
||||
bucket_id = 'avatars'
|
||||
AND (storage.foldername(name))[1] = auth.uid()::text
|
||||
);
|
||||
|
||||
-- Storage policies: face-enrollment (private, owner read/write, admin read)
|
||||
DROP POLICY IF EXISTS "Users can upload own face" ON storage.objects;
|
||||
CREATE POLICY "Users can upload own face"
|
||||
ON storage.objects FOR INSERT
|
||||
WITH CHECK (
|
||||
bucket_id = 'face-enrollment'
|
||||
AND (storage.foldername(name))[1] = auth.uid()::text
|
||||
);
|
||||
|
||||
DROP POLICY IF EXISTS "Users can view own face" ON storage.objects;
|
||||
CREATE POLICY "Users can view own face"
|
||||
ON storage.objects FOR SELECT
|
||||
USING (
|
||||
bucket_id = 'face-enrollment'
|
||||
AND (
|
||||
(storage.foldername(name))[1] = auth.uid()::text
|
||||
OR EXISTS (
|
||||
SELECT 1 FROM profiles
|
||||
WHERE profiles.id = auth.uid() AND profiles.role = 'admin'
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
-- Storage policies: attendance-verification (owner + admin read, owner write)
|
||||
DROP POLICY IF EXISTS "Users can upload verification photo" ON storage.objects;
|
||||
CREATE POLICY "Users can upload verification photo"
|
||||
ON storage.objects FOR INSERT
|
||||
WITH CHECK (
|
||||
bucket_id = 'attendance-verification'
|
||||
AND (storage.foldername(name))[1] = auth.uid()::text
|
||||
);
|
||||
|
||||
DROP POLICY IF EXISTS "Users and admins can view verification photos" ON storage.objects;
|
||||
CREATE POLICY "Users and admins can view verification photos"
|
||||
ON storage.objects FOR SELECT
|
||||
USING (
|
||||
bucket_id = 'attendance-verification'
|
||||
AND (
|
||||
(storage.foldername(name))[1] = auth.uid()::text
|
||||
OR EXISTS (
|
||||
SELECT 1 FROM profiles
|
||||
WHERE profiles.id = auth.uid()
|
||||
AND profiles.role IN ('admin', 'dispatcher', 'it_staff')
|
||||
)
|
||||
)
|
||||
);
|
||||
Reference in New Issue
Block a user