diff --git a/labconnect/main/opportunity_routes.py b/labconnect/main/opportunity_routes.py index 4d04eb6f..52f95937 100644 --- a/labconnect/main/opportunity_routes.py +++ b/labconnect/main/opportunity_routes.py @@ -2,6 +2,7 @@ from flask import abort, request from flask_jwt_extended import get_jwt_identity, jwt_required +from sqlalchemy import func from labconnect import db from labconnect.helpers import LocationEnum, SemesterEnum, format_credits @@ -12,6 +13,7 @@ RecommendsClassYears, User, Courses, + RecommendsMajors, ) from . import main_blueprint @@ -108,16 +110,13 @@ def packageIndividualOpportunity(opportunityInfo): "name": opportunityInfo.name, "description": opportunityInfo.description, "recommended_experience": opportunityInfo.recommended_experience, - "author": "", - "department": "", - } - data = { - "id": opportunityInfo.id, - "name": opportunityInfo.name, - "description": opportunityInfo.description, - "recommended_experience": opportunityInfo.recommended_experience, - "author": "", + "authors": "", "department": "", + "pay": opportunityInfo.pay, + "credits": None, + "semester": f"{opportunityInfo.semester} {opportunityInfo.year}", + "application_due": opportunityInfo.application_due, + "recommended_class_years": "", } opportunity_credits = "" @@ -133,35 +132,16 @@ def packageIndividualOpportunity(opportunityInfo): if opportunity_credits != "": opportunity_credits += " credits" - data["aboutSection"] = [ - { - "title": "Pay", - "description": f"${opportunityInfo.pay} per hour", - }, - { - "title": "Semester", - "description": f"{opportunityInfo.semester} {opportunityInfo.year}", - }, - { - "title": "Application Due", - "description": opportunityInfo.application_due, - }, - ] - if opportunity_credits != "": - data["aboutSection"].append( - { - "title": "Credits", - "description": opportunity_credits, - } - ) + data["credits"] = opportunity_credits # get professor and department by getting Leads and LabManager query = db.session.execute( - db.select(Leads, LabManager) + db.select(Leads, LabManager, User) .where(Leads.opportunity_id == opportunityInfo.id) .join(LabManager, Leads.lab_manager_id == LabManager.id) + .join(User, LabManager.id == User.lab_manager_id) ) queryInfo = query.all() @@ -171,14 +151,11 @@ def packageIndividualOpportunity(opportunityInfo): data["department"] = queryInfo[0][1].department_id - # for i, item in enumerate(queryInfo): - # data["author"] += item[1].getName() - # data["author"] += "look at def packageIndividualOpportunity(opportunityInfo):" - # if i != len(queryInfo) - 1: - # data["author"] += ", " + author_info = [ + [item[2].first_name + " " + item[2].last_name, item[2].id] for item in queryInfo + ] - author_names = [item[1].getName() for item in queryInfo] - data["author"] = ", ".join(author_names) + data["authors"] = author_info if len(queryInfo) > 1: data["authorProfile"] = ( @@ -218,164 +195,175 @@ def packageOpportunityCard(opportunity): return card -# @main_blueprint.get("/getOpportunity/") -# def getOpportunity(opp_id: int): -# # query database for opportunity -# query = db.session.execute( -# db.select(Opportunities).where(Opportunities.id == opp_id) -# ) - -# data = query.all() - -# # check if opportunity exists -# if not data or len(data) == 0: -# abort(404) +@main_blueprint.get("/getOpportunity/") +def getOpportunity(opp_id: int): + # query database for opportunity and recommended class years + query = db.session.execute( + db.select( + Opportunities, + # Creates an array for all of the recommended class years for the opportunity labeled recommended_years + func.array_agg(RecommendsClassYears.class_year).label("recommended_years"), + ) + .join( + RecommendsClassYears, + Opportunities.id == RecommendsClassYears.opportunity_id, + ) + .where(Opportunities.id == opp_id) + .group_by(Opportunities.id) + ) -# data = data[0] -# oppData = packageIndividualOpportunity(data[0]) + data = query.all() + print(data) -# # return data in the below format if opportunity is found -# return {"data": oppData} + # check if opportunity exists + if not data or len(data) == 0: + abort(404) + data = data[0] + oppData = packageIndividualOpportunity(data[0]) + oppData["recommended_class_years"] = data[1] -# @main_blueprint.get("/opportunity/filter") -# @main_blueprint.route("/opportunity/filter", methods=["GET"]) -# def getOpportunities(): -# # Handle GET requests for fetching default active opportunities -# data = db.session.execute( -# db.select(Opportunities) -# .where(Opportunities.active == True) -# .limit(20) -# .order_by(Opportunities.last_updated.desc()) -# .distinct() -# ).scalars() -# result = [opportunity.to_dict() for opportunity in data] -# return result + # return data in the below format if opportunity is found + return {"data": oppData} -##@main_blueprint.route("/opportunity/filter", methods=["POST"]) -##def filterOpportunities(): -# Handle POST requests for filtering opportunities -##json_request_data = request.get_json() +@main_blueprint.get("/opportunity/filter") +def getOpportunities(): + # Handle GET requests for fetching default active opportunities + data = db.session.execute( + db.select(Opportunities) + .where(Opportunities.active == True) + .limit(20) + .order_by(Opportunities.last_updated.desc()) + .distinct() + ).scalars() + result = [opportunity.to_dict() for opportunity in data] + return result -# if not json_request_data: -# abort(400) +@main_blueprint.post("/opportunity/filter") +def filterOpportunities(): + # Handle POST requests for filtering opportunities + json_request_data = request.get_json() -# filters = json_request_data.get("filters", None) + if not json_request_data: + abort(400) -# data = None + filters = json_request_data.get("filters", None) -# if filters is None: -# data = db.session.execute(db.select(Opportunities).limit(20)).scalars() + data = None -# elif not isinstance(filters, list): -# abort(400) + if filters is None: + data = db.session.execute(db.select(Opportunities).limit(20)).scalars() -# else: + elif not isinstance(filters, list): + abort(400) -# where_conditions = [] -# query = ( -# db.select(Opportunities) -# .where(Opportunities.active == True) -# .limit(20) -# .order_by(Opportunities.last_updated) -# .distinct() -# ) -# for given_filter in filters: -# field = given_filter.get("field", None) -# value = given_filter.get("value", None) - -# if field and value: -# field = field.lower() - -# # Location filter -# if field == "location": -# if value.lower() == "remote": -# where_conditions.append(Opportunities.location == "REMOTE") -# else: -# where_conditions.append(Opportunities.location != "REMOTE") - -# # Class year filter -# elif field == "class_year": -# # if not isinstance(value, list): -# # abort(400) -# # query = query.join( -# # RecommendsClassYears, -# # Opportunities.id == RecommendsClassYears.opportunity_id, -# # ).where(RecommendsClassYears.class_year.in_(value)) - -# # # Credits filter -# elif field == "credits": -# if not isinstance(value, list): -# abort(400) -# # credit_conditions = [] -# # for credit in value: -# # if credit == 1: -# # credit_conditions.append(Opportunities.one_credit.is_(True)) -# # elif credit == 2: -# # credit_conditions.append( -# Opportunities.two_credits.is_(True) -# # ) -# elif credit == 3: -# # credit_conditions.append( -# # Opportunities.three_credits.is_(True) -# # ) -# # elif credit == 4: -# # credit_conditions.append( -# Opportunities.four_credits.is_(True) -# # ) -# else: -# # abort(400) -# where_conditions.append(db.or_(*credit_conditions)) - -# # # Majors filter -# # elif field == "majors": -# # if not isinstance(value, list): -# # abort(400) -# # query = query.join( -# # RecommendsMajors, -# # Opportunities.id == RecommendsMajors.opportunity_id, -# # ).where(RecommendsMajors.major_code.in_(value)) - -# # # Departments filter -# elif field == "departments": -# # if not isinstance(value, list): -# # abort(400) -# # query = ( -# # query.join(Leads, Opportunities.id == Leads.opportunity_id) -# # .join(LabManager, Leads.lab_manager_id == LabManager.id) -# # .where(LabManager.department_id.in_(value)) -# # ) - -# # # Pay filter -# elif field == "pay": -# # if not isinstance(value, dict): -# # abort(400) -# # min_pay = value.get("min") -# # max_pay = value.get("max") -# # if min_pay is None or max_pay is None: -# # abort(400) -# # where_conditions.append(Opportunities.pay.between(min_pay, max_pay)) - -# # # Other fields -# else: -# # try: -# # where_conditions.append( -# # getattr(Opportunities, field).ilike(f"%{value}%") -# # ) -# # except AttributeError: -# # abort(400) - -# # query = query.where(*where_conditions) -# # data = db.session.execute(query).scalars() - -# # if not data: -# # abort(404) - -# # result = [opportunity.to_dict() for opportunity in data] - -# # return result + else: + where_conditions = [] + query = ( + db.select(Opportunities) + .where(Opportunities.active == True) + .limit(20) + .order_by(Opportunities.last_updated) + .distinct() + ) + for given_filter in filters: + field = given_filter.get("field", None) + value = given_filter.get("value", None) + + if field and value: + field = field.lower() + + # Location filter + if field == "location": + if value.lower() == "remote": + where_conditions.append(Opportunities.location == "REMOTE") + else: + where_conditions.append(Opportunities.location != "REMOTE") + + # Class year filter + elif field == "class_year": + if not isinstance(value, list): + abort(400) + query = query.join( + RecommendsClassYears, + Opportunities.id == RecommendsClassYears.opportunity_id, + ).where(RecommendsClassYears.class_year.in_(value)) + + # Credits filter + elif field == "credits": + if not isinstance(value, list): + abort(400) + credit_conditions = [] + for credit in value: + if credit == 1: + credit_conditions.append(Opportunities.one_credit.is_(True)) + elif credit == 2: + credit_conditions.append( + Opportunities.two_credits.is_(True) + ) + elif credit == 3: + credit_conditions.append( + Opportunities.three_credits.is_(True) + ) + elif credit == 4: + credit_conditions.append( + Opportunities.four_credits.is_(True) + ) + else: + abort(400) + where_conditions.append(db.or_(*credit_conditions)) + + # Majors filter + elif field == "majors": + if not isinstance(value, list): + abort(400) + query = query.join( + RecommendsMajors, + Opportunities.id == RecommendsMajors.opportunity_id, + ).where(RecommendsMajors.major_code.in_(value)) + + # Departments filter + elif field == "departments": + if not isinstance(value, list): + abort(400) + query = ( + query.join(Leads, Opportunities.id == Leads.opportunity_id) + .join(LabManager, Leads.lab_manager_id == LabManager.id) + .where(LabManager.department_id.in_(value)) + ) + + # Pay filter + elif field == "pay": + if not isinstance(value, dict): + abort(400) + min_pay = value.get("min") + max_pay = value.get("max") + if min_pay is None: + min_pay = 0 + if max_pay is None: + max_pay = float("inf") + where_conditions.append(Opportunities.pay.between(min_pay, max_pay)) + + # Other fields + else: + try: + where_conditions.append( + getattr(Opportunities, field).ilike(f"%{value}%") + ) + except AttributeError: + abort(400) + + query = query.where(*where_conditions) + data = db.session.execute(query).scalars() + + if not data: + abort(404) + + result = [opportunity.to_dict() for opportunity in data] + + return result # @main_blueprint.put("/opportunity") @@ -636,11 +624,6 @@ def searchCourses(query: str): .distinct() .where( (Courses.code.ilike(f"%{query}%")) - | ( - User.last_name.ilike( - f"%{query}%" - ) # Case-insensitive partial match on course code - ) | ( Courses.name.ilike( f"%{query}%"