From eb1871a9ad30c912e0f1099728fa1e311e4654af Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Tue, 11 Mar 2025 16:49:05 -0400 Subject: [PATCH 1/6] [#52] Create page to show saved opportunities https://pm.rafaelcenzano.com/work_packages/52 From 9ea2f6997903c6decbe55a46717c4f528da4caa8 Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Tue, 11 Mar 2025 17:43:16 -0400 Subject: [PATCH 2/6] cleanup code --- labconnect/main/opportunity_routes.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/labconnect/main/opportunity_routes.py b/labconnect/main/opportunity_routes.py index d38379f1..62a7a959 100644 --- a/labconnect/main/opportunity_routes.py +++ b/labconnect/main/opportunity_routes.py @@ -791,11 +791,9 @@ def deleteOpportunity(opportunity_id): # Save User Opportunity - - -@main_blueprint.post("/saveUserOpportunity/") +@main_blueprint.post("/saveOpportunity/") @jwt_required() -def saveUserOpportunity(opportunity_id): +def saveUserOpportunity(opportunity_id: int): data = request.get_json() if not data: abort(400, "Missing JSON data") @@ -821,7 +819,6 @@ def saveUserOpportunity(opportunity_id): new_opp = UserSavedOpportunities() new_opp.user_id = save_opp_user_id new_opp.opportunity_id = save_opp_opportunity_id - db.session.add(new_opp) db.session.commit() @@ -829,9 +826,9 @@ def saveUserOpportunity(opportunity_id): # Delete an opportunitiy saved by a user -@main_blueprint.delete("/deleteUserOpportunity/") +@main_blueprint.delete("/deleteSaveOpportunity/") @jwt_required() -def deleteUserOpportunity(opportunity_id): +def deleteUserOpportunity(opportunity_id: int): data = request.get_json() if not data: abort(400, "Missing JSON data") From 9618797eb899c8596c5d920bc88440101498e391 Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Tue, 11 Mar 2025 17:43:20 -0400 Subject: [PATCH 3/6] clean up imports --- db_init.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/db_init.py b/db_init.py index 3c08aed1..40cb4af2 100644 --- a/db_init.py +++ b/db_init.py @@ -31,6 +31,9 @@ UserCourses, UserDepartments, UserMajors, + UserSavedOpportunities, + Codes, + LabManager, ) url_regex = re.compile(r"^(https?|ftp)://[^\s/$.?#].[^\s]*$") From baa6da17328051826fa1f8b87b1e09b811de465d Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Thu, 18 Sep 2025 00:13:47 -0400 Subject: [PATCH 4/6] cleanup functions --- labconnect/main/opportunity_routes.py | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/labconnect/main/opportunity_routes.py b/labconnect/main/opportunity_routes.py index 62a7a959..009d03f4 100644 --- a/labconnect/main/opportunity_routes.py +++ b/labconnect/main/opportunity_routes.py @@ -826,18 +826,19 @@ def saveUserOpportunity(opportunity_id: int): # Delete an opportunitiy saved by a user -@main_blueprint.delete("/deleteSaveOpportunity/") +@main_blueprint.delete("/unsaveOpportunity/") @jwt_required() def deleteUserOpportunity(opportunity_id: int): data = request.get_json() if not data: abort(400, "Missing JSON data") - save_opp_user_id = get_jwt_identity() save_opp_opportunity_id = db.session.get(Opportunities, opportunity_id) if not save_opp_opportunity_id: return {"error": "Opportunity not found"}, 404 + save_opp_user_id = get_jwt_identity() + # Find the saved opportunity get_saved_opp_info = db.session.execute( db.select(UserSavedOpportunities).where( @@ -847,17 +848,17 @@ def deleteUserOpportunity(opportunity_id: int): ).scalar_one_or_none() if not get_saved_opp_info: - return {"message": "Opportunity not found"}, 404 + return {"message": "Opportunity not saved by user"} # Delete the opportunity db.session.delete(get_saved_opp_info) db.session.commit() - return {"message": "Opportunity deleted"}, 200 + return {"message": "Opportunity deleted"} # Create route to return a list saved opportunities -@main_blueprint.get("/AllSavedUserOpportunities/") +@main_blueprint.get("/savedOpportunities/") @jwt_required() def allSavedUserOportunities(): # Get current users ID @@ -874,21 +875,24 @@ def allSavedUserOportunities(): .all() ) if not saved_opps: - return {"message": "No saved opportunities found"}, 404 + return [] # Put opportunities into a dictionary saved_opportunities_list = [opp.to_dict() for opp in saved_opps] - return saved_opportunities_list, 200 + return saved_opportunities_list # Create route to allow for multiple pages to be unsaved given a list of opp_ids -@main_blueprint.delete("/UnsaveMultiplePages/") +@main_blueprint.delete("/unsaveOpportunities/") @jwt_required() # Delete id that appear on delete_ids list def UnsaveMultipleOpps(): # Get a list of opportunity IDs data = request.get_json() + if not data: + abort(400) + delete_ids = data.get("delete_ids") if not delete_ids or not isinstance(delete_ids, list): return {"message": "Invalid or missing delete_ids"}, 400 @@ -906,7 +910,7 @@ def UnsaveMultipleOpps(): .all() ) if not saved_opps: - return {"message": "User has no saved opportunities"}, 404 + return {"message": "User did not have these opportunities saved"} # Delete the opportinities for opp in saved_opps: From 8129f4d012f3ecb55051d968d1551819f6c44f3c Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Fri, 17 Oct 2025 02:59:43 -0400 Subject: [PATCH 5/6] Fixed up save opportunities list route --- Makefile | 2 +- db_init.py | 29 ++++++++--- labconnect/main/opportunity_routes.py | 71 ++++++++++++++++++++++----- 3 files changed, 83 insertions(+), 19 deletions(-) diff --git a/Makefile b/Makefile index 80f6b7a4..7c81d563 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ run: develop: python3 app.py -test: drop create +test: clean drop create python3 -m pytest --cov --cov-report=html:coverage_report drop: diff --git a/db_init.py b/db_init.py index 40cb4af2..0acbfea0 100644 --- a/db_init.py +++ b/db_init.py @@ -16,8 +16,9 @@ from labconnect.helpers import LocationEnum, SemesterEnum from labconnect.models import ( ClassYears, + Codes, Courses, - LabManager, # Professors and Grad students + LabManager, Leads, Majors, Opportunities, @@ -32,8 +33,6 @@ UserDepartments, UserMajors, UserSavedOpportunities, - Codes, - LabManager, ) url_regex = re.compile(r"^(https?|ftp)://[^\s/$.?#].[^\s]*$") @@ -573,6 +572,21 @@ def main() -> None: db.session.add(row) db.session.commit() + user_saved_opportunities_rows = ( + ("cenzar", 2), + ("cenzar", 3), + ("test", 3), + ("test", 1), + ) + + for r in user_saved_opportunities_rows: + row = UserSavedOpportunities() + row.user_id = r[0] + row.opportunity_id = r[1] + + db.session.add(row) + db.session.commit() + tables = [ ClassYears, Courses, @@ -589,6 +603,8 @@ def main() -> None: UserCourses, UserDepartments, UserMajors, + UserSavedOpportunities, + Codes, ] for table in tables: @@ -598,11 +614,10 @@ def main() -> None: inst = db.inspect(table) attr_names = [c_attr.key for c_attr in inst.mapper.column_attrs] - print(f"{table.__tablename__}") - print(attr_names) + app.logger.info(f"{table.__tablename__}") + app.logger.info(attr_names) for row in result: - print(row) - print() + app.logger.info(row) print("Number of tables:", len(tables)) diff --git a/labconnect/main/opportunity_routes.py b/labconnect/main/opportunity_routes.py index 009d03f4..939ca754 100644 --- a/labconnect/main/opportunity_routes.py +++ b/labconnect/main/opportunity_routes.py @@ -804,10 +804,17 @@ def saveUserOpportunity(opportunity_id: int): save_opp_user_id = get_jwt_identity() + user = db.session.execute( + db.select(User).where(User.email == save_opp_user_id) + ).scalar_one_or_none() + + if not user: + return {"error": "User not found"}, 404 + # Check if the opportunity already exists in saved opportunities find_opp = db.session.execute( db.select(UserSavedOpportunities).where( - (UserSavedOpportunities.user_id == save_opp_user_id) + (UserSavedOpportunities.user_id == user.id) & (UserSavedOpportunities.opportunity_id == save_opp_opportunity_id) ) ).scalar_one_or_none() @@ -839,10 +846,17 @@ def deleteUserOpportunity(opportunity_id: int): save_opp_user_id = get_jwt_identity() + user = db.session.execute( + db.select(User).where(User.email == save_opp_user_id) + ).scalar_one_or_none() + + if not user: + return {"error": "User not found"}, 404 + # Find the saved opportunity get_saved_opp_info = db.session.execute( db.select(UserSavedOpportunities).where( - (UserSavedOpportunities.user_id == save_opp_user_id) + (UserSavedOpportunities.user_id == user.id) & (UserSavedOpportunities.opportunity_id == save_opp_opportunity_id) ) ).scalar_one_or_none() @@ -864,21 +878,56 @@ def allSavedUserOportunities(): # Get current users ID user_id = get_jwt_identity() + user = db.session.execute( + db.select(User).where(User.email == user_id) + ).scalar_one_or_none() + + if not user: + return {"error": "User not found"}, 404 + # Get all saved opportunities for the user - saved_opps = ( - db.session.execute( - db.select(UserSavedOpportunities).where( - UserSavedOpportunities.user_id == user_id - ) + saved_opps = db.session.execute( + db.select( + Opportunities.id, + Opportunities.name, + Opportunities.description, + Opportunities.application_due, + Opportunities.pay, + Opportunities.one_credit, + Opportunities.two_credits, + Opportunities.three_credits, + Opportunities.four_credits, + Opportunities.active, + Opportunities.semester, + Opportunities.year, + Opportunities.location, ) - .scalars() - .all() - ) + .join( + UserSavedOpportunities, + Opportunities.id == UserSavedOpportunities.opportunity_id, + ) + .where(UserSavedOpportunities.user_id == user.id) + ).all() + if not saved_opps: return [] # Put opportunities into a dictionary - saved_opportunities_list = [opp.to_dict() for opp in saved_opps] + saved_opportunities_list = [ + { + "id": row[0], + "name": row[1], + "description": row[2], + "application_due": row[3].strftime("%-m/%-d/%y"), + "pay": row[4], + "credits": format_credits(row[5], row[6], row[7], row[8]), + "active": row[9], + "semester": row[10], + "year": row[11], + "location": row[12], + } + for row in saved_opps + ] return saved_opportunities_list From c427e215f8e8d6055f58d7db0c50b90e0cec51e4 Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Fri, 17 Oct 2025 14:55:49 -0400 Subject: [PATCH 6/6] fix save and unsave opportunity --- labconnect/main/opportunity_routes.py | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/labconnect/main/opportunity_routes.py b/labconnect/main/opportunity_routes.py index 939ca754..b106d7c5 100644 --- a/labconnect/main/opportunity_routes.py +++ b/labconnect/main/opportunity_routes.py @@ -811,21 +811,23 @@ def saveUserOpportunity(opportunity_id: int): if not user: return {"error": "User not found"}, 404 + opp_id = save_opp_opportunity_id.id + # Check if the opportunity already exists in saved opportunities find_opp = db.session.execute( db.select(UserSavedOpportunities).where( (UserSavedOpportunities.user_id == user.id) - & (UserSavedOpportunities.opportunity_id == save_opp_opportunity_id) + & (UserSavedOpportunities.opportunity_id == opp_id) ) ).scalar_one_or_none() if find_opp: return {"message": "Opportunity already saved"}, 200 - # Save the new opportunity + # Save the new opportunity using scalar IDs new_opp = UserSavedOpportunities() - new_opp.user_id = save_opp_user_id - new_opp.opportunity_id = save_opp_opportunity_id + new_opp.user_id = user.id + new_opp.opportunity_id = opp_id db.session.add(new_opp) db.session.commit() @@ -835,13 +837,9 @@ def saveUserOpportunity(opportunity_id: int): # Delete an opportunitiy saved by a user @main_blueprint.delete("/unsaveOpportunity/") @jwt_required() -def deleteUserOpportunity(opportunity_id: int): - data = request.get_json() - if not data: - abort(400, "Missing JSON data") - - save_opp_opportunity_id = db.session.get(Opportunities, opportunity_id) - if not save_opp_opportunity_id: +def unsaveUserOpportunity(opportunity_id: int): + opp_obj = db.session.get(Opportunities, opportunity_id) + if not opp_obj: return {"error": "Opportunity not found"}, 404 save_opp_user_id = get_jwt_identity() @@ -853,11 +851,11 @@ def deleteUserOpportunity(opportunity_id: int): if not user: return {"error": "User not found"}, 404 - # Find the saved opportunity + # Find the saved opportunity using scalar IDs get_saved_opp_info = db.session.execute( db.select(UserSavedOpportunities).where( (UserSavedOpportunities.user_id == user.id) - & (UserSavedOpportunities.opportunity_id == save_opp_opportunity_id) + & (UserSavedOpportunities.opportunity_id == opportunity_id) ) ).scalar_one_or_none()