11from collections .abc import Sequence
2- from datetime import date , datetime
2+ from datetime import date
33
44import sqlalchemy
55from fastapi import HTTPException
1111import utils
1212from data import semesters
1313from officers .constants import OfficerPosition
14- from officers .models import OfficerInfoResponse , OfficerTermCreate
14+ from officers .models import OfficerInfoResponse
1515from officers .tables import OfficerInfo , OfficerTerm
1616
1717# NOTE: this module should not do any data validation; that should be done in the urls.py or higher layer
1818
19+
1920async def current_officers (
2021 db_session : database .DBSession ,
2122) -> list [OfficerInfoResponse ]:
2223 """
2324 Get info about officers that are active. Go through all active & complete officer terms.
24-
25- Returns a mapping between officer position and officer terms
2625 """
2726 curr_time = date .today ()
28- query = (sqlalchemy .select (OfficerTerm , OfficerInfo )
29- .join (OfficerInfo , OfficerTerm .computing_id == OfficerInfo .computing_id )
30- .where ((OfficerTerm .start_date <= curr_time ) & (OfficerTerm .end_date >= curr_time ))
31- .order_by (OfficerTerm .start_date .desc ())
32- )
27+ query = (
28+ sqlalchemy .select (OfficerTerm , OfficerInfo )
29+ .join (OfficerInfo , OfficerTerm .computing_id == OfficerInfo .computing_id )
30+ .where ((OfficerTerm .start_date <= curr_time ) & (OfficerTerm .end_date >= curr_time ))
31+ .order_by (OfficerTerm .start_date .desc ())
32+ )
3333
3434 result : Sequence [sqlalchemy .Row [tuple [OfficerTerm , OfficerInfo ]]] = (await db_session .execute (query )).all ()
35- officer_list = []
35+ officer_list : list [ OfficerInfoResponse ] = []
3636 for term , officer in result :
37- officer_list .append (OfficerInfoResponse (
38- legal_name = officer .legal_name ,
39- is_active = True ,
40- position = term .position ,
41- start_date = term .start_date ,
42- end_date = term .end_date ,
43- biography = term .biography ,
44- csss_email = OfficerPosition .to_email (term .position ),
45-
46- discord_id = officer .discord_id ,
47- discord_name = officer .discord_name ,
48- discord_nickname = officer .discord_nickname ,
49- computing_id = officer .computing_id ,
50- phone_number = officer .phone_number ,
51- github_username = officer .github_username ,
52- google_drive_email = officer .google_drive_email ,
53- photo_url = term .photo_url
54- ))
37+ officer_list .append (
38+ OfficerInfoResponse (
39+ legal_name = officer .legal_name ,
40+ is_active = True ,
41+ position = term .position ,
42+ start_date = term .start_date ,
43+ end_date = term .end_date ,
44+ biography = term .biography ,
45+ csss_email = OfficerPosition .to_email (term .position ),
46+ discord_id = officer .discord_id ,
47+ discord_name = officer .discord_name ,
48+ discord_nickname = officer .discord_nickname ,
49+ computing_id = officer .computing_id ,
50+ phone_number = officer .phone_number ,
51+ github_username = officer .github_username ,
52+ google_drive_email = officer .google_drive_email ,
53+ photo_url = term .photo_url ,
54+ )
55+ )
5556
5657 return officer_list
5758
58- async def all_officers (
59- db_session : AsyncSession ,
60- include_future_terms : bool
61- ) -> list [OfficerInfoResponse ]:
59+
60+ async def all_officers (db_session : AsyncSession , include_future_terms : bool ) -> list [OfficerInfoResponse ]:
6261 """
6362 This could be a lot of data, so be careful
6463 """
6564 # NOTE: paginate data if needed
66- query = (sqlalchemy .select (OfficerTerm , OfficerInfo )
67- .join (OfficerInfo , OfficerTerm .computing_id == OfficerInfo .computing_id )
68- .order_by (OfficerTerm .start_date .desc ())
69- )
65+ query = (
66+ sqlalchemy .select (OfficerTerm , OfficerInfo )
67+ .join (OfficerInfo , OfficerTerm .computing_id == OfficerInfo .computing_id )
68+ .order_by (OfficerTerm .start_date .desc ())
69+ )
7070
7171 if not include_future_terms :
7272 query = utils .has_started_term (query )
7373 result : Sequence [sqlalchemy .Row [tuple [OfficerTerm , OfficerInfo ]]] = (await db_session .execute (query )).all ()
74- officer_list = []
74+ officer_list : list [ OfficerInfoResponse ] = []
7575 for term , officer in result :
76- officer_list .append (OfficerInfoResponse (
77- legal_name = officer .legal_name ,
78- is_active = utils .is_active_term (term ),
79- position = term .position ,
80- start_date = term .start_date ,
81- end_date = term .end_date ,
82- biography = term .biography ,
83- csss_email = OfficerPosition .to_email (term .position ),
84-
85- discord_id = officer .discord_id ,
86- discord_name = officer .discord_name ,
87- discord_nickname = officer .discord_nickname ,
88- computing_id = officer .computing_id ,
89- phone_number = officer .phone_number ,
90- github_username = officer .github_username ,
91- google_drive_email = officer .google_drive_email ,
92- photo_url = term .photo_url
93- ))
76+ officer_list .append (
77+ OfficerInfoResponse (
78+ legal_name = officer .legal_name ,
79+ is_active = utils .is_active_term (term ),
80+ position = term .position ,
81+ start_date = term .start_date ,
82+ end_date = term .end_date ,
83+ biography = term .biography ,
84+ csss_email = OfficerPosition .to_email (term .position ),
85+ discord_id = officer .discord_id ,
86+ discord_name = officer .discord_name ,
87+ discord_nickname = officer .discord_nickname ,
88+ computing_id = officer .computing_id ,
89+ phone_number = officer .phone_number ,
90+ github_username = officer .github_username ,
91+ google_drive_email = officer .google_drive_email ,
92+ photo_url = term .photo_url ,
93+ )
94+ )
9495
9596 return officer_list
9697
98+
9799async def get_officer_info_or_raise (db_session : database .DBSession , computing_id : str ) -> OfficerInfo :
98100 officer_term = await db_session .scalar (
99- sqlalchemy
100- .select (OfficerInfo )
101- .where (OfficerInfo .computing_id == computing_id )
101+ sqlalchemy .select (OfficerInfo ).where (OfficerInfo .computing_id == computing_id )
102102 )
103103 if officer_term is None :
104104 raise HTTPException (status_code = 404 , detail = f"officer_info for computing_id={ computing_id } does not exist yet" )
105105 return officer_term
106106
107+
107108async def get_new_officer_info_or_raise (db_session : database .DBSession , computing_id : str ) -> OfficerInfo :
108109 """
109110 This check is for after a create/update
110111 """
111112 officer_term = await db_session .scalar (
112- sqlalchemy
113- .select (OfficerInfo )
114- .where (OfficerInfo .computing_id == computing_id )
113+ sqlalchemy .select (OfficerInfo ).where (OfficerInfo .computing_id == computing_id )
115114 )
116115 if officer_term is None :
117116 raise HTTPException (status_code = 500 , detail = f"failed to fetch { computing_id } after update" )
118117 return officer_term
119118
119+
120120async def get_officer_terms (
121121 db_session : database .DBSession ,
122122 computing_id : str ,
123123 include_future_terms : bool ,
124124) -> list [OfficerTerm ]:
125125 query = (
126- sqlalchemy
127- .select (OfficerTerm )
126+ sqlalchemy .select (OfficerTerm )
128127 .where (OfficerTerm .computing_id == computing_id )
129128 # In order of most recent start date first
130129 .order_by (OfficerTerm .start_date .desc ())
@@ -134,17 +133,14 @@ async def get_officer_terms(
134133
135134 return (await db_session .scalars (query )).all ()
136135
137- async def get_active_officer_terms (
138- db_session : database .DBSession ,
139- computing_id : str
140- ) -> list [OfficerTerm ]:
136+
137+ async def get_active_officer_terms (db_session : database .DBSession , computing_id : str ) -> list [OfficerTerm ]:
141138 """
142139 Returns the list of active officer terms for a user. Returns [] if the user is not currently an officer.
143140 An officer can have multiple positions at once, such as Webmaster, Frosh chair, and DoEE.
144141 """
145142 query = (
146- sqlalchemy
147- .select (OfficerTerm )
143+ sqlalchemy .select (OfficerTerm )
148144 .where (OfficerTerm .computing_id == computing_id )
149145 # In order of most recent start date first
150146 .order_by (OfficerTerm .start_date .desc ())
@@ -154,54 +150,46 @@ async def get_active_officer_terms(
154150 officer_term_list = (await db_session .scalars (query )).all ()
155151 return officer_term_list
156152
153+
157154async def current_officer_positions (db_session : database .DBSession , computing_id : str ) -> list [str ]:
158155 """
159156 Returns the list of officer positions a user currently has. [] if not currently an officer.
160157 """
161158 officer_term_list = await get_active_officer_terms (db_session , computing_id )
162159 return [term .position for term in officer_term_list ]
163160
164- async def get_officer_term_by_id_or_raise (db_session : database .DBSession , term_id : int , is_new : bool = False ) -> OfficerTerm :
165- officer_term = await db_session .scalar (
166- sqlalchemy
167- .select (OfficerTerm )
168- .where (OfficerTerm .id == term_id )
169- )
161+
162+ async def get_officer_term_by_id_or_raise (
163+ db_session : database .DBSession , term_id : int , is_new : bool = False
164+ ) -> OfficerTerm :
165+ officer_term = await db_session .scalar (sqlalchemy .select (OfficerTerm ).where (OfficerTerm .id == term_id ))
170166 if officer_term is None :
171167 if is_new :
172168 raise HTTPException (status_code = 500 , detail = f"could not find new officer_term with id={ term_id } " )
173169 else :
174170 raise HTTPException (status_code = 404 , detail = f"could not find officer_term with id={ term_id } " )
175171 return officer_term
176172
177- async def create_new_officer_info (
178- db_session : database .DBSession ,
179- new_officer_info : OfficerInfo
180- ) -> bool :
173+
174+ async def create_new_officer_info (db_session : database .DBSession , new_officer_info : OfficerInfo ) -> bool :
181175 """Return False if the officer already exists & don't do anything."""
182176 if not await auth .crud .site_user_exists (db_session , new_officer_info .computing_id ):
183177 # if computing_id has not been created as a site_user yet, add them
184- db_session .add (auth .tables .SiteUser (
185- computing_id = new_officer_info .computing_id ,
186- first_logged_in = None ,
187- last_logged_in = None
188- ))
178+ db_session .add (
179+ auth .tables .SiteUser (computing_id = new_officer_info .computing_id , first_logged_in = None , last_logged_in = None )
180+ )
189181
190182 existing_officer_info = await db_session .scalar (
191- sqlalchemy
192- .select (OfficerInfo )
193- .where (OfficerInfo .computing_id == new_officer_info .computing_id )
183+ sqlalchemy .select (OfficerInfo ).where (OfficerInfo .computing_id == new_officer_info .computing_id )
194184 )
195185 if existing_officer_info is not None :
196186 return False
197187
198188 db_session .add (new_officer_info )
199189 return True
200190
201- async def create_new_officer_term (
202- db_session : database .DBSession ,
203- new_officer_term : OfficerTerm
204- ):
191+
192+ async def create_new_officer_term (db_session : database .DBSession , new_officer_term : OfficerTerm ):
205193 position_length = OfficerPosition .length_in_semesters (new_officer_term .position )
206194 if position_length is not None :
207195 # when creating a new position, assign a default end date if one exists
@@ -211,31 +199,27 @@ async def create_new_officer_term(
211199 )
212200 db_session .add (new_officer_term )
213201
214- async def update_officer_info (
215- db_session : database .DBSession ,
216- new_officer_info : OfficerInfo
217- ) -> bool :
202+
203+ async def update_officer_info (db_session : database .DBSession , new_officer_info : OfficerInfo ) -> bool :
218204 """
219205 Return False if the officer doesn't exist yet
220206 """
221207 officer_info = await db_session .scalar (
222- sqlalchemy
223- .select (OfficerInfo )
224- .where (OfficerInfo .computing_id == new_officer_info .computing_id )
208+ sqlalchemy .select (OfficerInfo ).where (OfficerInfo .computing_id == new_officer_info .computing_id )
225209 )
226210 if officer_info is None :
227211 return False
228212
229213 # NOTE: if there's ever an insert entry error, it will raise SQLAlchemyError
230214 # see: https://stackoverflow.com/questions/2136739/how-to-check-and-handle-errors-in-sqlalchemy
231215 await db_session .execute (
232- sqlalchemy
233- .update (OfficerInfo )
216+ sqlalchemy .update (OfficerInfo )
234217 .where (OfficerInfo .computing_id == officer_info .computing_id )
235218 .values (new_officer_info .to_update_dict ())
236219 )
237220 return True
238221
222+
239223async def update_officer_term (
240224 db_session : database .DBSession ,
241225 new_officer_term : OfficerTerm ,
@@ -244,25 +228,17 @@ async def update_officer_term(
244228 Update all officer term data in `new_officer_term` based on the term id.
245229 Returns false if the above entry does not exist.
246230 """
247- officer_term = await db_session .scalar (
248- sqlalchemy
249- .select (OfficerTerm )
250- .where (OfficerTerm .id == new_officer_term .id )
251- )
231+ officer_term = await db_session .scalar (sqlalchemy .select (OfficerTerm ).where (OfficerTerm .id == new_officer_term .id ))
252232 if officer_term is None :
253233 return False
254234
255235 await db_session .execute (
256- sqlalchemy
257- .update (OfficerTerm )
236+ sqlalchemy .update (OfficerTerm )
258237 .where (OfficerTerm .id == new_officer_term .id )
259238 .values (new_officer_term .to_update_dict ())
260239 )
261240 return True
262241
242+
263243async def delete_officer_term_by_id (db_session : database .DBSession , term_id : int ):
264- await db_session .execute (
265- sqlalchemy
266- .delete (OfficerTerm )
267- .where (OfficerTerm .id == term_id )
268- )
244+ await db_session .execute (sqlalchemy .delete (OfficerTerm ).where (OfficerTerm .id == term_id ))
0 commit comments