123 lines
4.5 KiB
Python
123 lines
4.5 KiB
Python
from django.db import migrations, transaction
|
|
from django.db.utils import InternalError, OperationalError, ProgrammingError
|
|
|
|
sql_forwards = """
|
|
-- Add technical columns
|
|
ALTER TABLE agendas_event ADD COLUMN _end_datetime TIMESTAMP WITH TIME ZONE;
|
|
ALTER TABLE agendas_event ADD COLUMN _ignore_reason CHARACTER VARYING(20);
|
|
|
|
-- trigger and procedure to maintain _ignore_reason from bookings
|
|
CREATE OR REPLACE FUNCTION set_ignore_reason() RETURNS TRIGGER AS $$
|
|
BEGIN
|
|
IF (TG_OP = 'INSERT') THEN
|
|
IF NEW.cancellation_datetime IS NOT NULL THEN
|
|
UPDATE agendas_event SET _ignore_reason = 'cancel' WHERE id = NEW.event_id;
|
|
END IF;
|
|
RETURN NEW;
|
|
ELSE
|
|
PERFORM 1 FROM agendas_booking b WHERE b.event_id = OLD.event_id AND b.cancellation_datetime IS NOT NULL;
|
|
IF FOUND THEN
|
|
UPDATE agendas_event SET _ignore_reason = 'cancel' WHERE id = OLD.event_id;
|
|
ELSE
|
|
UPDATE agendas_event SET _ignore_reason = NULL WHERE id = OLD.event_id;
|
|
END IF;
|
|
IF (TG_OP = 'UPDATE') THEN
|
|
RETURN NEW;
|
|
ELSE
|
|
RETURN OLD;
|
|
END IF;
|
|
END IF;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
DROP TRIGGER IF EXISTS set_ignore_reason_trg ON agendas_booking;
|
|
CREATE TRIGGER set_ignore_reason_trg
|
|
AFTER INSERT OR UPDATE OR DELETE ON agendas_booking
|
|
FOR EACH ROW
|
|
EXECUTE PROCEDURE set_ignore_reason();
|
|
|
|
-- triggers to maintain _end_datetime
|
|
CREATE OR REPLACE FUNCTION update_duration() RETURNS TRIGGER AS $$
|
|
BEGIN
|
|
UPDATE agendas_event SET _end_datetime = start_datetime + (NEW.duration ||' minutes')::interval WHERE meeting_type_id = NEW.id;
|
|
RETURN NEW;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
DROP TRIGGER IF EXISTS update_duration_trg ON agendas_meetingtype;
|
|
CREATE TRIGGER update_duration_trg
|
|
AFTER UPDATE ON agendas_meetingtype
|
|
FOR EACH ROW
|
|
WHEN (OLD.duration != NEW.duration)
|
|
EXECUTE PROCEDURE update_duration();
|
|
|
|
CREATE OR REPLACE FUNCTION set_end_datetime() RETURNS TRIGGER AS $$
|
|
BEGIN
|
|
IF NEW.meeting_type_id IS NULL THEN
|
|
NEW._end_datetime = NULL;
|
|
ELSE
|
|
NEW._end_datetime = NEW.start_datetime + ((
|
|
SELECT mt.duration FROM agendas_meetingtype mt WHERE mt.id = NEW.meeting_type_id) ||' minutes')::interval;
|
|
END IF;
|
|
RETURN NEW;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
DROP TRIGGER IF EXISTS set_end_datetime_trg ON agendas_event;
|
|
CREATE TRIGGER set_end_datetime_trg
|
|
BEFORE INSERT OR UPDATE ON agendas_event
|
|
FOR EACH ROW
|
|
EXECUTE PROCEDURE set_end_datetime();
|
|
|
|
-- Init legacy
|
|
UPDATE agendas_event SET _ignore_reason = 'history';
|
|
UPDATE
|
|
agendas_event
|
|
SET
|
|
_end_datetime = agendas_event.start_datetime + (agendas_meetingtype.duration ||' minutes')::interval
|
|
FROM
|
|
agendas_meetingtype
|
|
WHERE
|
|
agendas_meetingtype.id = agendas_event.meeting_type_id;
|
|
"""
|
|
|
|
sql_backwards = """
|
|
DROP TRIGGER IF EXISTS set_ignore_reason_trg ON agendas_booking;
|
|
DROP FUNCTION IF EXISTS set_ignore_reason;
|
|
DROP TRIGGER IF EXISTS update_duration_trg ON agendas_meetingtype;
|
|
DROP FUNCTION IF EXISTS update_duration;
|
|
DROP TRIGGER IF EXISTS set_end_datetime_trg ON agendas_event;
|
|
DROP FUNCTION IF EXISTS set_end_datetime;
|
|
ALTER TABLE agendas_event DROP COLUMN _end_datetime;
|
|
ALTER TABLE agendas_event DROP COLUMN _ignore_reason;
|
|
"""
|
|
|
|
|
|
class Migration(migrations.Migration):
|
|
|
|
dependencies = [
|
|
('agendas', '0051_default_view'),
|
|
]
|
|
|
|
operations = [migrations.RunSQL(sql=sql_forwards, reverse_sql=sql_backwards)]
|
|
|
|
def _check_db(self, project_state, schema_editor):
|
|
try:
|
|
with transaction.atomic():
|
|
try:
|
|
# will fail if extension does not exist and can not be created
|
|
schema_editor.execute('CREATE EXTENSION IF NOT EXISTS btree_Gist SCHEMA public')
|
|
except (OperationalError, ProgrammingError):
|
|
# if no extension, do not create columns and triggers
|
|
return project_state
|
|
except InternalError:
|
|
return project_state
|
|
|
|
def apply(self, project_state, schema_editor, *args, **kwargs):
|
|
result = self._check_db(project_state, schema_editor)
|
|
return result or super().apply(project_state, schema_editor, *args, **kwargs)
|
|
|
|
def unapply(self, project_state, schema_editor, *args, **kwargs):
|
|
result = self._check_db(project_state, schema_editor)
|
|
return result or super().unapply(project_state, schema_editor, *args, **kwargs)
|