diff --git a/pyproject.toml b/pyproject.toml index bc2bc57..bd8ba11 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -63,9 +63,6 @@ markers = [ line-length = 120 indent-width = 4 target-version = "py313" -exclude = [ - "src/alembic/*" -] [tool.ruff.format] quote-style = "double" diff --git a/src/alembic/env.py b/src/alembic/env.py index d3280c0..f69d90c 100644 --- a/src/alembic/env.py +++ b/src/alembic/env.py @@ -12,10 +12,10 @@ import elections.tables import event.tables import honorary.tables +import image_asset.tables import nominees.tables import officers.tables import translink.tables -import image_asset.tables from alembic import context # this is the Alembic Config object, which provides diff --git a/src/alembic/versions/00b56b264c3c_add_names_to_site_users.py b/src/alembic/versions/00b56b264c3c_add_names_to_site_users.py index cca2c5b..66e29d5 100644 --- a/src/alembic/versions/00b56b264c3c_add_names_to_site_users.py +++ b/src/alembic/versions/00b56b264c3c_add_names_to_site_users.py @@ -5,30 +5,31 @@ Create Date: 2026-10-12 21:23:27.758870 """ -from typing import Sequence -from alembic import op +from collections.abc import Sequence + import sqlalchemy as sa +from alembic import op # revision identifiers, used by Alembic. -revision: str = '00b56b264c3c' -down_revision: str | None= 'd9a62b4f013e' +revision: str = "00b56b264c3c" +down_revision: str | None = "d9a62b4f013e" branch_labels: str | Sequence[str] | None = None depends_on: str | Sequence[str] | None = None def upgrade() -> None: # ### commands auto generated by Alembic - please adjust! ### - op.add_column('site_user', sa.Column('first_name', sa.String(length=64), nullable=True)) - op.add_column('site_user', sa.Column('last_name', sa.String(length=64), nullable=True)) - op.add_column('site_user', sa.Column('preferred_name', sa.String(length=64), nullable=True)) + op.add_column("site_user", sa.Column("first_name", sa.String(length=64), nullable=True)) + op.add_column("site_user", sa.Column("last_name", sa.String(length=64), nullable=True)) + op.add_column("site_user", sa.Column("preferred_name", sa.String(length=64), nullable=True)) # ### end Alembic commands ### def downgrade() -> None: # ### commands auto generated by Alembic - please adjust! ### - op.drop_column('site_user', 'preferred_name') - op.drop_column('site_user', 'last_name') - op.drop_column('site_user', 'first_name') + op.drop_column("site_user", "preferred_name") + op.drop_column("site_user", "last_name") + op.drop_column("site_user", "first_name") # ### end Alembic commands ### diff --git a/src/alembic/versions/2cf2279e48ef_initial_schema.py b/src/alembic/versions/2cf2279e48ef_initial_schema.py index 1c9cf90..ccb8219 100644 --- a/src/alembic/versions/2cf2279e48ef_initial_schema.py +++ b/src/alembic/versions/2cf2279e48ef_initial_schema.py @@ -5,202 +5,330 @@ Create Date: 2026-10-03 18:15:06.047418 """ -from typing import Sequence -from alembic import op +from collections.abc import Sequence + import sqlalchemy as sa from sqlalchemy.dialects import postgresql + import utils.types +from alembic import op # revision identifiers, used by Alembic. -revision: str = '2cf2279e48ef' -down_revision: str | None= None +revision: str = "2cf2279e48ef" +down_revision: str | None = None branch_labels: str | Sequence[str] | None = None depends_on: str | Sequence[str] | None = None def upgrade() -> None: # ### commands auto generated by Alembic - please adjust! ### - op.execute('CREATE EXTENSION IF NOT EXISTS btree_gist') - op.create_table('auth_redirect', - sa.Column('id', sa.String(length=43), nullable=False), - sa.Column('return_to', sa.Text(), nullable=False), - sa.Column('expires_at', sa.DateTime(timezone=True), nullable=False), - sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False), - sa.PrimaryKeyConstraint('id', name=op.f('pk_auth_redirect')) + op.execute("CREATE EXTENSION IF NOT EXISTS btree_gist") + op.create_table( + "auth_redirect", + sa.Column("id", sa.String(length=43), nullable=False), + sa.Column("return_to", sa.Text(), nullable=False), + sa.Column("expires_at", sa.DateTime(timezone=True), nullable=False), + sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False), + sa.PrimaryKeyConstraint("id", name=op.f("pk_auth_redirect")), ) - op.create_table('election', - sa.Column('slug', sa.String(length=64), nullable=False), - sa.Column('name', sa.String(length=64), nullable=False), - sa.Column('type', sa.String(length=32), nullable=False), - sa.Column('datetime_start_nominations', sa.DateTime(timezone=True), nullable=False), - sa.Column('datetime_start_voting', sa.DateTime(timezone=True), nullable=False), - sa.Column('datetime_end_voting', sa.DateTime(timezone=True), nullable=False), - sa.Column('available_positions', utils.types.StringList(), nullable=False), - sa.Column('survey_link', sa.String(length=300), nullable=True), - sa.PrimaryKeyConstraint('slug', name=op.f('pk_election')) + op.create_table( + "election", + sa.Column("slug", sa.String(length=64), nullable=False), + sa.Column("name", sa.String(length=64), nullable=False), + sa.Column("type", sa.String(length=32), nullable=False), + sa.Column("datetime_start_nominations", sa.DateTime(timezone=True), nullable=False), + sa.Column("datetime_start_voting", sa.DateTime(timezone=True), nullable=False), + sa.Column("datetime_end_voting", sa.DateTime(timezone=True), nullable=False), + sa.Column("available_positions", utils.types.StringList(), nullable=False), + sa.Column("survey_link", sa.String(length=300), nullable=True), + sa.PrimaryKeyConstraint("slug", name=op.f("pk_election")), ) - op.create_table('election_nominee_info', - sa.Column('computing_id', sa.String(length=16), nullable=False), - sa.Column('full_name', sa.String(length=64), nullable=False), - sa.Column('linked_in', sa.String(length=128), nullable=True), - sa.Column('instagram', sa.String(length=128), nullable=True), - sa.Column('email', sa.String(length=64), nullable=True), - sa.Column('discord_username', sa.String(length=32), nullable=True), - sa.CheckConstraint("computing_id ~ '^[a-z0-9]+$' AND computing_id = lower(computing_id)", name=op.f('ck_election_nominee_info_computing_id_format')), - sa.PrimaryKeyConstraint('computing_id', name=op.f('pk_election_nominee_info')) + op.create_table( + "election_nominee_info", + sa.Column("computing_id", sa.String(length=16), nullable=False), + sa.Column("full_name", sa.String(length=64), nullable=False), + sa.Column("linked_in", sa.String(length=128), nullable=True), + sa.Column("instagram", sa.String(length=128), nullable=True), + sa.Column("email", sa.String(length=64), nullable=True), + sa.Column("discord_username", sa.String(length=32), nullable=True), + sa.CheckConstraint( + "computing_id ~ '^[a-z0-9]+$' AND computing_id = lower(computing_id)", + name=op.f("ck_election_nominee_info_computing_id_format"), + ), + sa.PrimaryKeyConstraint("computing_id", name=op.f("pk_election_nominee_info")), ) - op.create_table('honorary_member', - sa.Column('id', sa.Integer(), autoincrement=True, nullable=False), - sa.Column('name', sa.String(length=128), nullable=False), - sa.Column('start_date', sa.Date(), nullable=False), - sa.Column('end_date', sa.Date(), nullable=True), - sa.PrimaryKeyConstraint('id', name=op.f('pk_honorary_member')) + op.create_table( + "honorary_member", + sa.Column("id", sa.Integer(), autoincrement=True, nullable=False), + sa.Column("name", sa.String(length=128), nullable=False), + sa.Column("start_date", sa.Date(), nullable=False), + sa.Column("end_date", sa.Date(), nullable=True), + sa.PrimaryKeyConstraint("id", name=op.f("pk_honorary_member")), ) - op.create_table('image_asset', - sa.Column('image_id', sa.Integer(), autoincrement=True, nullable=False), - sa.Column('storage_key', sa.Text(), nullable=False), - sa.Column('original_filename', sa.Text(), nullable=False), - sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False), - sa.PrimaryKeyConstraint('image_id', name=op.f('pk_image_asset')), - sa.UniqueConstraint('storage_key', name=op.f('uq_image_asset_storage_key')) + op.create_table( + "image_asset", + sa.Column("image_id", sa.Integer(), autoincrement=True, nullable=False), + sa.Column("storage_key", sa.Text(), nullable=False), + sa.Column("original_filename", sa.Text(), nullable=False), + sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False), + sa.PrimaryKeyConstraint("image_id", name=op.f("pk_image_asset")), + sa.UniqueConstraint("storage_key", name=op.f("uq_image_asset_storage_key")), ) - op.create_table('officer_position', - sa.Column('id', sa.Integer(), autoincrement=True, nullable=False), - sa.Column('position', sa.String(length=64), nullable=False), - sa.CheckConstraint("position IS NOT NULL AND btrim(position) <> ''", name=op.f('ck_officer_position_position_not_blank')), - sa.PrimaryKeyConstraint('id', name=op.f('pk_officer_position')), - sa.UniqueConstraint('position', name=op.f('uq_officer_position_position')) + op.create_table( + "officer_position", + sa.Column("id", sa.Integer(), autoincrement=True, nullable=False), + sa.Column("position", sa.String(length=64), nullable=False), + sa.CheckConstraint( + "position IS NOT NULL AND btrim(position) <> ''", name=op.f("ck_officer_position_position_not_blank") + ), + sa.PrimaryKeyConstraint("id", name=op.f("pk_officer_position")), + sa.UniqueConstraint("position", name=op.f("uq_officer_position_position")), ) - op.create_table('site_user', - sa.Column('computing_id', sa.String(length=16), nullable=False), - sa.Column('first_logged_in', sa.DateTime(timezone=True), nullable=True), - sa.Column('last_logged_in', sa.DateTime(timezone=True), nullable=True), - sa.CheckConstraint("computing_id ~ '^[a-z0-9]+$' AND computing_id = lower(computing_id)", name=op.f('ck_site_user_computing_id_format')), - sa.PrimaryKeyConstraint('computing_id', name=op.f('pk_site_user')) + op.create_table( + "site_user", + sa.Column("computing_id", sa.String(length=16), nullable=False), + sa.Column("first_logged_in", sa.DateTime(timezone=True), nullable=True), + sa.Column("last_logged_in", sa.DateTime(timezone=True), nullable=True), + sa.CheckConstraint( + "computing_id ~ '^[a-z0-9]+$' AND computing_id = lower(computing_id)", + name=op.f("ck_site_user_computing_id_format"), + ), + sa.PrimaryKeyConstraint("computing_id", name=op.f("pk_site_user")), ) - op.create_table('translink_realtime_cache', - sa.Column('id', sa.Integer(), nullable=False), - sa.Column('fetched_at', sa.DateTime(timezone=True), nullable=False), - sa.Column('response_bytes', sa.LargeBinary(), nullable=False), - sa.PrimaryKeyConstraint('id', name=op.f('pk_translink_realtime_cache')) + op.create_table( + "translink_realtime_cache", + sa.Column("id", sa.Integer(), nullable=False), + sa.Column("fetched_at", sa.DateTime(timezone=True), nullable=False), + sa.Column("response_bytes", sa.LargeBinary(), nullable=False), + sa.PrimaryKeyConstraint("id", name=op.f("pk_translink_realtime_cache")), ) - op.create_table('translink_static_schedule', - sa.Column('id', sa.Integer(), nullable=False), - sa.Column('date_fetched', sa.Date(), nullable=False), - sa.Column('schedule', postgresql.JSONB(astext_type=sa.Text()), nullable=False), - sa.PrimaryKeyConstraint('id', name=op.f('pk_translink_static_schedule')) + op.create_table( + "translink_static_schedule", + sa.Column("id", sa.Integer(), nullable=False), + sa.Column("date_fetched", sa.Date(), nullable=False), + sa.Column("schedule", postgresql.JSONB(astext_type=sa.Text()), nullable=False), + sa.PrimaryKeyConstraint("id", name=op.f("pk_translink_static_schedule")), ) - op.create_table('election_nominee_application', - sa.Column('computing_id', sa.String(length=16), nullable=False), - sa.Column('nominee_election', sa.String(length=64), nullable=False), - sa.Column('position', sa.String(length=64), nullable=False), - sa.Column('speech', sa.Text(), nullable=True), - sa.CheckConstraint("computing_id ~ '^[a-z0-9]+$' AND computing_id = lower(computing_id)", name=op.f('ck_election_nominee_application_computing_id_format')), - sa.ForeignKeyConstraint(['computing_id'], ['election_nominee_info.computing_id'], name=op.f('fk_election_nominee_application_computing_id_election_nominee_info')), - sa.ForeignKeyConstraint(['nominee_election'], ['election.slug'], name=op.f('fk_election_nominee_application_nominee_election_election')), - sa.PrimaryKeyConstraint('computing_id', 'nominee_election', 'position', name=op.f('pk_election_nominee_application')) + op.create_table( + "election_nominee_application", + sa.Column("computing_id", sa.String(length=16), nullable=False), + sa.Column("nominee_election", sa.String(length=64), nullable=False), + sa.Column("position", sa.String(length=64), nullable=False), + sa.Column("speech", sa.Text(), nullable=True), + sa.CheckConstraint( + "computing_id ~ '^[a-z0-9]+$' AND computing_id = lower(computing_id)", + name=op.f("ck_election_nominee_application_computing_id_format"), + ), + sa.ForeignKeyConstraint( + ["computing_id"], + ["election_nominee_info.computing_id"], + name=op.f("fk_election_nominee_application_computing_id_election_nominee_info"), + ), + sa.ForeignKeyConstraint( + ["nominee_election"], + ["election.slug"], + name=op.f("fk_election_nominee_application_nominee_election_election"), + ), + sa.PrimaryKeyConstraint( + "computing_id", "nominee_election", "position", name=op.f("pk_election_nominee_application") + ), ) - op.create_table('event_info', - sa.Column('eid', sa.Integer(), autoincrement=True, nullable=False), - sa.Column('description', sa.Text(), nullable=False), - sa.Column('name', sa.Text(), nullable=False), - sa.Column('start_datetime', sa.DateTime(timezone=True), nullable=False), - sa.Column('end_datetime', sa.DateTime(timezone=True), nullable=False), - sa.Column('group_id', sa.Uuid(), nullable=True), - sa.Column('location', sa.Text(), nullable=True), - sa.Column('organizer', sa.Text(), nullable=True), - sa.Column('status', sa.Enum('cancelled', 'scheduled', name='valid_status', native_enum=False, create_constraint=True), nullable=False), - sa.Column('url', sa.Text(), nullable=True), - sa.Column('image_id', sa.Integer(), nullable=True), - sa.CheckConstraint('start_datetime <= end_datetime', name=op.f('ck_event_info_check_start_datetime_before_end_datetime')), - sa.ForeignKeyConstraint(['image_id'], ['image_asset.image_id'], name=op.f('fk_event_info_image_id_image_asset')), - sa.PrimaryKeyConstraint('eid', name=op.f('pk_event_info')) + op.create_table( + "event_info", + sa.Column("eid", sa.Integer(), autoincrement=True, nullable=False), + sa.Column("description", sa.Text(), nullable=False), + sa.Column("name", sa.Text(), nullable=False), + sa.Column("start_datetime", sa.DateTime(timezone=True), nullable=False), + sa.Column("end_datetime", sa.DateTime(timezone=True), nullable=False), + sa.Column("group_id", sa.Uuid(), nullable=True), + sa.Column("location", sa.Text(), nullable=True), + sa.Column("organizer", sa.Text(), nullable=True), + sa.Column( + "status", + sa.Enum("cancelled", "scheduled", name="valid_status", native_enum=False, create_constraint=True), + nullable=False, + ), + sa.Column("url", sa.Text(), nullable=True), + sa.Column("image_id", sa.Integer(), nullable=True), + sa.CheckConstraint( + "start_datetime <= end_datetime", name=op.f("ck_event_info_check_start_datetime_before_end_datetime") + ), + sa.ForeignKeyConstraint( + ["image_id"], ["image_asset.image_id"], name=op.f("fk_event_info_image_id_image_asset") + ), + sa.PrimaryKeyConstraint("eid", name=op.f("pk_event_info")), ) - op.create_index(op.f('ix_event_info_group_id'), 'event_info', ['group_id'], unique=False) - op.create_table('officer_info', - sa.Column('id', sa.Integer(), autoincrement=True, nullable=False), - sa.Column('computing_id', sa.String(length=16), nullable=True), - sa.Column('legal_name', sa.String(length=128), nullable=False), - sa.Column('preferred_name', sa.String(length=128), nullable=True), - sa.Column('phone_number', sa.String(length=30), nullable=True), - sa.Column('discord_id', sa.String(length=32), nullable=True), - sa.Column('google_drive_email', sa.String(length=256), nullable=True), - sa.Column('github_username', sa.String(length=39), nullable=True), - sa.CheckConstraint("computing_id IS NULL OR (computing_id ~ '^[a-z0-9]+$' AND computing_id = lower(computing_id))", name=op.f('ck_officer_info_computing_id_format')), - sa.CheckConstraint("legal_name IS NOT NULL AND btrim(legal_name) <> ''", name=op.f('ck_officer_info_legal_name_not_blank')), - sa.ForeignKeyConstraint(['computing_id'], ['site_user.computing_id'], name=op.f('fk_officer_info_computing_id_site_user'), ondelete='SET NULL'), - sa.PrimaryKeyConstraint('id', name=op.f('pk_officer_info')), - sa.UniqueConstraint('computing_id', name=op.f('uq_officer_info_computing_id')), - sa.UniqueConstraint('discord_id', name=op.f('uq_officer_info_discord_id')) + op.create_index(op.f("ix_event_info_group_id"), "event_info", ["group_id"], unique=False) + op.create_table( + "officer_info", + sa.Column("id", sa.Integer(), autoincrement=True, nullable=False), + sa.Column("computing_id", sa.String(length=16), nullable=True), + sa.Column("legal_name", sa.String(length=128), nullable=False), + sa.Column("preferred_name", sa.String(length=128), nullable=True), + sa.Column("phone_number", sa.String(length=30), nullable=True), + sa.Column("discord_id", sa.String(length=32), nullable=True), + sa.Column("google_drive_email", sa.String(length=256), nullable=True), + sa.Column("github_username", sa.String(length=39), nullable=True), + sa.CheckConstraint( + "computing_id IS NULL OR (computing_id ~ '^[a-z0-9]+$' AND computing_id = lower(computing_id))", + name=op.f("ck_officer_info_computing_id_format"), + ), + sa.CheckConstraint( + "legal_name IS NOT NULL AND btrim(legal_name) <> ''", name=op.f("ck_officer_info_legal_name_not_blank") + ), + sa.ForeignKeyConstraint( + ["computing_id"], + ["site_user.computing_id"], + name=op.f("fk_officer_info_computing_id_site_user"), + ondelete="SET NULL", + ), + sa.PrimaryKeyConstraint("id", name=op.f("pk_officer_info")), + sa.UniqueConstraint("computing_id", name=op.f("uq_officer_info_computing_id")), + sa.UniqueConstraint("discord_id", name=op.f("uq_officer_info_discord_id")), ) - op.create_table('officer_position_version', - sa.Column('id', sa.Integer(), autoincrement=True, nullable=False), - sa.Column('position_id', sa.Integer(), nullable=False), - sa.Column('type', sa.Enum('executive', 'appointed_representative', 'elected_representative', name='type_valid', native_enum=False, create_constraint=True), nullable=False), - sa.Column('multiple_allowed', sa.Boolean(), nullable=True), - sa.Column('effective_from', sa.Date(), nullable=False), - sa.Column('effective_to', sa.Date(), nullable=True), - postgresql.ExcludeConstraint((sa.column('position_id'), '='), (sa.func.daterange(sa.column('effective_from'), sa.column('effective_to'), '[]'), '&&'), using='gist', name='no_overlapping_versions'), - sa.CheckConstraint("CASE WHEN type = 'executive' THEN multiple_allowed IS NOT NULL WHEN type IN ('elected_representative', 'appointed_representative') THEN multiple_allowed IS NULL ELSE FALSE END", name=op.f('ck_officer_position_version_multiple_allowed_by_type')), - sa.CheckConstraint('effective_to IS NULL OR effective_to >= effective_from', name=op.f('ck_officer_position_version_effective_end_after_start')), - sa.ForeignKeyConstraint(['position_id'], ['officer_position.id'], name=op.f('fk_officer_position_version_position_id_officer_position')), - sa.PrimaryKeyConstraint('id', name=op.f('pk_officer_position_version')) + op.create_table( + "officer_position_version", + sa.Column("id", sa.Integer(), autoincrement=True, nullable=False), + sa.Column("position_id", sa.Integer(), nullable=False), + sa.Column( + "type", + sa.Enum( + "executive", + "appointed_representative", + "elected_representative", + name="type_valid", + native_enum=False, + create_constraint=True, + ), + nullable=False, + ), + sa.Column("multiple_allowed", sa.Boolean(), nullable=True), + sa.Column("effective_from", sa.Date(), nullable=False), + sa.Column("effective_to", sa.Date(), nullable=True), + postgresql.ExcludeConstraint( + (sa.column("position_id"), "="), + (sa.func.daterange(sa.column("effective_from"), sa.column("effective_to"), "[]"), "&&"), + using="gist", + name="no_overlapping_versions", + ), + sa.CheckConstraint( + "CASE WHEN type = 'executive' THEN multiple_allowed IS NOT NULL WHEN type IN ('elected_representative', 'appointed_representative') THEN multiple_allowed IS NULL ELSE FALSE END", + name=op.f("ck_officer_position_version_multiple_allowed_by_type"), + ), + sa.CheckConstraint( + "effective_to IS NULL OR effective_to >= effective_from", + name=op.f("ck_officer_position_version_effective_end_after_start"), + ), + sa.ForeignKeyConstraint( + ["position_id"], + ["officer_position.id"], + name=op.f("fk_officer_position_version_position_id_officer_position"), + ), + sa.PrimaryKeyConstraint("id", name=op.f("pk_officer_position_version")), ) - op.create_table('site_user_role', - sa.Column('computing_id', sa.String(length=16), nullable=False), - sa.Column('role', sa.Enum('access', 'admin', 'exec', 'officer', 'user', 'event', 'election', name='role_valid', native_enum=False, create_constraint=True), nullable=False), - sa.Column('added_by', sa.String(length=16), nullable=True), - sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False), - sa.CheckConstraint("added_by IS NULL OR added_by ~ '^[a-z0-9]+$'", name=op.f('ck_site_user_role_added_by_format')), - sa.CheckConstraint("computing_id ~ '^[a-z0-9]+$' AND computing_id = lower(computing_id)", name=op.f('ck_site_user_role_computing_id_format')), - sa.ForeignKeyConstraint(['added_by'], ['site_user.computing_id'], name=op.f('fk_site_user_role_added_by_site_user'), ondelete='SET NULL'), - sa.ForeignKeyConstraint(['computing_id'], ['site_user.computing_id'], name=op.f('fk_site_user_role_computing_id_site_user')), - sa.PrimaryKeyConstraint('computing_id', 'role', name=op.f('pk_site_user_role')) + op.create_table( + "site_user_role", + sa.Column("computing_id", sa.String(length=16), nullable=False), + sa.Column( + "role", + sa.Enum( + "access", + "admin", + "exec", + "officer", + "user", + "event", + "election", + name="role_valid", + native_enum=False, + create_constraint=True, + ), + nullable=False, + ), + sa.Column("added_by", sa.String(length=16), nullable=True), + sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False), + sa.CheckConstraint( + "added_by IS NULL OR added_by ~ '^[a-z0-9]+$'", name=op.f("ck_site_user_role_added_by_format") + ), + sa.CheckConstraint( + "computing_id ~ '^[a-z0-9]+$' AND computing_id = lower(computing_id)", + name=op.f("ck_site_user_role_computing_id_format"), + ), + sa.ForeignKeyConstraint( + ["added_by"], + ["site_user.computing_id"], + name=op.f("fk_site_user_role_added_by_site_user"), + ondelete="SET NULL", + ), + sa.ForeignKeyConstraint( + ["computing_id"], ["site_user.computing_id"], name=op.f("fk_site_user_role_computing_id_site_user") + ), + sa.PrimaryKeyConstraint("computing_id", "role", name=op.f("pk_site_user_role")), ) - op.create_index(op.f('ix_site_user_role_role'), 'site_user_role', ['role'], unique=False) - op.create_table('user_session', - sa.Column('session_hash', sa.LargeBinary(length=32), nullable=False), - sa.Column('computing_id', sa.String(length=16), nullable=False), - sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False), - sa.Column('expires_at', sa.DateTime(timezone=True), nullable=False), - sa.CheckConstraint("computing_id ~ '^[a-z0-9]+$' AND computing_id = lower(computing_id)", name=op.f('ck_user_session_computing_id_format')), - sa.ForeignKeyConstraint(['computing_id'], ['site_user.computing_id'], name=op.f('fk_user_session_computing_id_site_user')), - sa.PrimaryKeyConstraint('session_hash', name=op.f('pk_user_session')) + op.create_index(op.f("ix_site_user_role_role"), "site_user_role", ["role"], unique=False) + op.create_table( + "user_session", + sa.Column("session_hash", sa.LargeBinary(length=32), nullable=False), + sa.Column("computing_id", sa.String(length=16), nullable=False), + sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False), + sa.Column("expires_at", sa.DateTime(timezone=True), nullable=False), + sa.CheckConstraint( + "computing_id ~ '^[a-z0-9]+$' AND computing_id = lower(computing_id)", + name=op.f("ck_user_session_computing_id_format"), + ), + sa.ForeignKeyConstraint( + ["computing_id"], ["site_user.computing_id"], name=op.f("fk_user_session_computing_id_site_user") + ), + sa.PrimaryKeyConstraint("session_hash", name=op.f("pk_user_session")), ) - op.create_index(op.f('ix_user_session_computing_id'), 'user_session', ['computing_id'], unique=False) - op.create_table('blog_posts', - sa.Column('title', sa.String(length=128), nullable=False), - sa.Column('computing_id', sa.String(length=16), nullable=False), - sa.Column('date_created', sa.DateTime(timezone=True), nullable=False), - sa.Column('last_edited', sa.DateTime(timezone=True), nullable=False), - sa.Column('html_content', sa.Text(), nullable=False), - sa.Column('post_tags', sa.String(length=128), nullable=True), - sa.CheckConstraint("computing_id ~ '^[a-z0-9]+$' AND computing_id = lower(computing_id)", name=op.f('ck_blog_posts_computing_id_format')), - sa.ForeignKeyConstraint(['computing_id'], ['officer_info.computing_id'], name=op.f('fk_blog_posts_computing_id_officer_info')), - sa.PrimaryKeyConstraint('title', name=op.f('pk_blog_posts')) + op.create_index(op.f("ix_user_session_computing_id"), "user_session", ["computing_id"], unique=False) + op.create_table( + "blog_posts", + sa.Column("title", sa.String(length=128), nullable=False), + sa.Column("computing_id", sa.String(length=16), nullable=False), + sa.Column("date_created", sa.DateTime(timezone=True), nullable=False), + sa.Column("last_edited", sa.DateTime(timezone=True), nullable=False), + sa.Column("html_content", sa.Text(), nullable=False), + sa.Column("post_tags", sa.String(length=128), nullable=True), + sa.CheckConstraint( + "computing_id ~ '^[a-z0-9]+$' AND computing_id = lower(computing_id)", + name=op.f("ck_blog_posts_computing_id_format"), + ), + sa.ForeignKeyConstraint( + ["computing_id"], ["officer_info.computing_id"], name=op.f("fk_blog_posts_computing_id_officer_info") + ), + sa.PrimaryKeyConstraint("title", name=op.f("pk_blog_posts")), ) - op.create_table('officer_term', - sa.Column('id', sa.Integer(), autoincrement=True, nullable=False), - sa.Column('officer_id', sa.Integer(), nullable=False), - sa.Column('position_version_id', sa.Integer(), nullable=False), - sa.Column('start_date', sa.Date(), nullable=False), - sa.Column('end_date', sa.Date(), nullable=True), - sa.Column('photo_url', sa.Text(), nullable=True), - sa.CheckConstraint('end_date IS NULL OR end_date >= start_date', name=op.f('ck_officer_term_end_after_start')), - sa.ForeignKeyConstraint(['officer_id'], ['officer_info.id'], name=op.f('fk_officer_term_officer_id_officer_info')), - sa.ForeignKeyConstraint(['position_version_id'], ['officer_position_version.id'], name=op.f('fk_officer_term_position_version_id_officer_position_version')), - sa.PrimaryKeyConstraint('id', name=op.f('pk_officer_term')) + op.create_table( + "officer_term", + sa.Column("id", sa.Integer(), autoincrement=True, nullable=False), + sa.Column("officer_id", sa.Integer(), nullable=False), + sa.Column("position_version_id", sa.Integer(), nullable=False), + sa.Column("start_date", sa.Date(), nullable=False), + sa.Column("end_date", sa.Date(), nullable=True), + sa.Column("photo_url", sa.Text(), nullable=True), + sa.CheckConstraint("end_date IS NULL OR end_date >= start_date", name=op.f("ck_officer_term_end_after_start")), + sa.ForeignKeyConstraint( + ["officer_id"], ["officer_info.id"], name=op.f("fk_officer_term_officer_id_officer_info") + ), + sa.ForeignKeyConstraint( + ["position_version_id"], + ["officer_position_version.id"], + name=op.f("fk_officer_term_position_version_id_officer_position_version"), + ), + sa.PrimaryKeyConstraint("id", name=op.f("pk_officer_term")), ) - op.create_table('officer_term_data', - sa.Column('id', sa.Integer(), nullable=False), - sa.Column('favourite_course_0', sa.String(length=16), nullable=True), - sa.Column('favourite_course_1', sa.String(length=16), nullable=True), - sa.Column('favourite_pl_0', sa.String(length=32), nullable=True), - sa.Column('favourite_pl_1', sa.String(length=32), nullable=True), - sa.Column('biography', sa.Text(), nullable=True), - sa.ForeignKeyConstraint(['id'], ['officer_term.id'], name=op.f('fk_officer_term_data_id_officer_term')), - sa.PrimaryKeyConstraint('id', name=op.f('pk_officer_term_data')) + op.create_table( + "officer_term_data", + sa.Column("id", sa.Integer(), nullable=False), + sa.Column("favourite_course_0", sa.String(length=16), nullable=True), + sa.Column("favourite_course_1", sa.String(length=16), nullable=True), + sa.Column("favourite_pl_0", sa.String(length=32), nullable=True), + sa.Column("favourite_pl_1", sa.String(length=32), nullable=True), + sa.Column("biography", sa.Text(), nullable=True), + sa.ForeignKeyConstraint(["id"], ["officer_term.id"], name=op.f("fk_officer_term_data_id_officer_term")), + sa.PrimaryKeyConstraint("id", name=op.f("pk_officer_term_data")), ) # Prevents a single officer from holding multiple Executive positions at once (August 2015 Constitution). @@ -445,35 +573,35 @@ def upgrade() -> None: def downgrade() -> None: # ### commands auto generated by Alembic - please adjust! ### - op.execute('DROP TRIGGER check_position_version_single_holder_overlap ON public.officer_position_version') - op.execute('DROP TRIGGER check_single_holder_position_overlap ON public.officer_term') - op.execute('DROP TRIGGER check_position_version_term_dates ON public.officer_position_version') - op.execute('DROP TRIGGER check_officer_term_position_version_dates ON public.officer_term') - op.execute('DROP TRIGGER check_executive_term_overlap ON public.officer_term') - op.execute('DROP FUNCTION public.check_position_version_single_holder_overlap()') - op.execute('DROP FUNCTION public.check_single_holder_position_overlap()') - op.execute('DROP FUNCTION public.check_position_version_term_dates()') - op.execute('DROP FUNCTION public.check_officer_term_position_version_dates()') - op.execute('DROP FUNCTION public.check_executive_term_overlap()') - op.drop_table('officer_term_data') - op.drop_table('officer_term') - op.drop_table('blog_posts') - op.drop_index(op.f('ix_user_session_computing_id'), table_name='user_session') - op.drop_table('user_session') - op.drop_index(op.f('ix_site_user_role_role'), table_name='site_user_role') - op.drop_table('site_user_role') - op.drop_table('officer_position_version') - op.drop_table('officer_info') - op.drop_index(op.f('ix_event_info_group_id'), table_name='event_info') - op.drop_table('event_info') - op.drop_table('election_nominee_application') - op.drop_table('translink_static_schedule') - op.drop_table('translink_realtime_cache') - op.drop_table('site_user') - op.drop_table('officer_position') - op.drop_table('image_asset') - op.drop_table('honorary_member') - op.drop_table('election_nominee_info') - op.drop_table('election') - op.drop_table('auth_redirect') + op.execute("DROP TRIGGER check_position_version_single_holder_overlap ON public.officer_position_version") + op.execute("DROP TRIGGER check_single_holder_position_overlap ON public.officer_term") + op.execute("DROP TRIGGER check_position_version_term_dates ON public.officer_position_version") + op.execute("DROP TRIGGER check_officer_term_position_version_dates ON public.officer_term") + op.execute("DROP TRIGGER check_executive_term_overlap ON public.officer_term") + op.execute("DROP FUNCTION public.check_position_version_single_holder_overlap()") + op.execute("DROP FUNCTION public.check_single_holder_position_overlap()") + op.execute("DROP FUNCTION public.check_position_version_term_dates()") + op.execute("DROP FUNCTION public.check_officer_term_position_version_dates()") + op.execute("DROP FUNCTION public.check_executive_term_overlap()") + op.drop_table("officer_term_data") + op.drop_table("officer_term") + op.drop_table("blog_posts") + op.drop_index(op.f("ix_user_session_computing_id"), table_name="user_session") + op.drop_table("user_session") + op.drop_index(op.f("ix_site_user_role_role"), table_name="site_user_role") + op.drop_table("site_user_role") + op.drop_table("officer_position_version") + op.drop_table("officer_info") + op.drop_index(op.f("ix_event_info_group_id"), table_name="event_info") + op.drop_table("event_info") + op.drop_table("election_nominee_application") + op.drop_table("translink_static_schedule") + op.drop_table("translink_realtime_cache") + op.drop_table("site_user") + op.drop_table("officer_position") + op.drop_table("image_asset") + op.drop_table("honorary_member") + op.drop_table("election_nominee_info") + op.drop_table("election") + op.drop_table("auth_redirect") # ### end Alembic commands ### diff --git a/src/alembic/versions/8a4b2d6e901c_add_public_event_ids.py b/src/alembic/versions/8a4b2d6e901c_add_public_event_ids.py index de0be79..e03e673 100644 --- a/src/alembic/versions/8a4b2d6e901c_add_public_event_ids.py +++ b/src/alembic/versions/8a4b2d6e901c_add_public_event_ids.py @@ -7,9 +7,10 @@ from collections.abc import Sequence import sqlalchemy as sa -from alembic import op from ulid import ULID +from alembic import op + revision: str = "8a4b2d6e901c" down_revision: str | None = "f06f13097539" branch_labels: str | Sequence[str] | None = None diff --git a/src/alembic/versions/c7e41a0b926d_add_public_user_ids.py b/src/alembic/versions/c7e41a0b926d_add_public_user_ids.py index 135fbba..a2b0ccf 100644 --- a/src/alembic/versions/c7e41a0b926d_add_public_user_ids.py +++ b/src/alembic/versions/c7e41a0b926d_add_public_user_ids.py @@ -8,9 +8,10 @@ from uuid import uuid4 import sqlalchemy as sa -from alembic import op from sqlalchemy.engine.interfaces import ReflectedForeignKeyConstraint +from alembic import op + revision: str = "c7e41a0b926d" down_revision: str | None = "8a4b2d6e901c" branch_labels: str | Sequence[str] | None = None @@ -41,8 +42,11 @@ def _replace_primary_key(columns: list[str], *, drop_computing_id_unique: bool = if name is None: raise ValueError(f"Cannot replace an unnamed foreign key on {table}") op.create_foreign_key( - op.f(name), table, "site_user", - foreign_key["constrained_columns"], foreign_key["referred_columns"], + op.f(name), + table, + "site_user", + foreign_key["constrained_columns"], + foreign_key["referred_columns"], **foreign_key.get("options", {}), ) diff --git a/src/alembic/versions/f06f13097539_add_position_uniqueness_constraint.py b/src/alembic/versions/f06f13097539_add_position_uniqueness_constraint.py index fd8e8a9..bbb454e 100644 --- a/src/alembic/versions/f06f13097539_add_position_uniqueness_constraint.py +++ b/src/alembic/versions/f06f13097539_add_position_uniqueness_constraint.py @@ -5,28 +5,31 @@ Create Date: 2026-10-04 12:56:24.392349 """ -from typing import Sequence -from alembic import op +from collections.abc import Sequence + import sqlalchemy as sa +from alembic import op # revision identifiers, used by Alembic. -revision: str = 'f06f13097539' -down_revision: str | None= '2cf2279e48ef' +revision: str = "f06f13097539" +down_revision: str | None = "2cf2279e48ef" branch_labels: str | Sequence[str] | None = None depends_on: str | Sequence[str] | None = None def upgrade() -> None: # ### commands auto generated by Alembic - please adjust! ### - op.drop_constraint(op.f('uq_officer_position_position'), 'officer_position', type_='unique') - op.create_index('lower_case', 'officer_position', [sa.literal_column('lower(btrim(position))')], unique=True) + op.drop_constraint(op.f("uq_officer_position_position"), "officer_position", type_="unique") + op.create_index("lower_case", "officer_position", [sa.literal_column("lower(btrim(position))")], unique=True) # ### end Alembic commands ### def downgrade() -> None: # ### commands auto generated by Alembic - please adjust! ### - op.drop_index('lower_case', table_name='officer_position') - op.create_unique_constraint(op.f('uq_officer_position_position'), 'officer_position', ['position'], postgresql_nulls_not_distinct=False) + op.drop_index("lower_case", table_name="officer_position") + op.create_unique_constraint( + op.f("uq_officer_position_position"), "officer_position", ["position"], postgresql_nulls_not_distinct=False + ) # ### end Alembic commands ###