Skip to content

Commit 8c637fb

Browse files
Fix frosh attendance (#464)
* attempt to fix upgrading accounts breaking frosh attendance * actually fix hm attendance and reorder opperations to create then delete * local db explaination * trailing whitespace :)))))))) * fix typo * fix variable name
1 parent c4a03d6 commit 8c637fb

File tree

8 files changed

+196
-12
lines changed

8 files changed

+196
-12
lines changed

README.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,19 @@ This will run the asset pipeline, start the Python server, and start BrowserSync
6161

6262
To add new dependencies, add them to `requirements.in` and then run `pip-compile requirements.in` to produce a new locked `requirements.txt`. Do not edit `requirements.txt` directly as it will be overwritten by future PRs.
6363

64-
after app initialization
64+
### Local database
65+
66+
You can run the database locally using the docker compose, make sure to upgrade it as explained below
67+
68+
To populate it with dev data for example, you can use the command
69+
70+
```
71+
PGPASSWORD='[DB PASSWORD]' pg_dump -h postgres.csh.rit.edu -p 5432 -U conditional-dev conditional-dev | PGPASSWORD='fancypantspassword' psql -h localhost -p 5432 -U conditional conditional
72+
```
73+
74+
This can be helpful for changing the database schema
75+
76+
NOTE: to use flask db commands with a database running in the compose file, you will have to update your url to point to localhost, not conditional-postgres
6577

6678
### Database Migrations
6779

conditional/blueprints/member_management.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -462,22 +462,20 @@ def member_management_upgrade_user(user_dict=None):
462462
db.session.add(new_acct)
463463
for fca in FreshmanCommitteeAttendance.query.filter(FreshmanCommitteeAttendance.fid == fid):
464464
db.session.add(MemberCommitteeAttendance(uid, fca.meeting_id))
465-
db.session.delete(fca)
466465

467466
for fts in FreshmanSeminarAttendance.query.filter(FreshmanSeminarAttendance.fid == fid):
468467
db.session.add(MemberSeminarAttendance(uid, fts.seminar_id))
469-
db.session.delete(fts)
470468

471469
for fhm in FreshmanHouseMeetingAttendance.query.filter(FreshmanHouseMeetingAttendance.fid == fid):
472470
# Don't duplicate HM attendance records
473471
mhm = MemberHouseMeetingAttendance.query.filter(
474-
MemberHouseMeetingAttendance.meeting_id == fhm.meeting_id).first()
472+
MemberHouseMeetingAttendance.meeting_id == fhm.meeting_id,
473+
MemberHouseMeetingAttendance.uid == uid).first()
475474
if mhm is None:
476475
db.session.add(MemberHouseMeetingAttendance(
477476
uid, fhm.meeting_id, fhm.excuse, fhm.attendance_status))
478477
else:
479478
log.info(f'Duplicate house meeting attendance! fid: {fid}, uid: {uid}, id: {fhm.meeting_id}')
480-
db.session.delete(fhm)
481479

482480
new_account = ldap_get_member(uid)
483481
if acct.onfloor_status:
@@ -487,6 +485,9 @@ def member_management_upgrade_user(user_dict=None):
487485
if acct.room_number:
488486
ldap_set_roomnumber(new_account, acct.room_number)
489487

488+
db.session.flush()
489+
db.session.commit()
490+
490491
db.session.delete(acct)
491492

492493
db.session.flush()

conditional/models/models.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ def __init__(self, uid, meeting_id):
8383
class FreshmanCommitteeAttendance(db.Model):
8484
__tablename__ = 'freshman_committee_attendance'
8585
id = Column(Integer, primary_key=True)
86-
fid = Column(ForeignKey('freshman_accounts.id'), nullable=False)
86+
fid = Column(ForeignKey('freshman_accounts.id', ondelete="cascade"), nullable=False)
8787
meeting_id = Column(ForeignKey('committee_meetings.id'), nullable=False)
8888

8989
def __init__(self, fid, meeting_id):
@@ -120,7 +120,7 @@ def __init__(self, uid, seminar_id):
120120
class FreshmanSeminarAttendance(db.Model):
121121
__tablename__ = 'freshman_seminar_attendance'
122122
id = Column(Integer, primary_key=True)
123-
fid = Column(ForeignKey('freshman_accounts.id'), nullable=False)
123+
fid = Column(ForeignKey('freshman_accounts.id', ondelete="cascade"), nullable=False)
124124
seminar_id = Column(ForeignKey('technical_seminars.id'), nullable=False)
125125

126126
def __init__(self, fid, seminar_id):
@@ -178,7 +178,7 @@ def __init__(self, uid, meeting_id, excuse, status):
178178
class FreshmanHouseMeetingAttendance(db.Model):
179179
__tablename__ = 'freshman_hm_attendance'
180180
id = Column(Integer, primary_key=True)
181-
fid = Column(ForeignKey('freshman_accounts.id'), nullable=False)
181+
fid = Column(ForeignKey('freshman_accounts.id', ondelete="cascade"), nullable=False)
182182
meeting_id = Column(ForeignKey('house_meetings.id'), nullable=False)
183183
excuse = Column(Text)
184184
attendance_status = Column(attendance_enum)

conditional/util/member.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -186,13 +186,13 @@ def get_voting_members():
186186
active_not_intro = active_members - intro_members
187187
active_not_intro = set(map(lambda member: member.uid, active_not_intro))
188188

189-
elligible_members = (active_not_intro - coop_members) | passed_fall_members
189+
eligible_members = (active_not_intro - coop_members) | passed_fall_members
190190

191191
# Check to see if there's an Intro Evals in the future of this semester. If there is, everyone gets to vote!
192192
before_evals_one = len(FreshmanAccount.query.filter(FreshmanAccount.eval_date > today).limit(1).all())
193193
before_evals_two = len(FreshmanEvalData.query.filter(FreshmanEvalData.eval_date > today).limit(1).all())
194194
if before_evals_one > 0 or before_evals_two > 0:
195-
return elligible_members
195+
return eligible_members
196196

197197
passing_dm = set(member.uid for member in MemberCommitteeAttendance.query.join(
198198
CommitteeMeeting,
@@ -245,7 +245,7 @@ def get_voting_members():
245245

246246
passing_reqs = (passing_dm & passing_ts) - absent_hm
247247

248-
return elligible_members & passing_reqs
248+
return eligible_members & passing_reqs
249249

250250

251251
def gatekeep_status(username):

config.env.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
PROFILING = env.get("CONDITIONAL_PROFILING", "false").lower() == "true"
1919

2020
# DB Info
21-
SQLALCHEMY_DATABASE_URI = env.get("SQLALCHEMY_DATABASE_URI", "")
21+
SQLALCHEMY_DATABASE_URI = "postgresql://conditional:fancypantspassword@conditional-postgres:5432/conditional"
2222
SQLALCHEMY_TRACK_MODIFICATIONS = False
2323

2424
# LDAP config

docker-compose.yaml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
version: "3"
2+
services:
3+
conditional:
4+
build: .
5+
container_name: conditional
6+
depends_on:
7+
- conditional-postgres
8+
ports:
9+
- "127.0.0.1:8080:8080"
10+
conditional-postgres:
11+
image: docker.io/postgres
12+
container_name: conditional-postgres
13+
environment:
14+
POSTGRES_PASSWORD: fancypantspassword
15+
POSTGRES_USER: conditional
16+
POSTGRES_DATABASE: conditional
17+
ports:
18+
- "127.0.0.1:5432:5432"
19+
volumes:
20+
- pgdata:/var/lib/postgresql
21+
22+
volumes:
23+
pgdata:
24+
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
"""Freshmen data cascade
2+
3+
Revision ID: 7a3904cac24b
4+
Revises: e38beaf3e875
5+
Create Date: 2026-02-03 12:14:37.119352
6+
7+
"""
8+
9+
# revision identifiers, used by Alembic.
10+
revision = '7a3904cac24b'
11+
down_revision = 'e38beaf3e875'
12+
13+
from alembic import op
14+
import sqlalchemy as sa
15+
16+
17+
def upgrade():
18+
# ### commands auto generated by Alembic - please adjust! ###
19+
op.drop_constraint('freshman_committee_attendance_fid_fkey', 'freshman_committee_attendance', type_='foreignkey')
20+
op.create_foreign_key(None, 'freshman_committee_attendance', 'freshman_accounts', ['fid'], ['id'], ondelete='cascade')
21+
op.drop_constraint('freshman_hm_attendance_fid_fkey', 'freshman_hm_attendance', type_='foreignkey')
22+
op.create_foreign_key(None, 'freshman_hm_attendance', 'freshman_accounts', ['fid'], ['id'], ondelete='cascade')
23+
op.drop_constraint('freshman_seminar_attendance_fid_fkey', 'freshman_seminar_attendance', type_='foreignkey')
24+
op.create_foreign_key(None, 'freshman_seminar_attendance', 'freshman_accounts', ['fid'], ['id'], ondelete='cascade')
25+
# ### end Alembic commands ###
26+
27+
28+
def downgrade():
29+
# ### commands auto generated by Alembic - please adjust! ###
30+
op.drop_constraint(None, 'freshman_seminar_attendance', type_='foreignkey')
31+
op.create_foreign_key('freshman_seminar_attendance_fid_fkey', 'freshman_seminar_attendance', 'freshman_accounts', ['fid'], ['id'])
32+
op.drop_constraint(None, 'freshman_hm_attendance', type_='foreignkey')
33+
op.create_foreign_key('freshman_hm_attendance_fid_fkey', 'freshman_hm_attendance', 'freshman_accounts', ['fid'], ['id'])
34+
op.drop_constraint(None, 'freshman_committee_attendance', type_='foreignkey')
35+
op.create_foreign_key('freshman_committee_attendance_fid_fkey', 'freshman_committee_attendance', 'freshman_accounts', ['fid'], ['id'])
36+
# ### end Alembic commands ###
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
"""update db
2+
3+
Revision ID: e38beaf3e875
4+
Revises: 757e18146d16
5+
Create Date: 2026-02-03 12:12:11.451367
6+
7+
"""
8+
9+
# revision identifiers, used by Alembic.
10+
revision = 'e38beaf3e875'
11+
down_revision = '757e18146d16'
12+
13+
from alembic import op
14+
import sqlalchemy as sa
15+
from sqlalchemy.dialects import postgresql
16+
17+
def upgrade():
18+
# ### commands auto generated by Alembic - please adjust! ###
19+
op.drop_index('member_batch_users_id_idx', table_name='member_batch_users')
20+
op.drop_table('member_batch_users')
21+
op.drop_index('freshman_batch_pulls_id_idx', table_name='freshman_batch_pulls')
22+
op.drop_table('freshman_batch_pulls')
23+
op.drop_index('member_batch_pulls_id_idx', table_name='member_batch_pulls')
24+
op.drop_table('member_batch_pulls')
25+
op.drop_index('freshman_batch_users_id_pkey', table_name='freshman_batch_users')
26+
op.drop_table('freshman_batch_users')
27+
op.drop_table('batch_conditions')
28+
op.alter_column('freshman_accounts', 'onfloor_status',
29+
existing_type=sa.BOOLEAN(),
30+
nullable=True)
31+
op.alter_column('freshman_accounts', 'rit_username',
32+
existing_type=sa.VARCHAR(length=10),
33+
nullable=True)
34+
op.alter_column('freshman_hm_attendance', 'attendance_status',
35+
existing_type=postgresql.ENUM('Attended', 'Excused', 'Absent', name='attendance_enum'),
36+
nullable=True)
37+
op.alter_column('member_hm_attendance', 'attendance_status',
38+
existing_type=postgresql.ENUM('Attended', 'Excused', 'Absent', name='attendance_enum'),
39+
nullable=True)
40+
op.drop_table('batch')
41+
# ### end Alembic commands ###
42+
43+
44+
def downgrade():
45+
# ### commands auto generated by Alembic - please adjust! ###
46+
op.alter_column('member_hm_attendance', 'attendance_status',
47+
existing_type=postgresql.ENUM('Attended', 'Excused', 'Absent', name='attendance_enum'),
48+
nullable=False)
49+
op.alter_column('freshman_hm_attendance', 'attendance_status',
50+
existing_type=postgresql.ENUM('Attended', 'Excused', 'Absent', name='attendance_enum'),
51+
nullable=False)
52+
op.alter_column('freshman_accounts', 'rit_username',
53+
existing_type=sa.VARCHAR(length=10),
54+
nullable=False)
55+
op.alter_column('freshman_accounts', 'onfloor_status',
56+
existing_type=sa.BOOLEAN(),
57+
nullable=False)
58+
op.create_table('batch_conditions',
59+
sa.Column('id', sa.INTEGER(), autoincrement=True, nullable=False),
60+
sa.Column('value', sa.INTEGER(), autoincrement=False, nullable=False),
61+
sa.Column('condition', postgresql.ENUM('packet', 'seminar', 'committee', 'house', name='batch_ctype_enum'), autoincrement=False, nullable=False),
62+
sa.Column('comparison', postgresql.ENUM('less', 'equal', 'greater', name='batch_comparison'), autoincrement=False, nullable=False),
63+
sa.Column('batch_id', sa.INTEGER(), autoincrement=False, nullable=False),
64+
sa.ForeignKeyConstraint(['batch_id'], ['batch.id'], name='batch_conditions_fk'),
65+
sa.PrimaryKeyConstraint('id', name='batch_conditions_pkey')
66+
)
67+
op.create_table('freshman_batch_users',
68+
sa.Column('id', sa.INTEGER(), autoincrement=True, nullable=False),
69+
sa.Column('fid', sa.INTEGER(), autoincrement=False, nullable=False),
70+
sa.Column('batch_id', sa.INTEGER(), autoincrement=False, nullable=False),
71+
sa.ForeignKeyConstraint(['batch_id'], ['batch.id'], name='freshman_batch_users_fk'),
72+
sa.ForeignKeyConstraint(['fid'], ['freshman_accounts.id'], name='freshman_batch_users_fk_1'),
73+
sa.PrimaryKeyConstraint('id', name='freshman_batch_users_pkey')
74+
)
75+
op.create_index('freshman_batch_users_id_pkey', 'freshman_batch_users', ['id'], unique=True)
76+
op.create_table('batch',
77+
sa.Column('id', sa.INTEGER(), server_default=sa.text("nextval('batch_id_seq'::regclass)"), autoincrement=True, nullable=False),
78+
sa.Column('name', sa.TEXT(), autoincrement=False, nullable=False),
79+
sa.Column('uid', sa.VARCHAR(length=32), autoincrement=False, nullable=False),
80+
sa.Column('approved', sa.BOOLEAN(), autoincrement=False, nullable=False),
81+
sa.PrimaryKeyConstraint('id', name='batch_pkey'),
82+
postgresql_ignore_search_path=False
83+
)
84+
op.create_table('member_batch_pulls',
85+
sa.Column('id', sa.INTEGER(), autoincrement=True, nullable=False),
86+
sa.Column('uid', sa.VARCHAR(length=32), autoincrement=False, nullable=False),
87+
sa.Column('approved', sa.BOOLEAN(), server_default=sa.text('false'), autoincrement=False, nullable=False),
88+
sa.Column('reason', sa.TEXT(), server_default=sa.text("''::text"), autoincrement=False, nullable=False),
89+
sa.Column('puller', sa.VARCHAR(), autoincrement=False, nullable=False),
90+
sa.PrimaryKeyConstraint('id', name='member_batch_pulls_pkey')
91+
)
92+
op.create_index('member_batch_pulls_id_idx', 'member_batch_pulls', ['id'], unique=True)
93+
op.create_table('freshman_batch_pulls',
94+
sa.Column('id', sa.INTEGER(), autoincrement=True, nullable=False),
95+
sa.Column('fid', sa.INTEGER(), autoincrement=False, nullable=False),
96+
sa.Column('approved', sa.BOOLEAN(), server_default=sa.text('false'), autoincrement=False, nullable=False),
97+
sa.Column('reason', sa.TEXT(), server_default=sa.text("''::text"), autoincrement=False, nullable=False),
98+
sa.Column('puller', sa.VARCHAR(), autoincrement=False, nullable=False),
99+
sa.ForeignKeyConstraint(['fid'], ['freshman_accounts.id'], name='freshman_batch_pulls_fk_1'),
100+
sa.PrimaryKeyConstraint('id', name='freshman_batch_pulls_pkey')
101+
)
102+
op.create_index('freshman_batch_pulls_id_idx', 'freshman_batch_pulls', ['id'], unique=True)
103+
op.create_table('member_batch_users',
104+
sa.Column('id', sa.INTEGER(), autoincrement=True, nullable=False),
105+
sa.Column('uid', sa.VARCHAR(length=32), autoincrement=False, nullable=False),
106+
sa.Column('batch_id', sa.INTEGER(), autoincrement=False, nullable=False),
107+
sa.ForeignKeyConstraint(['batch_id'], ['batch.id'], name='member_batch_users_fk'),
108+
sa.PrimaryKeyConstraint('id', name='member_batch_users_pkey')
109+
)
110+
op.create_index('member_batch_users_id_idx', 'member_batch_users', ['id'], unique=False)
111+
# ### end Alembic commands ###

0 commit comments

Comments
 (0)