148 lines
4.4 KiB
PL/PgSQL
148 lines
4.4 KiB
PL/PgSQL
-- Leave of Absence table
|
|
DO $$
|
|
BEGIN
|
|
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'leave_type') THEN
|
|
CREATE TYPE leave_type AS ENUM (
|
|
'emergency_leave',
|
|
'parental_leave',
|
|
'sick_leave',
|
|
'vacation_leave'
|
|
);
|
|
END IF;
|
|
END $$;
|
|
|
|
DO $$
|
|
BEGIN
|
|
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'leave_status') THEN
|
|
CREATE TYPE leave_status AS ENUM (
|
|
'pending',
|
|
'approved',
|
|
'rejected',
|
|
'cancelled'
|
|
);
|
|
END IF;
|
|
END $$;
|
|
|
|
CREATE TABLE IF NOT EXISTS leave_of_absence (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
|
|
leave_type leave_type NOT NULL,
|
|
justification TEXT NOT NULL,
|
|
start_time TIMESTAMPTZ NOT NULL,
|
|
end_time TIMESTAMPTZ NOT NULL,
|
|
status leave_status NOT NULL DEFAULT 'pending',
|
|
filed_by UUID NOT NULL REFERENCES auth.users(id),
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
|
|
CONSTRAINT valid_time_range CHECK (end_time > start_time)
|
|
);
|
|
|
|
-- Indexes
|
|
CREATE INDEX IF NOT EXISTS idx_leave_user_id ON leave_of_absence(user_id);
|
|
CREATE INDEX IF NOT EXISTS idx_leave_start_time ON leave_of_absence(start_time);
|
|
CREATE INDEX IF NOT EXISTS idx_leave_status ON leave_of_absence(status);
|
|
|
|
-- RLS
|
|
ALTER TABLE leave_of_absence ENABLE ROW LEVEL SECURITY;
|
|
|
|
DROP POLICY IF EXISTS "Privileged users can view all leaves" ON leave_of_absence;
|
|
DROP POLICY IF EXISTS "Users can view own leaves" ON leave_of_absence;
|
|
DROP POLICY IF EXISTS "Privileged users can file own leaves" ON leave_of_absence;
|
|
DROP POLICY IF EXISTS "Users can file own leaves" ON leave_of_absence;
|
|
DROP POLICY IF EXISTS "Admins can approve or reject leaves" ON leave_of_absence;
|
|
DROP POLICY IF EXISTS "Users can cancel own future approved leaves" ON leave_of_absence;
|
|
DROP POLICY IF EXISTS "Admins can cancel future approved leaves" ON leave_of_absence;
|
|
DROP POLICY IF EXISTS "Privileged users can update leaves" ON leave_of_absence;
|
|
DROP POLICY IF EXISTS "Users can cancel own pending leaves" ON leave_of_absence;
|
|
|
|
-- Admin/dispatcher/it_staff can see all leaves
|
|
CREATE POLICY "Privileged users can view all leaves"
|
|
ON leave_of_absence FOR SELECT
|
|
USING (
|
|
EXISTS (
|
|
SELECT 1 FROM profiles
|
|
WHERE profiles.id = auth.uid()
|
|
AND profiles.role IN ('admin', 'dispatcher', 'it_staff')
|
|
)
|
|
);
|
|
|
|
-- All users can see their own leaves
|
|
CREATE POLICY "Users can view own leaves"
|
|
ON leave_of_absence FOR SELECT
|
|
USING (user_id = auth.uid());
|
|
|
|
-- Only admin/dispatcher/it_staff can file leaves (for themselves)
|
|
CREATE POLICY "Privileged users can file own leaves"
|
|
ON leave_of_absence FOR INSERT
|
|
WITH CHECK (
|
|
user_id = auth.uid()
|
|
AND filed_by = auth.uid()
|
|
AND EXISTS (
|
|
SELECT 1 FROM profiles
|
|
WHERE profiles.id = auth.uid()
|
|
AND profiles.role IN ('admin', 'dispatcher', 'it_staff')
|
|
)
|
|
);
|
|
|
|
-- Only admins can approve/reject pending leaves
|
|
CREATE POLICY "Admins can approve or reject leaves"
|
|
ON leave_of_absence FOR UPDATE
|
|
USING (
|
|
status = 'pending'
|
|
AND EXISTS (
|
|
SELECT 1 FROM profiles
|
|
WHERE profiles.id = auth.uid()
|
|
AND profiles.role = 'admin'
|
|
)
|
|
)
|
|
WITH CHECK (
|
|
status IN ('approved', 'rejected')
|
|
);
|
|
|
|
-- Users can cancel their own future approved leaves
|
|
CREATE POLICY "Users can cancel own future approved leaves"
|
|
ON leave_of_absence FOR UPDATE
|
|
USING (
|
|
user_id = auth.uid()
|
|
AND status = 'approved'
|
|
AND start_time > now()
|
|
)
|
|
WITH CHECK (
|
|
status = 'cancelled'
|
|
);
|
|
|
|
-- Admins can cancel future approved leaves
|
|
CREATE POLICY "Admins can cancel future approved leaves"
|
|
ON leave_of_absence FOR UPDATE
|
|
USING (
|
|
status = 'approved'
|
|
AND start_time > now()
|
|
AND EXISTS (
|
|
SELECT 1 FROM profiles
|
|
WHERE profiles.id = auth.uid()
|
|
AND profiles.role = 'admin'
|
|
)
|
|
)
|
|
WITH CHECK (
|
|
status = 'cancelled'
|
|
);
|
|
|
|
-- Drop legacy reason column if it exists from an earlier migration
|
|
ALTER TABLE leave_of_absence DROP COLUMN IF EXISTS reason;
|
|
|
|
-- Updated_at trigger
|
|
CREATE OR REPLACE FUNCTION update_leave_updated_at()
|
|
RETURNS TRIGGER AS $$
|
|
BEGIN
|
|
NEW.updated_at = now();
|
|
RETURN NEW;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
DROP TRIGGER IF EXISTS trigger_leave_updated_at ON leave_of_absence;
|
|
CREATE TRIGGER trigger_leave_updated_at
|
|
BEFORE UPDATE ON leave_of_absence
|
|
FOR EACH ROW
|
|
EXECUTE FUNCTION update_leave_updated_at();
|