diff --git a/lib/hawat/migrations/versions/4a172cd00ef0_clean_mail_to_and_add_not_null_.py b/lib/hawat/migrations/versions/4a172cd00ef0_clean_mail_to_and_add_not_null_.py new file mode 100644 index 0000000000000000000000000000000000000000..eb717f6aee3834cf1ea842a117ef0f5226329514 --- /dev/null +++ b/lib/hawat/migrations/versions/4a172cd00ef0_clean_mail_to_and_add_not_null_.py @@ -0,0 +1,96 @@ +"""Clean mail_to, emails and add not null constraints + +Revision ID: 4a172cd00ef0 +Revises: c2b4c2af6196 +Create Date: 2021-07-20 10:46:04.138409 + +""" +from alembic import op + + +# revision identifiers, used by Alembic. +revision = '4a172cd00ef0' +down_revision = 'c2b4c2af6196' +branch_labels = None +depends_on = None + + +def upgrade(): + op.execute( + """CREATE OR REPLACE FUNCTION alembic_4a172cd00ef0_trim_array(character varying[]) + RETURNS character varying[] + AS + $$ + DECLARE + arr ALIAS FOR $1; + element character varying; + retVal character varying[]; + BEGIN + FOREACH element IN ARRAY arr + LOOP + retVal := array_append(retVal, trim(element)::varchar); + END LOOP; + RETURN retVal; + END; + $$ + LANGUAGE plpgsql + STABLE + RETURNS NULL ON NULL INPUT;""" + ) + op.execute( + """CREATE OR REPLACE FUNCTION alembic_4a172cd00ef0_split_strings(character varying[]) + RETURNS character varying[] + AS + $$ + DECLARE + arr ALIAS FOR $1; + element character varying; + retVal character varying[]; + BEGIN + FOREACH element IN ARRAY arr + LOOP + retVal := retVal || alembic_4a172cd00ef0_trim_array(string_to_array(element, ',')::varchar[]); + END LOOP; + RETURN retVal; + END; + $$ + LANGUAGE plpgsql + STABLE + RETURNS NULL ON NULL INPUT;""" + ) + + op.execute( + "UPDATE reports_events SET mail_to = alembic_4a172cd00ef0_trim_array(mail_to)" + ) + op.execute( + "UPDATE reports_events SET mail_to = ARRAY[]::varchar[] WHERE mail_to IS NULL OR mail_to = '{None}'" + ) + op.execute( + "ALTER TABLE reports_events ALTER COLUMN mail_to SET NOT NULL" + ) + + op.execute( + "UPDATE settings_reporting SET emails = alembic_4a172cd00ef0_split_strings(emails)" + ) + op.execute( + "UPDATE settings_reporting SET emails = ARRAY[]::varchar[] WHERE emails IS NULL" + ) + op.execute( + "ALTER TABLE settings_reporting ALTER COLUMN emails SET NOT NULL" + ) + + op.execute( + "DROP FUNCTION alembic_4a172cd00ef0_split_strings(character varying[])" + ) + op.execute( + "DROP FUNCTION alembic_4a172cd00ef0_trim_array(character varying[])" + ) + + +def downgrade(): + op.execute( + "ALTER TABLE reports_events ALTER COLUMN mail_to DROP NOT NULL" + ) + op.execute( + "ALTER TABLE settings_reporting ALTER COLUMN emails DROP NOT NULL" + ) diff --git a/lib/mentat/datatype/sqldb.py b/lib/mentat/datatype/sqldb.py index f1d3ef6e3493b0639d0043cdf97b08e900808a01..edd2c8fc7b9755bfc978ac6c56ff8c9dff5427f3 100644 --- a/lib/mentat/datatype/sqldb.py +++ b/lib/mentat/datatype/sqldb.py @@ -585,7 +585,7 @@ class SettingsReportingModel(MODEL): # pylint: disable=locally-disabled,too-few group_id = sqlalchemy.Column(sqlalchemy.Integer, sqlalchemy.ForeignKey('groups.id', onupdate = "CASCADE", ondelete = "CASCADE"), nullable = False) group = sqlalchemy.orm.relationship('GroupModel', back_populates = 'settings_rep') - emails = sqlalchemy.Column(sqlalchemy.dialects.postgresql.ARRAY(sqlalchemy.String, dimensions = 1)) + emails = sqlalchemy.Column(sqlalchemy.dialects.postgresql.ARRAY(sqlalchemy.String, dimensions = 1), default = [], nullable = False) mode = sqlalchemy.Column(sqlalchemy.Enum(*REPORTING_MODES, name='reporting_modes')) locale = sqlalchemy.Column(sqlalchemy.String) timezone = sqlalchemy.Column(sqlalchemy.String) @@ -603,7 +603,7 @@ class SettingsReportingModel(MODEL): # pylint: disable=locally-disabled,too-few 'id': int(self.id), 'createtime': str(self.createtime), 'group': str(self.group), - 'emails': [str(x) for x in self.emails] if self.emails is not None else None, + 'emails': [str(x) for x in self.emails], 'mode': str(self.mode) if self.mode is not None else None, 'locale': str(self.locale) if self.locale is not None else None, 'timezone': str(self.timezone) if self.timezone is not None else None, @@ -619,7 +619,7 @@ def setrepmodel_from_typeddict(structure, defaults = None): defaults = {} sqlobj = SettingsReportingModel() - sqlobj.emails = structure.get('rep_emails', None) + sqlobj.emails = structure.get('rep_emails', []) sqlobj.mode = structure.get('rep_mode', None) sqlobj.redirect = structure.get('rep_redirect', None) @@ -759,7 +759,7 @@ class EventReportModel(MODEL): # Number of relapsed events. evcount_rlp = sqlalchemy.Column(sqlalchemy.Integer) - mail_to = sqlalchemy.Column(sqlalchemy.dialects.postgresql.ARRAY(sqlalchemy.String, dimensions = 1)) + mail_to = sqlalchemy.Column(sqlalchemy.dialects.postgresql.ARRAY(sqlalchemy.String, dimensions = 1), default = [], nullable = False) mail_dt = sqlalchemy.Column(sqlalchemy.DateTime) mail_res = sqlalchemy.Column(sqlalchemy.String)