Skip to content

Commit 373c3ec

Browse files
committed
Adding lottery interface
1 parent fb3d1ba commit 373c3ec

37 files changed

+2643
-315
lines changed

alembic/versions/6902e1cceec6_relationships_overhaul.py

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,21 @@ def sqlite_column_reflect_listener(inspector, table, column_info):
5151
# ===========================================================================
5252

5353

54+
def _rename_unique_constraint(table, old_name, new_name, columns):
55+
"""Rename a unique constraint, handling fresh DBs where old name may not exist."""
56+
conn = op.get_bind()
57+
has_old = conn.execute(sa.text(
58+
f"SELECT 1 FROM pg_constraint WHERE conname = '{old_name}'"
59+
)).fetchone()
60+
has_new = conn.execute(sa.text(
61+
f"SELECT 1 FROM pg_constraint WHERE conname = '{new_name}'"
62+
)).fetchone()
63+
if has_old:
64+
op.drop_constraint(op.f(old_name), table, type_='unique')
65+
if not has_new:
66+
op.create_unique_constraint(op.f(new_name), table, columns)
67+
68+
5469
def upgrade():
5570
op.drop_table('attendee_tournament')
5671
op.drop_constraint(op.f('fk_admin_account_attendee_id_attendee'), 'admin_account', type_='foreignkey')
@@ -104,16 +119,14 @@ def upgrade():
104119
op.create_foreign_key(op.f('fk_attendee_group_id_group'), 'attendee', 'group', ['group_id'], ['id'])
105120
op.create_foreign_key(op.f('fk_attendee_creator_id_attendee'), 'attendee', 'attendee', ['creator_id'], ['id'])
106121
op.drop_column('attendee', 'affiliate')
107-
op.drop_constraint(op.f('attraction_name_key'), 'attraction', type_='unique')
108-
op.create_unique_constraint(op.f('uq_attraction_name'), 'attraction', ['name'])
122+
_rename_unique_constraint('attraction', 'attraction_name_key', 'uq_attraction_name', ['name'])
109123
op.drop_constraint(op.f('fk_attraction_event_location_id_event_location'), 'attraction_event', type_='foreignkey')
110124
op.drop_constraint(op.f('fk_attraction_event_attraction_id_attraction'), 'attraction_event', type_='foreignkey')
111125
op.drop_constraint(op.f('fk_attraction_event_attraction_feature_id_attraction_feature'), 'attraction_event', type_='foreignkey')
112126
op.create_foreign_key(op.f('fk_attraction_event_attraction_id_attraction'), 'attraction_event', 'attraction', ['attraction_id'], ['id'], ondelete='CASCADE')
113127
op.create_foreign_key(op.f('fk_attraction_event_attraction_feature_id_attraction_feature'), 'attraction_event', 'attraction_feature', ['attraction_feature_id'], ['id'], ondelete='CASCADE')
114128
op.create_foreign_key(op.f('fk_attraction_event_event_location_id_event_location'), 'attraction_event', 'event_location', ['event_location_id'], ['id'])
115-
op.drop_constraint(op.f('attraction_feature_name_attraction_id_key'), 'attraction_feature', type_='unique')
116-
op.create_unique_constraint(op.f('uq_attraction_feature_name'), 'attraction_feature', ['name', 'attraction_id'])
129+
_rename_unique_constraint('attraction_feature', 'attraction_feature_name_attraction_id_key', 'uq_attraction_feature_name', ['name', 'attraction_id'])
117130
op.drop_constraint(op.f('fk_attraction_feature_attraction_id_attraction'), 'attraction_feature', type_='foreignkey')
118131
op.create_foreign_key(op.f('fk_attraction_feature_attraction_id_attraction'), 'attraction_feature', 'attraction', ['attraction_id'], ['id'], ondelete='CASCADE')
119132
op.drop_constraint(op.f('fk_attraction_notification_attraction_event_id_attraction_event'), 'attraction_notification', type_='foreignkey')
@@ -134,8 +147,7 @@ def upgrade():
134147
op.drop_constraint(op.f('fk_bulk_printing_request_department_id_department'), 'bulk_printing_request', type_='foreignkey')
135148
op.create_foreign_key(op.f('fk_bulk_printing_request_department_id_department'), 'bulk_printing_request', 'department', ['department_id'], ['id'], ondelete='CASCADE')
136149
op.drop_column('bulk_printing_request', 'required')
137-
op.drop_constraint(op.f('department_name_key'), 'department', type_='unique')
138-
op.create_unique_constraint(op.f('uq_department_name'), 'department', ['name'])
150+
_rename_unique_constraint('department', 'department_name_key', 'uq_department_name', ['name'])
139151
op.drop_constraint(op.f('fk_department_parent_id_department'), 'department', type_='foreignkey')
140152
op.create_foreign_key(op.f('fk_department_parent_id_department'), 'department', 'department', ['parent_id'], ['id'], ondelete='CASCADE')
141153
op.drop_constraint(op.f('fk_dept_checklist_item_department_id_department'), 'dept_checklist_item', type_='foreignkey')
@@ -315,8 +327,7 @@ def upgrade():
315327
op.create_foreign_key(op.f('fk_tabletop_checkout_attendee_id_attendee'), 'tabletop_checkout', 'attendee', ['attendee_id'], ['id'], ondelete='CASCADE')
316328
op.drop_constraint(op.f('fk_tabletop_game_attendee_id_attendee'), 'tabletop_game', type_='foreignkey')
317329
op.create_foreign_key(op.f('fk_tabletop_game_attendee_id_attendee'), 'tabletop_game', 'attendee', ['attendee_id'], ['id'], ondelete='CASCADE')
318-
op.drop_constraint(op.f('txn_request_tracking_incr_id_key'), 'txn_request_tracking', type_='unique')
319-
op.create_unique_constraint(op.f('uq_txn_request_tracking_incr_id'), 'txn_request_tracking', ['incr_id'])
330+
_rename_unique_constraint('txn_request_tracking', 'txn_request_tracking_incr_id_key', 'uq_txn_request_tracking_incr_id', ['incr_id'])
320331

321332

322333
def downgrade():
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
"""Add hotel booking tables and columns
2+
3+
Revision ID: a1b2c3d4e5f6
4+
Revises: 5a0e898174d4
5+
Create Date: 2026-04-08 00:00:00.000000
6+
7+
"""
8+
9+
10+
# revision identifiers, used by Alembic.
11+
revision = 'a1b2c3d4e5f6'
12+
down_revision = '4df6bfee2c69'
13+
branch_labels = None
14+
depends_on = None
15+
16+
from alembic import op
17+
import sqlalchemy as sa
18+
from sqlalchemy.dialects import postgresql
19+
20+
21+
try:
22+
is_sqlite = op.get_context().dialect.name == 'sqlite'
23+
except Exception:
24+
is_sqlite = False
25+
26+
if is_sqlite:
27+
op.get_context().connection.execute('PRAGMA foreign_keys=ON;')
28+
utcnow_server_default = "(datetime('now', 'utc'))"
29+
else:
30+
utcnow_server_default = "timezone('utc', current_timestamp)"
31+
32+
def sqlite_column_reflect_listener(inspector, table, column_info):
33+
"""Adds parenthesis around SQLite datetime defaults for utcnow."""
34+
if column_info['default'] == "datetime('now', 'utc')":
35+
column_info['default'] = utcnow_server_default
36+
37+
sqlite_reflect_kwargs = {
38+
'listeners': [('column_reflect', sqlite_column_reflect_listener)]
39+
}
40+
41+
# ===========================================================================
42+
# HOWTO: Handle alter statements in SQLite
43+
#
44+
# def upgrade():
45+
# if is_sqlite:
46+
# with op.batch_alter_table('table_name', reflect_kwargs=sqlite_reflect_kwargs) as batch_op:
47+
# batch_op.alter_column('column_name', type_=sa.Unicode(), server_default='', nullable=False)
48+
# else:
49+
# op.alter_column('table_name', 'column_name', type_=sa.Unicode(), server_default='', nullable=False)
50+
#
51+
# ===========================================================================
52+
53+
54+
def upgrade():
55+
op.create_table('lottery_run',
56+
sa.Column('id', sa.Uuid(as_uuid=False), nullable=False),
57+
sa.Column('created', sa.DateTime(timezone=True), server_default=sa.text(utcnow_server_default), nullable=False),
58+
sa.Column('last_updated', sa.DateTime(timezone=True), server_default=sa.text(utcnow_server_default), nullable=False),
59+
sa.Column('external_id', postgresql.JSONB(astext_type=sa.Text()), server_default='{}', nullable=False),
60+
sa.Column('last_synced', postgresql.JSONB(astext_type=sa.Text()), server_default='{}', nullable=False),
61+
sa.Column('name', sa.Unicode(), server_default='', nullable=False),
62+
sa.Column('status', sa.Integer(), server_default='0', nullable=False),
63+
sa.Column('run_at', sa.DateTime(timezone=True), nullable=True),
64+
sa.Column('awarded_at', sa.DateTime(timezone=True), nullable=True),
65+
sa.Column('reverted_at', sa.DateTime(timezone=True), nullable=True),
66+
sa.Column('lottery_group', sa.Unicode(), server_default='attendee', nullable=False),
67+
sa.Column('lottery_type', sa.Unicode(), server_default='room', nullable=False),
68+
sa.Column('cutoff', sa.DateTime(timezone=True), nullable=True),
69+
sa.Column('hotel_filter', sa.Unicode(), nullable=True),
70+
sa.Column('room_type_filter', sa.Unicode(), nullable=True),
71+
sa.Column('entries_considered', sa.Integer(), server_default='0', nullable=False),
72+
sa.Column('rooms_assigned', sa.Integer(), server_default='0', nullable=False),
73+
sa.Column('rooms_available_before', sa.Integer(), server_default='0', nullable=False),
74+
sa.PrimaryKeyConstraint('id', name=op.f('pk_lottery_run'))
75+
)
76+
77+
op.create_table('hotel_room_inventory',
78+
sa.Column('id', sa.Uuid(as_uuid=False), nullable=False),
79+
sa.Column('created', sa.DateTime(timezone=True), server_default=sa.text(utcnow_server_default), nullable=False),
80+
sa.Column('last_updated', sa.DateTime(timezone=True), server_default=sa.text(utcnow_server_default), nullable=False),
81+
sa.Column('external_id', postgresql.JSONB(astext_type=sa.Text()), server_default='{}', nullable=False),
82+
sa.Column('last_synced', postgresql.JSONB(astext_type=sa.Text()), server_default='{}', nullable=False),
83+
sa.Column('hotel', sa.Integer(), server_default='0', nullable=False),
84+
sa.Column('room_type', sa.Integer(), nullable=True),
85+
sa.Column('suite_type', sa.Integer(), nullable=True),
86+
sa.Column('quantity', sa.Integer(), server_default='0', nullable=False),
87+
sa.Column('capacity', sa.Integer(), server_default='2', nullable=False),
88+
sa.Column('min_capacity', sa.Integer(), server_default='1', nullable=False),
89+
sa.Column('name', sa.Unicode(), server_default='', nullable=False),
90+
sa.Column('is_suite', sa.Boolean(), server_default='False', nullable=False),
91+
sa.Column('active', sa.Boolean(), server_default='True', nullable=False),
92+
sa.Column('vault_reference', sa.Unicode(), nullable=True),
93+
sa.PrimaryKeyConstraint('id', name=op.f('pk_hotel_room_inventory'))
94+
)
95+
96+
op.create_table('hotel_export_log',
97+
sa.Column('id', sa.Uuid(as_uuid=False), nullable=False),
98+
sa.Column('created', sa.DateTime(timezone=True), server_default=sa.text(utcnow_server_default), nullable=False),
99+
sa.Column('last_updated', sa.DateTime(timezone=True), server_default=sa.text(utcnow_server_default), nullable=False),
100+
sa.Column('external_id', postgresql.JSONB(astext_type=sa.Text()), server_default='{}', nullable=False),
101+
sa.Column('last_synced', postgresql.JSONB(astext_type=sa.Text()), server_default='{}', nullable=False),
102+
sa.Column('hotel', sa.Integer(), server_default='0', nullable=False),
103+
sa.Column('export_type', sa.Unicode(), server_default='', nullable=False),
104+
sa.Column('exported_at', sa.DateTime(timezone=True), nullable=True),
105+
sa.Column('exported_by', sa.Unicode(), server_default='', nullable=False),
106+
sa.Column('record_count', sa.Integer(), server_default='0', nullable=False),
107+
sa.Column('notes', sa.Unicode(), server_default='', nullable=False),
108+
sa.PrimaryKeyConstraint('id', name=op.f('pk_hotel_export_log'))
109+
)
110+
111+
op.add_column('lottery_application', sa.Column('cc_token', sa.Unicode(), nullable=True))
112+
op.add_column('lottery_application', sa.Column('cc_last_four', sa.Unicode(), nullable=True))
113+
op.add_column('lottery_application', sa.Column('cc_card_type', sa.Unicode(), nullable=True))
114+
op.add_column('lottery_application', sa.Column('cc_captured_at', sa.DateTime(timezone=True), nullable=True))
115+
op.add_column('lottery_application', sa.Column('hotel_confirmation_number', sa.Unicode(), nullable=True))
116+
op.add_column('lottery_application', sa.Column('special_requests', sa.Unicode(), server_default='', nullable=False))
117+
op.add_column('lottery_application', sa.Column('last_modified_at', sa.DateTime(timezone=True), nullable=True))
118+
op.add_column('lottery_application', sa.Column('lottery_run_id', sa.Uuid(as_uuid=False), nullable=True))
119+
op.create_foreign_key(
120+
op.f('fk_lottery_application_lottery_run_id_lottery_run'),
121+
'lottery_application', 'lottery_run',
122+
['lottery_run_id'], ['id']
123+
)
124+
125+
126+
def downgrade():
127+
op.drop_constraint(op.f('fk_lottery_application_lottery_run_id_lottery_run'), 'lottery_application', type_='foreignkey')
128+
op.drop_column('lottery_application', 'lottery_run_id')
129+
op.drop_column('lottery_application', 'last_modified_at')
130+
op.drop_column('lottery_application', 'special_requests')
131+
op.drop_column('lottery_application', 'hotel_confirmation_number')
132+
op.drop_column('lottery_application', 'cc_captured_at')
133+
op.drop_column('lottery_application', 'cc_card_type')
134+
op.drop_column('lottery_application', 'cc_last_four')
135+
op.drop_column('lottery_application', 'cc_token')
136+
op.drop_table('hotel_export_log')
137+
op.drop_table('hotel_room_inventory')
138+
op.drop_table('lottery_run')
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
"""Add lottery hotel and room type tables
2+
3+
Revision ID: b2c3d4e5f6a7
4+
Revises: a1b2c3d4e5f6
5+
Create Date: 2026-04-08 00:00:00.000000
6+
7+
"""
8+
9+
10+
# revision identifiers, used by Alembic.
11+
revision = 'b2c3d4e5f6a7'
12+
down_revision = 'a1b2c3d4e5f6'
13+
branch_labels = None
14+
depends_on = None
15+
16+
from alembic import op
17+
import sqlalchemy as sa
18+
from sqlalchemy.dialects import postgresql
19+
20+
21+
try:
22+
is_sqlite = op.get_context().dialect.name == 'sqlite'
23+
except Exception:
24+
is_sqlite = False
25+
26+
if is_sqlite:
27+
op.get_context().connection.execute('PRAGMA foreign_keys=ON;')
28+
utcnow_server_default = "(datetime('now', 'utc'))"
29+
else:
30+
utcnow_server_default = "timezone('utc', current_timestamp)"
31+
32+
def sqlite_column_reflect_listener(inspector, table, column_info):
33+
"""Adds parenthesis around SQLite datetime defaults for utcnow."""
34+
if column_info['default'] == "datetime('now', 'utc')":
35+
column_info['default'] = utcnow_server_default
36+
37+
sqlite_reflect_kwargs = {
38+
'listeners': [('column_reflect', sqlite_column_reflect_listener)]
39+
}
40+
41+
42+
def upgrade():
43+
op.create_table('lottery_hotel',
44+
sa.Column('id', postgresql.UUID(), nullable=False),
45+
sa.Column('created', sa.DateTime(), server_default=sa.text(utcnow_server_default), nullable=False),
46+
sa.Column('last_updated', sa.DateTime(), server_default=sa.text(utcnow_server_default), nullable=False),
47+
sa.Column('external_id', postgresql.JSONB(), server_default='{}', nullable=False),
48+
sa.Column('last_synced', postgresql.JSONB(), server_default='{}', nullable=False),
49+
sa.Column('name', sa.Unicode(), server_default='', nullable=False),
50+
sa.Column('export_name', sa.Unicode(), server_default='', nullable=False),
51+
sa.Column('price', sa.Unicode(), server_default='', nullable=False),
52+
sa.Column('staff_price', sa.Unicode(), server_default='', nullable=False),
53+
sa.Column('description', sa.Unicode(), server_default='', nullable=False),
54+
sa.Column('description_right', sa.Unicode(), server_default='', nullable=False),
55+
sa.Column('footnote', sa.Unicode(), server_default='', nullable=False),
56+
sa.Column('active', sa.Boolean(), server_default='True', nullable=False),
57+
sa.Column('choice_id', sa.Integer(), nullable=False),
58+
sa.PrimaryKeyConstraint('id', name=op.f('pk_lottery_hotel')),
59+
sa.UniqueConstraint('choice_id', name=op.f('uq_lottery_hotel_choice_id')),
60+
)
61+
62+
op.create_table('lottery_room_type',
63+
sa.Column('id', postgresql.UUID(), nullable=False),
64+
sa.Column('created', sa.DateTime(), server_default=sa.text(utcnow_server_default), nullable=False),
65+
sa.Column('last_updated', sa.DateTime(), server_default=sa.text(utcnow_server_default), nullable=False),
66+
sa.Column('external_id', postgresql.JSONB(), server_default='{}', nullable=False),
67+
sa.Column('last_synced', postgresql.JSONB(), server_default='{}', nullable=False),
68+
sa.Column('name', sa.Unicode(), server_default='', nullable=False),
69+
sa.Column('export_name', sa.Unicode(), server_default='', nullable=False),
70+
sa.Column('price', sa.Unicode(), server_default='', nullable=False),
71+
sa.Column('staff_price', sa.Unicode(), server_default='', nullable=False),
72+
sa.Column('description', sa.Unicode(), server_default='', nullable=False),
73+
sa.Column('description_right', sa.Unicode(), server_default='', nullable=False),
74+
sa.Column('footnote', sa.Unicode(), server_default='', nullable=False),
75+
sa.Column('capacity', sa.Integer(), server_default='4', nullable=False),
76+
sa.Column('min_capacity', sa.Integer(), server_default='1', nullable=False),
77+
sa.Column('is_suite', sa.Boolean(), server_default='False', nullable=False),
78+
sa.Column('active', sa.Boolean(), server_default='True', nullable=False),
79+
sa.Column('choice_id', sa.Integer(), nullable=False),
80+
sa.PrimaryKeyConstraint('id', name=op.f('pk_lottery_room_type')),
81+
sa.UniqueConstraint('choice_id', name=op.f('uq_lottery_room_type_choice_id')),
82+
)
83+
84+
85+
def downgrade():
86+
op.drop_table('lottery_room_type')
87+
op.drop_table('lottery_hotel')
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
"""Add address fields to lottery application
2+
3+
Revision ID: c3d4e5f6a7b8
4+
Revises: b2c3d4e5f6a7
5+
Create Date: 2026-04-08 00:00:00.000000
6+
7+
"""
8+
9+
10+
# revision identifiers, used by Alembic.
11+
revision = 'c3d4e5f6a7b8'
12+
down_revision = 'b2c3d4e5f6a7'
13+
branch_labels = None
14+
depends_on = None
15+
16+
from alembic import op
17+
import sqlalchemy as sa
18+
19+
20+
try:
21+
is_sqlite = op.get_context().dialect.name == 'sqlite'
22+
except Exception:
23+
is_sqlite = False
24+
25+
if is_sqlite:
26+
op.get_context().connection.execute('PRAGMA foreign_keys=ON;')
27+
utcnow_server_default = "(datetime('now', 'utc'))"
28+
else:
29+
utcnow_server_default = "timezone('utc', current_timestamp)"
30+
31+
32+
def upgrade():
33+
op.add_column('lottery_application', sa.Column('address1', sa.Unicode(), server_default='', nullable=False))
34+
op.add_column('lottery_application', sa.Column('address2', sa.Unicode(), server_default='', nullable=False))
35+
op.add_column('lottery_application', sa.Column('city', sa.Unicode(), server_default='', nullable=False))
36+
op.add_column('lottery_application', sa.Column('region', sa.Unicode(), server_default='', nullable=False))
37+
op.add_column('lottery_application', sa.Column('zip_code', sa.Unicode(), server_default='', nullable=False))
38+
op.add_column('lottery_application', sa.Column('country', sa.Unicode(), server_default='', nullable=False))
39+
40+
41+
def downgrade():
42+
op.drop_column('lottery_application', 'country')
43+
op.drop_column('lottery_application', 'zip_code')
44+
op.drop_column('lottery_application', 'region')
45+
op.drop_column('lottery_application', 'city')
46+
op.drop_column('lottery_application', 'address2')
47+
op.drop_column('lottery_application', 'address1')

0 commit comments

Comments
 (0)