br-office-suite/database/migrations/003_triggers_views_and_helpers.sql
2026-05-10 10:46:05 +02:00

90 lines
3.7 KiB
PL/PgSQL

CREATE OR REPLACE FUNCTION set_updated_at() RETURNS trigger AS $$
BEGIN
NEW.updated_at = NOW();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_trigger WHERE tgname = 'trg_case_updated_at') THEN
CREATE TRIGGER trg_case_updated_at BEFORE UPDATE ON br_case FOR EACH ROW EXECUTE FUNCTION set_updated_at();
CREATE TRIGGER trg_deadline_updated_at BEFORE UPDATE ON deadline FOR EACH ROW EXECUTE FUNCTION set_updated_at();
CREATE TRIGGER trg_meeting_updated_at BEFORE UPDATE ON meeting FOR EACH ROW EXECUTE FUNCTION set_updated_at();
CREATE TRIGGER trg_decision_updated_at BEFORE UPDATE ON decision FOR EACH ROW EXECUTE FUNCTION set_updated_at();
CREATE TRIGGER trg_task_updated_at BEFORE UPDATE ON task FOR EACH ROW EXECUTE FUNCTION set_updated_at();
CREATE TRIGGER trg_document_updated_at BEFORE UPDATE ON document_item FOR EACH ROW EXECUTE FUNCTION set_updated_at();
CREATE TRIGGER trg_template_updated_at BEFORE UPDATE ON template_item FOR EACH ROW EXECUTE FUNCTION set_updated_at();
END IF;
END $$;
CREATE OR REPLACE FUNCTION audit_if_changed() RETURNS trigger AS $$
BEGIN
INSERT INTO audit_log(actor_user_id, action, entity_type, entity_id, metadata)
VALUES (
NULL,
TG_OP,
TG_TABLE_NAME,
COALESCE(NEW.id, OLD.id),
jsonb_build_object('old', to_jsonb(OLD), 'new', to_jsonb(NEW))
);
RETURN COALESCE(NEW, OLD);
END;
$$ LANGUAGE plpgsql;
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_trigger WHERE tgname = 'trg_audit_case') THEN
CREATE TRIGGER trg_audit_case AFTER INSERT OR UPDATE OR DELETE ON br_case FOR EACH ROW EXECUTE FUNCTION audit_if_changed();
CREATE TRIGGER trg_audit_deadline AFTER INSERT OR UPDATE OR DELETE ON deadline FOR EACH ROW EXECUTE FUNCTION audit_if_changed();
CREATE TRIGGER trg_audit_meeting AFTER INSERT OR UPDATE OR DELETE ON meeting FOR EACH ROW EXECUTE FUNCTION audit_if_changed();
CREATE TRIGGER trg_audit_decision AFTER INSERT OR UPDATE OR DELETE ON decision FOR EACH ROW EXECUTE FUNCTION audit_if_changed();
CREATE TRIGGER trg_audit_task AFTER INSERT OR UPDATE OR DELETE ON task FOR EACH ROW EXECUTE FUNCTION audit_if_changed();
CREATE TRIGGER trg_audit_document AFTER INSERT OR UPDATE OR DELETE ON document_item FOR EACH ROW EXECUTE FUNCTION audit_if_changed();
END IF;
END $$;
CREATE OR REPLACE FUNCTION app_user_id() RETURNS BIGINT AS $$
SELECT COALESCE(NULLIF(current_setting('app.user_id', true), ''), '0')::BIGINT;
$$ LANGUAGE SQL STABLE;
CREATE OR REPLACE FUNCTION app_role() RETURNS TEXT AS $$
SELECT COALESCE(NULLIF(current_setting('app.user_role', true), ''), 'anonymous');
$$ LANGUAGE SQL STABLE;
CREATE OR REPLACE FUNCTION app_committee_id() RETURNS BIGINT AS $$
SELECT COALESCE(NULLIF(current_setting('app.committee_id', true), ''), '0')::BIGINT;
$$ LANGUAGE SQL STABLE;
CREATE OR REPLACE FUNCTION can_read_conf_level(level conf_level, owner BIGINT, committee BIGINT) RETURNS BOOLEAN AS $$
BEGIN
IF app_role() = 'admin' THEN RETURN TRUE; END IF;
IF level = 'intern' THEN RETURN TRUE; END IF;
IF level = 'vertraulich' THEN
RETURN owner = app_user_id() OR committee = app_committee_id() OR app_role() IN ('chair','secretary');
END IF;
RETURN owner = app_user_id() OR app_role() IN ('chair');
END;
$$ LANGUAGE plpgsql STABLE;
CREATE OR REPLACE VIEW v_case_masked AS
SELECT
id,
case_number,
title,
case_type,
status,
priority,
confidentiality_level,
CASE
WHEN confidentiality_level = 'streng_vertraulich' AND app_role() NOT IN ('admin','chair') AND owner_user_id <> app_user_id()
THEN '***'
ELSE COALESCE(affected_employee_name, '')
END AS affected_employee_name_masked,
department,
committee_id,
owner_user_id,
created_at
FROM br_case
WHERE deleted_at IS NULL;