22
33from flask import abort , request
44from flask_jwt_extended import get_jwt_identity , jwt_required
5- from sqlalchemy import func
5+ from sqlalchemy import func , case
66
77from labconnect import db
88from labconnect .helpers import (
@@ -143,31 +143,6 @@ def packageIndividualOpportunity(opportunityInfo):
143143 return data
144144
145145
146- def packageOpportunityCard (opportunity ):
147- # get professor and department by getting Leads and LabManager
148- query = db .session .execute (
149- db .select (Leads , LabManager , User .first_name , User .last_name )
150- .where (Leads .opportunity_id == opportunity .id )
151- .join (LabManager , Leads .lab_manager_id == LabManager .id )
152- .join (User , LabManager .id == User .lab_manager_id )
153- )
154-
155- data = query .all ()
156-
157- professorInfo = ", " .join (item [1 ].getName () for item in data )
158-
159- card = {
160- "id" : opportunity .id ,
161- "title" : opportunity .name ,
162- "professor" : professorInfo ,
163- "season" : opportunity .semester ,
164- "location" : "TBA" ,
165- "year" : opportunity .year ,
166- }
167-
168- return card
169-
170-
171146@main_blueprint .get ("/getOpportunity/<int:opp_id>" )
172147def getOpportunity (opp_id : int ):
173148 # query database for opportunity and recommended class years
@@ -200,86 +175,94 @@ def getOpportunity(opp_id: int):
200175
201176
202177@main_blueprint .get ("/opportunity/filter" )
203- def getOpportunities ():
204- # Handle GET requests for fetching default active opportunities
205- data = db .session .execute (
206- db .select (Opportunities )
207- .where (Opportunities .active )
208- .limit (20 )
209- .order_by (Opportunities .last_updated .desc ())
210- .distinct ()
211- ).scalars ()
212- result = [serialize_opportunity (opportunity ) for opportunity in data ]
213- return result
214-
215-
216- @main_blueprint .post ("/opportunity/filter" )
178+ @jwt_required ()
217179def filterOpportunities ():
218- # Handle POST requests for filtering opportunities
219- json_request_data = request .get_json ()
220-
221- if not json_request_data :
222- abort (400 )
223-
224- filters = json_request_data .get ("filters" , None )
225-
180+ # Handle GET requests for filtering opportunities using query parameters
181+ filters = request .args .to_dict (flat = False )
182+ user_id = get_jwt_identity ()
226183 data = None
227184
228- if filters is None :
229- data = db .session .execute (db .select (Opportunities ).limit (20 )).scalars ()
230-
231- elif not isinstance (filters , list ):
232- abort (400 )
233-
234- else :
235- where_conditions = []
236- query = (
237- db .select (Opportunities )
238- .where (Opportunities .active )
239- .limit (20 )
240- .order_by (Opportunities .last_updated )
241- .distinct ()
185+ query = (
186+ db .select (
187+ Opportunities ,
188+ func .json_agg (
189+ func .json_build_object (
190+ "first_name" ,
191+ User .first_name ,
192+ "last_name" ,
193+ User .last_name ,
194+ "preferred_name" ,
195+ User .preferred_name ,
196+ )
197+ ).label ("lab_managers" ),
198+ case ((UserSavedOpportunities .user_id .isnot (None ), True ), else_ = False ).label (
199+ "is_saved"
200+ ),
201+ )
202+ .join (Leads , Opportunities .id == Leads .opportunity_id )
203+ .join (LabManager , Leads .lab_manager_id == LabManager .id )
204+ .join (User , LabManager .id == User .lab_manager_id )
205+ .outerjoin (
206+ RecommendsMajors , Opportunities .id == RecommendsMajors .opportunity_id
242207 )
243- for given_filter in filters :
244- field = given_filter .get ("field" , None )
245- value = given_filter .get ("value" , None )
208+ .outerjoin (
209+ UserSavedOpportunities ,
210+ db .and_ (
211+ Opportunities .id == UserSavedOpportunities .opportunity_id ,
212+ UserSavedOpportunities .user_id == user_id , # filter for current user
213+ ),
214+ )
215+ .where (Opportunities .active )
216+ .group_by (Opportunities .id , UserSavedOpportunities .user_id )
217+ .order_by (Opportunities .last_updated )
218+ .limit (20 )
219+ )
246220
221+ if filters is not None or filters != {}:
222+ where_conditions = []
223+ for field , value in filters .items ():
247224 if field and value :
248225 field = field .lower ()
226+ value = value [0 ].split ("," )
249227
250228 # Location filter
229+ # not in use yet
251230 if field == "location" :
252- if value .lower () == "remote" :
253- where_conditions .append (Opportunities .location == "REMOTE" )
254- else :
255- where_conditions .append (Opportunities .location != "REMOTE" )
231+ for location in value :
232+ if location .lower () == "remote" :
233+ where_conditions .append (Opportunities .location == "REMOTE" )
234+ else :
235+ where_conditions .append (Opportunities .location != "REMOTE" )
256236
257237 # Class year filter
258- elif field == "class_year " :
238+ elif field == "years " :
259239 if not isinstance (value , list ):
260240 abort (400 )
241+ years = list (map (int , filter (str .isdigit , value )))
242+ if len (years ) == 0 :
243+ abort (400 )
261244 query = query .join (
262245 RecommendsClassYears ,
263246 Opportunities .id == RecommendsClassYears .opportunity_id ,
264- ).where (RecommendsClassYears .class_year .in_ (value ))
247+ ).where (RecommendsClassYears .class_year .in_ (years ))
265248
266249 # Credits filter
267250 elif field == "credits" :
268251 if not isinstance (value , list ):
269252 abort (400 )
270253 credit_conditions = []
271254 for credit in value :
272- if credit == 1 :
255+ if credit == "1" :
273256 credit_conditions .append (Opportunities .one_credit .is_ (True ))
274- elif credit == 2 :
257+ elif credit == "2" :
275258 credit_conditions .append (
276259 Opportunities .two_credits .is_ (True )
277260 )
278- elif credit == 3 :
261+ elif credit == "3" :
279262 credit_conditions .append (
280263 Opportunities .three_credits .is_ (True )
281264 )
282- elif credit == 4 :
265+ elif credit == "4" :
283266 credit_conditions .append (
284267 Opportunities .four_credits .is_ (True )
285268 )
@@ -291,12 +274,10 @@ def filterOpportunities():
291274 elif field == "majors" :
292275 if not isinstance (value , list ):
293276 abort (400 )
294- query = query .join (
295- RecommendsMajors ,
296- Opportunities .id == RecommendsMajors .opportunity_id ,
297- ).where (RecommendsMajors .major_code .in_ (value ))
277+ where_conditions .append (RecommendsMajors .major_code .in_ (value ))
298278
299279 # Departments filter
280+ # not currently in use
300281 elif field == "departments" :
301282 if not isinstance (value , list ):
302283 abort (400 )
@@ -307,16 +288,11 @@ def filterOpportunities():
307288 )
308289
309290 # Pay filter
310- elif field == "pay" :
311- if not isinstance (value , dict ):
291+ elif field == "hourlypay" :
292+ pay = value [0 ]
293+ if not pay .isnumeric ():
312294 abort (400 )
313- min_pay = value .get ("min" )
314- max_pay = value .get ("max" )
315- if min_pay is None :
316- min_pay = 0
317- if max_pay is None :
318- max_pay = float ("inf" )
319- where_conditions .append (Opportunities .pay .between (min_pay , max_pay ))
295+ where_conditions .append (Opportunities .pay >= float (pay ))
320296
321297 # Other fields
322298 else :
@@ -328,29 +304,29 @@ def filterOpportunities():
328304 abort (400 )
329305
330306 query = query .where (* where_conditions )
331- data = db .session .execute (query ).scalars ()
307+
308+ data = db .session .execute (query ).all ()
332309
333310 if not data :
334311 abort (404 )
335312
336- result = [serialize_opportunity (opportunity ) for opportunity in data ]
313+ result = [
314+ serialize_opportunity (
315+ opportunity [0 ],
316+ lab_managers = ", " .join (
317+ [
318+ f"{ name .get ('preferred_name' , None ) or name .get ('first_name' )} { name .get ('last_name' )} "
319+ for name in opportunity [1 ]
320+ ]
321+ ),
322+ saved = opportunity [2 ],
323+ )
324+ for opportunity in data
325+ ]
337326
338327 return result
339328
340329
341- # Jobs page
342- @main_blueprint .get ("/getOpportunityCards" )
343- def getOpportunityCards ():
344- # query database for opportunity
345- query = db .session .execute (db .select (Opportunities ).where (Opportunities .active ))
346-
347- data = query .fetchall ()
348- # return data in the below format if opportunity is found
349- cards = {"data" : [packageOpportunityCard (opportunity [0 ]) for opportunity in data ]}
350-
351- return cards
352-
353-
354330@main_blueprint .get ("/staff/opportunities/<string:rcs_id>" )
355331def getLabManagerOpportunityCards (rcs_id : str ) -> list [dict [str , str ]]:
356332 query = (
@@ -388,6 +364,7 @@ def getLabManagerOpportunityCards(rcs_id: str) -> list[dict[str, str]]:
388364
389365
390366@main_blueprint .get ("/profile/opportunities/<string:rcs_id>" )
367+ @jwt_required ()
391368def getProfileOpportunities (rcs_id : str ) -> list [dict [str , str ]]:
392369 query = (
393370 db .select (
0 commit comments