Skip to content

Commit a377d83

Browse files
authored
Clean TODOs (#68)
* check next_url & refactor OfficerPosition module * refactor into the is_active_officer function * refactor officer data constructor into function * refactor is_filled_in blocks into methods * be explicit about the autoincrement constraint * update many TODOs & clean code
1 parent e9d2dcd commit a377d83

17 files changed

+248
-324
lines changed

src/admin/admin.py

-8
This file was deleted.

src/alembic/versions/066f3772fce6_create_user_session_table.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
def upgrade() -> None:
2323
op.create_table(
2424
"user_session",
25-
sa.Column("id", sa.Integer, primary_key=True),
25+
sa.Column("id", sa.Integer, primary_key=True, autoincrement=True),
2626
sa.Column("issue_time", sa.DateTime, nullable=False),
2727
sa.Column("session_id", sa.String(512), nullable=False),
2828
sa.Column("computing_id", sa.String(32), nullable=False),

src/alembic/versions/0db2c57ce969_add_persistent_user_table.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
def upgrade() -> None:
2323
op.create_table(
2424
"site_user",
25-
sa.Column("id", sa.Integer, primary_key=True),
25+
sa.Column("id", sa.Integer, primary_key=True, autoincrement=True),
2626
sa.Column("computing_id", sa.String(32), nullable=False),
2727
)
2828

src/alembic/versions/75857bf0c826_introduce_officer_tables.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -78,14 +78,14 @@ def downgrade() -> None:
7878
op.drop_table("site_user")
7979
op.create_table(
8080
"site_user",
81-
sa.Column("id", sa.Integer, primary_key=True),
81+
sa.Column("id", sa.Integer, primary_key=True, autoincrement=True),
8282
sa.Column("computing_id", sa.String(32), nullable=False),
8383
)
8484

8585
op.drop_table("user_session")
8686
op.create_table(
8787
"user_session",
88-
sa.Column("id", sa.Integer, primary_key=True),
88+
sa.Column("id", sa.Integer, primary_key=True, autoincrement=True),
8989
sa.Column("issue_time", sa.DateTime, nullable=False),
9090
sa.Column("session_id", sa.String(512), nullable=False),
9191
sa.Column("computing_id", sa.String(32), nullable=False),

src/auth/crud.py

+1-3
Original file line numberDiff line numberDiff line change
@@ -57,16 +57,14 @@ async def create_user_session(db_session: AsyncSession, session_id: str, computi
5757
async def remove_user_session(db_session: AsyncSession, session_id: str) -> dict:
5858
query = sqlalchemy.select(UserSession).where(UserSession.session_id == session_id)
5959
user_session = await db_session.scalars(query)
60-
await db_session.delete(user_session.first()) # TODO: what to do with this result that we're awaiting?
60+
await db_session.delete(user_session.first())
6161

6262

6363
async def check_user_session(db_session: AsyncSession, session_id: str) -> dict:
6464
query = sqlalchemy.select(UserSession).where(UserSession.session_id == session_id)
6565
existing_user_session = (await db_session.scalars(query)).first()
6666

6767
if existing_user_session:
68-
# TODO: replace this select with an sqlalchemy relationship access
69-
# see: https://docs.sqlalchemy.org/en/20/orm/basic_relationships.html
7068
query = sqlalchemy.select(SiteUser).where(SiteUser.computing_id == existing_user_session.computing_id)
7169
existing_user = (await db_session.scalars(query)).first()
7270
return {

src/auth/urls.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,15 @@ def generate_session_id_b64(num_bytes: int) -> str:
3737
description="Login to the sfucsss.org. Must redirect to this endpoint from SFU's cas authentication service for correct parameters",
3838
)
3939
async def login_user(
40-
next_url: str, # TODO: ensure next_url is a valid url? or local to our site or something...
40+
next_url: str,
4141
ticket: str,
4242
db_session: database.DBSession,
4343
background_tasks: BackgroundTasks,
4444
):
45+
# TODO: test this
46+
if not next_url.startswith(root_ip_address):
47+
raise HTTPException(status_code=400, detail=f"invalid next_url={next_url}, must be a page of our site")
48+
4549
# verify the ticket is valid
4650
url = (
4751
f"https://cas.sfu.ca/cas/serviceValidate?service={urllib.parse.quote(root_ip_address)}"

src/data/semesters.py

-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ def current_semester(the_date: date) -> Semester:
4848
elif the_date.month >= 1:
4949
return Semester.Spring
5050
else:
51-
# TODO: apparently static typecheckers exist in python!?
5251
assert_never()
5352

5453

src/load_test_db.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ async def load_test_officers_data(db_session: AsyncSession):
108108
await create_new_officer_term(db_session, OfficerTermData(
109109
computing_id="abc11",
110110

111-
position=OfficerPosition.VicePresident.value,
111+
position=OfficerPosition.VICE_PRESIDENT,
112112
start_date=date.today() - timedelta(days=365),
113113
end_date=date.today() - timedelta(days=1),
114114

@@ -125,7 +125,7 @@ async def load_test_officers_data(db_session: AsyncSession):
125125
await create_new_officer_term(db_session, OfficerTermData(
126126
computing_id="abc11",
127127

128-
position=OfficerPosition.ExecutiveAtLarge.value,
128+
position=OfficerPosition.EXECUTIVE_AT_LARGE,
129129
start_date=date.today(),
130130
end_date=None,
131131

@@ -142,7 +142,7 @@ async def load_test_officers_data(db_session: AsyncSession):
142142
await create_new_officer_term(db_session, OfficerTermData(
143143
computing_id="abc33",
144144

145-
position=OfficerPosition.President.value,
145+
position=OfficerPosition.PRESIDENT,
146146
start_date=date.today(),
147147
end_date=date.today() + timedelta(days=365),
148148

@@ -160,7 +160,7 @@ async def load_test_officers_data(db_session: AsyncSession):
160160
await create_new_officer_term(db_session, OfficerTermData(
161161
computing_id="abc22",
162162

163-
position=OfficerPosition.DirectorOfArchives.value,
163+
position=OfficerPosition.DIRECTOR_OF_ARCHIVES,
164164
start_date=date.today(),
165165
end_date=date.today() + timedelta(days=365),
166166

@@ -191,7 +191,7 @@ async def load_test_officers_data(db_session: AsyncSession):
191191
await update_officer_term(db_session, OfficerTermData(
192192
computing_id="abc33",
193193

194-
position=OfficerPosition.President.value,
194+
position=OfficerPosition.PRESIDENT,
195195
start_date=date.today(),
196196
end_date=date.today() + timedelta(days=365),
197197

@@ -226,7 +226,7 @@ async def load_sysadmin(db_session: AsyncSession):
226226
await create_new_officer_term(db_session, OfficerTermData(
227227
computing_id=SYSADMIN_COMPUTING_ID,
228228

229-
position=OfficerPosition.SystemAdministrator.value,
229+
position=OfficerPosition.SYSTEM_ADMINISTRATOR,
230230
start_date=date.today() - timedelta(days=365),
231231
end_date=None,
232232

src/officers/constants.py

+90-94
Original file line numberDiff line numberDiff line change
@@ -4,122 +4,72 @@
44

55
_logger = logging.getLogger(__name__)
66

7-
# TODO: remove enum, b/d python enums suck
8-
class OfficerPosition(Enum):
9-
President = "president"
10-
VicePresident = "vice-president"
11-
Treasurer = "treasurer"
12-
13-
DirectorOfResources = "director of resources"
14-
DirectorOfEvents = "director of events"
15-
DirectorOfEducationalEvents = "director of educational events"
16-
AssistantDirectorOfEvents = "assistant director of events"
17-
DirectorOfCommunications = "director of communications"
18-
#DirectorOfOutreach = "director of outreach"
19-
DirectorOfMultimedia = "director of multimedia"
20-
DirectorOfArchives = "director of archives"
21-
ExecutiveAtLarge = "executive at large"
22-
FirstYearRepresentative = "first year representative"
23-
24-
ElectionsOfficer = "elections officer"
25-
SFSSCouncilRepresentative = "sfss council representative"
26-
FroshWeekChair = "frosh week chair"
27-
28-
SystemAdministrator = "system administrator"
29-
Webmaster = "webmaster"
30-
SocialMediaManager = "social media manager"
7+
class OfficerPosition:
8+
PRESIDENT = "president"
9+
VICE_PRESIDENT = "vice-president"
10+
TREASURER = "treasurer"
11+
12+
DIRECTOR_OF_RESOURCES = "director of resources"
13+
DIRECTOR_OF_EVENTS = "director of events"
14+
DIRECTOR_OF_EDUCATIONAL_EVENTS = "director of educational events"
15+
ASSISTANT_DIRECTOR_OF_EVENTS = "assistant director of events"
16+
DIRECTOR_OF_COMMUNICATIONS = "director of communications"
17+
#DIRECTOR_OF_OUTREACH = "director of outreach"
18+
DIRECTOR_OF_MULTIMEDIA = "director of multimedia"
19+
DIRECTOR_OF_ARCHIVES = "director of archives"
20+
EXECUTIVE_AT_LARGE = "executive at large"
21+
FIRST_YEAR_REPRESENTATIVE = "first year representative"
22+
23+
ELECTIONS_OFFICER = "elections officer"
24+
SFSS_COUNCIL_REPRESENTATIVE = "sfss council representative"
25+
FROSH_WEEK_CHAIR = "frosh week chair"
26+
27+
SYSTEM_ADMINISTRATOR = "system administrator"
28+
WEBMASTER = "webmaster"
29+
SOCIAL_MEDIA_MANAGER = "social media manager"
3130

3231
@staticmethod
33-
def position_values() -> list[str]:
34-
return _OFFICER_POSITION_VALUES
32+
def position_list() -> list[str]:
33+
return _OFFICER_POSITION_LIST
3534

3635
@staticmethod
37-
def from_string(position: str) -> Self | None:
38-
for item in OfficerPosition:
39-
if position == item.value:
40-
return item
41-
42-
_logger.warning(f"Unknown OfficerPosition position = {position}. reporting N/A.")
43-
return None
44-
45-
def to_string(self) -> str:
46-
return self.value
47-
48-
def to_email(self) -> str:
49-
match self:
50-
case OfficerPosition.President:
51-
52-
case OfficerPosition.VicePresident:
53-
54-
case OfficerPosition.Treasurer:
55-
56-
57-
case OfficerPosition.DirectorOfResources:
58-
59-
case OfficerPosition.DirectorOfEvents:
60-
61-
case OfficerPosition.DirectorOfEducationalEvents:
62-
63-
case OfficerPosition.AssistantDirectorOfEvents:
64-
65-
case OfficerPosition.DirectorOfCommunications:
66-
67-
case OfficerPosition.DirectorOfMultimedia:
68-
69-
case OfficerPosition.DirectorOfArchives:
70-
71-
case OfficerPosition.ExecutiveAtLarge:
72-
73-
case OfficerPosition.FirstYearRepresentative:
74-
75-
76-
case OfficerPosition.ElectionsOfficer:
77-
78-
case OfficerPosition.SFSSCouncilRepresentative:
79-
80-
case OfficerPosition.FroshWeekChair:
81-
82-
83-
case OfficerPosition.SystemAdministrator:
84-
85-
case OfficerPosition.Webmaster:
86-
87-
case OfficerPosition.SocialMediaManager:
88-
return "N/A"
89-
90-
def num_active(self) -> int | None:
36+
def to_email(position: str) -> str | None:
37+
return _EMAIL_MAP.get(position, None)
38+
39+
@staticmethod
40+
def num_active(position: str) -> int | None:
9141
"""
9242
The number of executive positions active at a given time
9343
"""
9444
# None means there can be any number active
9545
if (
96-
self == OfficerPosition.ExecutiveAtLarge
97-
or self == OfficerPosition.FirstYearRepresentative
46+
position == OfficerPosition.ExecutiveAtLarge
47+
or position == OfficerPosition.FirstYearRepresentative
9848
):
9949
return 2
10050
elif (
101-
self == OfficerPosition.FroshWeekChair
102-
or self == OfficerPosition.SocialMediaManager
51+
position == OfficerPosition.FroshWeekChair
52+
or position == OfficerPosition.SocialMediaManager
10353
):
104-
# TODO: configure this value in a database table somewhere?
10554
return None
10655
else:
10756
return 1
10857

109-
def is_signer(self) -> bool:
58+
@staticmethod
59+
def is_signer(position: str) -> bool:
11060
"""
11161
If the officer is a signing authority of the CSSS
11262
"""
11363
return (
114-
self == OfficerPosition.President
115-
or self == OfficerPosition.VicePresident
116-
or self == OfficerPosition.Treasurer
117-
or self == OfficerPosition.DirectorOfResources
118-
or self == OfficerPosition.DirectorOfEvents
64+
position == OfficerPosition.President
65+
or position == OfficerPosition.VicePresident
66+
or position == OfficerPosition.Treasurer
67+
or position == OfficerPosition.DirectorOfResources
68+
or position == OfficerPosition.DirectorOfEvents
11969
)
12070

12171
@staticmethod
122-
def expected_positions() -> list[Self]:
72+
def expected_positions() -> list[str]:
12373
return [
12474
OfficerPosition.President,
12575
OfficerPosition.VicePresident,
@@ -145,6 +95,52 @@ def expected_positions() -> list[Self]:
14595
OfficerPosition.Webmaster,
14696
]
14797

148-
_OFFICER_POSITION_VALUES = [
149-
pos.value for pos in OfficerPosition.__members__.values()
98+
_EMAIL_MAP = {
99+
OfficerPosition.PRESIDENT: "[email protected]",
100+
OfficerPosition.VICE_PRESIDENT: "[email protected]",
101+
OfficerPosition.TREASURER: "[email protected]",
102+
103+
OfficerPosition.DIRECTOR_OF_RESOURCES: "[email protected]",
104+
OfficerPosition.DIRECTOR_OF_EVENTS: "[email protected]",
105+
OfficerPosition.DIRECTOR_OF_EDUCATIONAL_EVENTS: "[email protected]",
106+
OfficerPosition.ASSISTANT_DIRECTOR_OF_EVENTS: "[email protected]",
107+
OfficerPosition.DIRECTOR_OF_COMMUNICATIONS: "[email protected]",
108+
#OfficerPosition.DIRECTOR_OF_OUTREACH,
109+
OfficerPosition.DIRECTOR_OF_MULTIMEDIA: "[email protected]",
110+
OfficerPosition.DIRECTOR_OF_ARCHIVES: "[email protected]",
111+
OfficerPosition.EXECUTIVE_AT_LARGE: "[email protected]",
112+
OfficerPosition.FIRST_YEAR_REPRESENTATIVE: "[email protected]",
113+
114+
OfficerPosition.ELECTIONS_OFFICER: "[email protected]",
115+
OfficerPosition.SFSS_COUNCIL_REPRESENTATIVE: "[email protected]",
116+
OfficerPosition.FROSH_WEEK_CHAIR: "[email protected]",
117+
118+
OfficerPosition.SYSTEM_ADMINISTRATOR: "[email protected]",
119+
OfficerPosition.WEBMASTER: "[email protected]",
120+
OfficerPosition.SOCIAL_MEDIA_MANAGER: "N/A",
121+
}
122+
123+
_OFFICER_POSITION_LIST = [
124+
OfficerPosition.PRESIDENT,
125+
OfficerPosition.VICE_PRESIDENT,
126+
OfficerPosition.TREASURER,
127+
128+
OfficerPosition.DIRECTOR_OF_RESOURCES,
129+
OfficerPosition.DIRECTOR_OF_EVENTS,
130+
OfficerPosition.DIRECTOR_OF_EDUCATIONAL_EVENTS,
131+
OfficerPosition.ASSISTANT_DIRECTOR_OF_EVENTS,
132+
OfficerPosition.DIRECTOR_OF_COMMUNICATIONS,
133+
#OfficerPosition.DIRECTOR_OF_OUTREACH,
134+
OfficerPosition.DIRECTOR_OF_MULTIMEDIA,
135+
OfficerPosition.DIRECTOR_OF_ARCHIVES,
136+
OfficerPosition.EXECUTIVE_AT_LARGE,
137+
OfficerPosition.FIRST_YEAR_REPRESENTATIVE,
138+
139+
OfficerPosition.ELECTIONS_OFFICER,
140+
OfficerPosition.SFSS_COUNCIL_REPRESENTATIVE,
141+
OfficerPosition.FROSH_WEEK_CHAIR,
142+
143+
OfficerPosition.SYSTEM_ADMINISTRATOR,
144+
OfficerPosition.WEBMASTER,
145+
OfficerPosition.SOCIAL_MEDIA_MANAGER,
150146
]

0 commit comments

Comments
 (0)