refactor: remove obsolete member management API module
This commit is contained in:
@@ -0,0 +1,496 @@
|
||||
-- =====================================================
|
||||
-- Audit Logging for Courses, Events, Bookings
|
||||
--
|
||||
-- Full change history for compliance: who changed what
|
||||
-- field, old value -> new value, when. Mirrors the
|
||||
-- member_audit_log pattern from 20260416000007.
|
||||
-- =====================================================
|
||||
|
||||
-- -------------------------------------------------------
|
||||
-- A) Add created_by / updated_by to main tables
|
||||
-- -------------------------------------------------------
|
||||
|
||||
ALTER TABLE public.courses
|
||||
ADD COLUMN IF NOT EXISTS created_by uuid REFERENCES auth.users(id) ON DELETE SET NULL,
|
||||
ADD COLUMN IF NOT EXISTS updated_by uuid REFERENCES auth.users(id) ON DELETE SET NULL;
|
||||
|
||||
ALTER TABLE public.events
|
||||
ADD COLUMN IF NOT EXISTS created_by uuid REFERENCES auth.users(id) ON DELETE SET NULL,
|
||||
ADD COLUMN IF NOT EXISTS updated_by uuid REFERENCES auth.users(id) ON DELETE SET NULL;
|
||||
|
||||
ALTER TABLE public.bookings
|
||||
ADD COLUMN IF NOT EXISTS created_by uuid REFERENCES auth.users(id) ON DELETE SET NULL,
|
||||
ADD COLUMN IF NOT EXISTS updated_by uuid REFERENCES auth.users(id) ON DELETE SET NULL;
|
||||
|
||||
-- -------------------------------------------------------
|
||||
-- B) Audit log tables
|
||||
-- -------------------------------------------------------
|
||||
|
||||
-- B.1 Course audit log
|
||||
CREATE TABLE IF NOT EXISTS public.course_audit_log (
|
||||
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
||||
course_id uuid NOT NULL REFERENCES public.courses(id) ON DELETE CASCADE,
|
||||
account_id uuid NOT NULL REFERENCES public.accounts(id) ON DELETE CASCADE,
|
||||
user_id uuid REFERENCES auth.users(id) ON DELETE SET NULL,
|
||||
action text NOT NULL CHECK (action IN (
|
||||
'created', 'updated', 'status_changed', 'cancelled',
|
||||
'participant_enrolled', 'participant_cancelled',
|
||||
'participant_waitlisted', 'participant_promoted',
|
||||
'session_created', 'session_cancelled',
|
||||
'attendance_marked', 'instructor_changed', 'location_changed'
|
||||
)),
|
||||
changes jsonb NOT NULL DEFAULT '{}',
|
||||
metadata jsonb NOT NULL DEFAULT '{}',
|
||||
created_at timestamptz NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
COMMENT ON TABLE public.course_audit_log IS
|
||||
'Immutable audit trail for all course lifecycle events';
|
||||
|
||||
CREATE INDEX IF NOT EXISTS ix_course_audit_course
|
||||
ON public.course_audit_log(course_id, created_at DESC);
|
||||
CREATE INDEX IF NOT EXISTS ix_course_audit_account
|
||||
ON public.course_audit_log(account_id, created_at DESC);
|
||||
CREATE INDEX IF NOT EXISTS ix_course_audit_action
|
||||
ON public.course_audit_log(account_id, action);
|
||||
|
||||
ALTER TABLE public.course_audit_log ENABLE ROW LEVEL SECURITY;
|
||||
REVOKE ALL ON public.course_audit_log FROM authenticated, service_role;
|
||||
GRANT SELECT ON public.course_audit_log TO authenticated;
|
||||
GRANT INSERT, SELECT ON public.course_audit_log TO service_role;
|
||||
|
||||
CREATE POLICY course_audit_log_select
|
||||
ON public.course_audit_log FOR SELECT TO authenticated
|
||||
USING (public.has_role_on_account(account_id));
|
||||
|
||||
-- B.2 Event audit log
|
||||
CREATE TABLE IF NOT EXISTS public.event_audit_log (
|
||||
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
||||
event_id uuid NOT NULL REFERENCES public.events(id) ON DELETE CASCADE,
|
||||
account_id uuid NOT NULL REFERENCES public.accounts(id) ON DELETE CASCADE,
|
||||
user_id uuid REFERENCES auth.users(id) ON DELETE SET NULL,
|
||||
action text NOT NULL CHECK (action IN (
|
||||
'created', 'updated', 'status_changed', 'cancelled',
|
||||
'registration_confirmed', 'registration_waitlisted',
|
||||
'registration_cancelled', 'registration_promoted'
|
||||
)),
|
||||
changes jsonb NOT NULL DEFAULT '{}',
|
||||
metadata jsonb NOT NULL DEFAULT '{}',
|
||||
created_at timestamptz NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
COMMENT ON TABLE public.event_audit_log IS
|
||||
'Immutable audit trail for all event lifecycle events';
|
||||
|
||||
CREATE INDEX IF NOT EXISTS ix_event_audit_event
|
||||
ON public.event_audit_log(event_id, created_at DESC);
|
||||
CREATE INDEX IF NOT EXISTS ix_event_audit_account
|
||||
ON public.event_audit_log(account_id, created_at DESC);
|
||||
CREATE INDEX IF NOT EXISTS ix_event_audit_action
|
||||
ON public.event_audit_log(account_id, action);
|
||||
|
||||
ALTER TABLE public.event_audit_log ENABLE ROW LEVEL SECURITY;
|
||||
REVOKE ALL ON public.event_audit_log FROM authenticated, service_role;
|
||||
GRANT SELECT ON public.event_audit_log TO authenticated;
|
||||
GRANT INSERT, SELECT ON public.event_audit_log TO service_role;
|
||||
|
||||
CREATE POLICY event_audit_log_select
|
||||
ON public.event_audit_log FOR SELECT TO authenticated
|
||||
USING (public.has_role_on_account(account_id));
|
||||
|
||||
-- B.3 Booking audit log
|
||||
CREATE TABLE IF NOT EXISTS public.booking_audit_log (
|
||||
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
||||
booking_id uuid NOT NULL REFERENCES public.bookings(id) ON DELETE CASCADE,
|
||||
account_id uuid NOT NULL REFERENCES public.accounts(id) ON DELETE CASCADE,
|
||||
user_id uuid REFERENCES auth.users(id) ON DELETE SET NULL,
|
||||
action text NOT NULL CHECK (action IN (
|
||||
'created', 'updated', 'status_changed',
|
||||
'checked_in', 'checked_out', 'cancelled',
|
||||
'no_show', 'price_changed'
|
||||
)),
|
||||
changes jsonb NOT NULL DEFAULT '{}',
|
||||
metadata jsonb NOT NULL DEFAULT '{}',
|
||||
created_at timestamptz NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
COMMENT ON TABLE public.booking_audit_log IS
|
||||
'Immutable audit trail for all booking lifecycle events';
|
||||
|
||||
CREATE INDEX IF NOT EXISTS ix_booking_audit_booking
|
||||
ON public.booking_audit_log(booking_id, created_at DESC);
|
||||
CREATE INDEX IF NOT EXISTS ix_booking_audit_account
|
||||
ON public.booking_audit_log(account_id, created_at DESC);
|
||||
CREATE INDEX IF NOT EXISTS ix_booking_audit_action
|
||||
ON public.booking_audit_log(account_id, action);
|
||||
|
||||
ALTER TABLE public.booking_audit_log ENABLE ROW LEVEL SECURITY;
|
||||
REVOKE ALL ON public.booking_audit_log FROM authenticated, service_role;
|
||||
GRANT SELECT ON public.booking_audit_log TO authenticated;
|
||||
GRANT INSERT, SELECT ON public.booking_audit_log TO service_role;
|
||||
|
||||
CREATE POLICY booking_audit_log_select
|
||||
ON public.booking_audit_log FOR SELECT TO authenticated
|
||||
USING (public.has_role_on_account(account_id));
|
||||
|
||||
-- -------------------------------------------------------
|
||||
-- C) Auto-audit triggers for UPDATE
|
||||
-- -------------------------------------------------------
|
||||
|
||||
-- C.1 Courses UPDATE trigger
|
||||
CREATE OR REPLACE FUNCTION public.trg_course_audit_on_update()
|
||||
RETURNS trigger
|
||||
LANGUAGE plpgsql
|
||||
SECURITY DEFINER
|
||||
SET search_path = ''
|
||||
AS $$
|
||||
DECLARE
|
||||
v_changes jsonb := '{}'::jsonb;
|
||||
v_action text := 'updated';
|
||||
v_user_id uuid;
|
||||
BEGIN
|
||||
-- Build changes diff (field by field)
|
||||
IF OLD.name IS DISTINCT FROM NEW.name THEN
|
||||
v_changes := v_changes || jsonb_build_object('name', jsonb_build_object('old', OLD.name, 'new', NEW.name));
|
||||
END IF;
|
||||
IF OLD.description IS DISTINCT FROM NEW.description THEN
|
||||
v_changes := v_changes || jsonb_build_object('description', jsonb_build_object('old', OLD.description, 'new', NEW.description));
|
||||
END IF;
|
||||
IF OLD.course_number IS DISTINCT FROM NEW.course_number THEN
|
||||
v_changes := v_changes || jsonb_build_object('course_number', jsonb_build_object('old', OLD.course_number, 'new', NEW.course_number));
|
||||
END IF;
|
||||
IF OLD.category_id IS DISTINCT FROM NEW.category_id THEN
|
||||
v_changes := v_changes || jsonb_build_object('category_id', jsonb_build_object('old', OLD.category_id, 'new', NEW.category_id));
|
||||
END IF;
|
||||
IF OLD.instructor_id IS DISTINCT FROM NEW.instructor_id THEN
|
||||
v_changes := v_changes || jsonb_build_object('instructor_id', jsonb_build_object('old', OLD.instructor_id, 'new', NEW.instructor_id));
|
||||
END IF;
|
||||
IF OLD.location_id IS DISTINCT FROM NEW.location_id THEN
|
||||
v_changes := v_changes || jsonb_build_object('location_id', jsonb_build_object('old', OLD.location_id, 'new', NEW.location_id));
|
||||
END IF;
|
||||
IF OLD.start_date IS DISTINCT FROM NEW.start_date THEN
|
||||
v_changes := v_changes || jsonb_build_object('start_date', jsonb_build_object('old', OLD.start_date, 'new', NEW.start_date));
|
||||
END IF;
|
||||
IF OLD.end_date IS DISTINCT FROM NEW.end_date THEN
|
||||
v_changes := v_changes || jsonb_build_object('end_date', jsonb_build_object('old', OLD.end_date, 'new', NEW.end_date));
|
||||
END IF;
|
||||
IF OLD.fee IS DISTINCT FROM NEW.fee THEN
|
||||
v_changes := v_changes || jsonb_build_object('fee', jsonb_build_object('old', OLD.fee, 'new', NEW.fee));
|
||||
END IF;
|
||||
IF OLD.reduced_fee IS DISTINCT FROM NEW.reduced_fee THEN
|
||||
v_changes := v_changes || jsonb_build_object('reduced_fee', jsonb_build_object('old', OLD.reduced_fee, 'new', NEW.reduced_fee));
|
||||
END IF;
|
||||
IF OLD.capacity IS DISTINCT FROM NEW.capacity THEN
|
||||
v_changes := v_changes || jsonb_build_object('capacity', jsonb_build_object('old', OLD.capacity, 'new', NEW.capacity));
|
||||
END IF;
|
||||
IF OLD.min_participants IS DISTINCT FROM NEW.min_participants THEN
|
||||
v_changes := v_changes || jsonb_build_object('min_participants', jsonb_build_object('old', OLD.min_participants, 'new', NEW.min_participants));
|
||||
END IF;
|
||||
IF OLD.status IS DISTINCT FROM NEW.status THEN
|
||||
v_changes := v_changes || jsonb_build_object('status', jsonb_build_object('old', OLD.status, 'new', NEW.status));
|
||||
END IF;
|
||||
IF OLD.registration_deadline IS DISTINCT FROM NEW.registration_deadline THEN
|
||||
v_changes := v_changes || jsonb_build_object('registration_deadline', jsonb_build_object('old', OLD.registration_deadline, 'new', NEW.registration_deadline));
|
||||
END IF;
|
||||
IF OLD.notes IS DISTINCT FROM NEW.notes THEN
|
||||
v_changes := v_changes || jsonb_build_object('notes', jsonb_build_object('old', OLD.notes, 'new', NEW.notes));
|
||||
END IF;
|
||||
|
||||
-- Skip if nothing actually changed
|
||||
IF v_changes = '{}'::jsonb THEN
|
||||
RETURN NULL;
|
||||
END IF;
|
||||
|
||||
-- Classify the action
|
||||
IF OLD.status IS DISTINCT FROM NEW.status THEN
|
||||
v_action := 'status_changed';
|
||||
END IF;
|
||||
|
||||
v_user_id := COALESCE(
|
||||
NULLIF(current_setting('app.current_user_id', true), '')::uuid,
|
||||
auth.uid()
|
||||
);
|
||||
|
||||
INSERT INTO public.course_audit_log (course_id, account_id, user_id, action, changes)
|
||||
VALUES (NEW.id, NEW.account_id, v_user_id, v_action, v_changes);
|
||||
|
||||
RETURN NULL;
|
||||
END;
|
||||
$$;
|
||||
|
||||
CREATE OR REPLACE TRIGGER trg_courses_audit_on_update
|
||||
AFTER UPDATE ON public.courses
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION public.trg_course_audit_on_update();
|
||||
|
||||
-- C.2 Events UPDATE trigger
|
||||
CREATE OR REPLACE FUNCTION public.trg_event_audit_on_update()
|
||||
RETURNS trigger
|
||||
LANGUAGE plpgsql
|
||||
SECURITY DEFINER
|
||||
SET search_path = ''
|
||||
AS $$
|
||||
DECLARE
|
||||
v_changes jsonb := '{}'::jsonb;
|
||||
v_action text := 'updated';
|
||||
v_user_id uuid;
|
||||
BEGIN
|
||||
-- Build changes diff (field by field)
|
||||
IF OLD.name IS DISTINCT FROM NEW.name THEN
|
||||
v_changes := v_changes || jsonb_build_object('name', jsonb_build_object('old', OLD.name, 'new', NEW.name));
|
||||
END IF;
|
||||
IF OLD.description IS DISTINCT FROM NEW.description THEN
|
||||
v_changes := v_changes || jsonb_build_object('description', jsonb_build_object('old', OLD.description, 'new', NEW.description));
|
||||
END IF;
|
||||
IF OLD.event_date IS DISTINCT FROM NEW.event_date THEN
|
||||
v_changes := v_changes || jsonb_build_object('event_date', jsonb_build_object('old', OLD.event_date, 'new', NEW.event_date));
|
||||
END IF;
|
||||
IF OLD.event_time IS DISTINCT FROM NEW.event_time THEN
|
||||
v_changes := v_changes || jsonb_build_object('event_time', jsonb_build_object('old', OLD.event_time, 'new', NEW.event_time));
|
||||
END IF;
|
||||
IF OLD.end_date IS DISTINCT FROM NEW.end_date THEN
|
||||
v_changes := v_changes || jsonb_build_object('end_date', jsonb_build_object('old', OLD.end_date, 'new', NEW.end_date));
|
||||
END IF;
|
||||
IF OLD.location IS DISTINCT FROM NEW.location THEN
|
||||
v_changes := v_changes || jsonb_build_object('location', jsonb_build_object('old', OLD.location, 'new', NEW.location));
|
||||
END IF;
|
||||
IF OLD.capacity IS DISTINCT FROM NEW.capacity THEN
|
||||
v_changes := v_changes || jsonb_build_object('capacity', jsonb_build_object('old', OLD.capacity, 'new', NEW.capacity));
|
||||
END IF;
|
||||
IF OLD.min_age IS DISTINCT FROM NEW.min_age THEN
|
||||
v_changes := v_changes || jsonb_build_object('min_age', jsonb_build_object('old', OLD.min_age, 'new', NEW.min_age));
|
||||
END IF;
|
||||
IF OLD.max_age IS DISTINCT FROM NEW.max_age THEN
|
||||
v_changes := v_changes || jsonb_build_object('max_age', jsonb_build_object('old', OLD.max_age, 'new', NEW.max_age));
|
||||
END IF;
|
||||
IF OLD.fee IS DISTINCT FROM NEW.fee THEN
|
||||
v_changes := v_changes || jsonb_build_object('fee', jsonb_build_object('old', OLD.fee, 'new', NEW.fee));
|
||||
END IF;
|
||||
IF OLD.status IS DISTINCT FROM NEW.status THEN
|
||||
v_changes := v_changes || jsonb_build_object('status', jsonb_build_object('old', OLD.status, 'new', NEW.status));
|
||||
END IF;
|
||||
IF OLD.registration_deadline IS DISTINCT FROM NEW.registration_deadline THEN
|
||||
v_changes := v_changes || jsonb_build_object('registration_deadline', jsonb_build_object('old', OLD.registration_deadline, 'new', NEW.registration_deadline));
|
||||
END IF;
|
||||
IF OLD.contact_name IS DISTINCT FROM NEW.contact_name THEN
|
||||
v_changes := v_changes || jsonb_build_object('contact_name', jsonb_build_object('old', OLD.contact_name, 'new', NEW.contact_name));
|
||||
END IF;
|
||||
IF OLD.contact_email IS DISTINCT FROM NEW.contact_email THEN
|
||||
v_changes := v_changes || jsonb_build_object('contact_email', jsonb_build_object('old', OLD.contact_email, 'new', NEW.contact_email));
|
||||
END IF;
|
||||
IF OLD.contact_phone IS DISTINCT FROM NEW.contact_phone THEN
|
||||
v_changes := v_changes || jsonb_build_object('contact_phone', jsonb_build_object('old', OLD.contact_phone, 'new', NEW.contact_phone));
|
||||
END IF;
|
||||
|
||||
-- Skip if nothing actually changed
|
||||
IF v_changes = '{}'::jsonb THEN
|
||||
RETURN NULL;
|
||||
END IF;
|
||||
|
||||
-- Classify the action
|
||||
IF OLD.status IS DISTINCT FROM NEW.status THEN
|
||||
v_action := 'status_changed';
|
||||
END IF;
|
||||
|
||||
v_user_id := COALESCE(
|
||||
NULLIF(current_setting('app.current_user_id', true), '')::uuid,
|
||||
auth.uid()
|
||||
);
|
||||
|
||||
INSERT INTO public.event_audit_log (event_id, account_id, user_id, action, changes)
|
||||
VALUES (NEW.id, NEW.account_id, v_user_id, v_action, v_changes);
|
||||
|
||||
RETURN NULL;
|
||||
END;
|
||||
$$;
|
||||
|
||||
CREATE OR REPLACE TRIGGER trg_events_audit_on_update
|
||||
AFTER UPDATE ON public.events
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION public.trg_event_audit_on_update();
|
||||
|
||||
-- C.3 Bookings UPDATE trigger
|
||||
CREATE OR REPLACE FUNCTION public.trg_booking_audit_on_update()
|
||||
RETURNS trigger
|
||||
LANGUAGE plpgsql
|
||||
SECURITY DEFINER
|
||||
SET search_path = ''
|
||||
AS $$
|
||||
DECLARE
|
||||
v_changes jsonb := '{}'::jsonb;
|
||||
v_action text := 'updated';
|
||||
v_user_id uuid;
|
||||
BEGIN
|
||||
-- Build changes diff (field by field)
|
||||
IF OLD.room_id IS DISTINCT FROM NEW.room_id THEN
|
||||
v_changes := v_changes || jsonb_build_object('room_id', jsonb_build_object('old', OLD.room_id, 'new', NEW.room_id));
|
||||
END IF;
|
||||
IF OLD.guest_id IS DISTINCT FROM NEW.guest_id THEN
|
||||
v_changes := v_changes || jsonb_build_object('guest_id', jsonb_build_object('old', OLD.guest_id, 'new', NEW.guest_id));
|
||||
END IF;
|
||||
IF OLD.check_in IS DISTINCT FROM NEW.check_in THEN
|
||||
v_changes := v_changes || jsonb_build_object('check_in', jsonb_build_object('old', OLD.check_in, 'new', NEW.check_in));
|
||||
END IF;
|
||||
IF OLD.check_out IS DISTINCT FROM NEW.check_out THEN
|
||||
v_changes := v_changes || jsonb_build_object('check_out', jsonb_build_object('old', OLD.check_out, 'new', NEW.check_out));
|
||||
END IF;
|
||||
IF OLD.adults IS DISTINCT FROM NEW.adults THEN
|
||||
v_changes := v_changes || jsonb_build_object('adults', jsonb_build_object('old', OLD.adults, 'new', NEW.adults));
|
||||
END IF;
|
||||
IF OLD.children IS DISTINCT FROM NEW.children THEN
|
||||
v_changes := v_changes || jsonb_build_object('children', jsonb_build_object('old', OLD.children, 'new', NEW.children));
|
||||
END IF;
|
||||
IF OLD.status IS DISTINCT FROM NEW.status THEN
|
||||
v_changes := v_changes || jsonb_build_object('status', jsonb_build_object('old', OLD.status, 'new', NEW.status));
|
||||
END IF;
|
||||
IF OLD.total_price IS DISTINCT FROM NEW.total_price THEN
|
||||
v_changes := v_changes || jsonb_build_object('total_price', jsonb_build_object('old', OLD.total_price, 'new', NEW.total_price));
|
||||
END IF;
|
||||
IF OLD.notes IS DISTINCT FROM NEW.notes THEN
|
||||
v_changes := v_changes || jsonb_build_object('notes', jsonb_build_object('old', OLD.notes, 'new', NEW.notes));
|
||||
END IF;
|
||||
|
||||
-- Skip if nothing actually changed
|
||||
IF v_changes = '{}'::jsonb THEN
|
||||
RETURN NULL;
|
||||
END IF;
|
||||
|
||||
-- Classify the action
|
||||
IF OLD.status IS DISTINCT FROM NEW.status THEN
|
||||
v_action := 'status_changed';
|
||||
END IF;
|
||||
|
||||
v_user_id := COALESCE(
|
||||
NULLIF(current_setting('app.current_user_id', true), '')::uuid,
|
||||
auth.uid()
|
||||
);
|
||||
|
||||
INSERT INTO public.booking_audit_log (booking_id, account_id, user_id, action, changes)
|
||||
VALUES (NEW.id, NEW.account_id, v_user_id, v_action, v_changes);
|
||||
|
||||
RETURN NULL;
|
||||
END;
|
||||
$$;
|
||||
|
||||
CREATE OR REPLACE TRIGGER trg_bookings_audit_on_update
|
||||
AFTER UPDATE ON public.bookings
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION public.trg_booking_audit_on_update();
|
||||
|
||||
-- -------------------------------------------------------
|
||||
-- D) Auto-audit triggers for INSERT
|
||||
-- -------------------------------------------------------
|
||||
|
||||
-- D.1 Courses INSERT trigger
|
||||
CREATE OR REPLACE FUNCTION public.trg_course_audit_on_insert()
|
||||
RETURNS trigger
|
||||
LANGUAGE plpgsql
|
||||
SECURITY DEFINER
|
||||
SET search_path = ''
|
||||
AS $$
|
||||
DECLARE
|
||||
v_user_id uuid;
|
||||
BEGIN
|
||||
v_user_id := COALESCE(
|
||||
NULLIF(current_setting('app.current_user_id', true), '')::uuid,
|
||||
NEW.created_by
|
||||
);
|
||||
|
||||
INSERT INTO public.course_audit_log (course_id, account_id, user_id, action, metadata)
|
||||
VALUES (
|
||||
NEW.id, NEW.account_id, v_user_id, 'created',
|
||||
jsonb_build_object(
|
||||
'course_number', NEW.course_number,
|
||||
'name', NEW.name,
|
||||
'status', NEW.status,
|
||||
'fee', NEW.fee,
|
||||
'capacity', NEW.capacity,
|
||||
'start_date', NEW.start_date,
|
||||
'end_date', NEW.end_date
|
||||
)
|
||||
);
|
||||
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$;
|
||||
|
||||
CREATE OR REPLACE TRIGGER trg_courses_audit_on_insert
|
||||
AFTER INSERT ON public.courses
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION public.trg_course_audit_on_insert();
|
||||
|
||||
-- D.2 Events INSERT trigger
|
||||
CREATE OR REPLACE FUNCTION public.trg_event_audit_on_insert()
|
||||
RETURNS trigger
|
||||
LANGUAGE plpgsql
|
||||
SECURITY DEFINER
|
||||
SET search_path = ''
|
||||
AS $$
|
||||
DECLARE
|
||||
v_user_id uuid;
|
||||
BEGIN
|
||||
v_user_id := COALESCE(
|
||||
NULLIF(current_setting('app.current_user_id', true), '')::uuid,
|
||||
NEW.created_by
|
||||
);
|
||||
|
||||
INSERT INTO public.event_audit_log (event_id, account_id, user_id, action, metadata)
|
||||
VALUES (
|
||||
NEW.id, NEW.account_id, v_user_id, 'created',
|
||||
jsonb_build_object(
|
||||
'name', NEW.name,
|
||||
'status', NEW.status,
|
||||
'event_date', NEW.event_date,
|
||||
'location', NEW.location,
|
||||
'capacity', NEW.capacity,
|
||||
'fee', NEW.fee
|
||||
)
|
||||
);
|
||||
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$;
|
||||
|
||||
CREATE OR REPLACE TRIGGER trg_events_audit_on_insert
|
||||
AFTER INSERT ON public.events
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION public.trg_event_audit_on_insert();
|
||||
|
||||
-- D.3 Bookings INSERT trigger
|
||||
CREATE OR REPLACE FUNCTION public.trg_booking_audit_on_insert()
|
||||
RETURNS trigger
|
||||
LANGUAGE plpgsql
|
||||
SECURITY DEFINER
|
||||
SET search_path = ''
|
||||
AS $$
|
||||
DECLARE
|
||||
v_user_id uuid;
|
||||
BEGIN
|
||||
v_user_id := COALESCE(
|
||||
NULLIF(current_setting('app.current_user_id', true), '')::uuid,
|
||||
NEW.created_by
|
||||
);
|
||||
|
||||
INSERT INTO public.booking_audit_log (booking_id, account_id, user_id, action, metadata)
|
||||
VALUES (
|
||||
NEW.id, NEW.account_id, v_user_id, 'created',
|
||||
jsonb_build_object(
|
||||
'room_id', NEW.room_id,
|
||||
'guest_id', NEW.guest_id,
|
||||
'check_in', NEW.check_in,
|
||||
'check_out', NEW.check_out,
|
||||
'status', NEW.status,
|
||||
'total_price', NEW.total_price,
|
||||
'adults', NEW.adults,
|
||||
'children', NEW.children
|
||||
)
|
||||
);
|
||||
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$;
|
||||
|
||||
CREATE OR REPLACE TRIGGER trg_bookings_audit_on_insert
|
||||
AFTER INSERT ON public.bookings
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION public.trg_booking_audit_on_insert();
|
||||
Reference in New Issue
Block a user