From ddf10e3cc7230c78d57adfa64622bc96116e49f0 Mon Sep 17 00:00:00 2001 From: youssefr26 Date: Thu, 3 Oct 2024 21:31:05 -0400 Subject: [PATCH 01/99] Fixed several Deepsource errors. --- labconnect/main/opportunity_routes.py | 38 ++++++++++++++------------- labconnect/main/routes.py | 2 +- labconnect/models.py | 2 +- 3 files changed, 22 insertions(+), 20 deletions(-) diff --git a/labconnect/main/opportunity_routes.py b/labconnect/main/opportunity_routes.py index 5bb300c..e041182 100644 --- a/labconnect/main/opportunity_routes.py +++ b/labconnect/main/opportunity_routes.py @@ -1,6 +1,7 @@ import datetime from flask import abort, request + from flask_jwt_extended import ( get_jwt_identity, jwt_required, @@ -22,25 +23,25 @@ from . import main_blueprint -@main_blueprint.route("/searchOpportunity/", methods=["GET"]) -def searchOpportunity(input: str): +@main_blueprint.route("/searchOpportunity/", methods=["GET"]) +def searchOpportunity(query: str): # Perform a search stmt = ( db.select(Opportunities) .where( ( - Opportunities.search_vector.match(input) + Opportunities.search_vector.match(query) ) # Full-text search using pre-generated tsvector | ( - db.func.similarity(Opportunities.name, input) >= 0.1 + db.func.similarity(Opportunities.name, query) >= 0.1 ) # Fuzzy search on the 'name' field | ( - db.func.similarity(Opportunities.description, input) >= 0.1 + db.func.similarity(Opportunities.description, query) >= 0.1 ) # Fuzzy search on the 'description' field ) .order_by( db.func.similarity( - Opportunities.name, input + Opportunities.name, query ).desc() # Order by similarity for fuzzy search results ) ) @@ -94,13 +95,14 @@ def packageOpportunity(opportunityInfo, professorInfo): def packageIndividualOpportunity(opportunityInfo): - data = {} - data["id"] = opportunityInfo.id - data["name"] = opportunityInfo.name - data["description"] = opportunityInfo.description - data["recommended_experience"] = opportunityInfo.recommended_experience - data["author"] = "" - data["department"] = "" + data = { + "id": opportunityInfo.id, + "name": opportunityInfo.name, + "description": opportunityInfo.description, + "recommended_experience": opportunityInfo.recommended_experience, + "author": "", + "department": "", + } opportunity_credits = "" if opportunityInfo.one_credit: @@ -299,15 +301,15 @@ def filterOpportunities(): for credit in value: if credit == 1: - credit_conditions.append(Opportunities.one_credit == True) + credit_conditions.append(Opportunities.one_credit is True) elif credit == 2: - credit_conditions.append(Opportunities.two_credits == True) + credit_conditions.append(Opportunities.two_credits is True) elif credit == 3: credit_conditions.append( - Opportunities.three_credits == True + Opportunities.three_credits is True ) elif credit == 4: - credit_conditions.append(Opportunities.four_credits == True) + credit_conditions.append(Opportunities.four_credits is True) else: abort(400) @@ -710,7 +712,7 @@ def createOpportunity(): @main_blueprint.route("/editOpportunity", methods=["DELETE", "POST"]) def editOpportunity(): - if True: + if request.method in ["DELETE", "POST"]: data = request.get_json() id = data["id"] # authToken = data["authToken"] diff --git a/labconnect/main/routes.py b/labconnect/main/routes.py index 9c2b439..9aa01c3 100644 --- a/labconnect/main/routes.py +++ b/labconnect/main/routes.py @@ -428,7 +428,7 @@ def courses() -> list[Any]: @main_blueprint.get("/user") -def user(): +def get_user(): if not request.data: abort(400) diff --git a/labconnect/models.py b/labconnect/models.py index 28407e2..9bc3729 100644 --- a/labconnect/models.py +++ b/labconnect/models.py @@ -197,7 +197,7 @@ class Opportunities(db.Model, CustomSerializerMixin): @event.listens_for(Opportunities, "before_insert") @event.listens_for(Opportunities, "before_update") -def update_search_vector(mapper, connection, target): +def update_search_vector(_unusedmapper, _unusedconnection, target): target.search_vector = func.to_tsvector( "english", target.name + " " + target.description ) From 23c90b9733991908395e4eef90c61cacbdf670ec Mon Sep 17 00:00:00 2001 From: SarahWohlford <157171746+SarahWohlford@users.noreply.github.com> Date: Fri, 4 Oct 2024 16:56:20 -0400 Subject: [PATCH 02/99] Start of opportunity routes --- labconnect/main/opportunity_routes.py | 44 +++++++++------------------ 1 file changed, 14 insertions(+), 30 deletions(-) diff --git a/labconnect/main/opportunity_routes.py b/labconnect/main/opportunity_routes.py index 5bb300c..09008d7 100644 --- a/labconnect/main/opportunity_routes.py +++ b/labconnect/main/opportunity_routes.py @@ -22,7 +22,7 @@ from . import main_blueprint -@main_blueprint.route("/searchOpportunity/", methods=["GET"]) +@main_blueprint.get("/searchOpportunity/") def searchOpportunity(input: str): # Perform a search stmt = ( @@ -202,7 +202,7 @@ def packageOpportunityCard(opportunity): return card -@main_blueprint.route("/getOpportunity/", methods=["GET"]) +@main_blueprint.get("/getOpportunity/") def getOpportunity(opp_id: int): # query database for opportunity query = db.session.execute( @@ -396,9 +396,8 @@ def changeActiveStatus2(): return {"msg": "Opportunity updated successfully"}, 200 -@main_blueprint.route("/getOpportunityMeta/", methods=["GET"]) +@main_blueprint.get("/getOpportunityMeta/") def getOpportunityMeta(id: int): - if request.method == "GET": query = db.session.execute( db.select( Opportunities, RecommendsMajors, RecommendsCourses, RecommendsClassYears @@ -457,13 +456,9 @@ def getOpportunityMeta(id: int): return {"data": dictionary} - abort(500) - - # Jobs page -@main_blueprint.route("/getOpportunityCards", methods=["GET"]) +@main_blueprint.get("/getOpportunityCards") def getOpportunityCards(): - if request.method == "GET": # query database for opportunity query = db.session.execute( db.select(Opportunities).where(Opportunities.active == True) @@ -478,12 +473,8 @@ def getOpportunityCards(): return cards - abort(500) - - -@main_blueprint.route("/getOpportunities", methods=["GET"]) +@main_blueprint.get("/getOpportunities") def getOpportunities(): - if request.method == "GET": # query database for opportunity query = db.session.execute( db.select(Opportunities, Leads, LabManager) @@ -501,12 +492,9 @@ def getOpportunities(): ] } - abort(500) - -@main_blueprint.route("/getOpportunityByProfessor/", methods=["GET"]) +@main_blueprint.get("/getOpportunityByProfessor/") def getOpportunityByProfessor(rcs_id: str): - if request.method == "GET": # query database for opportunity query = db.session.execute( db.select(Opportunities, Leads) @@ -516,16 +504,14 @@ def getOpportunityByProfessor(rcs_id: str): data = query.all() print(data) - - # return data in the below format if opportunity is found + # return data in the format bellow if opportunity is found return {"data": [opportunity[0].to_dict() for opportunity in data]} - abort(500) -@main_blueprint.route("/getProfessorOpportunityCards/", methods=["GET"]) +@main_blueprint.get("/getProfessorOpportunityCards/") def getProfessorOpportunityCards(rcs_id: str): - if request.method == "GET": + # query database for opportunity user = db.first_or_404(db.select(User).where(User.email == rcs_id)) @@ -568,12 +554,11 @@ def getProfessorOpportunityCards(rcs_id: str): # return data in the below format if opportunity is found return cards - abort(500) -@main_blueprint.route("/getProfileOpportunities/", methods=["GET"]) + +@main_blueprint.get("/getProfileOpportunities/") def getProfileOpportunities(rcs_id: str): - if request.method == "GET": # query database for opportunity query = db.session.execute( @@ -612,13 +597,12 @@ def getProfileOpportunities(rcs_id: str): # return data in the below format if opportunity is found return cards - abort(500) # functions to create/edit/delete opportunities -@main_blueprint.route("/createOpportunity", methods=["POST"]) +@main_blueprint.post("/createOpportunity") def createOpportunity(): - if request.method == "POST": + #if request.method == "POST": data = request.get_json() authorID = data["authorID"] newPostData = data @@ -705,7 +689,7 @@ def createOpportunity(): return {"data": "Opportunity Created"} - abort(500) + #abort(500) @main_blueprint.route("/editOpportunity", methods=["DELETE", "POST"]) From ad22653370de8d63f6006b6f5765dd0318910fb8 Mon Sep 17 00:00:00 2001 From: youssefr26 Date: Fri, 4 Oct 2024 17:07:44 -0400 Subject: [PATCH 03/99] Need to merge. --- labconnect/main/opportunity_routes.py | 445 +++++++++++++------------- 1 file changed, 218 insertions(+), 227 deletions(-) diff --git a/labconnect/main/opportunity_routes.py b/labconnect/main/opportunity_routes.py index 09008d7..5c012be 100644 --- a/labconnect/main/opportunity_routes.py +++ b/labconnect/main/opportunity_routes.py @@ -94,13 +94,14 @@ def packageOpportunity(opportunityInfo, professorInfo): def packageIndividualOpportunity(opportunityInfo): - data = {} - data["id"] = opportunityInfo.id - data["name"] = opportunityInfo.name - data["description"] = opportunityInfo.description - data["recommended_experience"] = opportunityInfo.recommended_experience - data["author"] = "" - data["department"] = "" + data = { + "id": opportunityInfo.id, + "name": opportunityInfo.name, + "description": opportunityInfo.description, + "recommended_experience": opportunityInfo.recommended_experience, + "author": "", + "department": "", + } opportunity_credits = "" if opportunityInfo.one_credit: @@ -398,298 +399,288 @@ def changeActiveStatus2(): @main_blueprint.get("/getOpportunityMeta/") def getOpportunityMeta(id: int): - query = db.session.execute( - db.select( - Opportunities, RecommendsMajors, RecommendsCourses, RecommendsClassYears - ) - .where(Opportunities.id == id) - .join(RecommendsMajors, RecommendsMajors.opportunity_id == Opportunities.id) - .join( - RecommendsCourses, RecommendsCourses.opportunity_id == Opportunities.id - ) - .join( - RecommendsClassYears, - RecommendsClassYears.opportunity_id == Opportunities.id, - ) + query = db.session.execute( + db.select( + Opportunities, RecommendsMajors, RecommendsCourses, RecommendsClassYears ) - data = query.all() - print(data) + .where(Opportunities.id == id) + .join(RecommendsMajors, RecommendsMajors.opportunity_id == Opportunities.id) + .join(RecommendsCourses, RecommendsCourses.opportunity_id == Opportunities.id) + .join( + RecommendsClassYears, + RecommendsClassYears.opportunity_id == Opportunities.id, + ) + ) + data = query.all() + print(data) - if not data or len(data) == 0: - abort(404) + if not data or len(data) == 0: + abort(404) - dictionary = data[0][0].to_dict() - dictionary["semester"] = dictionary["semester"].upper() - dictionary["courses"] = set() - dictionary["majors"] = set() - dictionary["years"] = set() + dictionary = data[0][0].to_dict() + dictionary["semester"] = dictionary["semester"].upper() + dictionary["courses"] = set() + dictionary["majors"] = set() + dictionary["years"] = set() - for row in data: - dictionary["courses"].add(row[2].course_code) - dictionary["majors"].add(row[1].major_code) - dictionary["years"].add(row[3].class_year) + for row in data: + dictionary["courses"].add(row[2].course_code) + dictionary["majors"].add(row[1].major_code) + dictionary["years"].add(row[3].class_year) + + dictionary["courses"] = list(dictionary["courses"]) + dictionary["majors"] = list(dictionary["majors"]) + dictionary["years"] = list(dictionary["years"]) - dictionary["courses"] = list(dictionary["courses"]) - dictionary["majors"] = list(dictionary["majors"]) - dictionary["years"] = list(dictionary["years"]) + for i in range(len(dictionary["years"])): + dictionary["years"][i] = str(dictionary["years"][i]) - for i in range(len(dictionary["years"])): - dictionary["years"][i] = str(dictionary["years"][i]) + dictionary["credits"] = [] + if dictionary["one_credit"]: + dictionary["credits"].append("1") - dictionary["credits"] = [] - if dictionary["one_credit"]: - dictionary["credits"].append("1") + if dictionary["two_credits"]: + dictionary["credits"].append("2") - if dictionary["two_credits"]: - dictionary["credits"].append("2") + if dictionary["three_credits"]: + dictionary["credits"].append("3") - if dictionary["three_credits"]: - dictionary["credits"].append("3") + if dictionary["four_credits"]: + dictionary["credits"].append("4") - if dictionary["four_credits"]: - dictionary["credits"].append("4") + dictionary.pop("one_credit") + dictionary.pop("two_credits") + dictionary.pop("three_credits") + dictionary.pop("four_credits") - dictionary.pop("one_credit") - dictionary.pop("two_credits") - dictionary.pop("three_credits") - dictionary.pop("four_credits") + return {"data": dictionary} - return {"data": dictionary} # Jobs page @main_blueprint.get("/getOpportunityCards") def getOpportunityCards(): - # query database for opportunity - query = db.session.execute( - db.select(Opportunities).where(Opportunities.active == True) - ) + # query database for opportunity + query = db.session.execute( + db.select(Opportunities).where(Opportunities.active == True) + ) - data = query.fetchall() + data = query.fetchall() - # return data in the below format if opportunity is found - cards = { - "data": [packageOpportunityCard(opportunity[0]) for opportunity in data] - } + # return data in the below format if opportunity is found + cards = {"data": [packageOpportunityCard(opportunity[0]) for opportunity in data]} + + return cards - return cards @main_blueprint.get("/getOpportunities") def getOpportunities(): - # query database for opportunity - query = db.session.execute( - db.select(Opportunities, Leads, LabManager) - .join(Leads, Leads.opportunity_id == Opportunities.id) - .join(LabManager, Leads.lab_manager_id == LabManager.id) - ) - data = query.all() - print(data[0]) - - # return data in the below format if opportunity is found - return { - "data": [ - packageOpportunity(opportunity[0], opportunity[2]) - for opportunity in data - ] - } + # query database for opportunity + query = db.session.execute( + db.select(Opportunities, Leads, LabManager) + .join(Leads, Leads.opportunity_id == Opportunities.id) + .join(LabManager, Leads.lab_manager_id == LabManager.id) + ) + data = query.all() + print(data[0]) + + # return data in the below format if opportunity is found + return { + "data": [ + packageOpportunity(opportunity[0], opportunity[2]) for opportunity in data + ] + } @main_blueprint.get("/getOpportunityByProfessor/") def getOpportunityByProfessor(rcs_id: str): - # query database for opportunity - query = db.session.execute( - db.select(Opportunities, Leads) - .where(Leads.lab_manager_id == rcs_id) - .join(Opportunities, Leads.opportunity_id == Opportunities.id) - ) - - data = query.all() - print(data) - # return data in the format bellow if opportunity is found - return {"data": [opportunity[0].to_dict() for opportunity in data]} + # query database for opportunity + query = db.session.execute( + db.select(Opportunities, Leads) + .where(Leads.lab_manager_id == rcs_id) + .join(Opportunities, Leads.opportunity_id == Opportunities.id) + ) + data = query.all() + print(data) + # return data in the format bellow if opportunity is found + return {"data": [opportunity[0].to_dict() for opportunity in data]} @main_blueprint.get("/getProfessorOpportunityCards/") def getProfessorOpportunityCards(rcs_id: str): - # query database for opportunity - user = db.first_or_404(db.select(User).where(User.email == rcs_id)) - - query = db.session.execute( - db.select(Opportunities, Leads) - .where(Leads.lab_manager_id == user.lab_manager_id) - .join(Opportunities, Leads.opportunity_id == Opportunities.id) - ) - - data = query.all() + # query database for opportunity + user = db.first_or_404(db.select(User).where(User.email == rcs_id)) - cards = {"data": []} + query = db.session.execute( + db.select(Opportunities, Leads) + .where(Leads.lab_manager_id == user.lab_manager_id) + .join(Opportunities, Leads.opportunity_id == Opportunities.id) + ) - for row in data: - opportunity = row[0] + data = query.all() - if not opportunity.active: - continue + cards = {"data": []} - oppData = { - "id": opportunity.id, - "title": opportunity.name, - "body": "Due " + str(opportunity.application_due), - "attributes": [], - } + for row in data: + opportunity = row[0] - if opportunity.pay is not None and opportunity.pay > 0: - oppData["attributes"].append("Paid") + if not opportunity.active: + continue - if ( - opportunity.one_credit - or opportunity.two_credits - or opportunity.three_credits - or opportunity.four_credits - ): - oppData["attributes"].append("Credit Available") + oppData = { + "id": opportunity.id, + "title": opportunity.name, + "body": "Due " + str(opportunity.application_due), + "attributes": [], + } - cards["data"].append(oppData) + if opportunity.pay is not None and opportunity.pay > 0: + oppData["attributes"].append("Paid") - # return data in the below format if opportunity is found - return cards + if ( + opportunity.one_credit + or opportunity.two_credits + or opportunity.three_credits + or opportunity.four_credits + ): + oppData["attributes"].append("Credit Available") + cards["data"].append(oppData) + # return data in the below format if opportunity is found + return cards @main_blueprint.get("/getProfileOpportunities/") def getProfileOpportunities(rcs_id: str): - # query database for opportunity + # query database for opportunity - query = db.session.execute( - db.select(Opportunities, Leads) - .where(Leads.lab_manager_id == rcs_id) - .join(Opportunities, Leads.opportunity_id == Opportunities.id) - ) + query = db.session.execute( + db.select(Opportunities, Leads) + .where(Leads.lab_manager_id == rcs_id) + .join(Opportunities, Leads.opportunity_id == Opportunities.id) + ) - data = query.all() + data = query.all() - cards = {"data": []} + cards = {"data": []} - for row in data: - opportunity = row[0] - - oppData = { - "id": opportunity.id, - "title": opportunity.name, - "body": "Due " + str(opportunity.application_due), - "attributes": [], - "activeStatus": opportunity.active, - } + for row in data: + opportunity = row[0] - if opportunity.pay is not None and opportunity.pay > 0: - oppData["attributes"].append("Paid") - if ( - opportunity.one_credit - or opportunity.two_credits - or opportunity.three_credits - or opportunity.four_credits - ): - oppData["attributes"].append("Credits") + oppData = { + "id": opportunity.id, + "title": opportunity.name, + "body": "Due " + str(opportunity.application_due), + "attributes": [], + "activeStatus": opportunity.active, + } - cards["data"].append(oppData) + if opportunity.pay is not None and opportunity.pay > 0: + oppData["attributes"].append("Paid") + if ( + opportunity.one_credit + or opportunity.two_credits + or opportunity.three_credits + or opportunity.four_credits + ): + oppData["attributes"].append("Credits") - # return data in the below format if opportunity is found - return cards + cards["data"].append(oppData) + # return data in the below format if opportunity is found + return cards # functions to create/edit/delete opportunities @main_blueprint.post("/createOpportunity") def createOpportunity(): - #if request.method == "POST": - data = request.get_json() - authorID = data["authorID"] - newPostData = data - - # query database to see if the credentials above match - query = db.session.execute( - db.select(LabManager).where(LabManager.id == authorID) - ) - - data = query.all()[0][0] - - # TODO: how do we get the opportunity id? - # if match is found, create a new opportunity with the new data provided + # if request.method == "POST": + data = request.get_json() + authorID = data["authorID"] + newPostData = data + + # query database to see if the credentials above match + query = db.session.execute(db.select(LabManager).where(LabManager.id == authorID)) + + data = query.all()[0][0] + + # TODO: how do we get the opportunity id? + # if match is found, create a new opportunity with the new data provided + + one = False + two = False + three = False + four = False + + if "1" in newPostData["credits"]: + one = True + if "2" in newPostData["credits"]: + two = True + if "3" in newPostData["credits"]: + three = True + if "4" in newPostData["credits"]: + four = True + + lenum = convert_to_enum(newPostData["location"]) + + if lenum is None: + lenum = LocationEnum.TBD + + newOpportunity = Opportunities( + name=newPostData["name"], + description=newPostData["description"], + recommended_experience=newPostData["recommended_experience"], + pay=newPostData["pay"], + one_credit=one, + two_credits=two, + three_credits=three, + four_credits=four, + semester=newPostData["semester"], + year=newPostData["year"], + application_due=datetime.datetime.strptime( + newPostData["application_due"], "%Y-%m-%d" + ), + active=newPostData["active"], + location=lenum, + ) + print("before comitting") + db.session.add(newOpportunity) + db.session.commit() - one = False - two = False - three = False - four = False + print("got here atleast") - if "1" in newPostData["credits"]: - one = True - if "2" in newPostData["credits"]: - two = True - if "3" in newPostData["credits"]: - three = True - if "4" in newPostData["credits"]: - four = True + newLead = Leads(lab_manager_id=authorID, opportunity_id=newOpportunity.id) - lenum = convert_to_enum(newPostData["location"]) + db.session.add(newLead) + db.session.commit() - if lenum is None: - lenum = LocationEnum.TBD - - newOpportunity = Opportunities( - name=newPostData["name"], - description=newPostData["description"], - recommended_experience=newPostData["recommended_experience"], - pay=newPostData["pay"], - one_credit=one, - two_credits=two, - three_credits=three, - four_credits=four, - semester=newPostData["semester"], - year=newPostData["year"], - application_due=datetime.datetime.strptime( - newPostData["application_due"], "%Y-%m-%d" - ), - active=newPostData["active"], - location=lenum, + for course in newPostData["courses"]: + newCourse = RecommendsCourses( + opportunity_id=newOpportunity.id, course_code=course ) - print("before comitting") - db.session.add(newOpportunity) + db.session.add(newCourse) db.session.commit() - print("got here atleast") - - newLead = Leads(lab_manager_id=authorID, opportunity_id=newOpportunity.id) - - db.session.add(newLead) + for major in newPostData["majors"]: + newMajor = RecommendsMajors(opportunity_id=newOpportunity.id, major_code=major) + db.session.add(newMajor) db.session.commit() - for course in newPostData["courses"]: - newCourse = RecommendsCourses( - opportunity_id=newOpportunity.id, course_code=course - ) - db.session.add(newCourse) - db.session.commit() - - for major in newPostData["majors"]: - newMajor = RecommendsMajors( - opportunity_id=newOpportunity.id, major_code=major - ) - db.session.add(newMajor) - db.session.commit() + for year in newPostData["years"]: + newYear = RecommendsClassYears( + opportunity_id=newOpportunity.id, class_year=year + ) + db.session.add(newYear) + db.session.commit() - for year in newPostData["years"]: - newYear = RecommendsClassYears( - opportunity_id=newOpportunity.id, class_year=year - ) - db.session.add(newYear) - db.session.commit() + # db.session.add(newOpportunity) - # db.session.add(newOpportunity) + return {"data": "Opportunity Created"} - return {"data": "Opportunity Created"} - #abort(500) +# abort(500) @main_blueprint.route("/editOpportunity", methods=["DELETE", "POST"]) From d485cbdd374d49cea54cad295243c4169d23de89 Mon Sep 17 00:00:00 2001 From: Mrunal Athaley <112527910+athalm@users.noreply.github.com> Date: Thu, 10 Oct 2024 18:46:34 -0400 Subject: [PATCH 04/99] updated test_user.py test parameterization --- tests/test_user.py | 269 ++++++++++++++++++++------------------------- 1 file changed, 120 insertions(+), 149 deletions(-) diff --git a/tests/test_user.py b/tests/test_user.py index ab07577..dd25489 100644 --- a/tests/test_user.py +++ b/tests/test_user.py @@ -4,197 +4,168 @@ from flask import json from flask.testing import FlaskClient +import pytest -def test_user_route_with_input_id_1(test_client: FlaskClient) -> None: - """ - GIVEN a Flask application configured for testing - WHEN the '/user' page is requested (GET) - THEN check that the response is valid - """ - response = test_client.get("/user", json={"id": "1"}) - - assert response.status_code == 200 - - json_data = json.loads(response.data) - - assert json_data["id"] == 1 - assert json_data["first_name"] == "Rafael" - assert json_data["last_name"] == "Cenzano" - assert json_data["preferred_name"] == "Raf" - assert json_data["email"] == "cenzar@rpi.edu" - - departments_data = [ - {"user_id": 1, "department_id": "Computer Science"}, - {"user_id": 1, "department_id": "Math"}, - ] - - major_data = [ - {"user_id": 1, "major_code": "CSCI"}, - {"user_id": 1, "major_code": "MATH"}, - ] - - course_data = [ - {"in_progress": False, "user_id": 1, "course_code": "CSCI2300"}, - {"in_progress": True, "user_id": 1, "course_code": "CSCI4430"}, - ] - - assert json_data["departments"] == departments_data - assert json_data["majors"] == major_data - assert json_data["courses"] == course_data - - -def test_user_1_opportunity_cards(test_client: FlaskClient) -> None: - """ - GIVEN a Flask application configured for testing - WHEN the '/user' page is requested (GET) - THEN check that the response is valid - """ - response = test_client.get("/user", json={"id": 1}) - - assert response.status_code == 200 - - json_data = json.loads(response.data) - - lab_manager_opportunities_data = ( +@pytest.mark.parametrize( + "user_id, expected_status_code, expected_data", + [ ( - "Automated Cooling System", - "Energy efficient AC system", - "Thermodynamics", - 15.0, - "Spring", - 2024, - True, + 1, + 200, + { + "id": 1, + "first_name": "Rafael", + "last_name": "Cenzano", + "preferred_name": "Raf", + "email": "cenzar@rpi.edu", + "departments": [ + {"user_id": 1, "department_id": "Computer Science"}, + {"user_id": 1, "department_id": "Math"}, + ], + "majors": [ + {"user_id": 1, "major_code": "CSCI"}, + {"user_id": 1, "major_code": "MATH"}, + ], + "courses": [ + {"in_progress": False, "user_id": 1, "course_code": "CSCI2300"}, + {"in_progress": True, "user_id": 1, "course_code": "CSCI4430"}, + ], + }, ), ( - "Iphone 15 durability test", - "Scratching the Iphone, drop testing etc.", - "Experienced in getting angry and throwing temper tantrum", - None, - "Spring", - 2024, - True, + 2, + 200, + { + "id": 2, + "first_name": "RCOS", + "last_name": "RCOS", + "preferred_name": None, + "email": "test@rpi.edu", + "departments": [ + {"department_id": "Computer Science", "user_id": 2}, + ], + "majors": [ + {"user_id": 2, "major_code": "CSCI"}, + ], + "courses": [ + {"in_progress": False, "user_id": 2, "course_code": "CSCI2300"}, + ], + }, ), - ) - - for i, item in enumerate(json_data["opportunities"]): - assert item["name"] == lab_manager_opportunities_data[i][0] - assert item["description"] == lab_manager_opportunities_data[i][1] - assert item["recommended_experience"] == lab_manager_opportunities_data[i][2] - assert item["pay"] == lab_manager_opportunities_data[i][3] - assert item["semester"] == lab_manager_opportunities_data[i][4] - assert item["year"] == lab_manager_opportunities_data[i][5] - assert item["active"] == lab_manager_opportunities_data[i][6] - - -def test_user_route_with_input_id_2(test_client: FlaskClient) -> None: + ] +) +def test_user_route_with_input(test_client: FlaskClient, user_id, expected_status_code, expected_data) -> None: """ GIVEN a Flask application configured for testing WHEN the '/user' page is requested (GET) - THEN check that the response is valid + THEN check that the response and data are valid """ - response = test_client.get("/user", json={"id": 2}) - - assert response.status_code == 200 + response = test_client.get("/user", json={"id": str(user_id)}) + assert response.status_code == expected_status_code json_data = json.loads(response.data) + assert json_data == expected_data - assert json_data["id"] == 2 - assert json_data["first_name"] == "RCOS" - assert json_data["last_name"] == "RCOS" - assert json_data["preferred_name"] is None - assert json_data["email"] == "test@rpi.edu" - - departments_data = [ - {"department_id": "Computer Science", "user_id": 2}, - ] - - major_data = [ - {"user_id": 2, "major_code": "CSCI"}, - ] - - course_data = [ - {"in_progress": False, "user_id": 2, "course_code": "CSCI2300"}, - ] - - assert json_data["departments"] == departments_data - assert json_data["majors"] == major_data - assert json_data["courses"] == course_data - -def test_user_2_opportunity_cards(test_client: FlaskClient) -> None: +@pytest.mark.parametrize( + "user_id, expected_status_code, expected_opportunities", + [ + ( + 1, + 200, + [ + ( + "Automated Cooling System", + "Energy efficient AC system", + "Thermodynamics", + 15.0, + "Spring", + 2024, + True, + ), + ( + "Iphone 15 durability test", + "Scratching the Iphone, drop testing etc.", + "Experienced in getting angry and throwing temper tantrum", + None, + "Spring", + 2024, + True, + ), + ], + ), + ( + 2, + 200, + [ + ( + "Checking out cubes", + "Material Sciences", + "Experienced in materials.", + None, + "Fall", + 2024, + True, + ), + ( + "Test the water", + "Testing the quality of water in Troy pipes", + "Understanding of lead poisoning", + None, + "Summer", + 2024, + True, + ), + ], + ), + ], +) +def test_user_opportunity_cards(test_client: FlaskClient, user_id, expected_status_code, expected_opportunities) -> None: """ GIVEN a Flask application configured for testing WHEN the '/user' page is requested (GET) - THEN check that the response is valid + THEN check that the opportunity cards are valid """ - response = test_client.get("/user", json={"id": 2}) - - assert response.status_code == 200 + response = test_client.get("/user", json={"id": user_id}) + assert response.status_code == expected_status_code json_data = json.loads(response.data) - - lab_manager_opportunities_data = ( - ( - "Checking out cubes", - "Material Sciences", - "Experienced in materials.", - None, - "Fall", - 2024, - True, - ), - ( - "Test the water", - "Testing the quality of water in Troy pipes", - "Understanding of lead poisioning", - None, - "Summer", - 2024, - True, - ), - ) - for i, item in enumerate(json_data["opportunities"]): - assert item["name"] == lab_manager_opportunities_data[i][0] - assert item["description"] == lab_manager_opportunities_data[i][1] - assert item["recommended_experience"] == lab_manager_opportunities_data[i][2] - assert item["pay"] == lab_manager_opportunities_data[i][3] - assert item["semester"] == lab_manager_opportunities_data[i][4] - assert item["year"] == lab_manager_opportunities_data[i][5] - assert item["active"] == lab_manager_opportunities_data[i][6] + assert item["name"] == expected_opportunities[i][0] + assert item["description"] == expected_opportunities[i][1] + assert item["recommended_experience"] == expected_opportunities[i][2] + assert item["pay"] == expected_opportunities[i][3] + assert item["semester"] == expected_opportunities[i][4] + assert item["year"] == expected_opportunities[i][5] + assert item["active"] == expected_opportunities[i][6] def test_user_route_no_json(test_client: FlaskClient) -> None: """ GIVEN a Flask application configured for testing - WHEN the '/user' page is requested (GET) - THEN check that the response is valid + WHEN the '/user' page is requested (GET) with no JSON payload + THEN check that the response is a 400 error """ response = test_client.get("/user") - assert response.status_code == 400 def test_user_route_incorrect_json(test_client: FlaskClient) -> None: """ GIVEN a Flask application configured for testing - WHEN the '/user' page is requested (GET) - THEN check that the response is valid + WHEN the '/user' page is requested (GET) with incorrect JSON payload + THEN check that the response is a 400 error """ response = test_client.get("/user", json={"wrong": "wrong"}) - assert response.status_code == 400 def test_user_not_found(test_client: FlaskClient) -> None: """ GIVEN a Flask application configured for testing - WHEN the '/user' page is requested (GET) - THEN check that the response is valid + WHEN the '/user' page is requested (GET) with a non-existent user ID + THEN check that the response is a 404 error """ response = test_client.get("/user", json={"id": "not found"}) - - print(json.loads(response.data)) - assert response.status_code == 404 From 7dc9d961383e806b0b8945d79c06bbda5a19341d Mon Sep 17 00:00:00 2001 From: Mrunal Athaley <112527910+athalm@users.noreply.github.com> Date: Thu, 10 Oct 2024 18:51:27 -0400 Subject: [PATCH 05/99] updated test_opportunity.py test parameterization --- tests/test_opportunity.py | 301 +++++++++++++++----------------------- 1 file changed, 120 insertions(+), 181 deletions(-) diff --git a/tests/test_opportunity.py b/tests/test_opportunity.py index 55f7c24..33364bf 100644 --- a/tests/test_opportunity.py +++ b/tests/test_opportunity.py @@ -1,136 +1,88 @@ -""" -Test opportunity routes -""" - +import pytest import json -from flask import json from flask.testing import FlaskClient - from labconnect import db -from labconnect.helpers import OrJSONProvider, SemesterEnum -from labconnect.models import ( - ClassYears, - Courses, - LabManager, - Leads, - Majors, - Opportunities, - RecommendsClassYears, - RecommendsCourses, - RecommendsMajors, - RPIDepartments, - RPISchools, -) - - -def test_get_opportunity(test_client: FlaskClient) -> None: - """ - GIVEN a Flask application configured for testing - WHEN the '/opportunity' page is requested (GET) - THEN check that the response is valid - """ - response1 = test_client.get("/opportunity", json={"id": 1}) - response2 = test_client.get("/opportunity", json={"id": 2}) +from labconnect.models import Opportunities - assert response1.status_code == 200 - assert response2.status_code == 200 - json_data1 = json.loads(response1.data) - json_data2 = json.loads(response2.data) - - lab_manager_opportunities_data = ( +@pytest.mark.parametrize( + "opportunity_id, expected_data", + [ ( - "Automated Cooling System", - "Energy efficient AC system", - "Thermodynamics", - 15.0, - False, - False, - False, - True, - "Spring", - 2024, - True, + 1, + ( + "Automated Cooling System", + "Energy efficient AC system", + "Thermodynamics", + 15.0, + False, + False, + False, + True, + "Spring", + 2024, + True, + ), ), ( - "Iphone 15 durability test", - "Scratching the Iphone, drop testing etc.", - "Experienced in getting angry and throwing temper tantrum", - None, - True, - True, - True, - True, - "Spring", - 2024, - True, + 2, + ( + "Iphone 15 durability test", + "Scratching the Iphone, drop testing etc.", + "Experienced in getting angry and throwing temper tantrum", + None, + True, + True, + True, + True, + "Spring", + 2024, + True, + ), ), - ) + ], +) +def test_get_opportunity(test_client: FlaskClient, opportunity_id, expected_data) -> None: + response = test_client.get("/opportunity", json={"id": opportunity_id}) - assert json_data1["name"] == lab_manager_opportunities_data[0][0] - assert json_data1["description"] == lab_manager_opportunities_data[0][1] - assert json_data1["recommended_experience"] == lab_manager_opportunities_data[0][2] - assert json_data1["pay"] == lab_manager_opportunities_data[0][3] - assert json_data1["one_credit"] == lab_manager_opportunities_data[0][4] - assert json_data1["two_credits"] == lab_manager_opportunities_data[0][5] - assert json_data1["three_credits"] == lab_manager_opportunities_data[0][6] - assert json_data1["four_credits"] == lab_manager_opportunities_data[0][7] - assert json_data1["semester"] == lab_manager_opportunities_data[0][8] - assert json_data1["year"] == lab_manager_opportunities_data[0][9] - assert json_data1["active"] == lab_manager_opportunities_data[0][10] - - assert json_data2["name"] == lab_manager_opportunities_data[1][0] - assert json_data2["description"] == lab_manager_opportunities_data[1][1] - assert json_data2["recommended_experience"] == lab_manager_opportunities_data[1][2] - assert json_data2["pay"] == lab_manager_opportunities_data[1][3] - assert json_data2["one_credit"] == lab_manager_opportunities_data[1][4] - assert json_data2["two_credits"] == lab_manager_opportunities_data[1][5] - assert json_data2["three_credits"] == lab_manager_opportunities_data[1][6] - assert json_data2["four_credits"] == lab_manager_opportunities_data[1][7] - assert json_data2["semester"] == lab_manager_opportunities_data[1][8] - assert json_data2["year"] == lab_manager_opportunities_data[1][9] - assert json_data2["active"] == lab_manager_opportunities_data[1][10] - - print(json_data2) + assert response.status_code == 200 + + json_data = json.loads(response.data) + + assert json_data["name"] == expected_data[0] + assert json_data["description"] == expected_data[1] + assert json_data["recommended_experience"] == expected_data[2] + assert json_data["pay"] == expected_data[3] + assert json_data["one_credit"] == expected_data[4] + assert json_data["two_credits"] == expected_data[5] + assert json_data["three_credits"] == expected_data[6] + assert json_data["four_credits"] == expected_data[7] + assert json_data["semester"] == expected_data[8] + assert json_data["year"] == expected_data[9] + assert json_data["active"] == expected_data[10] def test_get_opportunity_no_json(test_client: FlaskClient) -> None: - """ - GIVEN a Flask application configured for testing - WHEN the '/opportunity' page is requested (GET) - THEN check that the response is valid - """ response = test_client.get("/opportunity") - assert response.status_code == 400 -def test_opportunity_incorrect_json(test_client: FlaskClient) -> None: - """ - GIVEN a Flask application configured for testing - WHEN the '/opportunity' page is requested (GET) - THEN check that the response is valid - """ - response = test_client.get("/opportunity", json={"wrong": "wrong"}) - +@pytest.mark.parametrize( + "wrong_data", [{"wrong": "wrong"}, {"invalid": "data"}] +) +def test_opportunity_incorrect_json(test_client: FlaskClient, wrong_data) -> None: + response = test_client.get("/opportunity", json=wrong_data) assert response.status_code == 400 -def test_get_opportunity_meta(test_client: FlaskClient) -> None: - """ - GIVEN a Flask application configured for testing - WHEN the '/getOpportunityMeta' endpoint is requested (GET) with valid data - THEN check that the response is valid and contains expected opportunity data - """ - - response = test_client.get("/getOpportunityMeta/1", content_type="application/json") - - # assert response.status_code == 200 - - data = json.loads(response.data) - data = data["data"] +@pytest.mark.parametrize( + "opportunity_meta_id", + [1, 2], +) +def test_get_opportunity_meta(test_client: FlaskClient, opportunity_meta_id) -> None: + response = test_client.get(f"/getOpportunityMeta/{opportunity_meta_id}", content_type="application/json") + data = json.loads(response.data)["data"] - # Assertions on the expected data assert "name" in data assert "description" in data assert "recommended_experience" in data @@ -143,19 +95,19 @@ def test_get_opportunity_meta(test_client: FlaskClient) -> None: assert "courses" in data assert "majors" in data assert "years" in data - assert "active" in data -def test_get_opportunity(test_client: FlaskClient) -> None: - response = test_client.get("/getOpportunity/2") +@pytest.mark.parametrize( + "opportunity_id", + [1, 2], +) +def test_get_opportunity_by_id(test_client: FlaskClient, opportunity_id) -> None: + response = test_client.get(f"/getOpportunity/{opportunity_id}") assert response.status_code == 200 - # Load the response data as JSON - data = json.loads(response.data.decode("utf-8")) - data = data["data"] + data = json.loads(response.data)["data"] - # Test that the "name" key exists assert "id" in data assert "name" in data assert "description" in data @@ -169,40 +121,35 @@ def test_get_opportunity(test_client: FlaskClient) -> None: assert "description" in eachSection -def test_get_opportunity_professor(test_client: FlaskClient) -> None: - response = test_client.get("/getOpportunityByProfessor/led") - +@pytest.mark.parametrize( + "professor_name", ["led", "drsmith"] +) +def test_get_opportunity_professor(test_client: FlaskClient, professor_name) -> None: + response = test_client.get(f"/getOpportunityByProfessor/{professor_name}") assert response.status_code == 200 - # Load the response data as JSON - data = json.loads(response.data.decode("utf-8")) - data = data["data"] + data = json.loads(response.data)["data"] - # Test that the "name" key exists for opportunity in data: assert "id" in opportunity assert "name" in opportunity assert "description" in opportunity assert "recommended_experience" in opportunity assert "pay" in opportunity - # assert "credits" in opportunity assert "semester" in opportunity assert "year" in opportunity assert "application_due" in opportunity assert "active" in opportunity - # assert "professor" in opportunity - # assert "department" in opportunity - -def test_get_professor_opportunity_cards(test_client: FlaskClient) -> None: - response = test_client.get( - "/getProfessorOpportunityCards/led", content_type="application/json" - ) +@pytest.mark.parametrize( + "professor_name", ["led", "drsmith"] +) +def test_get_professor_opportunity_cards(test_client: FlaskClient, professor_name) -> None: + response = test_client.get(f"/getProfessorOpportunityCards/{professor_name}", content_type="application/json") assert response.status_code == 200 - data = json.loads(response.data.decode("utf-8")) - data = data["data"] + data = json.loads(response.data)["data"] for eachCard in data: assert "title" in eachCard @@ -211,15 +158,14 @@ def test_get_professor_opportunity_cards(test_client: FlaskClient) -> None: assert "id" in eachCard -def test_profile_opportunities(test_client: FlaskClient) -> None: - response = test_client.get( - "/getProfileOpportunities/led", content_type="application/json" - ) - +@pytest.mark.parametrize( + "professor_name", ["led", "drsmith"] +) +def test_profile_opportunities(test_client: FlaskClient, professor_name) -> None: + response = test_client.get(f"/getProfileOpportunities/{professor_name}", content_type="application/json") assert response.status_code == 200 - data = json.loads(response.data.decode("utf-8")) - data = data["data"] + data = json.loads(response.data)["data"] for eachCard in data: assert "id" in eachCard @@ -229,51 +175,45 @@ def test_profile_opportunities(test_client: FlaskClient) -> None: assert "activeStatus" in eachCard -def test_create_opportunity(test_client: FlaskClient) -> None: - """ - GIVEN a Flask application configured for testing - WHEN the '/createOpportunity' endpoint is requested (POST) with valid data - THEN check that the response is valid and contains expected data - """ - - test_data = { - "authorID": "led", - "name": "Some test opportunity", - "description": "Some test description", - "recommended_experience": "Some test experience", - "pay": 25.0, - "credits": ["1", "2", "3", "4"], - "semester": "FALL", - "year": 2024, - "application_due": "2024-03-30", - "active": True, - "courses": ["CSCI4430"], - "majors": ["BIOL"], - "years": [2023, 2024], - "active": True, - "location": "TBD", - } - +@pytest.mark.parametrize( + "test_data", + [ + { + "authorID": "led", + "name": "Some test opportunity", + "description": "Some test description", + "recommended_experience": "Some test experience", + "pay": 25.0, + "credits": ["1", "2", "3", "4"], + "semester": "FALL", + "year": 2024, + "application_due": "2024-03-30", + "active": True, + "courses": ["CSCI4430"], + "majors": ["BIOL"], + "years": [2023, 2024], + "location": "TBD", + } + ], +) +def test_create_opportunity(test_client: FlaskClient, test_data) -> None: response = test_client.post( "/createOpportunity", data=json.dumps(test_data), content_type="application/json", ) - assert response.status_code == 200 - # query database to check for new opportunity with the same name query = db.session.query(Opportunities).filter( - Opportunities.name == "Some test opportunity", - Opportunities.description == "Some test description", - Opportunities.recommended_experience == "Some test experience", + Opportunities.name == test_data["name"], + Opportunities.description == test_data["description"], + Opportunities.recommended_experience == test_data["recommended_experience"], ) data = query.first() assert data is not None id = data.id - # delete the opportunity by sending request to deleteOpportunity response = test_client.post( "/deleteOpportunity", data=json.dumps({"id": id}), @@ -282,20 +222,19 @@ def test_create_opportunity(test_client: FlaskClient) -> None: assert response.status_code == 200 - # check that the opportunity was deleted query = db.session.query(Opportunities).filter(Opportunities.id == id) assert query.first() is None -def test_professor_opportunity_cards(test_client: FlaskClient) -> None: - - response = test_client.get("/getProfessorOpportunityCards/led") +@pytest.mark.parametrize( + "professor_name", ["led", "drsmith"] +) +def test_professor_opportunity_cards(test_client: FlaskClient, professor_name) -> None: + response = test_client.get(f"/getProfessorOpportunityCards/{professor_name}") assert response.status_code == 200 - # Load the response data as JSON - data = json.loads(response.data.decode("utf-8")) + data = json.loads(response.data)["data"] - # Test that the "name" key exists assert len(data.keys()) > 0 for eachCard in data["data"]: assert "title" in eachCard From 94faf17bee1dd5f517fe4615b3affba7d45de0fc Mon Sep 17 00:00:00 2001 From: Mrunal Athaley <112527910+athalm@users.noreply.github.com> Date: Thu, 10 Oct 2024 18:53:00 -0400 Subject: [PATCH 06/99] updated test_majors.py test parameterization --- tests/test_majors.py | 97 ++++++++++++++++++++++++++------------------ 1 file changed, 58 insertions(+), 39 deletions(-) diff --git a/tests/test_majors.py b/tests/test_majors.py index d759474..b4c89d8 100644 --- a/tests/test_majors.py +++ b/tests/test_majors.py @@ -4,9 +4,25 @@ from flask import json from flask.testing import FlaskClient +import pytest -def test_majors_route(test_client: FlaskClient) -> None: +@pytest.mark.parametrize( + "expected_majors", + [ + ( + ("CSCI", "ECSE", "BIOL", "MATH", "COGS"), + ( + "Computer Science", + "Electrical, Computer, and Systems Engineering", + "Biological Science", + "Mathematics", + "Cognitive Science", + ), + ) + ], +) +def test_majors_route(test_client: FlaskClient, expected_majors) -> None: """ GIVEN a Flask application configured for testing WHEN the '/majors' page is requested (GET) @@ -18,68 +34,71 @@ def test_majors_route(test_client: FlaskClient) -> None: json_data = json.loads(response.data) - majors_data = ( - ("CSCI", "ECSE", "BIOL", "MATH", "COGS"), - ( - "Computer Science", - "Electrical, Computer, and Systems Engineering", - "Biological Science", - "Mathematics", - "Cognitive Science", - ), - ) - for major in json_data: - assert major["code"] in majors_data[0] - assert major["name"] in majors_data[1] + assert major["code"] in expected_majors[0] + assert major["name"] in expected_majors[1] -def test_majors_route_with_input_name(test_client: FlaskClient) -> None: +@pytest.mark.parametrize( + "input_data, expected_majors", + [ + ( + {"input": "computer"}, + ( + ("CSCI", "ECSE"), + ( + "Computer Science", + "Electrical, Computer, and Systems Engineering", + ), + ), + ), + ], +) +def test_majors_route_with_input_name(test_client: FlaskClient, input_data, expected_majors) -> None: """ GIVEN a Flask application configured for testing WHEN the '/majors' page is requested (GET) THEN check that the response is valid """ - response = test_client.get("/majors", json={"input": "computer"}) + response = test_client.get("/majors", json=input_data) assert response.status_code == 200 json_data = json.loads(response.data) - majors_data = ( - ("CSCI", "ECSE"), - ( - "Computer Science", - "Electrical, Computer, and Systems Engineering", - ), - ) - for i, major in enumerate(json_data): - assert major["code"] == majors_data[0][i] - assert major["name"] == majors_data[1][i] + assert major["code"] == expected_majors[0][i] + assert major["name"] == expected_majors[1][i] -def test_majors_route_with_input_code(test_client: FlaskClient) -> None: +@pytest.mark.parametrize( + "input_data, expected_majors", + [ + ( + {"input": "cs"}, + ( + ("CSCI", "ECSE", "MATH"), + ( + "Computer Science", + "Electrical, Computer, and Systems Engineering", + "Mathematics", + ), + ), + ), + ], +) +def test_majors_route_with_input_code(test_client: FlaskClient, input_data, expected_majors) -> None: """ GIVEN a Flask application configured for testing WHEN the '/majors' page is requested (GET) THEN check that the response is valid """ - response = test_client.get("/majors", json={"input": "cs"}) + response = test_client.get("/majors", json=input_data) assert response.status_code == 200 json_data = json.loads(response.data) - majors_data = ( - ("CSCI", "ECSE", "MATH"), - ( - "Computer Science", - "Electrical, Computer, and Systems Engineering", - "Mathematics", - ), - ) - for i, major in enumerate(json_data): - assert major["code"] == majors_data[0][i] - assert major["name"] == majors_data[1][i] + assert major["code"] == expected_majors[0][i] + assert major["name"] == expected_majors[1][i] From 17cd39d83f19d8a5c6be2a55a046697de8bf7931 Mon Sep 17 00:00:00 2001 From: Mrunal Athaley <112527910+athalm@users.noreply.github.com> Date: Thu, 10 Oct 2024 18:54:15 -0400 Subject: [PATCH 07/99] update test_departments.py test parameterization --- tests/test_departments.py | 127 ++++++++++++++++++++++---------------- 1 file changed, 73 insertions(+), 54 deletions(-) diff --git a/tests/test_departments.py b/tests/test_departments.py index 445cd3c..9aab891 100644 --- a/tests/test_departments.py +++ b/tests/test_departments.py @@ -4,9 +4,35 @@ from flask import json from flask.testing import FlaskClient +import pytest -def test_departments_route(test_client: FlaskClient) -> None: +@pytest.mark.parametrize( + "expected_departments", + [ + ( + ( + "Computer Science", + "Biology", + "Materials Engineering", + "Math", + "Environmental Engineering", + "Aerospace Engineering", + "Aeronautical Engineering", + ), + ( + "DS", + "life", + "also pretty cool", + "quick maths", + "water", + "space, the final frontier", + "flying, need for speed", + ), + ) + ], +) +def test_departments_route(test_client: FlaskClient, expected_departments) -> None: """ GIVEN a Flask application configured for testing WHEN the '/departments' page is requested (GET) @@ -18,80 +44,73 @@ def test_departments_route(test_client: FlaskClient) -> None: json_data = json.loads(response.data) - rpi_departments_data = ( - ( - "Computer Science", - "Biology", - "Materials Engineering", - "Math", - "Environmental Engineering", - "Aerospace Engineering", - "Areonautical Engineering", - ), - ( - "DS", - "life", - "also pretty cool", - "quick maths", - "water", - "space, the final frontier", - "flying, need for speed", - ), - ) - for department in json_data: - assert department["name"] in rpi_departments_data[0] - assert department["description"] in rpi_departments_data[1] + assert department["name"] in expected_departments[0] + assert department["description"] in expected_departments[1] -def test_department_route(test_client: FlaskClient) -> None: +@pytest.mark.parametrize( + "input_data, expected_data", + [ + ( + {"department": "Computer Science"}, + { + "name": "Computer Science", + "description": "DS", + "school_id": "School of Science", + "professors": [ + {"name": "Duy Le", "rcs_id": "led"}, + {"name": "Rafael", "rcs_id": "cenzar"}, + {"name": "Turner", "rcs_id": "turner"}, + {"name": "Kuzmin", "rcs_id": "kuzmin"}, + {"name": "Goldschmidt", "rcs_id": "goldd"}, + ], + "opportunities": [ + {"id": 1, "name": "Automated Cooling System"}, + {"id": 2, "name": "Iphone 15 durability test"}, + ], + }, + ) + ], +) +def test_department_route(test_client: FlaskClient, input_data, expected_data) -> None: """ GIVEN a Flask application configured for testing WHEN the '/department' page is requested (GET) THEN check that the response is valid """ - response = test_client.get("/department", json={"department": "Computer Science"}) + response = test_client.get("/department", json=input_data) assert response.status_code == 200 json_data = json.loads(response.data) - assert json_data["name"] == "Computer Science" - assert json_data["description"] == "DS" - assert json_data["school_id"] == "School of Science" - - prof_names = ["Duy Le", "Rafael", "Turner", "Kuzmin", "Goldschmidt"] - prof_rcs_ids = ["led", "cenzar", "turner", "kuzmin", "goldd"] + assert json_data["name"] == expected_data["name"] + assert json_data["description"] == expected_data["description"] + assert json_data["school_id"] == expected_data["school_id"] for prof in json_data["professors"]: - assert prof["name"] in prof_names - assert prof["rcs_id"] in prof_rcs_ids - - opportunity_ids = [1, 2] - opportunity_names = ["Automated Cooling System", "Iphone 15 durability test"] + assert prof["name"] in [p["name"] for p in expected_data["professors"]] + assert prof["rcs_id"] in [p["rcs_id"] for p in expected_data["professors"]] for opportunity in json_data["opportunities"]: - assert opportunity["id"] in opportunity_ids - assert opportunity["name"] in opportunity_names - - -def test_department_route_no_json(test_client: FlaskClient) -> None: - """ - GIVEN a Flask application configured for testing - WHEN the '/department' page is requested (GET) - THEN check that the response is valid - """ - response = test_client.get("/department") - - assert response.status_code == 400 - - -def test_department_route_incorrect_json(test_client: FlaskClient) -> None: + assert opportunity["id"] in [o["id"] for o in expected_data["opportunities"]] + assert opportunity["name"] in [o["name"] for o in expected_data["opportunities"]] + + +@pytest.mark.parametrize( + "input_data", + [ + (None,), # Testing with no JSON + ({"wrong": "wrong"},) # Testing with incorrect JSON + ], +) +def test_department_route_invalid_json(test_client: FlaskClient, input_data) -> None: """ GIVEN a Flask application configured for testing WHEN the '/department' page is requested (GET) THEN check that the response is valid """ - response = test_client.get("/department", json={"wrong": "wrong"}) + response = test_client.get("/department", json=input_data) assert response.status_code == 400 From 7e24cda373dec75bc8e08d0dc889e474cba7ae05 Mon Sep 17 00:00:00 2001 From: Mrunal Athaley <112527910+athalm@users.noreply.github.com> Date: Thu, 10 Oct 2024 18:59:09 -0400 Subject: [PATCH 08/99] update test_general.py test parameterization --- tests/test_general.py | 61 +++++++++++++++++++++++++++++-------------- 1 file changed, 42 insertions(+), 19 deletions(-) diff --git a/tests/test_general.py b/tests/test_general.py index e472206..e69a222 100644 --- a/tests/test_general.py +++ b/tests/test_general.py @@ -4,6 +4,7 @@ from flask import json from flask.testing import FlaskClient +import pytest def test_home_page(test_client: FlaskClient) -> None: @@ -15,7 +16,6 @@ def test_home_page(test_client: FlaskClient) -> None: response = test_client.get("/") assert response.status_code == 200 - assert {"Hello": "There"} == json.loads(response.data) @@ -26,9 +26,10 @@ def test_discover_route(test_client: FlaskClient) -> None: THEN check that the response is valid """ response = test_client.get("/discover") - # data = json.loads(response.data.decode("utf-8")) + assert response.status_code == 200 - # print(data) + # Uncomment and modify the following line with expected response data + # data = json.loads(response.data.decode("utf-8")) # assert data["data"][0] == { # "title": "Nelson", # "major": "CS", @@ -37,23 +38,48 @@ def test_discover_route(test_client: FlaskClient) -> None: # } -def test_profile_page(test_client: FlaskClient) -> None: +@pytest.mark.parametrize( + "input_id, expected_profile", + [ + (1, { + "id": "cenzar", + "first_name": "Rafael", + "opportunities": [ ... ] # Replace with expected opportunities data + }) + ], +) +def test_profile_page(test_client: FlaskClient, input_id, expected_profile) -> None: """ GIVEN a Flask application configured for testing WHEN the '/profile/' page is requested (GET) THEN check that the response is valid """ - response = test_client.get("/profile", json={"id": 1}) + response = test_client.get("/profile", json={"id": input_id}) assert response.status_code == 200 json_data = json.loads(response.data) - assert json_data["id"] == "cenzar" - assert json_data["first_name"] == "Rafael" + assert json_data["id"] == expected_profile["id"] + assert json_data["first_name"] == expected_profile["first_name"] assert json_data["opportunities"] != [] -def test_schools_route(test_client: FlaskClient) -> None: +@pytest.mark.parametrize( + "expected_schools", + [ + ( + ( + "School of Science", + "School of Engineering", + ), + ( + "the coolest of them all", + "also pretty cool", + ), + ) + ], +) +def test_schools_route(test_client: FlaskClient, expected_schools) -> None: """ GIVEN a Flask application configured for testing WHEN the '/schools' page is requested (GET) @@ -65,14 +91,9 @@ def test_schools_route(test_client: FlaskClient) -> None: json_data = json.loads(response.data) - rpi_schools_data = ( - ("School of Science", "School of Engineering"), - ("the coolest of them all", "also pretty cool"), - ) - for school in json_data: - assert school["name"] in rpi_schools_data[0] - assert school["description"] in rpi_schools_data[1] + assert school["name"] in expected_schools[0] + assert school["description"] in expected_schools[1] def test_years_route(test_client: FlaskClient) -> None: @@ -84,20 +105,22 @@ def test_years_route(test_client: FlaskClient) -> None: response = test_client.get("/years") assert response.status_code == 200 - assert [2024, 2025, 2026, 2027, 2028, 2029, 2030, 2031] == json.loads(response.data) def test_professor_profile(test_client: FlaskClient) -> None: - + """ + GIVEN a Flask application configured for testing + WHEN the '/getProfessorProfile/' page is requested (GET) + THEN check that the response is valid + """ response = test_client.get("/getProfessorProfile/1") + assert response.status_code == 200 # Load the response data as JSON data = json.loads(response.data) - print(data) - # Test that the "name" key exists assert data["first_name"] == "Rafael" assert data["last_name"] == "Cenzano" assert data["preferred_name"] == "Raf" From fcceb0cd46026b23138136ba98b6425abd7f5460 Mon Sep 17 00:00:00 2001 From: SarahWohlford <157171746+SarahWohlford@users.noreply.github.com> Date: Fri, 11 Oct 2024 16:33:57 -0400 Subject: [PATCH 09/99] start of routes --- labconnect/main/opportunity_routes.py | 319 ++++++++++++++++++++++++-- labconnect/main/routes.py | 52 ++--- 2 files changed, 325 insertions(+), 46 deletions(-) diff --git a/labconnect/main/opportunity_routes.py b/labconnect/main/opportunity_routes.py index 575cf8b..7b4dd4e 100644 --- a/labconnect/main/opportunity_routes.py +++ b/labconnect/main/opportunity_routes.py @@ -1,20 +1,20 @@ import datetime -from flask import abort, request -from flask_jwt_extended import ( - get_jwt_identity, - jwt_required, -) +# from flask import abort, request +# from flask_jwt_extended import ( +# get_jwt_identity, +# jwt_required, +# ) from labconnect import db from labconnect.models import ( LabManager, Leads, Opportunities, - RecommendsClassYears, - RecommendsMajors, - RecommendsCourses, - User, + # RecommendsClassYears, + # RecommendsMajors, + # RecommendsCourses, + # User, ) from labconnect.helpers import LocationEnum @@ -225,9 +225,147 @@ def packageOpportunityCard(opportunity): # @main_blueprint.get("/opportunity/filter") -# @main_blueprint.route("/opportunity/filter", methods=["GET", "POST"]) # def filterOpportunities(): +# if not request.data: +# data = db.session.execute( +# db.select(Opportunities) +# .where(Opportunities.active == True) +# .limit(20) +# .order_by(Opportunities.last_updated) +# .distinct() +# ).scalars() + +# result = [opportunity.to_dict() for opportunity in data] + +# return result + +# json_request_data = request.get_json() + +# if not json_request_data: +# abort(400) + +# filters = json_request_data.get("filters", None) + +# data = None + +# if filters is None: +# data = db.session.execute(db.select(Opportunities).limit(20)).scalars() + +# elif not isinstance(filters, list): +# abort(400) + +# 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() + +# if field == "location" and value.lower() == "remote": +# where_conditions.append(Opportunities.location == "REMOTE") + +# elif field == "location": +# where_conditions.append(Opportunities.location != "REMOTE") + +# 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)) + +# 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 == True) +# elif credit == 2: +# credit_conditions.append(Opportunities.two_credits == True) +# elif credit == 3: +# credit_conditions.append( +# Opportunities.three_credits == True +# ) +# elif credit == 4: +# credit_conditions.append(Opportunities.four_credits == True) +# else: +# abort(400) + +# query = query.where(db.or_(*credit_conditions)) + +# 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)) + +# 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)) +# ) + +# elif field == "pay": + +# if not isinstance(value, dict): +# abort(400) + +# min_pay = value.get("min", None) +# max_pay = value.get("max", None) + +# if min_pay is None or max_pay is None: +# abort(400) + +# where_conditions.append(Opportunities.pay.between(min_pay, max_pay)) + +# 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.post("/opportunity/filter") +# def filterOpportunities(): # if not request.data: # data = db.session.execute( # db.select(Opportunities) @@ -603,13 +741,10 @@ def packageOpportunityCard(opportunity): # # return data in the below format if opportunity is found # return cards -# abort(500) - # functions to create/edit/delete opportunities # @main_blueprint.post("/createOpportunity") # def createOpportunity(): -# # if request.method == "POST": # data = request.get_json() # authorID = data["authorID"] # newPostData = data @@ -660,11 +795,9 @@ def packageOpportunityCard(opportunity): # active=newPostData["active"], # location=lenum, # ) -# print("before comitting") # db.session.add(newOpportunity) # db.session.commit() -# print("got here atleast") # newLead = Leads(lab_manager_id=authorID, opportunity_id=newOpportunity.id) @@ -700,9 +833,8 @@ def packageOpportunityCard(opportunity): # abort(500) -# @main_blueprint.route("/editOpportunity", methods=["DELETE", "POST"]) +# @main_blueprint.delete("/editOpportunity") # def editOpportunity(): -# if True: # data = request.get_json() # id = data["id"] # # authToken = data["authToken"] @@ -803,12 +935,110 @@ def packageOpportunityCard(opportunity): # return "Successful" -# abort(500) +#@main_blueprint.post("/editOpportunity") +# def editOpportunity(): +# data = request.get_json() +# id = data["id"] +# # authToken = data["authToken"] +# # authorID = data["authorID"] +# newPostData = data + +# # query database to see if the credentials above match +# query = db.session.execute( +# db.select( +# Opportunities, RecommendsMajors, RecommendsCourses, RecommendsClassYears +# ) +# .where(Opportunities.id == id) +# .join(RecommendsMajors, RecommendsMajors.opportunity_id == Opportunities.id) +# .join( +# RecommendsCourses, RecommendsCourses.opportunity_id == Opportunities.id +# ) +# .join( +# RecommendsClassYears, +# RecommendsClassYears.opportunity_id == Opportunities.id, +# ) +# ) + +# data = query.all() + +# if not data or len(data) == 0: +# abort(404) + +# opportunity = data[0][0] + +# one = False +# two = False +# three = False +# four = False + +# if "1" in newPostData["credits"]: +# one = True +# if "2" in newPostData["credits"]: +# two = True +# if "3" in newPostData["credits"]: +# three = True +# if "4" in newPostData["credits"]: +# four = True + +# lenum = convert_to_enum(newPostData["location"]) +# print(newPostData["location"]) +# print("printing lenum") +# print(lenum) + +# # if match is found, edit the opportunity with the new data provided +# opportunity.name = newPostData["name"] +# opportunity.description = newPostData["description"] +# opportunity.recommended_experience = newPostData["recommended_experience"] +# opportunity.pay = newPostData["pay"] +# opportunity.one_credit = one +# opportunity.two_credits = two +# opportunity.three_credits = three +# opportunity.four_credits = four +# opportunity.semester = newPostData["semester"] +# opportunity.year = newPostData["year"] +# opportunity.application_due = datetime.datetime.strptime( +# newPostData["application_due"], "%Y-%m-%d" +# ) +# opportunity.active = newPostData["active"] + +# if lenum is not None: +# opportunity.location = lenum + +# db.session.add(opportunity) +# db.session.commit() + +# # delete all the old data in the recommends tables + +# for row in data: +# db.session.delete(row[1]) +# db.session.delete(row[2]) +# db.session.delete(row[3]) + +# # create new data for allow the tables + +# for course in newPostData["courses"]: +# newCourse = RecommendsCourses( +# opportunity_id=opportunity.id, course_code=course +# ) +# db.session.add(newCourse) +# db.session.commit() + +# for major in newPostData["majors"]: +# newMajor = RecommendsMajors(opportunity_id=opportunity.id, major_code=major) +# db.session.add(newMajor) +# db.session.commit() + +# for year in newPostData["years"]: +# newYear = RecommendsClassYears( +# opportunity_id=opportunity.id, class_year=year +# ) +# db.session.add(newYear) +# db.session.commit() +# return "Successful" -# @main_blueprint.route("/deleteOpportunity", methods=["DELETE", "POST"]) +# @main_blueprint.delete("/deleteOpportunity") # def deleteOpportunity(): -# if request.method in ["DELETE", "POST"]: # data = request.get_json() # id = data["id"] @@ -855,3 +1085,52 @@ def packageOpportunityCard(opportunity): # return "Success" # abort(500) + +# @main_blueprint.post("/deleteOpportunity") +# def deleteOpportunity(): +# data = request.get_json() +# id = data["id"] + +# query = db.session.execute( +# db.select( +# Opportunities, +# RecommendsMajors, +# RecommendsCourses, +# RecommendsClassYears, +# Leads, +# ) +# .where(Opportunities.id == id) +# .join(RecommendsMajors, RecommendsMajors.opportunity_id == Opportunities.id) +# .join( +# RecommendsCourses, RecommendsCourses.opportunity_id == Opportunities.id +# ) +# .join( +# RecommendsClassYears, +# RecommendsClassYears.opportunity_id == Opportunities.id, +# ) +# .join(Leads, Leads.opportunity_id == Opportunities.id) +# ) + +# data = query.all() +# print(data) + +# if not data or len(data) == 0: +# abort(404) + +# opportunity = data[0][0] + +# for row in data: +# db.session.delete(row[1]) +# db.session.delete(row[2]) +# db.session.delete(row[3]) +# db.session.delete(row[4]) + +# leads = data[0][4] + +# db.session.delete(opportunity) + +# db.session.commit() + +# return "Success" + +# abort(500) \ No newline at end of file diff --git a/labconnect/main/routes.py b/labconnect/main/routes.py index 4e14488..3efc561 100644 --- a/labconnect/main/routes.py +++ b/labconnect/main/routes.py @@ -1,53 +1,53 @@ -from typing import Any +#from typing import Any from flask import abort, request -from flask_jwt_extended import ( - get_jwt_identity, - jwt_required, -) +#from flask_jwt_extended import ( + #get_jwt_identity, + #jwt_required, +#) from labconnect import db from labconnect.models import ( - ClassYears, - Courses, + #ClassYears, + #Courses, LabManager, Leads, - Majors, + #Majors, Opportunities, - Participates, - RecommendsClassYears, - RecommendsCourses, - RecommendsMajors, + #Participates, + #RecommendsClassYears, + #RecommendsCourses, + #RecommendsMajors, RPIDepartments, - RPISchools, + #RPISchools, User, - UserCourses, - UserDepartments, - UserMajors, + #UserCourses, + #UserDepartments, + #UserMajors, ) +# = not currently using from . import main_blueprint -@main_blueprint.route("/") -def index(): - return {"Hello": "There"} +# @main_blueprint.route("/") +# def index(): +# return {"Hello": "There"} @main_blueprint.get("/departments") def departmentCards(): data = db.session.execute( db.select(RPIDepartments.name, RPIDepartments.school_id) - ).all() - results = [ - { + ).all() + + results = [] + for department in data: + results.append({ "title": department.name, "school": department.school_id, "image": "https://cdn-icons-png.flaticon.com/512/5310/5310672.png", - } - for department in data - ] - + }) return results From a8e851ee664f9a7f4a28cc435763e50f8ab87d1b Mon Sep 17 00:00:00 2001 From: SarahWohlford <157171746+SarahWohlford@users.noreply.github.com> Date: Fri, 11 Oct 2024 16:46:39 -0400 Subject: [PATCH 10/99] Merge branch 'CleanUp' of https://github.com/LabConnect-RCOS/LabConnect-Backend into CleanUp --- .github/workflows/docker-test.yml | 9 ++ Dockerfile | 4 +- Makefile | 2 +- config.py | 20 +-- labconnect/__init__.py | 11 ++ labconnect/main/opportunity_routes.py | 194 +++++++++++++++----------- labconnect/models.py | 2 +- migrations/env.py | 12 ++ requirements.txt | 3 + run.sh | 9 +- 10 files changed, 166 insertions(+), 100 deletions(-) diff --git a/.github/workflows/docker-test.yml b/.github/workflows/docker-test.yml index 976174b..1b0d996 100644 --- a/.github/workflows/docker-test.yml +++ b/.github/workflows/docker-test.yml @@ -24,4 +24,13 @@ jobs: sleep 60 docker logs labconnect-backend-container docker stop labconnect-backend-container + + - name: "Check for Container Exit Code" + run: | + docker inspect labconnect-backend-container --format='{{.State.ExitCode}}' docker rm labconnect-backend-container + id: exit_code + + - name: "Fail if Container Fails" + if: steps.exit_code.outputs.exit_code != '0' + run: exit 1 diff --git a/Dockerfile b/Dockerfile index 627f70c..fb02001 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,12 +7,12 @@ RUN apk add --no-cache postgresql-dev gcc python3-dev musl-dev COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt -COPY labconnect . +COPY labconnect/ /app/labconnect/ +COPY migrations/ /app/migrations/ COPY app.py . COPY db_init.py . COPY config.py . COPY run.sh . -COPY migrations . RUN chmod +x run.sh HEALTHCHECK --interval=10s --timeout=5s --start-period=5s --retries=3 \ diff --git a/Makefile b/Makefile index e0d3b71..80f6b7a 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ run: gunicorn app:app -w 6 --preload --max-requests-jitter 300 --bind 0.0.0.0:9000 develop: - python3 run.py + python3 app.py test: drop create python3 -m pytest --cov --cov-report=html:coverage_report diff --git a/config.py b/config.py index d9c0a67..3a79146 100644 --- a/config.py +++ b/config.py @@ -19,21 +19,23 @@ class Config: SAML_CONFIG = os.path.join(basedir, "config/saml/") FRONTEND_URL = os.environ.get("FRONTEND_URL", "https://labconnect.cs.rpi.edu") + SENTRY_DSN = os.environ.get("SENTRY_DSN", "") + SENTRY_TRACES_SAMPLE_RATE = float(os.environ.get("SENTRY_TRACES_SAMPLE_RATE", 1.0)) + SENTRY_PROFILES_SAMPLE_RATE = float( + os.environ.get("SENTRY_PROFILES_SAMPLE_RATE", 1.0) + ) + + SQLALCHEMY_DATABASE_URI = os.environ.get( + "DB", f"sqlite:///{os.path.join(basedir, 'db', 'database.db')}" + ) + # "postgresql+psycopg2://postgres:root@localhost/labconnect" + class TestingConfig(Config): TESTING = True DEBUG = True - # Using SQLLITE locally - # SQLALCHEMY_DATABASE_URI = f"sqlite:///{os.path.join(basedir, 'database.db')}" - SQLALCHEMY_DATABASE_URI = "postgresql+psycopg2://postgres:root@localhost/labconnect" - class ProductionConfig(Config): TESTING = False DEBUG = False - - # Using SQLLITE locally as a fallback, the goal is to use postgresql in production - SQLALCHEMY_DATABASE_URI = os.environ.get( - "DB", f"sqlite:///{os.path.join(basedir, 'db', 'database.db')}" - ) diff --git a/labconnect/__init__.py b/labconnect/__init__.py index b760d48..35e60f2 100644 --- a/labconnect/__init__.py +++ b/labconnect/__init__.py @@ -1,5 +1,6 @@ import json import os + from datetime import datetime, timedelta, timezone # Import Flask modules @@ -12,7 +13,10 @@ get_jwt, get_jwt_identity, ) + from flask_sqlalchemy import SQLAlchemy +import sentry_sdk +from sentry_sdk.integrations.flask import FlaskIntegration from flask_migrate import Migrate from labconnect.helpers import OrJSONProvider @@ -29,6 +33,13 @@ def create_app() -> Flask: app.config.from_object(os.environ.get("CONFIG", "config.TestingConfig")) + sentry_sdk.init( + dsn=app.config["SENTRY_DSN"], + integrations=[FlaskIntegration()], + traces_sample_rate=app.config["SENTRY_TRACES_SAMPLE_RATE"], + profiles_sample_rate=app.config["SENTRY_PROFILES_SAMPLE_RATE"], + ) + initialize_extensions(app) register_blueprints(app) diff --git a/labconnect/main/opportunity_routes.py b/labconnect/main/opportunity_routes.py index 7b4dd4e..d766d86 100644 --- a/labconnect/main/opportunity_routes.py +++ b/labconnect/main/opportunity_routes.py @@ -1,10 +1,11 @@ import datetime -# from flask import abort, request -# from flask_jwt_extended import ( -# get_jwt_identity, -# jwt_required, -# ) +from flask import abort, request + +from flask_jwt_extended import ( + get_jwt_identity, + jwt_required, +) from labconnect import db from labconnect.models import ( @@ -28,6 +29,7 @@ def searchOpportunity(input: str): stmt = ( db.select(Opportunities) .where( + #Made query input ( Opportunities.search_vector.match(input) ) # Full-text search using pre-generated tsvector @@ -44,6 +46,27 @@ def searchOpportunity(input: str): ).desc() # Order by similarity for fuzzy search results ) ) + # Perform a search + # stmt = ( + # db.select(Opportunities) + # .where( + # ( + # Opportunities.search_vector.match(input) + # ) # Full-text search using pre-generated tsvector + # | ( + # db.func.similarity(Opportunities.name, input) >= 0.1 + # ) # Fuzzy search on the 'name' field + # | ( + # db.func.similarity(Opportunities.description, input) >= 0.1 + # ) # Fuzzy search on the 'description' field + # ) + # .order_by( + # db.func.similarity( + # Opportunities.name, input + # ).desc() # Order by similarity for fuzzy search results + # ) + # ) + data = db.session.execute(stmt).scalars().all() @@ -81,7 +104,7 @@ def searchOpportunity(input: str): def convert_to_enum(location_string): try: return LocationEnum[location_string] # Use upper() for case-insensitivity - except: + except KeyError: return None # Or raise an exception if you prefer @@ -102,6 +125,14 @@ def packageIndividualOpportunity(opportunityInfo): "author": "", "department": "", } + data = { + "id": opportunityInfo.id, + "name": opportunityInfo.name, + "description": opportunityInfo.description, + "recommended_experience": opportunityInfo.recommended_experience, + "author": "", + "department": "", + } opportunity_credits = "" if opportunityInfo.one_credit: @@ -409,100 +440,95 @@ def packageOpportunityCard(opportunity): # value = given_filter.get("value", None) # if field and value: - # field = field.lower() -# if field == "location" and value.lower() == "remote": -# where_conditions.append(Opportunities.location == "REMOTE") - -# elif field == "location": -# where_conditions.append(Opportunities.location != "REMOTE") +# # 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)) - +# # 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 == True) -# elif credit == 2: -# credit_conditions.append(Opportunities.two_credits == True) +# # 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 == True -# ) -# elif credit == 4: -# credit_conditions.append(Opportunities.four_credits == True) +# # credit_conditions.append( +# # Opportunities.three_credits.is_(True) +# # ) +# # elif credit == 4: +# # credit_conditions.append( +# Opportunities.four_credits.is_(True) +# # ) # else: -# abort(400) - -# query = query.where(db.or_(*credit_conditions)) - -# 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)) - +# # 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)) -# ) - +# # 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", None) -# max_pay = value.get("max", None) - -# if min_pay is None or max_pay is None: -# abort(400) - -# where_conditions.append(Opportunities.pay.between(min_pay, max_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) +# # 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() +# # query = query.where(*where_conditions) +# # data = db.session.execute(query).scalars() -# if not data: -# abort(404) +# # if not data: +# # abort(404) -# result = [opportunity.to_dict() for opportunity in data] +# # result = [opportunity.to_dict() for opportunity in data] -# return result +# # return result # @main_blueprint.put("/opportunity") diff --git a/labconnect/models.py b/labconnect/models.py index 28407e2..9bc3729 100644 --- a/labconnect/models.py +++ b/labconnect/models.py @@ -197,7 +197,7 @@ class Opportunities(db.Model, CustomSerializerMixin): @event.listens_for(Opportunities, "before_insert") @event.listens_for(Opportunities, "before_update") -def update_search_vector(mapper, connection, target): +def update_search_vector(_unusedmapper, _unusedconnection, target): target.search_vector = func.to_tsvector( "english", target.name + " " + target.description ) diff --git a/migrations/env.py b/migrations/env.py index 1a96fbf..6cac438 100644 --- a/migrations/env.py +++ b/migrations/env.py @@ -12,8 +12,20 @@ # Interpret the config file for Python logging. # This line sets up loggers basically. fileConfig(config.config_file_name) + +# Create a logger for the Alembic environment logger = logging.getLogger("alembic.env") +# Ensure that we only log important information in production environments +if context.config.get_main_option("environment") == "production": + logger.setLevel(logging.WARNING) # Set to WARNING or ERROR for production +else: + logger.setLevel(logging.INFO) # Allow INFO in non-production environments + +# Avoid logging sensitive information like credentials or tokens +logger.propagate = False +logger.addHandler(logging.StreamHandler()) # Add a basic handler if none exists + def get_engine(): try: diff --git a/requirements.txt b/requirements.txt index 0a7a567..a02a362 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,6 @@ alembic==1.13.3 blinker==1.8.2 +certifi==2024.8.30 click==8.1.7 coverage==7.6.1 Flask==3.0.3 @@ -25,10 +26,12 @@ pytest==8.3.3 pytest-cov==5.0.0 python3-saml==1.16.0 pytz==2024.2 +sentry-sdk==2.15.0 setuptools==70.3.0 six==1.16.0 SQLAlchemy==2.0.29 sqlalchemy-serializer==1.4.22 typing_extensions==4.12.2 +urllib3==2.2.3 Werkzeug==3.0.4 xmlsec==1.3.14 diff --git a/run.sh b/run.sh index 2e8f4ac..96cbe6e 100755 --- a/run.sh +++ b/run.sh @@ -1,5 +1,8 @@ #! /bin/sh +set -e # Fail on any error -# Eventually add alembic migrations here -flask db upgrade -gunicorn app:app -w 6 --preload --max-requests-jitter 300 --bind 0.0.0.0:9000 +# Migrate DB +flask db upgrade || exit 1 + +# Run the app +gunicorn app:app -w 6 --preload --max-requests-jitter 300 --bind 0.0.0.0:9000 || exit 1 \ No newline at end of file From afcf18c871ce53641a20941a7ff3af9b2ef28ed9 Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Sat, 12 Oct 2024 02:35:53 -0400 Subject: [PATCH 11/99] Setup db to use postgres --- config.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/config.py b/config.py index 3a79146..830ee1d 100644 --- a/config.py +++ b/config.py @@ -26,9 +26,8 @@ class Config: ) SQLALCHEMY_DATABASE_URI = os.environ.get( - "DB", f"sqlite:///{os.path.join(basedir, 'db', 'database.db')}" + "DB", "postgresql+psycopg2://postgres:root@localhost/labconnect" ) - # "postgresql+psycopg2://postgres:root@localhost/labconnect" class TestingConfig(Config): From 740fd0f6db40a7bc5c0ad591e40ca6352191026a Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Sat, 12 Oct 2024 02:36:24 -0400 Subject: [PATCH 12/99] add new columns for profile page --- db_init.py | 33 +++++++++++++++++++++++----- labconnect/models.py | 13 +++-------- migrations/versions/4dd3611b273e_.py | 32 +++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 16 deletions(-) create mode 100644 migrations/versions/4dd3611b273e_.py diff --git a/db_init.py b/db_init.py index 13a59f3..3342cf9 100644 --- a/db_init.py +++ b/db_init.py @@ -91,12 +91,24 @@ db.session.commit() lab_manager_rows = ( - ("led", "Duy", "Le", "Computer Science"), - ("turner", "Wes", "Turner", "Computer Science"), - ("kuzmin", "Konstantine", "Kuzmin", "Computer Science"), - ("goldd", "David", "Goldschmidt", "Computer Science"), - ("rami", "Rami", "Rami", "Material Science"), - ("holm", "Mark", "Holmes", "Math"), + ("led", "Duy", "Le", "Computer Science", "database database database"), + ( + "turner", + "Wes", + "Turner", + "Computer Science", + "open source stuff is cool", + ), + ( + "kuzmin", + "Konstantine", + "Kuzmin", + "Computer Science", + "java, psoft, etc.", + ), + ("goldd", "David", "Goldschmidt", "Computer Science", "VIM master"), + ("rami", "Rami", "Rami", "Material Science", "cubes are cool"), + ("holm", "Mark", "Holmes", "Math", "all about that math"), ) raf_test_user = ( @@ -106,6 +118,9 @@ "Raf", 2025, "Computer Science", + "labconnect is the best RCOS project", + "https://rafael.sirv.com/Images/rafael.jpeg?thumbnail=350&format=webp&q=90", + "https://rafaelcenzano.com", ) lab_manager = LabManager(department_id=raf_test_user[5]) @@ -121,6 +136,9 @@ preferred_name=raf_test_user[3], class_year=raf_test_user[4], lab_manager_id=lab_manager.id, + description=raf_test_user[6], + profile_picture=raf_test_user[7], + website=raf_test_user[8], ) db.session.add(user) @@ -138,6 +156,8 @@ first_name=row_tuple[1], last_name=row_tuple[2], lab_manager_id=lab_manager.id, + description=row_tuple[4], + profile_picture="https://www.svgrepo.com/show/206842/professor.svg", ) db.session.add(user) db.session.commit() @@ -326,6 +346,7 @@ last_name=r[3], preferred_name=r[4], class_year=r[5], + profile_picture="https://www.svgrepo.com/show/206842/professor.svg", ) db.session.add(row) db.session.commit() diff --git a/labconnect/models.py b/labconnect/models.py index 9bc3729..8477b1e 100644 --- a/labconnect/models.py +++ b/labconnect/models.py @@ -19,7 +19,7 @@ class User(db.Model, CustomSerializerMixin): "phone_number", "website", "class_year", - "lab_manager_id", + "description", ) serialize_rules = () @@ -30,6 +30,8 @@ class User(db.Model, CustomSerializerMixin): preferred_name = db.Column(db.String(50), nullable=True, unique=False) phone_number = db.Column(db.String(15), nullable=True, unique=False) website = db.Column(db.String(512), nullable=True, unique=False) + description = db.Column(db.String(4096), nullable=True, unique=False) + profile_picture = db.Column(db.String(512), nullable=True, unique=False) class_year = db.Column( db.Integer, db.ForeignKey("class_years.class_year"), @@ -90,15 +92,6 @@ class LabManager(db.Model, CustomSerializerMixin): "Leads", back_populates="lab_manager", passive_deletes=True ) - def getUser(self): - return User.query.filter_by(lab_manager_id=self.id).all() - - def getName(self): - return self.user[0].first_name + " " + self.user[0].last_name - - def getEmail(self): - return self.user[0].email - # rpi_schools( name, description ), key: name class RPISchools(db.Model, CustomSerializerMixin): diff --git a/migrations/versions/4dd3611b273e_.py b/migrations/versions/4dd3611b273e_.py new file mode 100644 index 0000000..3e688a6 --- /dev/null +++ b/migrations/versions/4dd3611b273e_.py @@ -0,0 +1,32 @@ +"""empty message + +Revision ID: 4dd3611b273e +Revises: 55928fddcb12 +Create Date: 2024-10-12 02:36:10.736719 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '4dd3611b273e' +down_revision = '55928fddcb12' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table('user', schema=None) as batch_op: + batch_op.create_unique_constraint(None, ['id']) + + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table('user', schema=None) as batch_op: + batch_op.drop_constraint(None, type_='unique') + + # ### end Alembic commands ### From c957e49ed19fd99538456b3e92f33791c54a57ee Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Sat, 12 Oct 2024 02:36:36 -0400 Subject: [PATCH 13/99] clean up auth routes --- labconnect/main/auth_routes.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/labconnect/main/auth_routes.py b/labconnect/main/auth_routes.py index 4df25c5..6c6e65c 100644 --- a/labconnect/main/auth_routes.py +++ b/labconnect/main/auth_routes.py @@ -16,7 +16,7 @@ from . import main_blueprint -@main_blueprint.route("/login") +@main_blueprint.get("/login") def saml_login(): # Initialize SAML auth request req = prepare_flask_request(request) @@ -58,11 +58,11 @@ def saml_callback(): # Send the JWT to the frontend return redirect(f"{current_app.config['FRONTEND_URL']}/?token={token}") - else: - return {"errors": errors}, 500 + + return {"errors": errors}, 500 -@main_blueprint.route("/metadata/") +@main_blueprint.get("/metadata/") def metadata(): req = prepare_flask_request(request) auth = auth = OneLogin_Saml2_Auth( From ba4cb633600aa44e113ec0b662951eb6e6d5cec0 Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Sat, 12 Oct 2024 02:36:52 -0400 Subject: [PATCH 14/99] fix up profile page --- labconnect/main/routes.py | 60 +++++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 28 deletions(-) diff --git a/labconnect/main/routes.py b/labconnect/main/routes.py index 4e14488..d164d77 100644 --- a/labconnect/main/routes.py +++ b/labconnect/main/routes.py @@ -29,7 +29,7 @@ from . import main_blueprint -@main_blueprint.route("/") +@main_blueprint.get("/") def index(): return {"Hello": "There"} @@ -175,33 +175,37 @@ def profile(): return result -# @main_blueprint.get("/getProfessorProfile/") -# def getProfessorProfile(email: int): -# # test code until database code is added -# query = db.session.execute(db.select(User).where(User.email == email)) -# data = query.all() -# user = data[0][0] -# lm = user.getLabManager() - -# result = {} - -# dictionary = user.to_dict() - -# dictionary["image"] = "https://www.svgrepo.com/show/206842/professor.svg" -# dictionary["department"] = lm.department_id -# dictionary["email"] = user.email -# dictionary["role"] = "admin" -# dictionary["description"] = ( -# "This is the description from the backend but we need to add more fields for LabManager" -# ) +@main_blueprint.get("/staff/") +def getProfessorProfile(id: str): -# # clean data -# dictionary["name"] = ( -# dictionary.pop("first_name") + " " + dictionary.pop("last_name") -# ) -# dictionary.pop("class_year") - -# return dictionary + # TODO: add ways to share phone number and email + # TODO: ensure this fails for non labmanager users + data = db.session.execute( + db.select( + User.preferred_name, + User.last_name, + User.profile_picture, + LabManager.department_id, + User.description, + User.website, + ) + .where(User.id == id) + .join(LabManager, User.lab_manager_id == LabManager.id) + ).first() + + if not data: + return {"error": "profile not found"}, 404 + + result = { + "name": data[0] + " " + data[1], + "image": data[2], + "department": data[3], + "description": data[4], + "website": data[5], + } + + print(result) + return result # @main_blueprint.get("/lab_manager/opportunities") @@ -296,7 +300,7 @@ def changeActiveStatus() -> dict[str, bool]: # return {"Hello": "There"} -@main_blueprint.route("/500") +@main_blueprint.get("/500") def force_error(): abort(500) From b1aa6226ea8f135a7a08df81d32fde7a90079e36 Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Sat, 12 Oct 2024 03:20:59 -0400 Subject: [PATCH 15/99] Create new function to format credits --- labconnect/helpers.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/labconnect/helpers.py b/labconnect/helpers.py index 6f5d600..ad35691 100644 --- a/labconnect/helpers.py +++ b/labconnect/helpers.py @@ -88,3 +88,27 @@ def prepare_flask_request(request): # 'lowercase_urlencoding': True, "post_data": request.form.copy(), } + + +def format_credits(credit_1, credit_2, credit_3, credit_4): + # Create a list to hold the active credit numbers + credits = [] + + if credit_1: + credits.append("1") + if credit_2: + credits.append("2") + if credit_3: + credits.append("3") + if credit_4: + credits.append("4") + + # Handle different cases + if len(credits) == 0: + return None + elif len(credits) == 1: + return f"{credits[0]} Credit" if credit_1 else f"{credits[0]} Credits" + elif len(credits) == 4: + return "1-4 Credits" + else: + return f"{','.join(credits)} Credits" From 31913f7d0b463cb683adc5997298c9baea95a451 Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Sat, 12 Oct 2024 03:21:26 -0400 Subject: [PATCH 16/99] fix profile page result with names --- labconnect/main/routes.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/labconnect/main/routes.py b/labconnect/main/routes.py index d164d77..2531a51 100644 --- a/labconnect/main/routes.py +++ b/labconnect/main/routes.py @@ -183,6 +183,7 @@ def getProfessorProfile(id: str): data = db.session.execute( db.select( User.preferred_name, + User.first_name, User.last_name, User.profile_picture, LabManager.department_id, @@ -197,14 +198,13 @@ def getProfessorProfile(id: str): return {"error": "profile not found"}, 404 result = { - "name": data[0] + " " + data[1], - "image": data[2], - "department": data[3], - "description": data[4], - "website": data[5], + "name": data[0] + " " + data[2] if data[0] else data[1] + " " + data[2], + "image": data[3], + "department": data[4], + "description": data[5], + "website": data[6], } - print(result) return result From 2b0e7bdf03c14d0af44a3585aff475b0c29d71d6 Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Sat, 12 Oct 2024 03:21:55 -0400 Subject: [PATCH 17/99] complete function to return data for user opportunities --- labconnect/main/opportunity_routes.py | 77 ++++++++++++--------------- 1 file changed, 34 insertions(+), 43 deletions(-) diff --git a/labconnect/main/opportunity_routes.py b/labconnect/main/opportunity_routes.py index e28e4f6..a45a5f2 100644 --- a/labconnect/main/opportunity_routes.py +++ b/labconnect/main/opportunity_routes.py @@ -18,7 +18,7 @@ User, ) -from labconnect.helpers import LocationEnum +from labconnect.helpers import LocationEnum, format_credits from . import main_blueprint @@ -523,52 +523,43 @@ def filterOpportunities(): # abort(500) -# @main_blueprint.route("/getProfessorOpportunityCards/", methods=["GET"]) -# def getProfessorOpportunityCards(rcs_id: str): -# if request.method == "GET": -# # query database for opportunity -# user = db.first_or_404(db.select(User).where(User.email == rcs_id)) - -# query = db.session.execute( -# db.select(Opportunities, Leads) -# .where(Leads.lab_manager_id == user.lab_manager_id) -# .join(Opportunities, Leads.opportunity_id == Opportunities.id) -# ) - -# data = query.all() - -# cards = {"data": []} - -# for row in data: -# opportunity = row[0] - -# if not opportunity.active: -# continue - -# oppData = { -# "id": opportunity.id, -# "title": opportunity.name, -# "body": "Due " + str(opportunity.application_due), -# "attributes": [], -# } - -# if opportunity.pay is not None and opportunity.pay > 0: -# oppData["attributes"].append("Paid") +@main_blueprint.get("/staff/opportunities/") +def getLabManagerOpportunityCards(rcs_id: str): -# if ( -# opportunity.one_credit -# or opportunity.two_credits -# or opportunity.three_credits -# or opportunity.four_credits -# ): -# oppData["attributes"].append("Credit Available") + query = ( + db.select( + Opportunities.id, + Opportunities.name, + Opportunities.application_due, + Opportunities.pay, + Opportunities.one_credit, + Opportunities.two_credits, + Opportunities.three_credits, + Opportunities.four_credits, + ) + .join(LabManager, User.lab_manager_id == LabManager.id) + .join(Leads, Leads.lab_manager_id == LabManager.id) + .join(Opportunities, Leads.opportunity_id == Opportunities.id) + .where(User.id == rcs_id) + .select_from(User) + ) -# cards["data"].append(oppData) + data = db.session.execute(query).all() -# # return data in the below format if opportunity is found -# return cards + cards = { + "data": [ + { + "id": row[0], + "title": row[1], + "due": row[2].strftime("%-m/%-d/%y"), + "pay": row[3], + "credits": format_credits(row[4], row[5], row[6], row[7]), + } + for row in data + ] + } -# abort(500) + return cards # @main_blueprint.route("/getProfileOpportunities/", methods=["GET"]) From b070d798908572cecfde3c3392e27ab18d5a5957 Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Sat, 12 Oct 2024 03:25:10 -0400 Subject: [PATCH 18/99] Update db image --- docs/database_docs/Labconnect_DB.png | Bin 90822 -> 93282 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/database_docs/Labconnect_DB.png b/docs/database_docs/Labconnect_DB.png index 5f6a00854b9ce6d3162d79c5d3cdc3f073e2fa9c..06bf109e5d9f2f53922e677dd08ac180864af523 100644 GIT binary patch delta 84853 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 Dp$Q}~ delta 82468 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 E12ZFuGynhq From 6585473cae318d072a41c0c75fbf71ecb9f150a0 Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Sat, 12 Oct 2024 03:29:16 -0400 Subject: [PATCH 19/99] Run black --- labconnect/main/auth_routes.py | 2 +- migrations/versions/4dd3611b273e_.py | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/labconnect/main/auth_routes.py b/labconnect/main/auth_routes.py index 6c6e65c..c5e7b13 100644 --- a/labconnect/main/auth_routes.py +++ b/labconnect/main/auth_routes.py @@ -58,7 +58,7 @@ def saml_callback(): # Send the JWT to the frontend return redirect(f"{current_app.config['FRONTEND_URL']}/?token={token}") - + return {"errors": errors}, 500 diff --git a/migrations/versions/4dd3611b273e_.py b/migrations/versions/4dd3611b273e_.py index 3e688a6..d4bf315 100644 --- a/migrations/versions/4dd3611b273e_.py +++ b/migrations/versions/4dd3611b273e_.py @@ -5,28 +5,29 @@ Create Date: 2024-10-12 02:36:10.736719 """ + from alembic import op import sqlalchemy as sa # revision identifiers, used by Alembic. -revision = '4dd3611b273e' -down_revision = '55928fddcb12' +revision = "4dd3611b273e" +down_revision = "55928fddcb12" branch_labels = None depends_on = None def upgrade(): # ### commands auto generated by Alembic - please adjust! ### - with op.batch_alter_table('user', schema=None) as batch_op: - batch_op.create_unique_constraint(None, ['id']) + with op.batch_alter_table("user", schema=None) as batch_op: + batch_op.create_unique_constraint(None, ["id"]) # ### end Alembic commands ### def downgrade(): # ### commands auto generated by Alembic - please adjust! ### - with op.batch_alter_table('user', schema=None) as batch_op: - batch_op.drop_constraint(None, type_='unique') + with op.batch_alter_table("user", schema=None) as batch_op: + batch_op.drop_constraint(None, type_="unique") # ### end Alembic commands ### From fdddb0a4807a7b6424ade4eeedf86f650119820e Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Sat, 12 Oct 2024 03:35:45 -0400 Subject: [PATCH 20/99] rename to not redefine a builtin function --- labconnect/helpers.py | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/labconnect/helpers.py b/labconnect/helpers.py index ad35691..a7f1bbe 100644 --- a/labconnect/helpers.py +++ b/labconnect/helpers.py @@ -92,23 +92,27 @@ def prepare_flask_request(request): def format_credits(credit_1, credit_2, credit_3, credit_4): # Create a list to hold the active credit numbers - credits = [] + credits_output = [] if credit_1: - credits.append("1") + credits_output.append("1") if credit_2: - credits.append("2") + credits_output.append("2") if credit_3: - credits.append("3") + credits_output.append("3") if credit_4: - credits.append("4") + credits_output.append("4") # Handle different cases - if len(credits) == 0: + if len(credits_output) == 0: return None - elif len(credits) == 1: - return f"{credits[0]} Credit" if credit_1 else f"{credits[0]} Credits" - elif len(credits) == 4: + elif len(credits_output) == 1: + return ( + f"{credits_output[0]} Credit" + if credit_1 + else f"{credits_output[0]} Credits" + ) + elif len(credits_output) == 4: return "1-4 Credits" else: - return f"{','.join(credits)} Credits" + return f"{','.join(credits_output)} Credits" From 516ab2923f1e4afc594adc5c63599ed027b60157 Mon Sep 17 00:00:00 2001 From: youssefr26 Date: Tue, 15 Oct 2024 15:58:05 -0400 Subject: [PATCH 21/99] Fixed syntax error --- labconnect/main/opportunity_routes.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/labconnect/main/opportunity_routes.py b/labconnect/main/opportunity_routes.py index 3b52e93..d9ae9c8 100644 --- a/labconnect/main/opportunity_routes.py +++ b/labconnect/main/opportunity_routes.py @@ -23,8 +23,8 @@ from . import main_blueprint -@main_blueprint.get("/searchOpportunity/") -def searchOpportunity(input: str): +@main_blueprint.get("/searchOpportunity/") +def searchOpportunity(query: str): # Perform a search stmt = ( db.select(Opportunities) From 4d4ad21822fc75493b94e69c34529589af807ac5 Mon Sep 17 00:00:00 2001 From: youssefr26 Date: Tue, 15 Oct 2024 16:12:18 -0400 Subject: [PATCH 22/99] Commit to pull --- labconnect/main/opportunity_routes.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/labconnect/main/opportunity_routes.py b/labconnect/main/opportunity_routes.py index 5ccbe49..4428e82 100644 --- a/labconnect/main/opportunity_routes.py +++ b/labconnect/main/opportunity_routes.py @@ -28,7 +28,7 @@ def searchOpportunity(query: str): stmt = ( db.select(Opportunities) .where( - #Made query input + # Made query input ( Opportunities.search_vector.match(query) ) # Full-text search using pre-generated tsvector @@ -66,7 +66,6 @@ def searchOpportunity(query: str): # ) # ) - data = db.session.execute(stmt).scalars().all() results = [] @@ -825,7 +824,7 @@ def filterOpportunities(): # return "Successful" -#@main_blueprint.post("/editOpportunity") +# @main_blueprint.post("/editOpportunity") # def editOpportunity(): # data = request.get_json() # id = data["id"] @@ -1023,4 +1022,4 @@ def filterOpportunities(): # return "Success" -# abort(500) \ No newline at end of file +# abort(500) From 0439264066932c894c93337c8c9295560d20378c Mon Sep 17 00:00:00 2001 From: SarahWohlford <157171746+SarahWohlford@users.noreply.github.com> Date: Tue, 15 Oct 2024 17:26:30 -0400 Subject: [PATCH 23/99] End opportunity_routes --- labconnect/main/discover_routes.py | 8 +-- labconnect/main/opportunity_routes.py | 92 ++++++++++----------------- 2 files changed, 36 insertions(+), 64 deletions(-) diff --git a/labconnect/main/discover_routes.py b/labconnect/main/discover_routes.py index 87a51bc..24c1b39 100644 --- a/labconnect/main/discover_routes.py +++ b/labconnect/main/discover_routes.py @@ -1,7 +1,7 @@ -from flask_jwt_extended import ( - get_jwt_identity, - jwt_required, -) +#from flask_jwt_extended import ( + #get_jwt_identity, + #jwt_required, +#) from labconnect import db from labconnect.models import ( diff --git a/labconnect/main/opportunity_routes.py b/labconnect/main/opportunity_routes.py index 1f0ef47..02d2a17 100644 --- a/labconnect/main/opportunity_routes.py +++ b/labconnect/main/opportunity_routes.py @@ -1,10 +1,11 @@ -import datetime +#import datetime -from flask import abort, request -from flask_jwt_extended import ( - get_jwt_identity, - jwt_required, -) +#from flask import request +#from flask import abort +#from flask_jwt_extended import ( + #get_jwt_identity, + #jwt_required, +#) from labconnect import db from labconnect.models import ( @@ -30,43 +31,21 @@ def searchOpportunity(input: str): .where( #Made query input ( - Opportunities.search_vector.match(query) + Opportunities.search_vector.match(input) ) # Full-text search using pre-generated tsvector | ( - db.func.similarity(Opportunities.name, query) >= 0.1 + db.func.similarity(Opportunities.name, input) >= 0.1 ) # Fuzzy search on the 'name' field | ( - db.func.similarity(Opportunities.description, query) >= 0.1 + db.func.similarity(Opportunities.description, input) >= 0.1 ) # Fuzzy search on the 'description' field ) .order_by( db.func.similarity( - Opportunities.name, query + Opportunities.name, input ).desc() # Order by similarity for fuzzy search results ) ) - # Perform a search - # stmt = ( - # db.select(Opportunities) - # .where( - # ( - # Opportunities.search_vector.match(input) - # ) # Full-text search using pre-generated tsvector - # | ( - # db.func.similarity(Opportunities.name, input) >= 0.1 - # ) # Fuzzy search on the 'name' field - # | ( - # db.func.similarity(Opportunities.description, input) >= 0.1 - # ) # Fuzzy search on the 'description' field - # ) - # .order_by( - # db.func.similarity( - # Opportunities.name, input - # ).desc() # Order by similarity for fuzzy search results - # ) - # ) - - data = db.session.execute(stmt).scalars().all() results = [] @@ -79,30 +58,22 @@ def searchOpportunity(input: str): # @main_blueprint.get("/opportunity") # def getOpportunity2(): - # if not request.data: # abort(400) - # json_request_data = request.get_json() - # if not json_request_data: # abort(400) - # id = json_request_data.get("id", None) - # if not id: # abort(400) - # data = db.first_or_404(db.select(Opportunities).where(Opportunities.id == id)) - # result = data.to_dict() - # return result def convert_to_enum(location_string): try: - return LocationEnum[location_string] # Use upper() for case-insensitivity + return LocationEnum[location_string.upper()] # Use upper() for case-insensitivity except KeyError: return None # Or raise an exception if you prefer @@ -111,10 +82,8 @@ def packageOpportunity(opportunityInfo, professorInfo): data = opportunityInfo.to_dict() data["professor"] = professorInfo.name data["department"] = professorInfo.department_id - return data - def packageIndividualOpportunity(opportunityInfo): data = { "id": opportunityInfo.id, @@ -178,18 +147,22 @@ def packageIndividualOpportunity(opportunityInfo): ) queryInfo = query.all() - print(queryInfo) + #print(queryInfo) if len(queryInfo) == 0: return data 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"] += ", " + #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_names = [item[1].getName() for item in queryInfo] + data["author"] = ", ".join(author_names) if len(queryInfo) > 1: data["authorProfile"] = ( @@ -216,10 +189,11 @@ def packageOpportunityCard(opportunity): professorInfo = "" - for i, item in enumerate(data): - professorInfo += item[1].getName() - if i != len(data) - 1: - professorInfo += ", " + #for i, item in enumerate(data): + #professorInfo += item[1].getName() + #if i != len(data) - 1: + #professorInfo += ", " + professorInfo = ", ".join(item[1].getName() for item in data) card = { "id": opportunity.id, @@ -247,7 +221,6 @@ def packageOpportunityCard(opportunity): # abort(404) # data = data[0] - # oppData = packageIndividualOpportunity(data[0]) # # return data in the below format if opportunity is found @@ -269,11 +242,11 @@ def packageOpportunityCard(opportunity): # return result -# -@main_blueprint.route("/opportunity/filter", methods=["POST"]) -def filterOpportunities(): + +##@main_blueprint.route("/opportunity/filter", methods=["POST"]) +##def filterOpportunities(): # Handle POST requests for filtering opportunities - json_request_data = request.get_json() + ##json_request_data = request.get_json() # if not json_request_data: @@ -646,7 +619,7 @@ def filterOpportunities(): # data = query.all()[0][0] -# # TODO: how do we get the opportunity id? +# # How do we get the opportunity id? # # if match is found, create a new opportunity with the new data provided # one = False @@ -719,7 +692,6 @@ def filterOpportunities(): # return {"data": "Opportunity Created"} -# # abort(500) From 3477e6de7aa55448e73b002299c0f2e99ec7b2ac Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Wed, 16 Oct 2024 01:38:33 -0400 Subject: [PATCH 24/99] Update DB diagram --- docs/database_docs/Labconnect_DB.png | Bin 93282 -> 96719 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/database_docs/Labconnect_DB.png b/docs/database_docs/Labconnect_DB.png index 06bf109e5d9f2f53922e677dd08ac180864af523..1bc76fe9c5739a3509fef1b0842e34f1ca63d57c 100644 GIT binary patch literal 96719 zcmeFZbx>Sg(=Uo83?u<2xCO$5puydBaCaLB?(Pl=K0p$jpdq*=5ZnUh?UcI{e*K5KQ|C~Ya(8m^{QY~Oy`%f`>S}0s#Ma)ms;X*qbX-
3rn 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 literal 93282 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∨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 U*lhlT;{4C_xTT#e-?3yB) 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 BxNQIc From edd86e402254a6c9248edbd2c9113a670c8ce0a8 Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Wed, 16 Oct 2024 01:38:54 -0400 Subject: [PATCH 25/99] Update models to include more data for the departments and update relationships for updated id --- labconnect/models.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/labconnect/models.py b/labconnect/models.py index 8477b1e..1aab771 100644 --- a/labconnect/models.py +++ b/labconnect/models.py @@ -84,7 +84,7 @@ class LabManager(db.Model, CustomSerializerMixin): serialize_rules = () id = db.Column(db.Integer, primary_key=True, autoincrement=True) - department_id = db.Column(db.String(64), db.ForeignKey("rpi_departments.name")) + department_id = db.Column(db.String(4), db.ForeignKey("rpi_departments.id")) user = db.relationship("User", back_populates="lab_manager") department = db.relationship("RPIDepartments", back_populates="lab_managers") @@ -113,8 +113,11 @@ class RPIDepartments(db.Model, CustomSerializerMixin): serialize_only = ("name", "description", "school_id") serialize_rules = () - name = db.Column(db.String(64), primary_key=True) + id = db.Column(db.String(4), primary_key=True) + name = db.Column(db.String(64), nullable=False, unique=False) + image = db.Column(db.String(512), nullable=True, unique=False) description = db.Column(db.String(2000), nullable=True, unique=False) + website = db.Column(db.String(512), nullable=True, unique=False) school_id = db.Column(db.String(64), db.ForeignKey("rpi_schools.name")) school = db.relationship("RPISchools", back_populates="departments") @@ -254,7 +257,7 @@ class UserDepartments(db.Model, CustomSerializerMixin): user_id = db.Column(db.String(9), db.ForeignKey("user.id"), primary_key=True) department_id = db.Column( - db.String(64), db.ForeignKey("rpi_departments.name"), primary_key=True + db.String(4), db.ForeignKey("rpi_departments.id"), primary_key=True ) user = db.relationship("User", back_populates="departments") From 4af4709d740529f867fd858e746c32a6a9213cbe Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Wed, 16 Oct 2024 01:39:11 -0400 Subject: [PATCH 26/99] Updated db init test data for testing to match the new db design --- db_init.py | 61 ++++++++++++++++++++++++++---------------------------- 1 file changed, 29 insertions(+), 32 deletions(-) diff --git a/db_init.py b/db_init.py index 3342cf9..cf467c7 100644 --- a/db_init.py +++ b/db_init.py @@ -54,31 +54,37 @@ db.session.commit() rpi_departments_rows = ( - ("Computer Science", "DS", "School of Science"), - ("Biology", "life", "School of Science"), - ("Materials Engineering", "also pretty cool", "School of Engineering"), - ("Environmental Engineering", "water", "School of Engineering"), - ("Math", "quick maths", "School of Science"), + ("Computer Science", "DS is rough", "School of Science", "CSCI"), + ("Biology", "life science", "School of Science", "BIOL"), ( - "Aerospace Engineering", - "space, the final frontier", + "Materials Engineering", + "also pretty cool", "School of Engineering", + "MTLE", ), ( - "Aeronautical Engineering", - "flying, need for speed", + "Environmental Engineering", + "water stuff", "School of Engineering", + "ENVE", ), + ("Math", "quick maths", "School of Science", "MATH"), ( - "Material Science", - "Creating the best materials", + "Mechanical, Aerospace, and Nuclear Engineering", + "space, the final frontier", "School of Engineering", + "MANE", ), ) for row_tuple in rpi_departments_rows: row = RPIDepartments( - name=row_tuple[0], description=row_tuple[1], school_id=row_tuple[2] + name=row_tuple[0], + description=row_tuple[1], + school_id=row_tuple[2], + id=row_tuple[3], + image="https://cdn-icons-png.flaticon.com/512/5310/5310672.png", + website="https://www.rpi.edu", ) db.session.add(row) db.session.commit() @@ -91,24 +97,24 @@ db.session.commit() lab_manager_rows = ( - ("led", "Duy", "Le", "Computer Science", "database database database"), + ("led", "Duy", "Le", "CSCI", "database database database"), ( "turner", "Wes", "Turner", - "Computer Science", + "CSCI", "open source stuff is cool", ), ( "kuzmin", "Konstantine", "Kuzmin", - "Computer Science", + "CSCI", "java, psoft, etc.", ), - ("goldd", "David", "Goldschmidt", "Computer Science", "VIM master"), - ("rami", "Rami", "Rami", "Material Science", "cubes are cool"), - ("holm", "Mark", "Holmes", "Math", "all about that math"), + ("goldd", "David", "Goldschmidt", "CSCI", "VIM master"), + ("rami", "Rami", "Rami", "MTLE", "cubes are cool"), + ("holm", "Mark", "Holmes", "MATH", "all about that math"), ) raf_test_user = ( @@ -117,7 +123,7 @@ "Cenzano", "Raf", 2025, - "Computer Science", + "CSCI", "labconnect is the best RCOS project", "https://rafael.sirv.com/Images/rafael.jpeg?thumbnail=350&format=webp&q=90", "https://rafaelcenzano.com", @@ -358,19 +364,10 @@ ) for r in user_majors: - row = UserMajors(user_id=r[0], major_code=r[1]) - db.session.add(row) - db.session.commit() - - user_departments = ( - ("cenzar", "Computer Science"), - ("cenzar", "Math"), - ("test", "Computer Science"), - ) - - for r in user_departments: - row = UserDepartments(user_id=r[0], department_id=r[1]) - db.session.add(row) + major = UserMajors(user_id=r[0], major_code=r[1]) + department = UserDepartments(user_id=r[0], department_id=r[1]) + db.session.add(major) + db.session.add(department) db.session.commit() user_courses = ( From 4fb56a39df292373dc77584de6a2f568117546e7 Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Wed, 16 Oct 2024 01:39:20 -0400 Subject: [PATCH 27/99] 2 new migrations for new db changes --- migrations/versions/c72f39e93d72_.py | 39 ++++++++++++++++++++++++++++ migrations/versions/f7518ca21f44_.py | 33 +++++++++++++++++++++++ 2 files changed, 72 insertions(+) create mode 100644 migrations/versions/c72f39e93d72_.py create mode 100644 migrations/versions/f7518ca21f44_.py diff --git a/migrations/versions/c72f39e93d72_.py b/migrations/versions/c72f39e93d72_.py new file mode 100644 index 0000000..653aebe --- /dev/null +++ b/migrations/versions/c72f39e93d72_.py @@ -0,0 +1,39 @@ +"""empty message + +Revision ID: c72f39e93d72 +Revises: 4dd3611b273e +Create Date: 2024-10-15 17:29:11.568986 + +""" + +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = "c72f39e93d72" +down_revision = "4dd3611b273e" +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table("rpi_departments", schema=None) as batch_op: + batch_op.add_column(sa.Column("website", sa.String(length=2000), nullable=True)) + + with op.batch_alter_table("user", schema=None) as batch_op: + batch_op.create_unique_constraint(None, ["id"]) + + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table("user", schema=None) as batch_op: + batch_op.drop_constraint(None, type_="unique") + + with op.batch_alter_table("rpi_departments", schema=None) as batch_op: + batch_op.drop_column("website") + + # ### end Alembic commands ### diff --git a/migrations/versions/f7518ca21f44_.py b/migrations/versions/f7518ca21f44_.py new file mode 100644 index 0000000..ec5a632 --- /dev/null +++ b/migrations/versions/f7518ca21f44_.py @@ -0,0 +1,33 @@ +"""empty message + +Revision ID: f7518ca21f44 +Revises: c72f39e93d72 +Create Date: 2024-10-16 01:35:20.577378 + +""" + +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = "f7518ca21f44" +down_revision = "c72f39e93d72" +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table("user", schema=None) as batch_op: + batch_op.create_unique_constraint(None, ["id"]) + + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table("user", schema=None) as batch_op: + batch_op.drop_constraint(None, type_="unique") + + # ### end Alembic commands ### From 00bc21d83f7554b9cab4057c0db281f828a92c0d Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Wed, 16 Oct 2024 01:40:09 -0400 Subject: [PATCH 28/99] Update routes for departments --- labconnect/main/routes.py | 70 +++++++++++++++++++++++---------------- 1 file changed, 42 insertions(+), 28 deletions(-) diff --git a/labconnect/main/routes.py b/labconnect/main/routes.py index 2531a51..0c466aa 100644 --- a/labconnect/main/routes.py +++ b/labconnect/main/routes.py @@ -37,11 +37,12 @@ def index(): @main_blueprint.get("/departments") def departmentCards(): data = db.session.execute( - db.select(RPIDepartments.name, RPIDepartments.school_id) + db.select(RPIDepartments.name, RPIDepartments.school_id, RPIDepartments.id) ).all() results = [ { "title": department.name, + "department_id": department.id, "school": department.school_id, "image": "https://cdn-icons-png.flaticon.com/512/5310/5310672.png", } @@ -54,35 +55,49 @@ def departmentCards(): @main_blueprint.get("/departments/") def departmentDetails(department: str): - if not department: - abort(400) - - department_data = db.first_or_404( - db.select(RPIDepartments).where(RPIDepartments.name == department) - ) - - result = department_data.to_dict() + department_data = db.session.execute( + db.select( + RPIDepartments.id, + RPIDepartments.name, + RPIDepartments.description, + RPIDepartments.image, + RPIDepartments.website, + ).where(RPIDepartments.id == department) + ).first() - prof_data = department_data.lab_managers + if department_data is None: + abort(404) - professors = [] - where_conditions = [] + staff_data = db.session.execute( + db.select( + User.id, + User.first_name, + User.preferred_name, + User.last_name, + User.profile_picture, + ) + .join(LabManager, User.lab_manager_id == LabManager.id) + .join(RPIDepartments, LabManager.department_id == RPIDepartments.id) + .where(RPIDepartments.id == department) + ).all() - for prof in prof_data: - professors.append( + result = { + "id": department_data[0], + "name": department_data[1], + "description": department_data[2], + "image": department_data[3], + "website": department_data[4], + "staff": [ { - "name": prof.getName(), - "rcs_id": prof.getEmail(), - "image": "https://www.svgrepo.com/show/206842/professor.svg", + "name": ( + staff[2] + " " + staff[3] if staff[2] else staff[1] + " " + staff[3] + ), + "id": staff[0], + "image": staff[4], } - ) - where_conditions.append(LabManager.id == prof.id) - - result["professors"] = professors - - result["image"] = ( - "https://t4.ftcdn.net/jpg/02/77/10/87/360_F_277108701_1JAbS8jg7Gw42dU6nz7sF72bWiCm3VMv.jpg" - ) + for staff in staff_data + ], + } return result @@ -178,20 +193,19 @@ def profile(): @main_blueprint.get("/staff/") def getProfessorProfile(id: str): - # TODO: add ways to share phone number and email - # TODO: ensure this fails for non labmanager users data = db.session.execute( db.select( User.preferred_name, User.first_name, User.last_name, User.profile_picture, - LabManager.department_id, + RPIDepartments.name, User.description, User.website, ) .where(User.id == id) .join(LabManager, User.lab_manager_id == LabManager.id) + .join(RPIDepartments, LabManager.department_id == RPIDepartments.id) ).first() if not data: From 8e58ff1bce2d18c7960d67beb6dbc5a30749f86b Mon Sep 17 00:00:00 2001 From: Mrunal Athaley <112527910+athalm@users.noreply.github.com> Date: Fri, 18 Oct 2024 14:02:51 -0400 Subject: [PATCH 29/99] update test_opportunities_filtering.py test parameterization --- tests/test_opportunities_filtering.py | 333 ++++++-------------------- 1 file changed, 67 insertions(+), 266 deletions(-) diff --git a/tests/test_opportunities_filtering.py b/tests/test_opportunities_filtering.py index 9297cf7..6610b25 100644 --- a/tests/test_opportunities_filtering.py +++ b/tests/test_opportunities_filtering.py @@ -2,284 +2,85 @@ Test opportunity filtering routes """ +import pytest from flask import json from flask.testing import FlaskClient - -def test_opportunity_filter_pay(test_client: FlaskClient) -> None: +@pytest.mark.parametrize( + "filters, expected_opportunities", + [ + ( + [{"field": "pay", "value": {"min": 14.9, "max": 21}}], + ["Automated Cooling System"] + ), + ( + [{"field": "departments", "value": ["Material Science"]}], + ["Checking out cubes"] + ), + ( + [{"field": "departments", "value": ["Computer Science", "Material Science"]}], + ["Iphone 15 durability test", "Checking out cubes", "Automated Cooling System"] + ), + ( + [{"field": "majors", "value": ["BIOL"]}], + ["Iphone 15 durability test", "Checking out cubes", "Automated Cooling System"] + ), + ( + [{"field": "majors", "value": ["CSCI", "BIOL"]}], + ["Iphone 15 durability test", "Checking out cubes", "Automated Cooling System"] + ), + ( + [{"field": "credits", "value": [1]}], + ["Iphone 15 durability test", "Checking out cubes"] + ), + ( + [{"field": "credits", "value": [2, 4]}], + ["Iphone 15 durability test", "Checking out cubes", "Automated Cooling System", "Test the water"] + ), + ( + [{"field": "class_year", "value": [2025]}], + ["Iphone 15 durability test"] + ), + ( + [{"field": "class_year", "value": [2025, 2027]}], + ["Iphone 15 durability test", "Automated Cooling System"] + ), + ( + [{"field": "location", "value": "Remote"}], + ["Automated Cooling System"] + ), + ( + [{"field": "location", "value": "In-Person"}], + ["Iphone 15 durability test", "Checking out cubes", "Test the water"] + ), + ( + [ + {"field": "location", "value": "In-Person"}, + {"field": "departments", "value": ["Computer Science"]} + ], + ["Iphone 15 durability test"] + ), + ( + [ + {"field": "credits", "value": [2, 4]}, + {"field": "departments", "value": ["Computer Science"]} + ], + ["Iphone 15 durability test", "Automated Cooling System"] + ), + ], +) +def test_opportunity_filter(test_client: FlaskClient, filters, expected_opportunities) -> None: """ GIVEN a Flask application configured for testing WHEN the '/opportunity/filter' page is requested (GET) THEN check that the response is valid """ - - json_data = {"filters": [{"field": "pay", "value": {"min": 14.9, "max": 21}}]} + json_data = {"filters": filters} response = test_client.get("/opportunity/filter", json=json_data) assert response.status_code == 200 json_data = json.loads(response.data) - assert "Automated Cooling System" == json_data[0]["name"] - - -def test_opportunity_filter_department(test_client: FlaskClient) -> None: - """ - GIVEN a Flask application configured for testing - WHEN the '/opportunity/filter' page is requested (GET) - THEN check that the response is valid - """ - - json_data = {"filters": [{"field": "departments", "value": ["Material Science"]}]} - response = test_client.get("/opportunity/filter", json=json_data) - - assert response.status_code == 200 - - json_data = json.loads(response.data) - - assert "Checking out cubes" == json_data[0]["name"] - - -def test_opportunity_filter_departments(test_client: FlaskClient) -> None: - """ - GIVEN a Flask application configured for testing - WHEN the '/opportunity/filter' page is requested (GET) - THEN check that the response is valid - """ - - json_data = { - "filters": [ - {"field": "departments", "value": ["Computer Science", "Material Science"]} - ] - } - response = test_client.get("/opportunity/filter", json=json_data) - - assert response.status_code == 200 - - json_data = json.loads(response.data) - - opportunities = ( - "Iphone 15 durability test", - "Checking out cubes", - "Automated Cooling System", - ) - for data in json_data: - assert data["name"] in opportunities - - -def test_opportunity_filter_major(test_client: FlaskClient) -> None: - """ - GIVEN a Flask application configured for testing - WHEN the '/opportunity/filter' page is requested (GET) - THEN check that the response is valid - """ - - json_data = {"filters": [{"field": "majors", "value": ["BIOL"]}]} - response = test_client.get("/opportunity/filter", json=json_data) - - assert response.status_code == 200 - - json_data = json.loads(response.data) - - opportunities = ( - "Iphone 15 durability test", - "Checking out cubes", - "Automated Cooling System", - ) - - for data in json_data: - assert data["name"] in opportunities - - -def test_opportunity_filter_majors(test_client: FlaskClient) -> None: - """ - GIVEN a Flask application configured for testing - WHEN the '/opportunity/filter' page is requested (GET) - THEN check that the response is valid - """ - - json_data = {"filters": [{"field": "majors", "value": ["CSCI", "BIOL"]}]} - response = test_client.get("/opportunity/filter", json=json_data) - - assert response.status_code == 200 - - json_data = json.loads(response.data) - - opportunities = ( - "Iphone 15 durability test", - "Checking out cubes", - "Automated Cooling System", - ) - - for data in json_data: - assert data["name"] in opportunities - - -def test_opportunity_filter_credits(test_client: FlaskClient) -> None: - """ - GIVEN a Flask application configured for testing - WHEN the '/opportunity/filter' page is requested (GET) - THEN check that the response is valid - """ - - json_data = {"filters": [{"field": "credits", "value": [1]}]} - response = test_client.get("/opportunity/filter", json=json_data) - - assert response.status_code == 200 - - json_data = json.loads(response.data) - - opportunities = ( - "Iphone 15 durability test", - "Checking out cubes", - ) - - for data in json_data: - assert data["name"] in opportunities - - json_data = {"filters": [{"field": "credits", "value": [2, 4]}]} - response = test_client.get("/opportunity/filter", json=json_data) - - assert response.status_code == 200 - - json_data = json.loads(response.data) - - opportunities = ( - "Iphone 15 durability test", - "Checking out cubes", - "Automated Cooling System", - "Test the water", - ) - - for data in json_data: - assert data["name"] in opportunities - - -def test_opportunity_filter_class_years(test_client: FlaskClient) -> None: - """ - GIVEN a Flask application configured for testing - WHEN the '/opportunity/filter' page is requested (GET) - THEN check that the response is valid - """ - - json_data = {"filters": [{"field": "class_year", "value": [2025]}]} - response = test_client.get("/opportunity/filter", json=json_data) - - assert response.status_code == 200 - - json_data = json.loads(response.data) - - opportunities = ("Iphone 15 durability test",) - - for data in json_data: - assert data["name"] in opportunities - - json_data = {"filters": [{"field": "class_year", "value": [2025, 2027]}]} - response = test_client.get("/opportunity/filter", json=json_data) - - assert response.status_code == 200 - - json_data = json.loads(response.data) - - opportunities = ( - "Iphone 15 durability test", - "Automated Cooling System", - ) - - for data in json_data: - assert data["name"] in opportunities - - -def test_opportunity_filter_location_remote(test_client: FlaskClient) -> None: - """ - GIVEN a Flask application configured for testing - WHEN the '/opportunity/filter' page is requested (GET) - THEN check that the response is valid - """ - - json_data = {"filters": [{"field": "location", "value": "Remote"}]} - response = test_client.get("/opportunity/filter", json=json_data) - - assert response.status_code == 200 - - json_data = json.loads(response.data) - - assert "Automated Cooling System" == json_data[0]["name"] - - -def test_opportunity_filter_location_in_person(test_client: FlaskClient) -> None: - """ - GIVEN a Flask application configured for testing - WHEN the '/opportunity/filter' page is requested (GET) - THEN check that the response is valid - """ - - json_data = {"filters": [{"field": "location", "value": "In-Person"}]} - response = test_client.get("/opportunity/filter", json=json_data) - - assert response.status_code == 200 - - json_data = json.loads(response.data) - - opportunities = ( - "Iphone 15 durability test", - "Checking out cubes", - "Test the water", - ) - - for data in json_data: - assert data["name"] in opportunities - - -def test_opportunity_filter_location_departments(test_client: FlaskClient) -> None: - """ - GIVEN a Flask application configured for testing - WHEN the '/opportunity/filter' page is requested (GET) - THEN check that the response is valid - """ - - json_data = { - "filters": [ - {"field": "location", "value": "In-Person"}, - {"field": "departments", "value": ["Computer Science"]}, - ] - } - response = test_client.get("/opportunity/filter", json=json_data) - - assert response.status_code == 200 - - json_data = json.loads(response.data) - - opportunities = ("Iphone 15 durability test",) - - for data in json_data: - assert data["name"] in opportunities - - -def test_opportunity_filter_credits_departments(test_client: FlaskClient) -> None: - """ - GIVEN a Flask application configured for testing - WHEN the '/opportunity/filter' page is requested (GET) - THEN check that the response is valid - """ - - json_data = { - "filters": [ - {"field": "credits", "value": [2, 4]}, - {"field": "departments", "value": ["Computer Science"]}, - ] - } - response = test_client.get("/opportunity/filter", json=json_data) - - assert response.status_code == 200 - - json_data = json.loads(response.data) - - opportunities = ("Iphone 15 durability test", "Automated Cooling System") - - for data in json_data: - assert data["name"] in opportunities - - -# TODO: Add test for no fields + assert data["name"] in expected_opportunities From bfdd042b240aa7fda183d745eeb69183f7cc23e8 Mon Sep 17 00:00:00 2001 From: Mrunal Athaley <112527910+athalm@users.noreply.github.com> Date: Fri, 18 Oct 2024 14:03:50 -0400 Subject: [PATCH 30/99] update test_lab_manager.py test parameterization --- tests/test_lab_manager.py | 167 ++++++++++++++++---------------------- 1 file changed, 72 insertions(+), 95 deletions(-) diff --git a/tests/test_lab_manager.py b/tests/test_lab_manager.py index 0cea0a0..d0a27c2 100644 --- a/tests/test_lab_manager.py +++ b/tests/test_lab_manager.py @@ -4,114 +4,91 @@ from flask import json from flask.testing import FlaskClient +import pytest -def test_lab_manager_route_with_input_id(test_client: FlaskClient) -> None: - """ - GIVEN a Flask application configured for testing - WHEN the '/lab_manager' page is requested (GET) - THEN check that the response is valid - """ - response = test_client.get("/lab_manager", json={"rcs_id": "cenzar"}) - - assert response.status_code == 200 - - json_data = json.loads(response.data) - - cenzar_data = { - "website": None, - "rcs_id": "cenzar", - "name": "Rafael", - "alt_email": None, - "phone_number": None, - "email": None, - } - - assert json_data == cenzar_data - - -def test_lab_manager_route_no_json(test_client: FlaskClient) -> None: - """ - GIVEN a Flask application configured for testing - WHEN the '/lab_manager' page is requested (GET) - THEN check that the response is valid - """ - response = test_client.get("/lab_manager") - - assert response.status_code == 400 - - -def test_lab_manager_route_incorrect_json(test_client: FlaskClient) -> None: +@pytest.mark.parametrize( + "json_data, expected_status, expected_response", + [ + ( + {"rcs_id": "cenzar"}, + 200, + { + "website": None, + "rcs_id": "cenzar", + "name": "Rafael", + "alt_email": None, + "phone_number": None, + "email": None, + }, + ), + (None, 400, None), + ({"wrong": "wrong"}, 400, None), + ], +) +def test_lab_manager_route(test_client: FlaskClient, json_data, expected_status, expected_response) -> None: """ GIVEN a Flask application configured for testing WHEN the '/lab_manager' page is requested (GET) - THEN check that the response is valid + THEN check that the response status and data are as expected """ - response = test_client.get("/lab_manager", json={"wrong": "wrong"}) + response = test_client.get("/lab_manager", json=json_data) - assert response.status_code == 400 + assert response.status_code == expected_status + if expected_response is not None: + json_response = json.loads(response.data) + assert json_response == expected_response -def test_lab_manager_opportunity_cards(test_client: FlaskClient) -> None: - """ - GIVEN a Flask application configured for testing - WHEN the '/lab_manager/opportunities' page is requested (GET) - THEN check that the response is valid - """ - response = test_client.get("/lab_manager/opportunities", json={"rcs_id": "cenzar"}) - - assert response.status_code == 200 - json_data = json.loads(response.data) - - lab_manager_opportunities_data = ( - ( - "Automated Cooling System", - "Energy efficient AC system", - "Thermodynamics", - 15.0, - "Spring", - 2024, - True, - ), +@pytest.mark.parametrize( + "json_data, expected_status, expected_opportunities", + [ ( - "Iphone 15 durability test", - "Scratching the Iphone, drop testing etc.", - "Experienced in getting angry and throwing temper tantrum", - None, - "Spring", - 2024, - True, + {"rcs_id": "cenzar"}, + 200, + [ + ( + "Automated Cooling System", + "Energy efficient AC system", + "Thermodynamics", + 15.0, + "Spring", + 2024, + True, + ), + ( + "Iphone 15 durability test", + "Scratching the Iphone, drop testing etc.", + "Experienced in getting angry and throwing temper tantrum", + None, + "Spring", + 2024, + True, + ), + ], ), - ) - - for i, item in enumerate(json_data["cenzar"]): - assert item["name"] == lab_manager_opportunities_data[i][0] - assert item["description"] == lab_manager_opportunities_data[i][1] - assert item["recommended_experience"] == lab_manager_opportunities_data[i][2] - assert item["pay"] == lab_manager_opportunities_data[i][3] - assert item["semester"] == lab_manager_opportunities_data[i][4] - assert item["year"] == lab_manager_opportunities_data[i][5] - assert item["active"] == lab_manager_opportunities_data[i][6] - - -def test_lab_manager_opportunity_cards_no_json(test_client: FlaskClient) -> None: + (None, 400, None), + ({"wrong": "wrong"}, 400, None), + ], +) +def test_lab_manager_opportunity_cards(test_client: FlaskClient, json_data, expected_status, expected_opportunities) -> None: """ GIVEN a Flask application configured for testing WHEN the '/lab_manager/opportunities' page is requested (GET) - THEN check that the response is valid - """ - response = test_client.get("/lab_manager/opportunities") - - assert response.status_code == 400 - - -def test_lab_manager_opportunity_cards_incorrect_json(test_client: FlaskClient) -> None: + THEN check that the response status and data are as expected """ - GIVEN a Flask application configured for testing - WHEN the '/lab_manager/opportunities' page is requested (GET) - THEN check that the response is valid - """ - response = test_client.get("/lab_manager/opportunities", json={"wrong": "wrong"}) - - assert response.status_code == 400 + response = test_client.get("/lab_manager/opportunities", json=json_data) + + assert response.status_code == expected_status + + if expected_opportunities is not None: + json_response = json.loads(response.data) + for i, item in enumerate(json_response["cenzar"]): + assert item["name"] == expected_opportunities[i][0] + assert item["description"] == expected_opportunities[i][1] + assert item["recommended_experience"] == expected_opportunities[i][2] + assert item["pay"] == expected_opportunities[i][3] + assert item["semester"] == expected_opportunities[i][4] + assert item["year"] == expected_opportunities[i][5] + assert item["active"] == expected_opportunities[i][6] From c8a5aa473bc5853ab1349855dae143235d889d08 Mon Sep 17 00:00:00 2001 From: Mrunal Athaley <112527910+athalm@users.noreply.github.com> Date: Fri, 18 Oct 2024 14:06:03 -0400 Subject: [PATCH 31/99] update test_errors.py test parameterization --- tests/test_errors.py | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/tests/test_errors.py b/tests/test_errors.py index 388aa8b..d44acaa 100644 --- a/tests/test_errors.py +++ b/tests/test_errors.py @@ -4,27 +4,28 @@ from flask import json from flask.testing import FlaskClient +import pytest -def test_404_page(test_client: FlaskClient) -> None: +@pytest.mark.parametrize( + "route, expected_status, expected_response", + [ + ("/abcsd", 404, {"error": "404 not found"}), + ( + "/500", + 500, + { + "error": "500 server error. You can report issues here: https://github.com/RafaelCenzano/LabConnect/issues" + }, + ), + ], +) +def test_error_pages(test_client: FlaskClient, route, expected_status, expected_response) -> None: """ GIVEN a Flask application configured for testing - WHEN the '/abcsd' page is requested (GET) - THEN check that the response is the 404 page + WHEN the specified error route is requested (GET) + THEN check that the response status and data are as expected """ - response = test_client.get("/abcsd") - assert response.status_code == 404 - assert {"error": "404 not found"} == json.loads(response.data) - - -def test_500_page(test_client: FlaskClient) -> None: - """ - GIVEN a Flask application configured for testing - WHEN the '/professor/' page is requested (GET) - THEN check that the response is valid - """ - response = test_client.get("/500") - assert response.status_code == 500 - assert { - "error": "500 server error. You can report issues here: https://github.com/RafaelCenzano/LabConnect/issues" - } == json.loads(response.data) + response = test_client.get(route) + assert response.status_code == expected_status + assert json.loads(response.data) == expected_response From 0127a6872702abcc40fc0af706b71ad0d15bc980 Mon Sep 17 00:00:00 2001 From: Mrunal Athaley <112527910+athalm@users.noreply.github.com> Date: Fri, 18 Oct 2024 14:09:18 -0400 Subject: [PATCH 32/99] update test_courses.py test parameterization --- tests/test_courses.py | 120 +++++++++++++++++++++--------------------- 1 file changed, 60 insertions(+), 60 deletions(-) diff --git a/tests/test_courses.py b/tests/test_courses.py index 9a29803..27d8eec 100644 --- a/tests/test_courses.py +++ b/tests/test_courses.py @@ -4,79 +4,79 @@ from flask import json from flask.testing import FlaskClient +import pytest -def test_courses_route_with_input_name(test_client: FlaskClient) -> None: - """ - GIVEN a Flask application configured for testing - WHEN the '/courses' page is requested (GET) - THEN check that the response is valid - """ - response = test_client.get("/courses", json={"input": "data"}) - - assert response.status_code == 200 - - json_data = json.loads(response.data) - - assert json_data[0]["code"] == "CSCI4390" - assert json_data[0]["name"] == "Data Mining" - - -def test_courses_route_with_input_code(test_client: FlaskClient) -> None: - """ - GIVEN a Flask application configured for testing - WHEN the '/courses' page is requested (GET) - THEN check that the response is valid - """ - response = test_client.get("/courses", json={"input": "cs"}) - - assert response.status_code == 200 - - json_data = json.loads(response.data) - - course_data = ( - ("CSCI2300", "CSCI2961", "CSCI4390", "CSCI4430"), +@pytest.mark.parametrize( + "request_json, expected_status, expected_response", + [ ( - "Introduction to Algorithms", - "Rensselaer Center for Open Source", - "Data Mining", - "Programming Languages", + {"input": "data"}, + 200, + [{"code": "CSCI4390", "name": "Data Mining"}], ), - ) - - for i, major in enumerate(json_data): - assert major["code"] == course_data[0][i] - assert major["name"] == course_data[1][i] - - -def test_courses_route_no_json(test_client: FlaskClient) -> None: + ( + {"input": "cs"}, + 200, + [ + {"code": "CSCI2300", "name": "Introduction to Algorithms"}, + {"code": "CSCI2961", "name": "Rensselaer Center for Open Source"}, + {"code": "CSCI4390", "name": "Data Mining"}, + {"code": "CSCI4430", "name": "Programming Languages"}, + ], + ), + (None, 400, None), + ({"wrong": "wrong"}, 400, None), + ({"input": "not found"}, 404, None), + ], +) +def test_courses_route(test_client: FlaskClient, request_json, expected_status, expected_response) -> None: """ GIVEN a Flask application configured for testing - WHEN the '/courses' page is requested (GET) - THEN check that the response is valid + WHEN the '/courses' page is requested (GET) with various inputs + THEN check that the response status and data are as expected """ - response = test_client.get("/courses") + response = test_client.get("/courses", json=request_json) if request_json else test_client.get("/courses") + + assert response.status_code == expected_status - assert response.status_code == 400 + if expected_response is not None: + json_data = json.loads(response.data) + if expected_status == 200: + assert json_data == expected_response + else: + assert json_data is not None -def test_courses_route_incorrect_json(test_client: FlaskClient) -> None: +@pytest.mark.parametrize( + "input_name, course_data", + [ + ( + "cs", + ( + ("CSCI2300", "CSCI2961", "CSCI4390", "CSCI4430"), + ( + "Introduction to Algorithms", + "Rensselaer Center for Open Source", + "Data Mining", + "Programming Languages", + ), + ), + ) + ], +) +def test_courses_route_with_specific_input(test_client: FlaskClient, input_name, course_data) -> None: """ GIVEN a Flask application configured for testing - WHEN the '/courses' page is requested (GET) - THEN check that the response is valid + WHEN the '/courses' page is requested (GET) with specific course input names + THEN check that the response data matches the expected courses """ - response = test_client.get("/courses", json={"wrong": "wrong"}) - - assert response.status_code == 400 + response = test_client.get("/courses", json={"input": input_name}) + assert response.status_code == 200 -def test_courses_not_found(test_client: FlaskClient) -> None: - """ - GIVEN a Flask application configured for testing - WHEN the '/courses' page is requested (GET) - THEN check that the response is valid - """ - response = test_client.get("/courses", json={"input": "not found"}) + json_data = json.loads(response.data) - assert response.status_code == 404 + for i, course in enumerate(json_data): + assert course["code"] == course_data[0][i] + assert course["name"] == course_data[1][i] From 1af3debd6b5ee6348a30d1dbe3b89878986cd05d Mon Sep 17 00:00:00 2001 From: SarahWohlford <157171746+SarahWohlford@users.noreply.github.com> Date: Fri, 18 Oct 2024 16:06:11 -0400 Subject: [PATCH 33/99] Opportunity_routes small fix --- labconnect/main/opportunity_routes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/labconnect/main/opportunity_routes.py b/labconnect/main/opportunity_routes.py index f8ebfd6..328f3ab 100644 --- a/labconnect/main/opportunity_routes.py +++ b/labconnect/main/opportunity_routes.py @@ -15,7 +15,7 @@ # RecommendsClassYears, # RecommendsMajors, # RecommendsCourses, - # User, + User, ) from labconnect.helpers import LocationEnum, format_credits From 08d65e8c6c7a8f7dd25b58b2fee1a4483868d6d0 Mon Sep 17 00:00:00 2001 From: youssefr26 Date: Fri, 18 Oct 2024 16:56:39 -0400 Subject: [PATCH 34/99] Fixed getOpportunityCards route --- labconnect/main/opportunity_routes.py | 36 ++++++++++++++------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/labconnect/main/opportunity_routes.py b/labconnect/main/opportunity_routes.py index a45a5f2..c47e190 100644 --- a/labconnect/main/opportunity_routes.py +++ b/labconnect/main/opportunity_routes.py @@ -178,17 +178,20 @@ def packageOpportunityCard(opportunity): # get professor and department by getting Leads and LabManager query = db.session.execute( - db.select(Leads, LabManager) + db.select(Leads, LabManager,User.first_name, User.last_name) .where(Leads.opportunity_id == opportunity.id) .join(LabManager, Leads.lab_manager_id == LabManager.id) + .join(User, LabManager.id == User.lab_manager_id) ) data = query.all() professorInfo = "" + for i, item in enumerate(data): - professorInfo += item[1].getName() + professor_name = f"{item[2]} {item[3]}" + professorInfo += professor_name if i != len(data) - 1: professorInfo += ", " @@ -460,25 +463,24 @@ def filterOpportunities(): # abort(500) -# # Jobs page -# @main_blueprint.route("/getOpportunityCards", methods=["GET"]) -# def getOpportunityCards(): -# if request.method == "GET": -# # query database for opportunity -# query = db.session.execute( -# db.select(Opportunities).where(Opportunities.active == True) -# ) +# Jobs page +@main_blueprint.get("/getOpportunityCards") +def getOpportunityCards(): + # query database for opportunity + query = db.session.execute( + db.select(Opportunities).where(Opportunities.active == True) + ) -# data = query.fetchall() + data = query.fetchall() -# # return data in the below format if opportunity is found -# cards = { -# "data": [packageOpportunityCard(opportunity[0]) for opportunity in data] -# } + # return data in the below format if opportunity is found + cards = { + "data": [packageOpportunityCard(opportunity[0]) for opportunity in data] + } -# return cards + return cards -# abort(500) + abort(500) # @main_blueprint.route("/getOpportunities", methods=["GET"]) From 1517152cf32cfe5edf3a2999704364a5b9334de8 Mon Sep 17 00:00:00 2001 From: youssefr26 Date: Tue, 22 Oct 2024 17:08:39 -0400 Subject: [PATCH 35/99] Fixed createOpportunity route --- labconnect/main/opportunity_routes.py | 161 +++++++++++++------------- 1 file changed, 82 insertions(+), 79 deletions(-) diff --git a/labconnect/main/opportunity_routes.py b/labconnect/main/opportunity_routes.py index c47e190..ced4dda 100644 --- a/labconnect/main/opportunity_routes.py +++ b/labconnect/main/opportunity_routes.py @@ -18,7 +18,7 @@ User, ) -from labconnect.helpers import LocationEnum, format_credits +from labconnect.helpers import LocationEnum, SemesterEnum, format_credits from . import main_blueprint @@ -609,96 +609,99 @@ def getLabManagerOpportunityCards(rcs_id: str): # functions to create/edit/delete opportunities -# @main_blueprint.route("/createOpportunity", methods=["POST"]) -# def createOpportunity(): -# if request.method == "POST": -# data = request.get_json() -# authorID = data["authorID"] -# newPostData = data - -# # query database to see if the credentials above match -# query = db.session.execute( -# db.select(LabManager).where(LabManager.id == authorID) -# ) - -# data = query.all()[0][0] - -# # TODO: how do we get the opportunity id? -# # if match is found, create a new opportunity with the new data provided - -# one = False -# two = False -# three = False -# four = False +@main_blueprint.post("/createOpportunity") +def createOpportunity(): + data = request.get_json() + -# if "1" in newPostData["credits"]: -# one = True -# if "2" in newPostData["credits"]: -# two = True -# if "3" in newPostData["credits"]: -# three = True -# if "4" in newPostData["credits"]: -# four = True + authorID = data[0]["id"] + newPostData = data[0] -# lenum = convert_to_enum(newPostData["location"]) + # query database to see if the credentials above match + query = db.session.execute( + db.select(LabManager).where(LabManager.id == authorID) + ) + + + data = query.all()[0][0] + + # TODO: how do we get the opportunity id? + # if match is found, create a new opportunity with the new data provided + + one = False + two = False + three = False + four = False + + if newPostData["one_credit"]: + one = True + if newPostData["two_credits"]: + two = True + if newPostData["three_credits"]: + three = True + if newPostData["four_credits"]: + four = True + + lenum = convert_to_enum(newPostData["location"]) + + if lenum is None: + lenum = LocationEnum.TBD + + newOpportunity = Opportunities( + name=newPostData["name"], + description=newPostData["description"], + recommended_experience=newPostData["recommended_experience"], + pay=newPostData["pay"], + one_credit=one, + two_credits=two, + three_credits=three, + four_credits=four, + semester=SemesterEnum[(newPostData["semester"]).upper()], + year=newPostData["year"], + application_due=datetime.datetime.strptime( + newPostData["application_due"], "%Y-%m-%d" + ), + active=newPostData["active"], + location=lenum, + ) + print("before comitting") + db.session.add(newOpportunity) + db.session.commit() -# if lenum is None: -# lenum = LocationEnum.TBD - -# newOpportunity = Opportunities( -# name=newPostData["name"], -# description=newPostData["description"], -# recommended_experience=newPostData["recommended_experience"], -# pay=newPostData["pay"], -# one_credit=one, -# two_credits=two, -# three_credits=three, -# four_credits=four, -# semester=newPostData["semester"], -# year=newPostData["year"], -# application_due=datetime.datetime.strptime( -# newPostData["application_due"], "%Y-%m-%d" -# ), -# active=newPostData["active"], -# location=lenum, -# ) -# print("before comitting") -# db.session.add(newOpportunity) -# db.session.commit() + print("got here atleast") -# print("got here atleast") + newLead = Leads(lab_manager_id=authorID, opportunity_id=newOpportunity.id) -# newLead = Leads(lab_manager_id=authorID, opportunity_id=newOpportunity.id) + db.session.add(newLead) + db.session.commit() -# db.session.add(newLead) -# db.session.commit() + for course in newPostData["courses"]: + newCourse = RecommendsCourses( + opportunity_id=newOpportunity.id, course_code=course + ) -# for course in newPostData["courses"]: -# newCourse = RecommendsCourses( -# opportunity_id=newOpportunity.id, course_code=course -# ) -# db.session.add(newCourse) -# db.session.commit() + db.session.add(newCourse) + db.session.commit() -# for major in newPostData["majors"]: -# newMajor = RecommendsMajors( -# opportunity_id=newOpportunity.id, major_code=major -# ) -# db.session.add(newMajor) -# db.session.commit() + for major in newPostData["majors"]: + newMajor = RecommendsMajors( + opportunity_id=newOpportunity.id, major_code=major + ) + db.session.add(newMajor) + db.session.commit() -# for year in newPostData["years"]: -# newYear = RecommendsClassYears( -# opportunity_id=newOpportunity.id, class_year=year -# ) -# db.session.add(newYear) -# db.session.commit() + for year in newPostData["years"]: + newYear = RecommendsClassYears( + opportunity_id=newOpportunity.id, class_year=year + ) + db.session.add(newYear) + db.session.commit() -# # db.session.add(newOpportunity) + db.session.add(newOpportunity) -# return {"data": "Opportunity Created"} + return {"data": "Opportunity Created"} -# abort(500) + abort(500) @main_blueprint.route("/editOpportunity", methods=["DELETE", "POST"]) From a3953b693a0e4e6c2db42705be055dca2aa40fe0 Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Wed, 23 Oct 2024 00:53:37 -0400 Subject: [PATCH 36/99] Add token blacklist set for future things --- config.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/config.py b/config.py index 830ee1d..ca75dc1 100644 --- a/config.py +++ b/config.py @@ -29,6 +29,8 @@ class Config: "DB", "postgresql+psycopg2://postgres:root@localhost/labconnect" ) + TOKEN_BLACKLIST = set() + class TestingConfig(Config): TESTING = True From 89564f6aff595ad96837e24104576f97ddc749e7 Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Wed, 23 Oct 2024 00:53:51 -0400 Subject: [PATCH 37/99] update CORS to allow calls from frontend --- labconnect/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/labconnect/__init__.py b/labconnect/__init__.py index 35e60f2..c2e774d 100644 --- a/labconnect/__init__.py +++ b/labconnect/__init__.py @@ -29,7 +29,6 @@ def create_app() -> Flask: # Create flask app object app = Flask(__name__) - CORS(app) app.config.from_object(os.environ.get("CONFIG", "config.TestingConfig")) @@ -40,6 +39,8 @@ def create_app() -> Flask: profiles_sample_rate=app.config["SENTRY_PROFILES_SAMPLE_RATE"], ) + CORS(app, supports_credentials=True, origins=[app.config["FRONTEND_URL"]]) + initialize_extensions(app) register_blueprints(app) From 51bbabfe992bb81bef8b765e9f19d7b097233bf0 Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Wed, 23 Oct 2024 00:54:09 -0400 Subject: [PATCH 38/99] add testing branches for auth items --- labconnect/main/auth_routes.py | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/labconnect/main/auth_routes.py b/labconnect/main/auth_routes.py index c5e7b13..ff9939e 100644 --- a/labconnect/main/auth_routes.py +++ b/labconnect/main/auth_routes.py @@ -15,9 +15,19 @@ from . import main_blueprint +from datetime import datetime + @main_blueprint.get("/login") def saml_login(): + + if current_app.config["TESTING"]: + # Generate JWT + token = create_access_token(identity=["test", datetime.now()]) + + # Send the JWT to the frontend + return redirect(f"{current_app.config['FRONTEND_URL']}/?token={token}") + # Initialize SAML auth request req = prepare_flask_request(request) auth = OneLogin_Saml2_Auth(req, custom_base_path=current_app.config["SAML_CONFIG"]) @@ -54,7 +64,7 @@ def saml_callback(): db.session.commit() # Generate JWT - token = create_access_token(identity=user_id) + token = create_access_token(identity=[user_id, datetime.now()]) # Send the JWT to the frontend return redirect(f"{current_app.config['FRONTEND_URL']}/?token={token}") @@ -81,7 +91,9 @@ def metadata(): @main_blueprint.get("/logout") -def logout() -> Response: - response = jsonify({"msg": "logout successful"}) - unset_jwt_cookies(response) - return response +def logout(): + if not current_app.config["TESTING"]: + # TODO: add token to blacklist + # current_app.config["TOKEN_BLACKLIST"].add() + pass + return {"msg": "logout successful"} From b5271f2b6e3814092c87caf27aac2f255f915405 Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Wed, 23 Oct 2024 00:59:17 -0400 Subject: [PATCH 39/99] rename route --- labconnect/main/auth_routes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/labconnect/main/auth_routes.py b/labconnect/main/auth_routes.py index ff9939e..85b05eb 100644 --- a/labconnect/main/auth_routes.py +++ b/labconnect/main/auth_routes.py @@ -73,7 +73,7 @@ def saml_callback(): @main_blueprint.get("/metadata/") -def metadata(): +def metadataRoute(): req = prepare_flask_request(request) auth = auth = OneLogin_Saml2_Auth( req, custom_base_path=current_app.config["SAML_CONFIG"] From 5d9504d35d5664211011c2c428f739b1b13df492 Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Wed, 23 Oct 2024 01:00:22 -0400 Subject: [PATCH 40/99] isort and black formatting --- labconnect/__init__.py | 9 ++++----- labconnect/main/__init__.py | 2 +- labconnect/main/auth_routes.py | 15 ++++----------- labconnect/main/discover_routes.py | 7 ++----- labconnect/main/opportunity_routes.py | 11 +++-------- labconnect/main/routes.py | 5 +---- labconnect/models.py | 2 +- migrations/env.py | 3 +-- migrations/versions/4dd3611b273e_.py | 3 +-- .../versions/55928fddcb12_initial_migration.py | 3 +-- migrations/versions/c72f39e93d72_.py | 3 +-- migrations/versions/f7518ca21f44_.py | 3 +-- tests/test_opportunity.py | 1 + 13 files changed, 22 insertions(+), 45 deletions(-) diff --git a/labconnect/__init__.py b/labconnect/__init__.py index c2e774d..f1e980a 100644 --- a/labconnect/__init__.py +++ b/labconnect/__init__.py @@ -1,23 +1,22 @@ import json import os - from datetime import datetime, timedelta, timezone +import sentry_sdk + # Import Flask modules from flask import Flask from flask_cors import CORS - from flask_jwt_extended import ( JWTManager, create_access_token, get_jwt, get_jwt_identity, ) - +from flask_migrate import Migrate from flask_sqlalchemy import SQLAlchemy -import sentry_sdk from sentry_sdk.integrations.flask import FlaskIntegration -from flask_migrate import Migrate + from labconnect.helpers import OrJSONProvider # Create Database object diff --git a/labconnect/main/__init__.py b/labconnect/main/__init__.py index 60f7fea..262d5d8 100644 --- a/labconnect/main/__init__.py +++ b/labconnect/main/__init__.py @@ -6,4 +6,4 @@ main_blueprint = Blueprint("main", __name__) -from . import opportunity_routes, routes, discover_routes, auth_routes +from . import auth_routes, discover_routes, opportunity_routes, routes diff --git a/labconnect/main/auth_routes.py b/labconnect/main/auth_routes.py index 85b05eb..201eacb 100644 --- a/labconnect/main/auth_routes.py +++ b/labconnect/main/auth_routes.py @@ -1,22 +1,15 @@ -from typing import Any +from datetime import datetime -from flask import Response, request, redirect, jsonify, current_app, make_response -from flask_jwt_extended import ( - create_access_token, - unset_jwt_cookies, -) +from flask import current_app, make_response, redirect, request +from flask_jwt_extended import create_access_token from onelogin.saml2.auth import OneLogin_Saml2_Auth from labconnect import db -from labconnect.models import ( - User, -) from labconnect.helpers import prepare_flask_request +from labconnect.models import User from . import main_blueprint -from datetime import datetime - @main_blueprint.get("/login") def saml_login(): diff --git a/labconnect/main/discover_routes.py b/labconnect/main/discover_routes.py index 87a51bc..06b8288 100644 --- a/labconnect/main/discover_routes.py +++ b/labconnect/main/discover_routes.py @@ -1,7 +1,4 @@ -from flask_jwt_extended import ( - get_jwt_identity, - jwt_required, -) +from flask_jwt_extended import get_jwt_identity, jwt_required from labconnect import db from labconnect.models import ( @@ -10,10 +7,10 @@ Leads, Majors, Opportunities, + RecommendsClassYears, RecommendsMajors, User, UserMajors, - RecommendsClassYears, ) from . import main_blueprint diff --git a/labconnect/main/opportunity_routes.py b/labconnect/main/opportunity_routes.py index a45a5f2..80b4d7f 100644 --- a/labconnect/main/opportunity_routes.py +++ b/labconnect/main/opportunity_routes.py @@ -1,25 +1,20 @@ import datetime from flask import abort, request - -from flask_jwt_extended import ( - get_jwt_identity, - jwt_required, -) +from flask_jwt_extended import get_jwt_identity, jwt_required from labconnect import db +from labconnect.helpers import LocationEnum, format_credits from labconnect.models import ( LabManager, Leads, Opportunities, RecommendsClassYears, - RecommendsMajors, RecommendsCourses, + RecommendsMajors, User, ) -from labconnect.helpers import LocationEnum, format_credits - from . import main_blueprint diff --git a/labconnect/main/routes.py b/labconnect/main/routes.py index 0c466aa..52456de 100644 --- a/labconnect/main/routes.py +++ b/labconnect/main/routes.py @@ -1,10 +1,7 @@ from typing import Any from flask import abort, request -from flask_jwt_extended import ( - get_jwt_identity, - jwt_required, -) +from flask_jwt_extended import get_jwt_identity, jwt_required from labconnect import db from labconnect.models import ( diff --git a/labconnect/models.py b/labconnect/models.py index 1aab771..069e1bc 100644 --- a/labconnect/models.py +++ b/labconnect/models.py @@ -1,4 +1,4 @@ -from sqlalchemy import Enum, Index, func, event +from sqlalchemy import Enum, Index, event, func from sqlalchemy.dialects.postgresql import TSVECTOR from labconnect import db diff --git a/migrations/env.py b/migrations/env.py index 6cac438..389c609 100644 --- a/migrations/env.py +++ b/migrations/env.py @@ -1,9 +1,8 @@ import logging from logging.config import fileConfig -from flask import current_app - from alembic import context +from flask import current_app # this is the Alembic Config object, which provides # access to the values within the .ini file in use. diff --git a/migrations/versions/4dd3611b273e_.py b/migrations/versions/4dd3611b273e_.py index d4bf315..5059d2e 100644 --- a/migrations/versions/4dd3611b273e_.py +++ b/migrations/versions/4dd3611b273e_.py @@ -6,9 +6,8 @@ """ -from alembic import op import sqlalchemy as sa - +from alembic import op # revision identifiers, used by Alembic. revision = "4dd3611b273e" diff --git a/migrations/versions/55928fddcb12_initial_migration.py b/migrations/versions/55928fddcb12_initial_migration.py index c0e4ea6..6843086 100644 --- a/migrations/versions/55928fddcb12_initial_migration.py +++ b/migrations/versions/55928fddcb12_initial_migration.py @@ -6,9 +6,8 @@ """ -from alembic import op import sqlalchemy as sa - +from alembic import op # revision identifiers, used by Alembic. revision = "55928fddcb12" diff --git a/migrations/versions/c72f39e93d72_.py b/migrations/versions/c72f39e93d72_.py index 653aebe..907940c 100644 --- a/migrations/versions/c72f39e93d72_.py +++ b/migrations/versions/c72f39e93d72_.py @@ -6,9 +6,8 @@ """ -from alembic import op import sqlalchemy as sa - +from alembic import op # revision identifiers, used by Alembic. revision = "c72f39e93d72" diff --git a/migrations/versions/f7518ca21f44_.py b/migrations/versions/f7518ca21f44_.py index ec5a632..4edd950 100644 --- a/migrations/versions/f7518ca21f44_.py +++ b/migrations/versions/f7518ca21f44_.py @@ -6,9 +6,8 @@ """ -from alembic import op import sqlalchemy as sa - +from alembic import op # revision identifiers, used by Alembic. revision = "f7518ca21f44" diff --git a/tests/test_opportunity.py b/tests/test_opportunity.py index 55f7c24..e37f954 100644 --- a/tests/test_opportunity.py +++ b/tests/test_opportunity.py @@ -3,6 +3,7 @@ """ import json + from flask import json from flask.testing import FlaskClient From 0609bca469a1a4589d3723dfa1d5ef03177ad4c8 Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Wed, 23 Oct 2024 14:17:40 -0400 Subject: [PATCH 41/99] Callback to specific callback route on frontend --- labconnect/main/auth_routes.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/labconnect/main/auth_routes.py b/labconnect/main/auth_routes.py index 201eacb..2c7fd77 100644 --- a/labconnect/main/auth_routes.py +++ b/labconnect/main/auth_routes.py @@ -19,7 +19,7 @@ def saml_login(): token = create_access_token(identity=["test", datetime.now()]) # Send the JWT to the frontend - return redirect(f"{current_app.config['FRONTEND_URL']}/?token={token}") + return redirect(f"{current_app.config['FRONTEND_URL']}/token/?token={token}") # Initialize SAML auth request req = prepare_flask_request(request) @@ -60,7 +60,7 @@ def saml_callback(): token = create_access_token(identity=[user_id, datetime.now()]) # Send the JWT to the frontend - return redirect(f"{current_app.config['FRONTEND_URL']}/?token={token}") + return redirect(f"{current_app.config['FRONTEND_URL']}/token/?token={token}") return {"errors": errors}, 500 From 9c2340f9d2205c405d6123515ec0109614d7b1f7 Mon Sep 17 00:00:00 2001 From: youssefr26 Date: Fri, 25 Oct 2024 16:14:10 -0400 Subject: [PATCH 42/99] Megre --- labconnect/main/opportunity_routes.py | 96 +++++++++++++-------------- 1 file changed, 47 insertions(+), 49 deletions(-) diff --git a/labconnect/main/opportunity_routes.py b/labconnect/main/opportunity_routes.py index ced4dda..88bd1d8 100644 --- a/labconnect/main/opportunity_routes.py +++ b/labconnect/main/opportunity_routes.py @@ -614,7 +614,7 @@ def createOpportunity(): data = request.get_json() - authorID = data[0]["id"] + authorID = data[0]["manager_id"] newPostData = data[0] # query database to see if the credentials above match @@ -663,12 +663,11 @@ def createOpportunity(): ), active=newPostData["active"], location=lenum, + last_updated=datetime.datetime.now(), ) - print("before comitting") db.session.add(newOpportunity) db.session.commit() - print("got here atleast") newLead = Leads(lab_manager_id=authorID, opportunity_id=newOpportunity.id) @@ -704,14 +703,13 @@ def createOpportunity(): abort(500) -@main_blueprint.route("/editOpportunity", methods=["DELETE", "POST"]) +@main_blueprint.post("/editOpportunity") def editOpportunity(): - if request.method in ["DELETE", "POST"]: - data = request.get_json() - id = data["id"] - # authToken = data["authToken"] - # authorID = data["authorID"] - newPostData = data + data = request.get_json() + id = data["id"] + # authToken = data["authToken"] + # authorID = data["authorID"] + newPostData = data # @main_blueprint.route("/editOpportunity", methods=["DELETE", "POST"]) @@ -820,52 +818,52 @@ def editOpportunity(): # abort(500) -# @main_blueprint.route("/deleteOpportunity", methods=["DELETE", "POST"]) -# def deleteOpportunity(): -# if request.method in ["DELETE", "POST"]: -# data = request.get_json() -# id = data["id"] +@main_blueprint.route("/deleteOpportunity", methods=["DELETE", "POST"]) +def deleteOpportunity(): + if request.method in ["DELETE", "POST"]: + data = request.get_json() + id = data["id"] -# query = db.session.execute( -# db.select( -# Opportunities, -# RecommendsMajors, -# RecommendsCourses, -# RecommendsClassYears, -# Leads, -# ) -# .where(Opportunities.id == id) -# .join(RecommendsMajors, RecommendsMajors.opportunity_id == Opportunities.id) -# .join( -# RecommendsCourses, RecommendsCourses.opportunity_id == Opportunities.id -# ) -# .join( -# RecommendsClassYears, -# RecommendsClassYears.opportunity_id == Opportunities.id, -# ) -# .join(Leads, Leads.opportunity_id == Opportunities.id) -# ) + query = db.session.execute( + db.select( + Opportunities, + RecommendsMajors, + RecommendsCourses, + RecommendsClassYears, + Leads, + ) + .where(Opportunities.id == id) + .join(RecommendsMajors, RecommendsMajors.opportunity_id == Opportunities.id) + .join( + RecommendsCourses, RecommendsCourses.opportunity_id == Opportunities.id + ) + .join( + RecommendsClassYears, + RecommendsClassYears.opportunity_id == Opportunities.id, + ) + .join(Leads, Leads.opportunity_id == Opportunities.id) + ) -# data = query.all() -# print(data) + data = query.all() + print(data) -# if not data or len(data) == 0: -# abort(404) + if not data or len(data) == 0: + abort(404) -# opportunity = data[0][0] + opportunity = data[0][0] -# for row in data: -# db.session.delete(row[1]) -# db.session.delete(row[2]) -# db.session.delete(row[3]) -# db.session.delete(row[4]) + for row in data: + db.session.delete(row[1]) + db.session.delete(row[2]) + db.session.delete(row[3]) + db.session.delete(row[4]) -# leads = data[0][4] + leads = data[0][4] -# db.session.delete(opportunity) + db.session.delete(opportunity) -# db.session.commit() + db.session.commit() -# return "Success" + return "Success" -# abort(500) + abort(500) From 6303682fcdd5dbfd0319448b39960919f7d3b0c1 Mon Sep 17 00:00:00 2001 From: SarahWohlford <157171746+SarahWohlford@users.noreply.github.com> Date: Fri, 25 Oct 2024 16:26:09 -0400 Subject: [PATCH 43/99] Updated Tests --- tests/test_departments.py | 45 +++++++++++++++++++++++++++++++++++++++ tests/test_lab_manager.py | 1 + tests/test_user.py | 16 +++++++++++++- 3 files changed, 61 insertions(+), 1 deletion(-) diff --git a/tests/test_departments.py b/tests/test_departments.py index 445cd3c..4d3dd49 100644 --- a/tests/test_departments.py +++ b/tests/test_departments.py @@ -37,11 +37,52 @@ def test_departments_route(test_client: FlaskClient) -> None: "space, the final frontier", "flying, need for speed", ), + ( + "School of science", + "School of science", + "School of engineering", + "School of science", + "School of engineering", + "School of engineering", + "School of engineering", + ), + ( + "CSCI", + "BIOL", + "MTLE" + "MATH", + "ENVI", + "MANE", + "MANE", + ), + ( + "https://cdn-icons-png.flaticon.com/512/5310/5310672.png", + "https://cdn-icons-png.flaticon.com/512/5310/5310672.png", + "https://cdn-icons-png.flaticon.com/512/5310/5310672.png" + "https://cdn-icons-png.flaticon.com/512/5310/5310672.png", + "https://cdn-icons-png.flaticon.com/512/5310/5310672.png", + "https://cdn-icons-png.flaticon.com/512/5310/5310672.png", + "https://cdn-icons-png.flaticon.com/512/5310/5310672.png", + ), + ( + "https://www.rpi.edu", + "https://www.rpi.edu", + "https://www.rpi.edu", + "https://www.rpi.edu", + "https://www.rpi.edu", + "https://www.rpi.edu", + "https://www.rpi.edu", + ), ) for department in json_data: assert department["name"] in rpi_departments_data[0] assert department["description"] in rpi_departments_data[1] + #Added + assert department["school_id"] in rpi_departments_data[2] + assert department["id"] in rpi_departments_data[3] + assert department["image"] in rpi_departments_data[4] + assert department["webcite"] in rpi_departments_data[5] def test_department_route(test_client: FlaskClient) -> None: @@ -59,6 +100,10 @@ def test_department_route(test_client: FlaskClient) -> None: assert json_data["name"] == "Computer Science" assert json_data["description"] == "DS" assert json_data["school_id"] == "School of Science" + #Added + assert json_data["id"] == "CSCI" + assert json_data["image"] == "https://cdn-icons-png.flaticon.com/512/5310/5310672.png" + assert json_data["webcite"] == "https://www.rpi.edu" prof_names = ["Duy Le", "Rafael", "Turner", "Kuzmin", "Goldschmidt"] prof_rcs_ids = ["led", "cenzar", "turner", "kuzmin", "goldd"] diff --git a/tests/test_lab_manager.py b/tests/test_lab_manager.py index 0cea0a0..7e28883 100644 --- a/tests/test_lab_manager.py +++ b/tests/test_lab_manager.py @@ -25,6 +25,7 @@ def test_lab_manager_route_with_input_id(test_client: FlaskClient) -> None: "alt_email": None, "phone_number": None, "email": None, + "description": None, } assert json_data == cenzar_data diff --git a/tests/test_user.py b/tests/test_user.py index ab07577..d1e7d40 100644 --- a/tests/test_user.py +++ b/tests/test_user.py @@ -20,9 +20,17 @@ def test_user_route_with_input_id_1(test_client: FlaskClient) -> None: assert json_data["id"] == 1 assert json_data["first_name"] == "Rafael" - assert json_data["last_name"] == "Cenzano" assert json_data["preferred_name"] == "Raf" + assert json_data["last_name"] == "Cenzano" assert json_data["email"] == "cenzar@rpi.edu" + #Added + assert json_data["description"] == "labconnect is the best RCOS project" + assert json_data["profile_picture"] == "https://rafael.sirv.com/Images/rafael.jpeg?thumbnail=350&format=webp&q=90" + assert json_data["website"] == "https://rafaelcenzano.com" + #class year + assert json_data["class_year"] == "2025" + #lab manager id + assert json_data["lab_manager_id"] == 1 departments_data = [ {"user_id": 1, "department_id": "Computer Science"}, @@ -104,6 +112,12 @@ def test_user_route_with_input_id_2(test_client: FlaskClient) -> None: assert json_data["last_name"] == "RCOS" assert json_data["preferred_name"] is None assert json_data["email"] == "test@rpi.edu" + #Added + assert json_data["description"] is None + assert json_data["profile_picture"] == "https://www.svgrepo.com/show/206842/professor.svg" # Adjust based on your test data + assert json_data["website"] is None + assert json_data["class_year"] is None + assert json_data["lab_manager_id"] is None departments_data = [ {"department_id": "Computer Science", "user_id": 2}, From a0a9c2c17abc3fbafce5188fc260d3c487cd372b Mon Sep 17 00:00:00 2001 From: youssefr26 Date: Fri, 25 Oct 2024 16:43:45 -0400 Subject: [PATCH 44/99] Added deleteOpportuniy route --- labconnect/main/opportunity_routes.py | 60 +++++++-------------------- 1 file changed, 16 insertions(+), 44 deletions(-) diff --git a/labconnect/main/opportunity_routes.py b/labconnect/main/opportunity_routes.py index 575ffbc..c1ee5bd 100644 --- a/labconnect/main/opportunity_routes.py +++ b/labconnect/main/opportunity_routes.py @@ -815,52 +815,24 @@ def editOpportunity(): # abort(500) -@main_blueprint.route("/deleteOpportunity", methods=["DELETE", "POST"]) -def deleteOpportunity(): - if request.method in ["DELETE", "POST"]: - data = request.get_json() - id = data["id"] - - query = db.session.execute( - db.select( - Opportunities, - RecommendsMajors, - RecommendsCourses, - RecommendsClassYears, - Leads, - ) - .where(Opportunities.id == id) - .join(RecommendsMajors, RecommendsMajors.opportunity_id == Opportunities.id) - .join( - RecommendsCourses, RecommendsCourses.opportunity_id == Opportunities.id - ) - .join( - RecommendsClassYears, - RecommendsClassYears.opportunity_id == Opportunities.id, - ) - .join(Leads, Leads.opportunity_id == Opportunities.id) - ) - - data = query.all() - print(data) - - if not data or len(data) == 0: - abort(404) - - opportunity = data[0][0] - - for row in data: - db.session.delete(row[1]) - db.session.delete(row[2]) - db.session.delete(row[3]) - db.session.delete(row[4]) +@main_blueprint.delete("/deleteOpportunity/") +def deleteOpportunity(opportunity_id): + opportunity = db.session.get(Opportunities, opportunity_id) - leads = data[0][4] - - db.session.delete(opportunity) + if not opportunity: + return {"error": "Opportunity not found"}, 404 + + #TODO: Add check to see if user has permission to delete opportunity - db.session.commit() + # Delete related records in other tables (e.g., Leads, RecommendsCourses, RecommendsMajors, RecommendsClassYears) + db.session.query(Leads).filter_by(opportunity_id=opportunity_id).delete() + db.session.query(RecommendsCourses).filter_by(opportunity_id=opportunity_id).delete() + db.session.query(RecommendsMajors).filter_by(opportunity_id=opportunity_id).delete() + db.session.query(RecommendsClassYears).filter_by(opportunity_id=opportunity_id).delete() - return "Success" + # Delete the opportunity itself + db.session.delete(opportunity) + db.session.commit() + return {"data": "Opportunity Deleted"} abort(500) From 7204119d7bab1ed56febda37e78dc51e4b235fb0 Mon Sep 17 00:00:00 2001 From: youssefr26 Date: Fri, 25 Oct 2024 18:56:33 -0400 Subject: [PATCH 45/99] Added edit routes get and put --- labconnect/main/opportunity_routes.py | 255 ++++++++++++++------------ 1 file changed, 137 insertions(+), 118 deletions(-) diff --git a/labconnect/main/opportunity_routes.py b/labconnect/main/opportunity_routes.py index c1ee5bd..ab06fa3 100644 --- a/labconnect/main/opportunity_routes.py +++ b/labconnect/main/opportunity_routes.py @@ -175,7 +175,7 @@ def packageOpportunityCard(opportunity): # get professor and department by getting Leads and LabManager query = db.session.execute( - db.select(Leads, LabManager,User.first_name, User.last_name) + db.select(Leads, LabManager, User.first_name, User.last_name) .where(Leads.opportunity_id == opportunity.id) .join(LabManager, Leads.lab_manager_id == LabManager.id) .join(User, LabManager.id == User.lab_manager_id) @@ -185,7 +185,6 @@ def packageOpportunityCard(opportunity): professorInfo = "" - for i, item in enumerate(data): professor_name = f"{item[2]} {item[3]}" professorInfo += professor_name @@ -471,9 +470,7 @@ def getOpportunityCards(): data = query.fetchall() # return data in the below format if opportunity is found - cards = { - "data": [packageOpportunityCard(opportunity[0]) for opportunity in data] - } + cards = {"data": [packageOpportunityCard(opportunity[0]) for opportunity in data]} return cards @@ -609,16 +606,12 @@ def getLabManagerOpportunityCards(rcs_id: str): @main_blueprint.post("/createOpportunity") def createOpportunity(): data = request.get_json() - authorID = data[0]["manager_id"] newPostData = data[0] # query database to see if the credentials above match - query = db.session.execute( - db.select(LabManager).where(LabManager.id == authorID) - ) - + query = db.session.execute(db.select(LabManager).where(LabManager.id == authorID)) data = query.all()[0][0] @@ -665,7 +658,6 @@ def createOpportunity(): db.session.add(newOpportunity) db.session.commit() - newLead = Leads(lab_manager_id=authorID, opportunity_id=newOpportunity.id) db.session.add(newLead) @@ -680,9 +672,7 @@ def createOpportunity(): db.session.commit() for major in newPostData["majors"]: - newMajor = RecommendsMajors( - opportunity_id=newOpportunity.id, major_code=major - ) + newMajor = RecommendsMajors(opportunity_id=newOpportunity.id, major_code=major) db.session.add(newMajor) db.session.commit() @@ -700,119 +690,144 @@ def createOpportunity(): abort(500) -@main_blueprint.post("/editOpportunity") -def editOpportunity(): - data = request.get_json() - id = data["id"] - # authToken = data["authToken"] - # authorID = data["authorID"] - newPostData = data - - -# @main_blueprint.route("/editOpportunity", methods=["DELETE", "POST"]) -# def editOpportunity(): -# if True: -# data = request.get_json() -# id = data["id"] -# # authToken = data["authToken"] -# # authorID = data["authorID"] -# newPostData = data - -# # query database to see if the credentials above match -# query = db.session.execute( -# db.select( -# Opportunities, RecommendsMajors, RecommendsCourses, RecommendsClassYears -# ) -# .where(Opportunities.id == id) -# .join(RecommendsMajors, RecommendsMajors.opportunity_id == Opportunities.id) -# .join( -# RecommendsCourses, RecommendsCourses.opportunity_id == Opportunities.id -# ) -# .join( -# RecommendsClassYears, -# RecommendsClassYears.opportunity_id == Opportunities.id, -# ) -# ) +@main_blueprint.get("/editOpportunity/") +def editOpportunity_get(opportunity_id): -# data = query.all() + opportunity = db.session.execute( + db.select(Opportunities).where(Opportunities.id == opportunity_id) + ).first() -# if not data or len(data) == 0: -# abort(404) + if not opportunity: + return {"error": "Opportunity not found"}, 404 -# opportunity = data[0][0] - -# one = False -# two = False -# three = False -# four = False - -# if "1" in newPostData["credits"]: -# one = True -# if "2" in newPostData["credits"]: -# two = True -# if "3" in newPostData["credits"]: -# three = True -# if "4" in newPostData["credits"]: -# four = True - -# lenum = convert_to_enum(newPostData["location"]) -# print(newPostData["location"]) -# print("printing lenum") -# print(lenum) - -# # if match is found, edit the opportunity with the new data provided -# opportunity.name = newPostData["name"] -# opportunity.description = newPostData["description"] -# opportunity.recommended_experience = newPostData["recommended_experience"] -# opportunity.pay = newPostData["pay"] -# opportunity.one_credit = one -# opportunity.two_credits = two -# opportunity.three_credits = three -# opportunity.four_credits = four -# opportunity.semester = newPostData["semester"] -# opportunity.year = newPostData["year"] -# opportunity.application_due = datetime.datetime.strptime( -# newPostData["application_due"], "%Y-%m-%d" -# ) -# opportunity.active = newPostData["active"] + opportunity = opportunity[0] -# if lenum is not None: -# opportunity.location = lenum + # Query related courses + courses_data = db.session.execute( + db.select(RecommendsCourses.course_code).where( + RecommendsCourses.opportunity_id == opportunity_id + ) + ).all() -# db.session.add(opportunity) -# db.session.commit() + # Query related majors + majors_data = db.session.execute( + db.select(RecommendsMajors.major_code).where( + RecommendsMajors.opportunity_id == opportunity_id + ) + ).all() -# # delete all the old data in the recommends tables + # Query related class years + years_data = db.session.execute( + db.select(RecommendsClassYears.class_year).where( + RecommendsClassYears.opportunity_id == opportunity_id + ) + ).all() -# for row in data: -# db.session.delete(row[1]) -# db.session.delete(row[2]) -# db.session.delete(row[3]) + # Format opportunity data as JSON + opportunity_data = { + "id": opportunity.id, + "name": opportunity.name, + "description": opportunity.description, + "recommended_experience": opportunity.recommended_experience, + "pay": opportunity.pay, + "one_credit": opportunity.one_credit, + "two_credits": opportunity.two_credits, + "three_credits": opportunity.three_credits, + "four_credits": opportunity.four_credits, + "semester": opportunity.semester.name, # Convert enum to string + "year": opportunity.year, + "application_due": opportunity.application_due.strftime("%Y-%m-%d"), + "active": opportunity.active, + "location": opportunity.location.name, # Convert enum to string + "last_updated": opportunity.last_updated.strftime("%Y-%m-%d %H:%M:%S"), + "courses": [ + course.course_code for course in courses_data + ], # Assuming relationship setup + "majors": [major.major_code for major in majors_data], + "years": [year.class_year for year in years_data], + } -# # create new data for allow the tables + return opportunity_data -# for course in newPostData["courses"]: -# newCourse = RecommendsCourses( -# opportunity_id=opportunity.id, course_code=course -# ) -# db.session.add(newCourse) -# db.session.commit() -# for major in newPostData["majors"]: -# newMajor = RecommendsMajors(opportunity_id=opportunity.id, major_code=major) -# db.session.add(newMajor) -# db.session.commit() +@main_blueprint.put("/editOpportunity/") +def editOpportunity(opportunity_id): + data = request.get_json() -# for year in newPostData["years"]: -# newYear = RecommendsClassYears( -# opportunity_id=opportunity.id, class_year=year -# ) -# db.session.add(newYear) -# db.session.commit() + # Check if the opportunity and author exist + opportunity = db.session.execute( + db.select(Opportunities).where(Opportunities.id == opportunity_id) + ).first() -# return "Successful" + if not opportunity: + return {"error": "Opportunity not found"}, 404 -# abort(500) + opportunity = opportunity[0] + data = data[0] + + # TODO: Add check to see if person has permission to edit opportunity + + # Update fields for opportunity based on the input data + opportunity.name = data["name"] + opportunity.description = data["description"] + opportunity.recommended_experience = data["recommended_experience"] + opportunity.pay = data["pay"] + opportunity.one_credit = data["one_credit"] + opportunity.two_credits = data["two_credits"] + opportunity.three_credits = data["three_credits"] + opportunity.four_credits = data["four_credits"] + opportunity.semester = ( + SemesterEnum[(data["semester"]).upper()] + if "semester" in data + else opportunity.semester + ) + opportunity.year = data["year"] + opportunity.application_due = ( + datetime.datetime.strptime(data["application_due"], "%Y-%m-%d") + if "application_due" in data + else opportunity.application_due + ) + opportunity.active = data["active"] + opportunity.location = ( + convert_to_enum(data["location"]) + if "location" in data + else opportunity.location + ) + opportunity.last_updated = datetime.datetime.now() + + # Update related tables for courses, majors, and years + # Clear current recommendations + db.session.query(RecommendsCourses).filter_by( + opportunity_id=opportunity_id + ).delete() + db.session.query(RecommendsMajors).filter_by(opportunity_id=opportunity_id).delete() + db.session.query(RecommendsClassYears).filter_by( + opportunity_id=opportunity_id + ).delete() + + # Re-add new recommendations + for course in data["courses"]: + newCourse = RecommendsCourses(opportunity_id=opportunity.id, course_code=course) + + db.session.add(newCourse) + db.session.commit() + + for major in data["majors"]: + newMajor = RecommendsMajors(opportunity_id=opportunity.id, major_code=major) + db.session.add(newMajor) + db.session.commit() + + for year in data["years"]: + newYear = RecommendsClassYears(opportunity_id=opportunity.id, class_year=year) + db.session.add(newYear) + db.session.commit() + + print(opportunity) + + # Commit all changes to the database + db.session.commit() + + return {"data": "Opportunity Updated"} @main_blueprint.delete("/deleteOpportunity/") @@ -821,14 +836,18 @@ def deleteOpportunity(opportunity_id): if not opportunity: return {"error": "Opportunity not found"}, 404 - - #TODO: Add check to see if user has permission to delete opportunity + + # TODO: Add check to see if user has permission to delete opportunity # Delete related records in other tables (e.g., Leads, RecommendsCourses, RecommendsMajors, RecommendsClassYears) db.session.query(Leads).filter_by(opportunity_id=opportunity_id).delete() - db.session.query(RecommendsCourses).filter_by(opportunity_id=opportunity_id).delete() + db.session.query(RecommendsCourses).filter_by( + opportunity_id=opportunity_id + ).delete() db.session.query(RecommendsMajors).filter_by(opportunity_id=opportunity_id).delete() - db.session.query(RecommendsClassYears).filter_by(opportunity_id=opportunity_id).delete() + db.session.query(RecommendsClassYears).filter_by( + opportunity_id=opportunity_id + ).delete() # Delete the opportunity itself db.session.delete(opportunity) From 80bd3afb4a77de8f8d055d7f1532702a064abb93 Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Tue, 29 Oct 2024 10:29:17 -0400 Subject: [PATCH 46/99] Update Werkzeug --- requirements.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index a02a362..89e3308 100644 --- a/requirements.txt +++ b/requirements.txt @@ -27,11 +27,12 @@ pytest-cov==5.0.0 python3-saml==1.16.0 pytz==2024.2 sentry-sdk==2.15.0 -setuptools==70.3.0 +setuptools==75.3.0 six==1.16.0 SQLAlchemy==2.0.29 sqlalchemy-serializer==1.4.22 typing_extensions==4.12.2 urllib3==2.2.3 -Werkzeug==3.0.4 +Werkzeug==3.0.6 +wheel==0.44.0 xmlsec==1.3.14 From adf5dd97760bdbeede534be695dcd9d6f48f2c80 Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Tue, 29 Oct 2024 16:51:12 -0400 Subject: [PATCH 47/99] Improved auth system that encrypts token in a response --- labconnect/main/auth_routes.py | 66 ++++++++++++++++++++++++++++++---- 1 file changed, 59 insertions(+), 7 deletions(-) diff --git a/labconnect/main/auth_routes.py b/labconnect/main/auth_routes.py index 2c7fd77..04ea504 100644 --- a/labconnect/main/auth_routes.py +++ b/labconnect/main/auth_routes.py @@ -1,4 +1,5 @@ -from datetime import datetime +from datetime import datetime, timedelta +from uuid import uuid4 from flask import current_app, make_response, redirect, request from flask_jwt_extended import create_access_token @@ -10,16 +11,49 @@ from . import main_blueprint +temp_codes = {} + + +def generate_temporary_code(user_email: str) -> str: + # Generate a unique temporary code + code = str(uuid4()) + expires_at = datetime.now() + timedelta(seconds=60) # expires in 5 seconds + temp_codes[code] = {"email": user_email, "expires_at": expires_at} + return code + + +def validate_code_and_get_user_email(code: str) -> str | None: + token_data = temp_codes.get(code, {}) + if not token_data: + return None + + user_email = token_data.get("email", None) + expire = token_data.get("expires_at", None) + + if user_email and expire and expire > datetime.now(): + # If found, delete the code to prevent reuse + del temp_codes[code] + return user_email + elif expire: + # If the code has expired, delete it + del temp_codes[code] + + return None + @main_blueprint.get("/login") def saml_login(): - if current_app.config["TESTING"]: + # In testing skip RPI login purely for local development + if ( + current_app.config["TESTING"] + and current_app.config["Frontend_URL"] == "http://localhost:3000" + ): # Generate JWT - token = create_access_token(identity=["test", datetime.now()]) + code = generate_temporary_code("test@rpi.edu") # Send the JWT to the frontend - return redirect(f"{current_app.config['FRONTEND_URL']}/token/?token={token}") + return redirect(f"{current_app.config['FRONTEND_URL']}/callback/?code={code}") # Initialize SAML auth request req = prepare_flask_request(request) @@ -37,7 +71,7 @@ def saml_callback(): if not errors: user_info = auth.get_attributes() - user_id = auth.get_nameid() + # user_id = auth.get_nameid() data = db.session.execute(db.select(User).where(User.email == "email")).scalar() @@ -57,14 +91,32 @@ def saml_callback(): db.session.commit() # Generate JWT - token = create_access_token(identity=[user_id, datetime.now()]) + # token = create_access_token(identity=[user_id, datetime.now()]) + code = generate_temporary_code(user_info["email"][0]) # Send the JWT to the frontend - return redirect(f"{current_app.config['FRONTEND_URL']}/token/?token={token}") + return redirect(f"{current_app.config['FRONTEND_URL']}/callback/?code={code}") return {"errors": errors}, 500 +@main_blueprint.post("/token") +def token(): + if request.json is None or request.json.get("code", None) is None: + return {"msg": "Missing JSON body in request"}, 400 + # Validate the temporary code + code = request.json["code"] + if code is None: + return {"msg": "Missing code in request"}, 400 + user_email = validate_code_and_get_user_email(code) + + if user_email is None: + return {"msg": "Invalid code"}, 400 + + token = create_access_token(identity=[user_email, datetime.now()]) + return {"token": token} + + @main_blueprint.get("/metadata/") def metadataRoute(): req = prepare_flask_request(request) From 63cd185f807da5e5f528b5da637545646efe1054 Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Tue, 29 Oct 2024 16:53:12 -0400 Subject: [PATCH 48/99] restore expire time now that it is working --- labconnect/main/auth_routes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/labconnect/main/auth_routes.py b/labconnect/main/auth_routes.py index 04ea504..b20354d 100644 --- a/labconnect/main/auth_routes.py +++ b/labconnect/main/auth_routes.py @@ -17,7 +17,7 @@ def generate_temporary_code(user_email: str) -> str: # Generate a unique temporary code code = str(uuid4()) - expires_at = datetime.now() + timedelta(seconds=60) # expires in 5 seconds + expires_at = datetime.now() + timedelta(seconds=5) # expires in 5 seconds temp_codes[code] = {"email": user_email, "expires_at": expires_at} return code From 60f59cef21c4670c9f8139c9f08ec054681665c6 Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Tue, 29 Oct 2024 16:55:43 -0400 Subject: [PATCH 49/99] remove setuptools --- requirements.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 89e3308..cca4541 100644 --- a/requirements.txt +++ b/requirements.txt @@ -27,7 +27,6 @@ pytest-cov==5.0.0 python3-saml==1.16.0 pytz==2024.2 sentry-sdk==2.15.0 -setuptools==75.3.0 six==1.16.0 SQLAlchemy==2.0.29 sqlalchemy-serializer==1.4.22 From c3f2d397d05b4c9121e5920a295891dabf307ca7 Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Tue, 29 Oct 2024 16:56:03 -0400 Subject: [PATCH 50/99] Remove wheel --- requirements.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index cca4541..db6f111 100644 --- a/requirements.txt +++ b/requirements.txt @@ -33,5 +33,4 @@ sqlalchemy-serializer==1.4.22 typing_extensions==4.12.2 urllib3==2.2.3 Werkzeug==3.0.6 -wheel==0.44.0 xmlsec==1.3.14 From ae21a206f306dcd0666097532a75138b3797ce4c Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Tue, 29 Oct 2024 16:59:53 -0400 Subject: [PATCH 51/99] Rename to prevent issues --- labconnect/main/auth_routes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/labconnect/main/auth_routes.py b/labconnect/main/auth_routes.py index b20354d..80fa713 100644 --- a/labconnect/main/auth_routes.py +++ b/labconnect/main/auth_routes.py @@ -101,7 +101,7 @@ def saml_callback(): @main_blueprint.post("/token") -def token(): +def tokenRoute(): if request.json is None or request.json.get("code", None) is None: return {"msg": "Missing JSON body in request"}, 400 # Validate the temporary code From 55441c2c293533fc351c7b34ca7a9fe1ada41b36 Mon Sep 17 00:00:00 2001 From: youssefr26 Date: Tue, 29 Oct 2024 23:11:12 -0400 Subject: [PATCH 52/99] Added auth to create, edit and delete oppotunity routes. --- labconnect/main/auth_routes.py | 2 +- labconnect/main/opportunity_routes.py | 64 ++++++++++++++++++++++----- 2 files changed, 55 insertions(+), 11 deletions(-) diff --git a/labconnect/main/auth_routes.py b/labconnect/main/auth_routes.py index 2c7fd77..faac04f 100644 --- a/labconnect/main/auth_routes.py +++ b/labconnect/main/auth_routes.py @@ -16,7 +16,7 @@ def saml_login(): if current_app.config["TESTING"]: # Generate JWT - token = create_access_token(identity=["test", datetime.now()]) + token = create_access_token(identity="test@rpi.edu") # Send the JWT to the frontend return redirect(f"{current_app.config['FRONTEND_URL']}/token/?token={token}") diff --git a/labconnect/main/opportunity_routes.py b/labconnect/main/opportunity_routes.py index ab06fa3..a1c2b1d 100644 --- a/labconnect/main/opportunity_routes.py +++ b/labconnect/main/opportunity_routes.py @@ -604,10 +604,16 @@ def getLabManagerOpportunityCards(rcs_id: str): # functions to create/edit/delete opportunities @main_blueprint.post("/createOpportunity") +@jwt_required() def createOpportunity(): data = request.get_json() - authorID = data[0]["manager_id"] + user_id = get_jwt_identity() + author = db.session.execute( + db.select(User).where(User.email == user_id) + ).scalar_one_or_none() + + authorID = author.lab_manager_id newPostData = data[0] # query database to see if the credentials above match @@ -692,7 +698,6 @@ def createOpportunity(): @main_blueprint.get("/editOpportunity/") def editOpportunity_get(opportunity_id): - opportunity = db.session.execute( db.select(Opportunities).where(Opportunities.id == opportunity_id) ).first() @@ -701,6 +706,7 @@ def editOpportunity_get(opportunity_id): return {"error": "Opportunity not found"}, 404 opportunity = opportunity[0] + print(opportunity) # Query related courses courses_data = db.session.execute( @@ -722,6 +728,7 @@ def editOpportunity_get(opportunity_id): RecommendsClassYears.opportunity_id == opportunity_id ) ).all() + print((opportunity.location)) # Format opportunity data as JSON opportunity_data = { @@ -734,15 +741,13 @@ def editOpportunity_get(opportunity_id): "two_credits": opportunity.two_credits, "three_credits": opportunity.three_credits, "four_credits": opportunity.four_credits, - "semester": opportunity.semester.name, # Convert enum to string + "semester": SemesterEnum(opportunity.semester), # Convert enum to string "year": opportunity.year, "application_due": opportunity.application_due.strftime("%Y-%m-%d"), "active": opportunity.active, - "location": opportunity.location.name, # Convert enum to string + "location": opportunity.location, # Convert enum to string "last_updated": opportunity.last_updated.strftime("%Y-%m-%d %H:%M:%S"), - "courses": [ - course.course_code for course in courses_data - ], # Assuming relationship setup + "courses": [course.course_code for course in courses_data], "majors": [major.major_code for major in majors_data], "years": [year.class_year for year in years_data], } @@ -751,7 +756,9 @@ def editOpportunity_get(opportunity_id): @main_blueprint.put("/editOpportunity/") +@jwt_required() def editOpportunity(opportunity_id): + data = request.get_json() # Check if the opportunity and author exist @@ -766,6 +773,25 @@ def editOpportunity(opportunity_id): data = data[0] # TODO: Add check to see if person has permission to edit opportunity + user_id = get_jwt_identity() + + lab_manager = db.session.execute( + db.select(LabManager) + .join(User, User.lab_manager_id == LabManager.id) + .where(User.email == user_id) + ).scalar_one_or_none() + + if lab_manager: + lead = db.session.execute( + db.select(Leads).where( + Leads.lab_manager_id == lab_manager.id, + Leads.opportunity_id == opportunity.id, + ) + ).scalar_one_or_none() + if not lead: + return {"error": "Don't have permission to edit!"}, 401 + else: + return {"error": "Don't have permission to edit!"}, 401 # Update fields for opportunity based on the input data opportunity.name = data["name"] @@ -822,15 +848,14 @@ def editOpportunity(opportunity_id): db.session.add(newYear) db.session.commit() - print(opportunity) - # Commit all changes to the database db.session.commit() - return {"data": "Opportunity Updated"} + return {"data": "Opportunity Updated"}, 200 @main_blueprint.delete("/deleteOpportunity/") +@jwt_required() def deleteOpportunity(opportunity_id): opportunity = db.session.get(Opportunities, opportunity_id) @@ -838,6 +863,25 @@ def deleteOpportunity(opportunity_id): return {"error": "Opportunity not found"}, 404 # TODO: Add check to see if user has permission to delete opportunity + user_id = get_jwt_identity() + + lab_manager = db.session.execute( + db.select(LabManager) + .join(User, User.lab_manager_id == LabManager.id) + .where(User.email == user_id) + ).scalar_one_or_none() + + if lab_manager: + lead = db.session.execute( + db.select(Leads).where( + Leads.lab_manager_id == lab_manager.id, + Leads.opportunity_id == opportunity.id, + ) + ).scalar_one_or_none() + if not lead: + return {"error": "Don't have permission to delete!"}, 401 + else: + return {"error": "Don't have permission to delete!"}, 401 # Delete related records in other tables (e.g., Leads, RecommendsCourses, RecommendsMajors, RecommendsClassYears) db.session.query(Leads).filter_by(opportunity_id=opportunity_id).delete() From 8b2fdbca234251c7a28de0b91c14f7c289bea235 Mon Sep 17 00:00:00 2001 From: youssefr26 Date: Tue, 29 Oct 2024 23:12:03 -0400 Subject: [PATCH 53/99] Added data to test users in db. --- db_init.py | 59 ++++++++++++++++++------------------------------------ 1 file changed, 20 insertions(+), 39 deletions(-) diff --git a/db_init.py b/db_init.py index cf467c7..ed89c97 100644 --- a/db_init.py +++ b/db_init.py @@ -115,6 +115,9 @@ ("goldd", "David", "Goldschmidt", "CSCI", "VIM master"), ("rami", "Rami", "Rami", "MTLE", "cubes are cool"), ("holm", "Mark", "Holmes", "MATH", "all about that math"), + ("test", "RCOS", "RCOS", "CSCI", "first test"), + ("test2", "RCOS", "RCOS", "CSCI", "Second test"), + ("test3", "RCOS", "RCOS", "CSCI", "Third test"), ) raf_test_user = ( @@ -233,6 +236,22 @@ datetime.now(), LocationEnum.JEC, ), + ( + "Data Science Research", + "Work with a team of researchers to analyze large datasets and extract meaningful insights.", + "Python, Machine Learning, Data Analysis", + 20.0, + True, + False, + True, + False, + SemesterEnum.FALL, + 2024, + "2024-10-31", + True, + "2024-10-10T10:30:00", + LocationEnum.JROWL, + ), ) for row_tuple in opportunities_rows: @@ -290,6 +309,7 @@ (2, 2), (1, 3), (4, 4), + (8, 5), ) for r in leads_rows: @@ -318,45 +338,6 @@ db.session.add(row) db.session.commit() - user_rows = ( - ( - "test", - "test@rpi.edu", - "RCOS", - "RCOS", - None, - 2028, - ), - ( - "test2", - "test2@rpi.edu", - "RCOS", - "RCOS", - None, - 2029, - ), - ( - "test3", - "test3@rpi.edu", - "RCOS", - "RCOS", - None, - 2025, - ), - ) - for r in user_rows: - row = User( - id=r[0], - email=r[1], - first_name=r[2], - last_name=r[3], - preferred_name=r[4], - class_year=r[5], - profile_picture="https://www.svgrepo.com/show/206842/professor.svg", - ) - db.session.add(row) - db.session.commit() - user_majors = ( ("cenzar", "MATH"), ("cenzar", "CSCI"), From fabe16d0335612ec874dd80d3ffebe614dd0537c Mon Sep 17 00:00:00 2001 From: youssefr26 Date: Tue, 29 Oct 2024 23:20:48 -0400 Subject: [PATCH 54/99] Cleaned up DeepSource errors. --- labconnect/main/opportunity_routes.py | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/labconnect/main/opportunity_routes.py b/labconnect/main/opportunity_routes.py index a1c2b1d..9d69a21 100644 --- a/labconnect/main/opportunity_routes.py +++ b/labconnect/main/opportunity_routes.py @@ -4,7 +4,7 @@ from flask_jwt_extended import get_jwt_identity, jwt_required from labconnect import db -from labconnect.helpers import LocationEnum, format_credits +from labconnect.helpers import LocationEnum, SemesterEnum, format_credits from labconnect.models import ( LabManager, Leads, @@ -15,7 +15,6 @@ User, ) -from labconnect.helpers import LocationEnum, SemesterEnum, format_credits from . import main_blueprint @@ -474,8 +473,6 @@ def getOpportunityCards(): return cards - abort(500) - # @main_blueprint.route("/getOpportunities", methods=["GET"]) # def getOpportunities(): @@ -693,8 +690,6 @@ def createOpportunity(): return {"data": "Opportunity Created"} - abort(500) - @main_blueprint.get("/editOpportunity/") def editOpportunity_get(opportunity_id): @@ -728,7 +723,6 @@ def editOpportunity_get(opportunity_id): RecommendsClassYears.opportunity_id == opportunity_id ) ).all() - print((opportunity.location)) # Format opportunity data as JSON opportunity_data = { @@ -898,4 +892,3 @@ def deleteOpportunity(opportunity_id): db.session.commit() return {"data": "Opportunity Deleted"} - abort(500) From 402ecd8bb6e9089c2f1f8cd3f3e7d9057e495159 Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Fri, 1 Nov 2024 12:25:33 -0400 Subject: [PATCH 55/99] Upgrade dependencies (#234) * Upgrade dependencies * lower sqlalchemy for sqlalchemy serializer dependency --- requirements.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/requirements.txt b/requirements.txt index db6f111..10b7f84 100644 --- a/requirements.txt +++ b/requirements.txt @@ -14,9 +14,9 @@ isodate==0.6.1 itsdangerous==2.2.0 Jinja2==3.1.4 lxml==5.3.0 -Mako==1.3.5 -MarkupSafe==2.1.5 -orjson==3.10.7 +Mako==1.3.6 +MarkupSafe==3.0.2 +orjson==3.10.10 packaging==24.1 pluggy==1.5.0 psycopg2==2.9.9 @@ -26,7 +26,7 @@ pytest==8.3.3 pytest-cov==5.0.0 python3-saml==1.16.0 pytz==2024.2 -sentry-sdk==2.15.0 +sentry-sdk==2.17.0 six==1.16.0 SQLAlchemy==2.0.29 sqlalchemy-serializer==1.4.22 From f000b74610bef8b2ffebc333d422f8094a109064 Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Fri, 1 Nov 2024 16:33:38 -0400 Subject: [PATCH 56/99] fix frontend name --- labconnect/main/auth_routes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/labconnect/main/auth_routes.py b/labconnect/main/auth_routes.py index 80fa713..ca9b7d4 100644 --- a/labconnect/main/auth_routes.py +++ b/labconnect/main/auth_routes.py @@ -47,7 +47,7 @@ def saml_login(): # In testing skip RPI login purely for local development if ( current_app.config["TESTING"] - and current_app.config["Frontend_URL"] == "http://localhost:3000" + and current_app.config["FRONTEND_URL"] == "http://localhost:3000" ): # Generate JWT code = generate_temporary_code("test@rpi.edu") From 3ddf87d460bb428b9ba53a7532c3715e0ab9994f Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Tue, 5 Nov 2024 23:43:19 -0500 Subject: [PATCH 57/99] Remove 2024 issues --- db_init.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/db_init.py b/db_init.py index ed89c97..798e285 100644 --- a/db_init.py +++ b/db_init.py @@ -89,7 +89,7 @@ db.session.add(row) db.session.commit() - class_years_rows = (2024, 2025, 2026, 2027, 2028, 2029, 2030, 2031) + class_years_rows = (2025, 2026, 2027, 2028, 2029, 2030, 2031) for row_item in class_years_rows: row = ClassYears(class_year=row_item, active=True) @@ -182,7 +182,7 @@ False, True, SemesterEnum.SPRING, - 2024, + 2025, date.today(), True, datetime.now(), @@ -198,7 +198,7 @@ True, True, SemesterEnum.SPRING, - 2024, + 2025, date.today(), True, datetime.now(), @@ -214,7 +214,7 @@ True, True, SemesterEnum.FALL, - 2024, + 2025, date.today(), True, datetime.now(), @@ -230,7 +230,7 @@ True, True, SemesterEnum.SUMMER, - 2024, + 2025, date.today(), True, datetime.now(), @@ -246,10 +246,10 @@ True, False, SemesterEnum.FALL, - 2024, - "2024-10-31", + 2025, + "2025-10-31", True, - "2024-10-10T10:30:00", + "2025-10-10T10:30:00", LocationEnum.JROWL, ), ) @@ -331,7 +331,7 @@ db.session.add(row) db.session.commit() - recommends_class_years_rows = ((2, 2024), (2, 2025), (2, 2026), (1, 2027)) + recommends_class_years_rows = ((3, 2025), (2, 2025), (2, 2026), (1, 2027)) for r in recommends_class_years_rows: row = RecommendsClassYears(opportunity_id=r[0], class_year=r[1]) From 4782c2822718918c680019d700f78ec4d686d09d Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Tue, 5 Nov 2024 23:43:43 -0500 Subject: [PATCH 58/99] Updates to handle input from frontend form for create opportunity --- labconnect/main/opportunity_routes.py | 91 ++++++++++++++++----------- 1 file changed, 54 insertions(+), 37 deletions(-) diff --git a/labconnect/main/opportunity_routes.py b/labconnect/main/opportunity_routes.py index 9d69a21..c253f2e 100644 --- a/labconnect/main/opportunity_routes.py +++ b/labconnect/main/opportunity_routes.py @@ -1,4 +1,4 @@ -import datetime +from datetime import datetime from flask import abort, request from flask_jwt_extended import get_jwt_identity, jwt_required @@ -603,36 +603,50 @@ def getLabManagerOpportunityCards(rcs_id: str): @main_blueprint.post("/createOpportunity") @jwt_required() def createOpportunity(): - data = request.get_json() - user_id = get_jwt_identity() + if not request.data or not user_id: + abort(400) + + request_data = request.get_json() + + if not request_data: + abort(400) + author = db.session.execute( db.select(User).where(User.email == user_id) ).scalar_one_or_none() + if author is None or author.lab_manager_id is None: + abort(400) + authorID = author.lab_manager_id - newPostData = data[0] + newPostData = request_data[0] # query database to see if the credentials above match - query = db.session.execute(db.select(LabManager).where(LabManager.id == authorID)) + # query = db.session.execute(db.select(LabManager).where(LabManager.id == authorID)) - data = query.all()[0][0] + # data = query.all()[0][0] # TODO: how do we get the opportunity id? # if match is found, create a new opportunity with the new data provided + if not newPostData["hourlyPay"].isdigit(): + abort(400) + + pay = int(newPostData["hourlyPay"]) + one = False two = False three = False four = False - if newPostData["one_credit"]: + if "1" in newPostData["credits"]: one = True - if newPostData["two_credits"]: + if "2" in newPostData["credits"]: two = True - if newPostData["three_credits"]: + if "3" in newPostData["credits"]: three = True - if newPostData["four_credits"]: + if "4" in newPostData["credits"]: four = True lenum = convert_to_enum(newPostData["location"]) @@ -641,22 +655,20 @@ def createOpportunity(): lenum = LocationEnum.TBD newOpportunity = Opportunities( - name=newPostData["name"], + name=newPostData["title"], description=newPostData["description"], recommended_experience=newPostData["recommended_experience"], - pay=newPostData["pay"], + pay=pay, one_credit=one, two_credits=two, three_credits=three, four_credits=four, - semester=SemesterEnum[(newPostData["semester"]).upper()], - year=newPostData["year"], - application_due=datetime.datetime.strptime( - newPostData["application_due"], "%Y-%m-%d" - ), - active=newPostData["active"], + semester=SemesterEnum.FALL, + year=datetime.now().year, + application_due=datetime.strptime(newPostData["application_due"], "%Y-%m-%d"), + active=True, location=lenum, - last_updated=datetime.datetime.now(), + last_updated=datetime.now(), ) db.session.add(newOpportunity) db.session.commit() @@ -666,27 +678,27 @@ def createOpportunity(): db.session.add(newLead) db.session.commit() - for course in newPostData["courses"]: - newCourse = RecommendsCourses( - opportunity_id=newOpportunity.id, course_code=course - ) + # for course in newPostData["courses"]: + # newCourse = RecommendsCourses( + # opportunity_id=newOpportunity.id, course_code=course + # ) - db.session.add(newCourse) - db.session.commit() + # db.session.add(newCourse) + # db.session.commit() - for major in newPostData["majors"]: - newMajor = RecommendsMajors(opportunity_id=newOpportunity.id, major_code=major) - db.session.add(newMajor) - db.session.commit() + # for major in newPostData["majors"]: + # newMajor = RecommendsMajors(opportunity_id=newOpportunity.id, major_code=major) + # db.session.add(newMajor) + # db.session.commit() for year in newPostData["years"]: - newYear = RecommendsClassYears( - opportunity_id=newOpportunity.id, class_year=year - ) - db.session.add(newYear) - db.session.commit() - - db.session.add(newOpportunity) + if year.isdigit(): + recommended_year = int(year) + newYear = RecommendsClassYears( + opportunity_id=newOpportunity.id, class_year=recommended_year + ) + db.session.add(newYear) + db.session.commit() return {"data": "Opportunity Created"} @@ -701,7 +713,6 @@ def editOpportunity_get(opportunity_id): return {"error": "Opportunity not found"}, 404 opportunity = opportunity[0] - print(opportunity) # Query related courses courses_data = db.session.execute( @@ -753,8 +764,14 @@ def editOpportunity_get(opportunity_id): @jwt_required() def editOpportunity(opportunity_id): + if not request.data: + abort(400) + data = request.get_json() + if not data: + abort(400) + # Check if the opportunity and author exist opportunity = db.session.execute( db.select(Opportunities).where(Opportunities.id == opportunity_id) From 38c5e421811aec814e4e1fe98bc99831a013e566 Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Tue, 5 Nov 2024 23:44:15 -0500 Subject: [PATCH 59/99] Updating years route --- labconnect/main/routes.py | 46 +++++++++++---------------------------- 1 file changed, 13 insertions(+), 33 deletions(-) diff --git a/labconnect/main/routes.py b/labconnect/main/routes.py index 52456de..564fee6 100644 --- a/labconnect/main/routes.py +++ b/labconnect/main/routes.py @@ -306,11 +306,6 @@ def changeActiveStatus() -> dict[str, bool]: return {"activeStatus": opportunity} -# @main_blueprint.post("/create_post") -# def create_post(): -# return {"Hello": "There"} - - @main_blueprint.get("/500") def force_error(): abort(500) @@ -329,21 +324,6 @@ def force_error(): # return result -# @main_blueprint.get("/departmentsList") -# def departments() -> list[Any]: - -# data = db.session.execute( -# db.select(RPIDepartments).order_by(RPIDepartments.name) -# ).scalars() - -# if not data: -# abort(404) - -# result = [department.to_dict() for department in data] - -# return result - - # @main_blueprint.get("/majors") # def majors() -> list[Any]: @@ -382,24 +362,24 @@ def force_error(): # return result -# @main_blueprint.get("/years") -# def years() -> list[Any]: +@main_blueprint.get("/years") +def years() -> list[int]: -# data = db.session.execute( -# db.select(ClassYears) -# .order_by(ClassYears.class_year) -# .where(ClassYears.active == True) -# ).scalars() + data = db.session.execute( + db.select(ClassYears) + .order_by(ClassYears.class_year) + .where(ClassYears.active == True) + ).scalars() -# if not data: -# abort(404) + if not data: + abort(404) -# result = [year.class_year for year in data] + result = [year.class_year for year in data] -# if result == []: -# abort(404) + if result == []: + abort(404) -# return result + return result # @main_blueprint.get("/courses") From 90b8160844f2e348f6d298ca7f5505ae5658f992 Mon Sep 17 00:00:00 2001 From: youssefr26 Date: Fri, 8 Nov 2024 16:13:12 -0500 Subject: [PATCH 60/99] Added registration for new users. --- labconnect/main/auth_routes.py | 58 +++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 22 deletions(-) diff --git a/labconnect/main/auth_routes.py b/labconnect/main/auth_routes.py index ca9b7d4..ea42d38 100644 --- a/labconnect/main/auth_routes.py +++ b/labconnect/main/auth_routes.py @@ -2,7 +2,7 @@ from uuid import uuid4 from flask import current_app, make_response, redirect, request -from flask_jwt_extended import create_access_token +from flask_jwt_extended import create_access_token, get_jwt_identity, jwt_required from onelogin.saml2.auth import OneLogin_Saml2_Auth from labconnect import db @@ -14,31 +14,36 @@ temp_codes = {} -def generate_temporary_code(user_email: str) -> str: +def generate_temporary_code(user_email: str, registered: bool) -> str: # Generate a unique temporary code code = str(uuid4()) expires_at = datetime.now() + timedelta(seconds=5) # expires in 5 seconds - temp_codes[code] = {"email": user_email, "expires_at": expires_at} + temp_codes[code] = { + "email": user_email, + "expires_at": expires_at, + "registered": registered, + } return code -def validate_code_and_get_user_email(code: str) -> str | None: +def validate_code_and_get_user_email(code: str) -> tuple[str | None, bool | None]: token_data = temp_codes.get(code, {}) if not token_data: return None user_email = token_data.get("email", None) expire = token_data.get("expires_at", None) + registered = token_data.get("registered", None) if user_email and expire and expire > datetime.now(): # If found, delete the code to prevent reuse del temp_codes[code] - return user_email + return user_email, registered elif expire: # If the code has expired, delete it del temp_codes[code] - return None + return None, None @main_blueprint.get("/login") @@ -70,6 +75,7 @@ def saml_callback(): errors = auth.get_errors() if not errors: + registered = True user_info = auth.get_attributes() # user_id = auth.get_nameid() @@ -77,22 +83,10 @@ def saml_callback(): # User doesn't exist, create a new user if data is None: - - # TODO: add data - user = User( - # email=email, - # first_name=first_name, - # last_name=last_name, - # preferred_name=json_request_data.get("preferred_name", None), - # class_year=class_year, - ) - - db.session.add(user) - db.session.commit() - + registered = False # Generate JWT # token = create_access_token(identity=[user_id, datetime.now()]) - code = generate_temporary_code(user_info["email"][0]) + code = generate_temporary_code(user_info["email"][0], registered) # Send the JWT to the frontend return redirect(f"{current_app.config['FRONTEND_URL']}/callback/?code={code}") @@ -100,6 +94,26 @@ def saml_callback(): return {"errors": errors}, 500 +@main_blueprint.post("/register") +@jwt_required() +def registerUser(): + user_id = get_jwt_identity() + + user = db.session.execute(db.select(User).where(User.email == user_id)) + + # Gather the new user's information + json_data = request.get_json() + user.first_name = json_data.get("first_name") + user.last_name = json_data.get("last_name") + user.preferred_name = json_data.get("preferred_name") + user.class_year = json_data.get("class_year") + user.profile_picture = json_data.get("profile_pictures") + user.website = json_data.get("website") + user.description = json_data.get("description") + + return {"msg": "Information added"} + + @main_blueprint.post("/token") def tokenRoute(): if request.json is None or request.json.get("code", None) is None: @@ -108,13 +122,13 @@ def tokenRoute(): code = request.json["code"] if code is None: return {"msg": "Missing code in request"}, 400 - user_email = validate_code_and_get_user_email(code) + user_email, registered = validate_code_and_get_user_email(code) if user_email is None: return {"msg": "Invalid code"}, 400 token = create_access_token(identity=[user_email, datetime.now()]) - return {"token": token} + return {"token": token, "registered": registered} @main_blueprint.get("/metadata/") From 3c2d641792dfde3cd13b17bed9fe58dfed6af403 Mon Sep 17 00:00:00 2001 From: youssefr26 Date: Fri, 8 Nov 2024 17:14:01 -0500 Subject: [PATCH 61/99] Added route to search for lab_managers and updated edit and create opportunities to add new leads. Also attempted to fix registration. --- labconnect/main/auth_routes.py | 25 ++++++----- labconnect/main/opportunity_routes.py | 62 +++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 11 deletions(-) diff --git a/labconnect/main/auth_routes.py b/labconnect/main/auth_routes.py index ea42d38..5eb0570 100644 --- a/labconnect/main/auth_routes.py +++ b/labconnect/main/auth_routes.py @@ -97,21 +97,24 @@ def saml_callback(): @main_blueprint.post("/register") @jwt_required() def registerUser(): - user_id = get_jwt_identity() - user = db.session.execute(db.select(User).where(User.email == user_id)) + user_id = get_jwt_identity() # Gather the new user's information json_data = request.get_json() - user.first_name = json_data.get("first_name") - user.last_name = json_data.get("last_name") - user.preferred_name = json_data.get("preferred_name") - user.class_year = json_data.get("class_year") - user.profile_picture = json_data.get("profile_pictures") - user.website = json_data.get("website") - user.description = json_data.get("description") - - return {"msg": "Information added"} + user = User( + email=user_id, + first_name=json_data.get("first_name"), + last_name=json_data.get("last_name"), + preferred_name=json_data.get("preferred_name"), + class_year=json_data.get("class_year"), + profile_picture=json_data.get("profile_pictures"), + website=json_data.get("website"), + description=json_data.get("description"), + ) + db.session.add(user) + db.session.commit() + return {"msg": "New user added"} @main_blueprint.post("/token") diff --git a/labconnect/main/opportunity_routes.py b/labconnect/main/opportunity_routes.py index 9d69a21..7d01a1f 100644 --- a/labconnect/main/opportunity_routes.py +++ b/labconnect/main/opportunity_routes.py @@ -599,6 +599,48 @@ def getLabManagerOpportunityCards(rcs_id: str): # abort(500) +# function to search for lab managers +@main_blueprint.get("/searchLabManagers/") +def searchLabManagers(query: str): + # Perform a search on User table by first name, last name, or email using ILIKE for exact partial matches + stmt = ( + db.select(User) + .join(LabManager, User.lab_manager_id == LabManager.id) + .where( + ( + User.first_name.ilike( + f"%{query}%" + ) # Case-insensitive partial match on first_name + ) + | ( + User.last_name.ilike( + f"%{query}%" + ) # Case-insensitive partial match on last_name + ) + | ( + User.email.ilike( + f"%{query}%" + ) # Case-insensitive partial match on email + ) + ) + ) + + results = db.session.execute(stmt).scalars().all() + + # Format results as JSON + lab_managers = [ + { + "lab_manager_id": user.lab_manager_id, + "first_name": user.first_name, + "last_name": user.last_name, + "email": user.email, + } + for user in results + ] + + return {"lab_managers": lab_managers}, 200 + + # functions to create/edit/delete opportunities @main_blueprint.post("/createOpportunity") @jwt_required() @@ -688,6 +730,16 @@ def createOpportunity(): db.session.add(newOpportunity) + # Add the selected managers to the Leads table + if "lab_manager_ids" in data: + for lab_manager_id in data["lab_manager_ids"]: + lead = Leads( + lab_manager_id=lab_manager_id, opportunity_id=newOpportunity.id + ) + db.session.add(lead) + + db.session.commit() # Commit all changes + return {"data": "Opportunity Created"} @@ -845,6 +897,16 @@ def editOpportunity(opportunity_id): # Commit all changes to the database db.session.commit() + # Add the updated list of managers + if "lab_manager_ids" in data: + for lab_manager_id in data["lab_manager_ids"]: + new_lead = Leads( + lab_manager_id=lab_manager_id, opportunity_id=opportunity_id + ) + db.session.add(new_lead) + + db.session.commit() # Commit all changes + return {"data": "Opportunity Updated"}, 200 From 29106a6d66fe27af9dfccba7b9cb4042ef1a7cf6 Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Sat, 9 Nov 2024 02:24:06 -0500 Subject: [PATCH 62/99] black formatting --- labconnect/main/opportunity_routes.py | 25 +++++++++++++++---------- labconnect/main/routes.py | 25 +++++++++++++------------ 2 files changed, 28 insertions(+), 22 deletions(-) diff --git a/labconnect/main/opportunity_routes.py b/labconnect/main/opportunity_routes.py index f6f9620..8cd59f3 100644 --- a/labconnect/main/opportunity_routes.py +++ b/labconnect/main/opportunity_routes.py @@ -88,7 +88,9 @@ def searchOpportunity(query: str): def convert_to_enum(location_string): try: - return LocationEnum[location_string.upper()] # Use upper() for case-insensitivity + return LocationEnum[ + location_string.upper() + ] # Use upper() for case-insensitivity except KeyError: return None # Or raise an exception if you prefer @@ -99,6 +101,7 @@ def packageOpportunity(opportunityInfo, professorInfo): data["department"] = professorInfo.department_id return data + def packageIndividualOpportunity(opportunityInfo): data = { "id": opportunityInfo.id, @@ -162,19 +165,18 @@ def packageIndividualOpportunity(opportunityInfo): ) queryInfo = query.all() - #print(queryInfo) + # print(queryInfo) if len(queryInfo) == 0: return data data["department"] = queryInfo[0][1].department_id - #for i, item in enumerate(queryInfo): - #data["author"] += item[1].getName() + # 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"] += ", " - + # if i != len(queryInfo) - 1: + # data["author"] += ", " author_names = [item[1].getName() for item in queryInfo] data["author"] = ", ".join(author_names) @@ -252,11 +254,10 @@ def packageOpportunityCard(opportunity): # return result - ##@main_blueprint.route("/opportunity/filter", methods=["POST"]) ##def filterOpportunities(): - # Handle POST requests for filtering opportunities - ##json_request_data = request.get_json() +# Handle POST requests for filtering opportunities +##json_request_data = request.get_json() # if not json_request_data: @@ -469,6 +470,7 @@ def packageOpportunityCard(opportunity): # abort(500) + # Jobs page @main_blueprint.get("/getOpportunityCards") def getOpportunityCards(): @@ -483,6 +485,7 @@ def getOpportunityCards(): return cards + # @main_blueprint.get("/getOpportunities") # def getOpportunities(): # # # query database for opportunity @@ -560,6 +563,7 @@ def getLabManagerOpportunityCards(rcs_id: str): return cards + # @main_blueprint.get("/getProfileOpportunities/") # def getProfileOpportunities(rcs_id: str): # # # query database for opportunity @@ -692,6 +696,7 @@ def createOpportunity(): return {"data": "Opportunity Created"} + @main_blueprint.get("/editOpportunity/") def editOpportunity_get(opportunity_id): opportunity = db.session.execute( diff --git a/labconnect/main/routes.py b/labconnect/main/routes.py index f3ee77c..5cfb9af 100644 --- a/labconnect/main/routes.py +++ b/labconnect/main/routes.py @@ -1,27 +1,28 @@ -#from typing import Any +# from typing import Any from flask import abort, request from flask_jwt_extended import get_jwt_identity, jwt_required from labconnect import db from labconnect.models import ( - #ClassYears, - #Courses, + # ClassYears, + # Courses, LabManager, Leads, - #Majors, + # Majors, Opportunities, - #Participates, - #RecommendsClassYears, - #RecommendsCourses, - #RecommendsMajors, + # Participates, + # RecommendsClassYears, + # RecommendsCourses, + # RecommendsMajors, RPIDepartments, - #RPISchools, + # RPISchools, User, - #UserCourses, - #UserDepartments, - #UserMajors, + # UserCourses, + # UserDepartments, + # UserMajors, ) + # = not currently using from . import main_blueprint From d03552338706bb066e72cda623f9bad6d0710af9 Mon Sep 17 00:00:00 2001 From: Mrunal Athaley <112527910+athalm@users.noreply.github.com> Date: Sat, 9 Nov 2024 14:40:28 -0500 Subject: [PATCH 63/99] updated test departments again with the new updated tests --- tests/test_departments.py | 223 ++++++++++++++++---------------------- 1 file changed, 95 insertions(+), 128 deletions(-) diff --git a/tests/test_departments.py b/tests/test_departments.py index 4d3dd49..866f55c 100644 --- a/tests/test_departments.py +++ b/tests/test_departments.py @@ -4,139 +4,106 @@ from flask import json from flask.testing import FlaskClient +import pytest - -def test_departments_route(test_client: FlaskClient) -> None: - """ - GIVEN a Flask application configured for testing - WHEN the '/departments' page is requested (GET) - THEN check that the response is valid - """ - response = test_client.get("/departments") - - assert response.status_code == 200 - - json_data = json.loads(response.data) - - rpi_departments_data = ( +@pytest.mark.parametrize( + "endpoint, request_json, expected_status, expected_response_checks", + [ ( - "Computer Science", - "Biology", - "Materials Engineering", - "Math", - "Environmental Engineering", - "Aerospace Engineering", - "Areonautical Engineering", + "/departments", + None, + 200, + [ + { + "field": "name", + "values": [ + "Computer Science", "Biology", "Materials Engineering", + "Math", "Environmental Engineering", "Aerospace Engineering", + "Areonautical Engineering" + ] + }, + { + "field": "description", + "values": [ + "DS", "life", "also pretty cool", "quick maths", "water", + "space, the final frontier", "flying, need for speed" + ] + }, + { + "field": "school_id", + "values": [ + "School of science", "School of science", "School of engineering", + "School of science", "School of engineering", "School of engineering", + "School of engineering" + ] + }, + { + "field": "id", + "values": ["CSCI", "BIOL", "MTLE", "MATH", "ENVI", "MANE", "MANE"] + }, + { + "field": "image", + "values": [ + "https://cdn-icons-png.flaticon.com/512/5310/5310672.png" + ] * 7 + }, + { + "field": "webcite", + "values": ["https://www.rpi.edu"] * 7 + } + ] ), ( - "DS", - "life", - "also pretty cool", - "quick maths", - "water", - "space, the final frontier", - "flying, need for speed", + "/department", + {"department": "Computer Science"}, + 200, + [ + {"field": "name", "values": ["Computer Science"]}, + {"field": "description", "values": ["DS"]}, + {"field": "school_id", "values": ["School of Science"]}, + {"field": "id", "values": ["CSCI"]}, + { + "field": "image", + "values": ["https://cdn-icons-png.flaticon.com/512/5310/5310672.png"] + }, + {"field": "webcite", "values": ["https://www.rpi.edu"]}, + { + "field": "professors", + "subfields": [ + {"subfield": "name", "values": ["Duy Le", "Rafael", "Turner", "Kuzmin", "Goldschmidt"]}, + {"subfield": "rcs_id", "values": ["led", "cenzar", "turner", "kuzmin", "goldd"]} + ] + }, + { + "field": "opportunities", + "subfields": [ + {"subfield": "id", "values": [1, 2]}, + {"subfield": "name", "values": ["Automated Cooling System", "Iphone 15 durability test"]} + ] + } + ] ), - ( - "School of science", - "School of science", - "School of engineering", - "School of science", - "School of engineering", - "School of engineering", - "School of engineering", - ), - ( - "CSCI", - "BIOL", - "MTLE" - "MATH", - "ENVI", - "MANE", - "MANE", - ), - ( - "https://cdn-icons-png.flaticon.com/512/5310/5310672.png", - "https://cdn-icons-png.flaticon.com/512/5310/5310672.png", - "https://cdn-icons-png.flaticon.com/512/5310/5310672.png" - "https://cdn-icons-png.flaticon.com/512/5310/5310672.png", - "https://cdn-icons-png.flaticon.com/512/5310/5310672.png", - "https://cdn-icons-png.flaticon.com/512/5310/5310672.png", - "https://cdn-icons-png.flaticon.com/512/5310/5310672.png", - ), - ( - "https://www.rpi.edu", - "https://www.rpi.edu", - "https://www.rpi.edu", - "https://www.rpi.edu", - "https://www.rpi.edu", - "https://www.rpi.edu", - "https://www.rpi.edu", - ), - ) - - for department in json_data: - assert department["name"] in rpi_departments_data[0] - assert department["description"] in rpi_departments_data[1] - #Added - assert department["school_id"] in rpi_departments_data[2] - assert department["id"] in rpi_departments_data[3] - assert department["image"] in rpi_departments_data[4] - assert department["webcite"] in rpi_departments_data[5] - - -def test_department_route(test_client: FlaskClient) -> None: + ("/department", None, 400, None), + ("/department", {"wrong": "wrong"}, 400, None) + ] +) +def test_department_routes(test_client: FlaskClient, endpoint, request_json, expected_status, expected_response_checks) -> None: """ GIVEN a Flask application configured for testing - WHEN the '/department' page is requested (GET) - THEN check that the response is valid + WHEN various '/departments' or '/department' routes are requested (GET) + THEN check that the response status and data are as expected """ - response = test_client.get("/department", json={"department": "Computer Science"}) - - assert response.status_code == 200 - - json_data = json.loads(response.data) - - assert json_data["name"] == "Computer Science" - assert json_data["description"] == "DS" - assert json_data["school_id"] == "School of Science" - #Added - assert json_data["id"] == "CSCI" - assert json_data["image"] == "https://cdn-icons-png.flaticon.com/512/5310/5310672.png" - assert json_data["webcite"] == "https://www.rpi.edu" - - prof_names = ["Duy Le", "Rafael", "Turner", "Kuzmin", "Goldschmidt"] - prof_rcs_ids = ["led", "cenzar", "turner", "kuzmin", "goldd"] - - for prof in json_data["professors"]: - assert prof["name"] in prof_names - assert prof["rcs_id"] in prof_rcs_ids - - opportunity_ids = [1, 2] - opportunity_names = ["Automated Cooling System", "Iphone 15 durability test"] - - for opportunity in json_data["opportunities"]: - assert opportunity["id"] in opportunity_ids - assert opportunity["name"] in opportunity_names - - -def test_department_route_no_json(test_client: FlaskClient) -> None: - """ - GIVEN a Flask application configured for testing - WHEN the '/department' page is requested (GET) - THEN check that the response is valid - """ - response = test_client.get("/department") - - assert response.status_code == 400 - - -def test_department_route_incorrect_json(test_client: FlaskClient) -> None: - """ - GIVEN a Flask application configured for testing - WHEN the '/department' page is requested (GET) - THEN check that the response is valid - """ - response = test_client.get("/department", json={"wrong": "wrong"}) - - assert response.status_code == 400 + response = test_client.get(endpoint, json=request_json) if request_json else test_client.get(endpoint) + assert response.status_code == expected_status + + if expected_response_checks: + json_data = json.loads(response.data) + + for check in expected_response_checks: + if "subfields" not in check: + for item in json_data: + assert item[check["field"]] in check["values"] + else: + for item in json_data.get(check["field"], []): + for subfield_check in check["subfields"]: + assert item[subfield_check["subfield"]] in subfield_check["values"] From d9801be846e321162fcd281785d18da82ca8af4f Mon Sep 17 00:00:00 2001 From: Mrunal Athaley <112527910+athalm@users.noreply.github.com> Date: Sat, 9 Nov 2024 14:41:52 -0500 Subject: [PATCH 64/99] updated test lab manager again --- tests/test_lab_manager.py | 179 ++++++++++++++++---------------------- 1 file changed, 74 insertions(+), 105 deletions(-) diff --git a/tests/test_lab_manager.py b/tests/test_lab_manager.py index 7e28883..562f6b2 100644 --- a/tests/test_lab_manager.py +++ b/tests/test_lab_manager.py @@ -1,118 +1,87 @@ """ -Test lab manager routes +Test lab manager routes with parameterization """ +import pytest from flask import json from flask.testing import FlaskClient -def test_lab_manager_route_with_input_id(test_client: FlaskClient) -> None: +@pytest.mark.parametrize( + "input_json, expected_status, expected_response", + [ + ({"rcs_id": "cenzar"}, 200, { + "website": None, + "rcs_id": "cenzar", + "name": "Rafael", + "alt_email": None, + "phone_number": None, + "email": None, + "description": None, + }), + (None, 400, None), # No input JSON case + ({"wrong": "wrong"}, 400, None) # Incorrect JSON structure case + ] +) +def test_lab_manager_route(test_client: FlaskClient, input_json, expected_status, expected_response) -> None: """ GIVEN a Flask application configured for testing - WHEN the '/lab_manager' page is requested (GET) - THEN check that the response is valid + WHEN the '/lab_manager' page is requested (GET) with different JSON inputs + THEN check that the response matches the expected outcome """ - response = test_client.get("/lab_manager", json={"rcs_id": "cenzar"}) - - assert response.status_code == 200 - - json_data = json.loads(response.data) - - cenzar_data = { - "website": None, - "rcs_id": "cenzar", - "name": "Rafael", - "alt_email": None, - "phone_number": None, - "email": None, - "description": None, - } - - assert json_data == cenzar_data - - -def test_lab_manager_route_no_json(test_client: FlaskClient) -> None: - """ - GIVEN a Flask application configured for testing - WHEN the '/lab_manager' page is requested (GET) - THEN check that the response is valid - """ - response = test_client.get("/lab_manager") - - assert response.status_code == 400 - - -def test_lab_manager_route_incorrect_json(test_client: FlaskClient) -> None: - """ - GIVEN a Flask application configured for testing - WHEN the '/lab_manager' page is requested (GET) - THEN check that the response is valid - """ - response = test_client.get("/lab_manager", json={"wrong": "wrong"}) - - assert response.status_code == 400 - - -def test_lab_manager_opportunity_cards(test_client: FlaskClient) -> None: + response = test_client.get("/lab_manager", json=input_json) + assert response.status_code == expected_status + + if expected_response: + json_data = json.loads(response.data) + assert json_data == expected_response + + +@pytest.mark.parametrize( + "input_json, expected_status", + [ + ({"rcs_id": "cenzar"}, 200), + (None, 400), # No input JSON case + ({"wrong": "wrong"}, 400) # Incorrect JSON structure case + ] +) +def test_lab_manager_opportunity_cards(test_client: FlaskClient, input_json, expected_status) -> None: """ GIVEN a Flask application configured for testing - WHEN the '/lab_manager/opportunities' page is requested (GET) - THEN check that the response is valid + WHEN the '/lab_manager/opportunities' page is requested (GET) with different JSON inputs + THEN check that the response matches the expected status code """ - response = test_client.get("/lab_manager/opportunities", json={"rcs_id": "cenzar"}) - - assert response.status_code == 200 - - json_data = json.loads(response.data) - - lab_manager_opportunities_data = ( - ( - "Automated Cooling System", - "Energy efficient AC system", - "Thermodynamics", - 15.0, - "Spring", - 2024, - True, - ), - ( - "Iphone 15 durability test", - "Scratching the Iphone, drop testing etc.", - "Experienced in getting angry and throwing temper tantrum", - None, - "Spring", - 2024, - True, - ), - ) - - for i, item in enumerate(json_data["cenzar"]): - assert item["name"] == lab_manager_opportunities_data[i][0] - assert item["description"] == lab_manager_opportunities_data[i][1] - assert item["recommended_experience"] == lab_manager_opportunities_data[i][2] - assert item["pay"] == lab_manager_opportunities_data[i][3] - assert item["semester"] == lab_manager_opportunities_data[i][4] - assert item["year"] == lab_manager_opportunities_data[i][5] - assert item["active"] == lab_manager_opportunities_data[i][6] - - -def test_lab_manager_opportunity_cards_no_json(test_client: FlaskClient) -> None: - """ - GIVEN a Flask application configured for testing - WHEN the '/lab_manager/opportunities' page is requested (GET) - THEN check that the response is valid - """ - response = test_client.get("/lab_manager/opportunities") - - assert response.status_code == 400 - - -def test_lab_manager_opportunity_cards_incorrect_json(test_client: FlaskClient) -> None: - """ - GIVEN a Flask application configured for testing - WHEN the '/lab_manager/opportunities' page is requested (GET) - THEN check that the response is valid - """ - response = test_client.get("/lab_manager/opportunities", json={"wrong": "wrong"}) - - assert response.status_code == 400 + response = test_client.get("/lab_manager/opportunities", json=input_json) + assert response.status_code == expected_status + + if input_json == {"rcs_id": "cenzar"} and expected_status == 200: + json_data = json.loads(response.data) + lab_manager_opportunities_data = [ + { + "name": "Automated Cooling System", + "description": "Energy efficient AC system", + "recommended_experience": "Thermodynamics", + "pay": 15.0, + "semester": "Spring", + "year": 2024, + "active": True, + }, + { + "name": "Iphone 15 durability test", + "description": "Scratching the Iphone, drop testing etc.", + "recommended_experience": "Experienced in getting angry and throwing temper tantrum", + "pay": None, + "semester": "Spring", + "year": 2024, + "active": True, + }, + ] + + for i, item in enumerate(json_data["cenzar"]): + assert item["name"] == lab_manager_opportunities_data[i]["name"] + assert item["description"] == lab_manager_opportunities_data[i]["description"] + assert item["recommended_experience"] == lab_manager_opportunities_data[i]["recommended_experience"] + assert item["pay"] == lab_manager_opportunities_data[i]["pay"] + assert item["semester"] == lab_manager_opportunities_data[i]["semester"] + assert item["year"] == lab_manager_opportunities_data[i]["year"] + assert item["active"] == lab_manager_opportunities_data[i]["active"] From ffcaa42907aedafbb7ec2befb22c6cd055a42df9 Mon Sep 17 00:00:00 2001 From: Mrunal Athaley <112527910+athalm@users.noreply.github.com> Date: Sat, 9 Nov 2024 14:45:59 -0500 Subject: [PATCH 65/99] update test user again --- tests/test_user.py | 318 ++++++++++++++++++--------------------------- 1 file changed, 126 insertions(+), 192 deletions(-) diff --git a/tests/test_user.py b/tests/test_user.py index d1e7d40..0e9ee86 100644 --- a/tests/test_user.py +++ b/tests/test_user.py @@ -2,213 +2,147 @@ Test user routes """ +import pytest from flask import json from flask.testing import FlaskClient - -def test_user_route_with_input_id_1(test_client: FlaskClient) -> None: - """ - GIVEN a Flask application configured for testing - WHEN the '/user' page is requested (GET) - THEN check that the response is valid - """ - response = test_client.get("/user", json={"id": "1"}) - - assert response.status_code == 200 - - json_data = json.loads(response.data) - - assert json_data["id"] == 1 - assert json_data["first_name"] == "Rafael" - assert json_data["preferred_name"] == "Raf" - assert json_data["last_name"] == "Cenzano" - assert json_data["email"] == "cenzar@rpi.edu" - #Added - assert json_data["description"] == "labconnect is the best RCOS project" - assert json_data["profile_picture"] == "https://rafael.sirv.com/Images/rafael.jpeg?thumbnail=350&format=webp&q=90" - assert json_data["website"] == "https://rafaelcenzano.com" - #class year - assert json_data["class_year"] == "2025" - #lab manager id - assert json_data["lab_manager_id"] == 1 - - departments_data = [ - {"user_id": 1, "department_id": "Computer Science"}, - {"user_id": 1, "department_id": "Math"}, - ] - - major_data = [ - {"user_id": 1, "major_code": "CSCI"}, - {"user_id": 1, "major_code": "MATH"}, - ] - - course_data = [ - {"in_progress": False, "user_id": 1, "course_code": "CSCI2300"}, - {"in_progress": True, "user_id": 1, "course_code": "CSCI4430"}, - ] - - assert json_data["departments"] == departments_data - assert json_data["majors"] == major_data - assert json_data["courses"] == course_data - - -def test_user_1_opportunity_cards(test_client: FlaskClient) -> None: - """ - GIVEN a Flask application configured for testing - WHEN the '/user' page is requested (GET) - THEN check that the response is valid - """ - response = test_client.get("/user", json={"id": 1}) - - assert response.status_code == 200 - - json_data = json.loads(response.data) - - lab_manager_opportunities_data = ( - ( - "Automated Cooling System", - "Energy efficient AC system", - "Thermodynamics", - 15.0, - "Spring", - 2024, - True, - ), - ( - "Iphone 15 durability test", - "Scratching the Iphone, drop testing etc.", - "Experienced in getting angry and throwing temper tantrum", - None, - "Spring", - 2024, - True, - ), +@pytest.mark.parametrize("input_data, expected_status, expected_output", [ + ( + {"id": "1"}, + 200, + { + "id": 1, + "first_name": "Rafael", + "preferred_name": "Raf", + "last_name": "Cenzano", + "email": "cenzar@rpi.edu", + "description": "labconnect is the best RCOS project", + "profile_picture": "https://rafael.sirv.com/Images/rafael.jpeg?thumbnail=350&format=webp&q=90", + "website": "https://rafaelcenzano.com", + "class_year": "2025", + "lab_manager_id": 1, + "departments": [ + {"user_id": 1, "department_id": "Computer Science"}, + {"user_id": 1, "department_id": "Math"} + ], + "majors": [ + {"user_id": 1, "major_code": "CSCI"}, + {"user_id": 1, "major_code": "MATH"} + ], + "courses": [ + {"in_progress": False, "user_id": 1, "course_code": "CSCI2300"}, + {"in_progress": True, "user_id": 1, "course_code": "CSCI4430"} + ] + } + ), + ( + {"id": "2"}, + 200, + { + "id": 2, + "first_name": "RCOS", + "preferred_name": None, + "last_name": "RCOS", + "email": "test@rpi.edu", + "description": None, + "profile_picture": "https://www.svgrepo.com/show/206842/professor.svg", + "website": None, + "class_year": None, + "lab_manager_id": None, + "departments": [ + {"user_id": 2, "department_id": "Computer Science"} + ], + "majors": [ + {"user_id": 2, "major_code": "CSCI"} + ], + "courses": [ + {"in_progress": False, "user_id": 2, "course_code": "CSCI2300"} + ] + } ) - - for i, item in enumerate(json_data["opportunities"]): - assert item["name"] == lab_manager_opportunities_data[i][0] - assert item["description"] == lab_manager_opportunities_data[i][1] - assert item["recommended_experience"] == lab_manager_opportunities_data[i][2] - assert item["pay"] == lab_manager_opportunities_data[i][3] - assert item["semester"] == lab_manager_opportunities_data[i][4] - assert item["year"] == lab_manager_opportunities_data[i][5] - assert item["active"] == lab_manager_opportunities_data[i][6] - - -def test_user_route_with_input_id_2(test_client: FlaskClient) -> None: +]) +def test_user_route(test_client: FlaskClient, input_data, expected_status, expected_output) -> None: """ GIVEN a Flask application configured for testing - WHEN the '/user' page is requested (GET) - THEN check that the response is valid + WHEN the '/user' page is requested (GET) with input data + THEN check that the response is valid and matches expected output """ - response = test_client.get("/user", json={"id": 2}) - - assert response.status_code == 200 - + response = test_client.get("/user", json=input_data) + assert response.status_code == expected_status json_data = json.loads(response.data) - - assert json_data["id"] == 2 - assert json_data["first_name"] == "RCOS" - assert json_data["last_name"] == "RCOS" - assert json_data["preferred_name"] is None - assert json_data["email"] == "test@rpi.edu" - #Added - assert json_data["description"] is None - assert json_data["profile_picture"] == "https://www.svgrepo.com/show/206842/professor.svg" # Adjust based on your test data - assert json_data["website"] is None - assert json_data["class_year"] is None - assert json_data["lab_manager_id"] is None - - departments_data = [ - {"department_id": "Computer Science", "user_id": 2}, - ] - - major_data = [ - {"user_id": 2, "major_code": "CSCI"}, - ] - - course_data = [ - {"in_progress": False, "user_id": 2, "course_code": "CSCI2300"}, - ] - - assert json_data["departments"] == departments_data - assert json_data["majors"] == major_data - assert json_data["courses"] == course_data - - -def test_user_2_opportunity_cards(test_client: FlaskClient) -> None: + assert json_data == expected_output + +@pytest.mark.parametrize("input_data, expected_opportunities", [ + ( + {"id": 1}, + [ + { + "name": "Automated Cooling System", + "description": "Energy efficient AC system", + "recommended_experience": "Thermodynamics", + "pay": 15.0, + "semester": "Spring", + "year": 2024, + "active": True + }, + { + "name": "Iphone 15 durability test", + "description": "Scratching the Iphone, drop testing etc.", + "recommended_experience": "Experienced in getting angry and throwing temper tantrum", + "pay": None, + "semester": "Spring", + "year": 2024, + "active": True + } + ] + ), + ( + {"id": 2}, + [ + { + "name": "Checking out cubes", + "description": "Material Sciences", + "recommended_experience": "Experienced in materials.", + "pay": None, + "semester": "Fall", + "year": 2024, + "active": True + }, + { + "name": "Test the water", + "description": "Testing the quality of water in Troy pipes", + "recommended_experience": "Understanding of lead poisioning", + "pay": None, + "semester": "Summer", + "year": 2024, + "active": True + } + ] + ) +]) +def test_user_opportunity_cards(test_client: FlaskClient, input_data, expected_opportunities) -> None: """ GIVEN a Flask application configured for testing - WHEN the '/user' page is requested (GET) - THEN check that the response is valid + WHEN the '/user' page is requested (GET) with input data + THEN check that the opportunity cards in the response are valid """ - response = test_client.get("/user", json={"id": 2}) - + response = test_client.get("/user", json=input_data) assert response.status_code == 200 - json_data = json.loads(response.data) - lab_manager_opportunities_data = ( - ( - "Checking out cubes", - "Material Sciences", - "Experienced in materials.", - None, - "Fall", - 2024, - True, - ), - ( - "Test the water", - "Testing the quality of water in Troy pipes", - "Understanding of lead poisioning", - None, - "Summer", - 2024, - True, - ), - ) - for i, item in enumerate(json_data["opportunities"]): - assert item["name"] == lab_manager_opportunities_data[i][0] - assert item["description"] == lab_manager_opportunities_data[i][1] - assert item["recommended_experience"] == lab_manager_opportunities_data[i][2] - assert item["pay"] == lab_manager_opportunities_data[i][3] - assert item["semester"] == lab_manager_opportunities_data[i][4] - assert item["year"] == lab_manager_opportunities_data[i][5] - assert item["active"] == lab_manager_opportunities_data[i][6] - - -def test_user_route_no_json(test_client: FlaskClient) -> None: + assert item == expected_opportunities[i] + +@pytest.mark.parametrize("input_data, expected_status", [ + (None, 400), + ({"wrong": "wrong"}, 400), + ({"id": "not found"}, 404) +]) +def test_user_route_edge_cases(test_client: FlaskClient, input_data, expected_status) -> None: """ GIVEN a Flask application configured for testing - WHEN the '/user' page is requested (GET) - THEN check that the response is valid + WHEN the '/user' page is requested (GET) with various edge case inputs + THEN check that the response status code is as expected """ - response = test_client.get("/user") - - assert response.status_code == 400 - - -def test_user_route_incorrect_json(test_client: FlaskClient) -> None: - """ - GIVEN a Flask application configured for testing - WHEN the '/user' page is requested (GET) - THEN check that the response is valid - """ - response = test_client.get("/user", json={"wrong": "wrong"}) - - assert response.status_code == 400 - - -def test_user_not_found(test_client: FlaskClient) -> None: - """ - GIVEN a Flask application configured for testing - WHEN the '/user' page is requested (GET) - THEN check that the response is valid - """ - response = test_client.get("/user", json={"id": "not found"}) - - print(json.loads(response.data)) - - assert response.status_code == 404 + response = test_client.get("/user", json=input_data) + assert response.status_code == expected_status From a900f5f2f424767595d7d24471334730fd63d8a4 Mon Sep 17 00:00:00 2001 From: youssefr26 Date: Tue, 12 Nov 2024 16:23:46 -0500 Subject: [PATCH 66/99] Clean up Deepsource error. --- labconnect/main/auth_routes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/labconnect/main/auth_routes.py b/labconnect/main/auth_routes.py index 5eb0570..7824313 100644 --- a/labconnect/main/auth_routes.py +++ b/labconnect/main/auth_routes.py @@ -55,7 +55,7 @@ def saml_login(): and current_app.config["FRONTEND_URL"] == "http://localhost:3000" ): # Generate JWT - code = generate_temporary_code("test@rpi.edu") + code = generate_temporary_code("test@rpi.edu", True) # Send the JWT to the frontend return redirect(f"{current_app.config['FRONTEND_URL']}/callback/?code={code}") From 9e86ce10347ed66172252916025b6f040dbfe631 Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Tue, 12 Nov 2024 17:35:04 -0500 Subject: [PATCH 67/99] Cleanup local login testing --- labconnect/main/auth_routes.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/labconnect/main/auth_routes.py b/labconnect/main/auth_routes.py index ca9b7d4..fae2de9 100644 --- a/labconnect/main/auth_routes.py +++ b/labconnect/main/auth_routes.py @@ -45,9 +45,9 @@ def validate_code_and_get_user_email(code: str) -> str | None: def saml_login(): # In testing skip RPI login purely for local development - if ( - current_app.config["TESTING"] - and current_app.config["FRONTEND_URL"] == "http://localhost:3000" + if current_app.config["TESTING"] and ( + current_app.config["FRONTEND_URL"] == "http://localhost:3000" + or current_app.config["FRONTEND_URL"] == "http://127.0.0.1:3000" ): # Generate JWT code = generate_temporary_code("test@rpi.edu") From 03bb278232d8c36d2c24b97d16cebeea66c401b0 Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Tue, 12 Nov 2024 17:35:22 -0500 Subject: [PATCH 68/99] Fix create route, start work on edit --- labconnect/main/opportunity_routes.py | 121 +++++++++++++------------- 1 file changed, 59 insertions(+), 62 deletions(-) diff --git a/labconnect/main/opportunity_routes.py b/labconnect/main/opportunity_routes.py index c253f2e..d253fde 100644 --- a/labconnect/main/opportunity_routes.py +++ b/labconnect/main/opportunity_routes.py @@ -145,7 +145,6 @@ def packageIndividualOpportunity(opportunityInfo): ) queryInfo = query.all() - print(queryInfo) if len(queryInfo) == 0: return data @@ -613,51 +612,31 @@ def createOpportunity(): abort(400) author = db.session.execute( - db.select(User).where(User.email == user_id) + db.select(User).where(User.email == user_id[0]) ).scalar_one_or_none() if author is None or author.lab_manager_id is None: abort(400) - authorID = author.lab_manager_id - newPostData = request_data[0] - - # query database to see if the credentials above match - # query = db.session.execute(db.select(LabManager).where(LabManager.id == authorID)) - - # data = query.all()[0][0] - - # TODO: how do we get the opportunity id? - # if match is found, create a new opportunity with the new data provided - - if not newPostData["hourlyPay"].isdigit(): - abort(400) - - pay = int(newPostData["hourlyPay"]) - - one = False - two = False - three = False - four = False + try: + pay = int(request_data["hourlyPay"]) + except: + pay = None - if "1" in newPostData["credits"]: - one = True - if "2" in newPostData["credits"]: - two = True - if "3" in newPostData["credits"]: - three = True - if "4" in newPostData["credits"]: - four = True + one = True if "1" in request_data["credits"] else False + two = True if "2" in request_data["credits"] else False + three = True if "3" in request_data["credits"] else False + four = True if "4" in request_data["credits"] else False - lenum = convert_to_enum(newPostData["location"]) + lenum = convert_to_enum(request_data["location"]) if lenum is None: lenum = LocationEnum.TBD newOpportunity = Opportunities( - name=newPostData["title"], - description=newPostData["description"], - recommended_experience=newPostData["recommended_experience"], + name=request_data["title"], + description=request_data["description"], + recommended_experience=request_data["recommended_experience"], pay=pay, one_credit=one, two_credits=two, @@ -665,7 +644,7 @@ def createOpportunity(): four_credits=four, semester=SemesterEnum.FALL, year=datetime.now().year, - application_due=datetime.strptime(newPostData["application_due"], "%Y-%m-%d"), + application_due=datetime.strptime(request_data["application_due"], "%Y-%m-%d"), active=True, location=lenum, last_updated=datetime.now(), @@ -673,7 +652,9 @@ def createOpportunity(): db.session.add(newOpportunity) db.session.commit() - newLead = Leads(lab_manager_id=authorID, opportunity_id=newOpportunity.id) + newLead = Leads( + lab_manager_id=author.lab_manager_id, opportunity_id=newOpportunity.id + ) db.session.add(newLead) db.session.commit() @@ -691,7 +672,7 @@ def createOpportunity(): # db.session.add(newMajor) # db.session.commit() - for year in newPostData["years"]: + for year in request_data["years"]: if year.isdigit(): recommended_year = int(year) newYear = RecommendsClassYears( @@ -700,7 +681,7 @@ def createOpportunity(): db.session.add(newYear) db.session.commit() - return {"data": "Opportunity Created"} + return {"data": "Opportunity Created", "id": newOpportunity.id}, 200 @main_blueprint.get("/editOpportunity/") @@ -715,18 +696,18 @@ def editOpportunity_get(opportunity_id): opportunity = opportunity[0] # Query related courses - courses_data = db.session.execute( - db.select(RecommendsCourses.course_code).where( - RecommendsCourses.opportunity_id == opportunity_id - ) - ).all() + # courses_data = db.session.execute( + # db.select(RecommendsCourses.course_code).where( + # RecommendsCourses.opportunity_id == opportunity_id + # ) + # ).all() # Query related majors - majors_data = db.session.execute( - db.select(RecommendsMajors.major_code).where( - RecommendsMajors.opportunity_id == opportunity_id - ) - ).all() + # majors_data = db.session.execute( + # db.select(RecommendsMajors.major_code).where( + # RecommendsMajors.opportunity_id == opportunity_id + # ) + # ).all() # Query related class years years_data = db.session.execute( @@ -735,26 +716,42 @@ def editOpportunity_get(opportunity_id): ) ).all() + credits = [ + str(i) + for i, credit in enumerate( + [ + opportunity.one_credit, + opportunity.two_credits, + opportunity.three_credits, + opportunity.four_credits, + ], + start=1, + ) + if credit + ] + # Format opportunity data as JSON opportunity_data = { "id": opportunity.id, - "name": opportunity.name, + "title": opportunity.name, + "application_due": opportunity.application_due.strftime("%Y-%m-%d"), + "type": ( + "Any" + if len(credits) > 0 and opportunity.pay > 0 + else "For Pay" if opportunity.pay > 0 else "For Credit" + ), + "hourlyPay": str(opportunity.pay), + "credits": credits, "description": opportunity.description, "recommended_experience": opportunity.recommended_experience, - "pay": opportunity.pay, - "one_credit": opportunity.one_credit, - "two_credits": opportunity.two_credits, - "three_credits": opportunity.three_credits, - "four_credits": opportunity.four_credits, - "semester": SemesterEnum(opportunity.semester), # Convert enum to string - "year": opportunity.year, - "application_due": opportunity.application_due.strftime("%Y-%m-%d"), - "active": opportunity.active, + # "semester": opportunity.semester, # Convert enum to string + # "year": opportunity.year, + # "active": opportunity.active, "location": opportunity.location, # Convert enum to string - "last_updated": opportunity.last_updated.strftime("%Y-%m-%d %H:%M:%S"), - "courses": [course.course_code for course in courses_data], - "majors": [major.major_code for major in majors_data], - "years": [year.class_year for year in years_data], + # "last_updated": opportunity.last_updated.strftime("%Y-%m-%d %H:%M:%S"), + # "courses": [course.course_code for course in courses_data], + # "majors": [major.major_code for major in majors_data], + "years": [str(year.class_year) for year in years_data], } return opportunity_data From f8d12ed5efce926a1091240b1e6af5763c8d3e2f Mon Sep 17 00:00:00 2001 From: youssefr26 Date: Fri, 15 Nov 2024 16:04:23 -0500 Subject: [PATCH 69/99] Updated register route --- labconnect/main/auth_routes.py | 62 ++++++++++++++++++++++++++++------ 1 file changed, 51 insertions(+), 11 deletions(-) diff --git a/labconnect/main/auth_routes.py b/labconnect/main/auth_routes.py index 7824313..2b901d4 100644 --- a/labconnect/main/auth_routes.py +++ b/labconnect/main/auth_routes.py @@ -1,13 +1,19 @@ from datetime import datetime, timedelta from uuid import uuid4 -from flask import current_app, make_response, redirect, request +from flask import current_app, make_response, redirect, request, abort from flask_jwt_extended import create_access_token, get_jwt_identity, jwt_required from onelogin.saml2.auth import OneLogin_Saml2_Auth from labconnect import db from labconnect.helpers import prepare_flask_request -from labconnect.models import User +from labconnect.models import ( + User, + UserCourses, + UserDepartments, + UserMajors, + ManagementPermissions, +) from . import main_blueprint @@ -95,25 +101,59 @@ def saml_callback(): @main_blueprint.post("/register") -@jwt_required() def registerUser(): - user_id = get_jwt_identity() - # Gather the new user's information json_data = request.get_json() + if not json_data: + abort(400) + user = User( - email=user_id, + email=json_data.get("email"), first_name=json_data.get("first_name"), last_name=json_data.get("last_name"), - preferred_name=json_data.get("preferred_name"), - class_year=json_data.get("class_year"), - profile_picture=json_data.get("profile_pictures"), - website=json_data.get("website"), - description=json_data.get("description"), + preferred_name=json_data.get("preferred_name", ""), + class_year=json_data.get("class_year", ""), + profile_picture=json_data.get( + "profile_picture", "https://www.svgrepo.com/show/206842/professor.svg" + ), + website=json_data.get("website", ""), + description=json_data.get("description", ""), ) db.session.add(user) db.session.commit() + + # Add UserDepartments if provided + if json_data.get("departments"): + for department_id in json_data["departments"]: + user_department = UserDepartments( + user_id=user.id, department_id=department_id + ) + db.session.add(user_department) + + # Additional auxiliary records (majors, courses, etc.) + if json_data.get("majors"): + for major_id in json_data["majors"]: + user_major = UserMajors(user_id=user.id, major_id=major_id) + db.session.add(user_major) + # Add Courses if provided + if json_data.get("courses"): + for course_id in json_data["courses"]: + user_course = UserCourses(user_id=user.id, course_id=course_id) + db.session.add(user_course) + + # Add ManagementPermissions if provided + if json_data.get("permissions"): + permissions = json_data["permissions"] + management_permissions = ManagementPermissions( + user_id=user.id, + super_admin=permissions.get("super_admin", False), + admin=permissions.get("admin", False), + moderator=permissions.get("moderator", False), + ) + db.session.add(management_permissions) + + db.session.commit() return {"msg": "New user added"} From 473ff8f9d90001d179bc87fca3855085501fe0fd Mon Sep 17 00:00:00 2001 From: youssefr26 Date: Fri, 15 Nov 2024 16:11:26 -0500 Subject: [PATCH 70/99] Fixed Deepsource errors --- labconnect/main/auth_routes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/labconnect/main/auth_routes.py b/labconnect/main/auth_routes.py index 2b901d4..d065ce1 100644 --- a/labconnect/main/auth_routes.py +++ b/labconnect/main/auth_routes.py @@ -2,7 +2,7 @@ from uuid import uuid4 from flask import current_app, make_response, redirect, request, abort -from flask_jwt_extended import create_access_token, get_jwt_identity, jwt_required +from flask_jwt_extended import create_access_token from onelogin.saml2.auth import OneLogin_Saml2_Auth from labconnect import db From a793085975f65d475b3b92221842dbe3a59382b0 Mon Sep 17 00:00:00 2001 From: youssefr26 Date: Fri, 15 Nov 2024 16:50:35 -0500 Subject: [PATCH 71/99] Added search route for courses --- labconnect/main/opportunity_routes.py | 36 +++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/labconnect/main/opportunity_routes.py b/labconnect/main/opportunity_routes.py index 8cd59f3..b9736af 100644 --- a/labconnect/main/opportunity_routes.py +++ b/labconnect/main/opportunity_routes.py @@ -11,6 +11,7 @@ RecommendsCourses, RecommendsMajors, User, + Courses, ) @@ -605,6 +606,41 @@ def getLabManagerOpportunityCards(rcs_id: str): # return cards +@main_blueprint.get("/searchCourses/") +def searchLabManagers(query: str): + # Perform a search on Courses table by code and name using ILIKE for exact partial matches + stmt = ( + db.select(Courses) + .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}%" + ) # Case-insensitive partial match on course name + ) + ) + ) + + results = db.session.execute(stmt).scalars().all() + + # Format results as JSON + courses = [ + { + "code": course.code, + "name": course.name, + } + for course in results + ] + + return {"courses": courses}, 200 + + # functions to create/edit/delete opportunities @main_blueprint.post("/createOpportunity") @jwt_required() From 7a682fc2829e35f0959a449ad81dc3a343934245 Mon Sep 17 00:00:00 2001 From: youssefr26 Date: Fri, 15 Nov 2024 16:51:23 -0500 Subject: [PATCH 72/99] Typo fix --- labconnect/main/opportunity_routes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/labconnect/main/opportunity_routes.py b/labconnect/main/opportunity_routes.py index b9736af..af3ecfb 100644 --- a/labconnect/main/opportunity_routes.py +++ b/labconnect/main/opportunity_routes.py @@ -607,7 +607,7 @@ def getLabManagerOpportunityCards(rcs_id: str): @main_blueprint.get("/searchCourses/") -def searchLabManagers(query: str): +def searchCourses(query: str): # Perform a search on Courses table by code and name using ILIKE for exact partial matches stmt = ( db.select(Courses) From 1b9dd71e5da7bca3572463237a2a78ee892e01e3 Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Fri, 15 Nov 2024 17:28:49 -0500 Subject: [PATCH 73/99] update db image --- docs/database_docs/Labconnect_DB.png | Bin 96719 -> 96485 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/database_docs/Labconnect_DB.png b/docs/database_docs/Labconnect_DB.png index 1bc76fe9c5739a3509fef1b0842e34f1ca63d57c..b8c8c39c3cd7efdad3aa58d75e9b61b0629fd7eb 100644 GIT binary patch delta 44561 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 fw24`Cmi_b~q7A5)(7>C3K(;{E)c^kgz*^kf delta 44837 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�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 INZs@QU&wjA8UO$Q From 97f2648bfb25e3f00197648c1e1aa75371910b90 Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Fri, 15 Nov 2024 17:29:01 -0500 Subject: [PATCH 74/99] complete create and edit routes --- labconnect/main/opportunity_routes.py | 278 +++++++++++--------------- 1 file changed, 118 insertions(+), 160 deletions(-) diff --git a/labconnect/main/opportunity_routes.py b/labconnect/main/opportunity_routes.py index d253fde..edc0c40 100644 --- a/labconnect/main/opportunity_routes.py +++ b/labconnect/main/opportunity_routes.py @@ -496,25 +496,6 @@ def getOpportunityCards(): # abort(500) -# @main_blueprint.route("/getOpportunityByProfessor/", methods=["GET"]) -# def getOpportunityByProfessor(rcs_id: str): -# if request.method == "GET": -# # query database for opportunity -# query = db.session.execute( -# db.select(Opportunities, Leads) -# .where(Leads.lab_manager_id == rcs_id) -# .join(Opportunities, Leads.opportunity_id == Opportunities.id) -# ) - -# data = query.all() -# print(data) - -# # return data in the below format if opportunity is found -# return {"data": [opportunity[0].to_dict() for opportunity in data]} - -# abort(500) - - @main_blueprint.get("/staff/opportunities/") def getLabManagerOpportunityCards(rcs_id: str): @@ -633,53 +614,41 @@ def createOpportunity(): if lenum is None: lenum = LocationEnum.TBD - newOpportunity = Opportunities( - name=request_data["title"], - description=request_data["description"], - recommended_experience=request_data["recommended_experience"], - pay=pay, - one_credit=one, - two_credits=two, - three_credits=three, - four_credits=four, - semester=SemesterEnum.FALL, - year=datetime.now().year, - application_due=datetime.strptime(request_data["application_due"], "%Y-%m-%d"), - active=True, - location=lenum, - last_updated=datetime.now(), + newOpportunity = Opportunities() + newOpportunity.name = request_data["title"] + newOpportunity.description = request_data["description"] + newOpportunity.recommended_experience = request_data["recommended_experience"] + newOpportunity.pay = pay + newOpportunity.one_credit = one + newOpportunity.two_credits = two + newOpportunity.three_credits = three + newOpportunity.four_credits = four + newOpportunity.semester = SemesterEnum.FALL + newOpportunity.year = datetime.now().year + newOpportunity.application_due = datetime.strptime( + request_data["application_due"], "%Y-%m-%d" ) + newOpportunity.active = True + newOpportunity.location = lenum + newOpportunity.last_updated = datetime.now() db.session.add(newOpportunity) db.session.commit() - newLead = Leads( - lab_manager_id=author.lab_manager_id, opportunity_id=newOpportunity.id - ) + newLead = Leads() + newLead.lab_manager_id = author.lab_manager_id + newLead.opportunity_id = newOpportunity.id db.session.add(newLead) - db.session.commit() - - # for course in newPostData["courses"]: - # newCourse = RecommendsCourses( - # opportunity_id=newOpportunity.id, course_code=course - # ) - - # db.session.add(newCourse) - # db.session.commit() - - # for major in newPostData["majors"]: - # newMajor = RecommendsMajors(opportunity_id=newOpportunity.id, major_code=major) - # db.session.add(newMajor) - # db.session.commit() for year in request_data["years"]: if year.isdigit(): recommended_year = int(year) - newYear = RecommendsClassYears( - opportunity_id=newOpportunity.id, class_year=recommended_year - ) + newYear = RecommendsClassYears() + newYear.opportunity_id = newOpportunity.id + newYear.class_year = recommended_year db.session.add(newYear) - db.session.commit() + + db.session.commit() return {"data": "Opportunity Created", "id": newOpportunity.id}, 200 @@ -730,6 +699,8 @@ def editOpportunity_get(opportunity_id): if credit ] + years = [str(year.class_year) for year in years_data] if years_data else [] + # Format opportunity data as JSON opportunity_data = { "id": opportunity.id, @@ -737,8 +708,8 @@ def editOpportunity_get(opportunity_id): "application_due": opportunity.application_due.strftime("%Y-%m-%d"), "type": ( "Any" - if len(credits) > 0 and opportunity.pay > 0 - else "For Pay" if opportunity.pay > 0 else "For Credit" + if len(credits) > 0 and opportunity.pay and opportunity.pay > 0 + else "For Pay" if opportunity.pay and opportunity.pay > 0 else "For Credit" ), "hourlyPay": str(opportunity.pay), "credits": credits, @@ -751,7 +722,7 @@ def editOpportunity_get(opportunity_id): # "last_updated": opportunity.last_updated.strftime("%Y-%m-%d %H:%M:%S"), # "courses": [course.course_code for course in courses_data], # "majors": [major.major_code for major in majors_data], - "years": [str(year.class_year) for year in years_data], + "years": years, } return opportunity_data @@ -761,102 +732,100 @@ def editOpportunity_get(opportunity_id): @jwt_required() def editOpportunity(opportunity_id): - if not request.data: + user_id = get_jwt_identity() + if not request.data or not user_id: abort(400) - data = request.get_json() + request_data = request.get_json() - if not data: + if not request_data: abort(400) # Check if the opportunity and author exist opportunity = db.session.execute( db.select(Opportunities).where(Opportunities.id == opportunity_id) - ).first() + ).scalar_one_or_none() - if not opportunity: - return {"error": "Opportunity not found"}, 404 + if opportunity is None: + abort(400) - opportunity = opportunity[0] - data = data[0] + author = db.session.execute( + db.select(User).where(User.email == user_id[0]) + ).scalar_one_or_none() - # TODO: Add check to see if person has permission to edit opportunity - user_id = get_jwt_identity() + if author is None or author.lab_manager_id is None: + abort(400) - lab_manager = db.session.execute( - db.select(LabManager) - .join(User, User.lab_manager_id == LabManager.id) - .where(User.email == user_id) + leads = db.session.execute( + db.select(Leads) + .where(Leads.opportunity_id == opportunity_id) + .where(Leads.lab_manager_id == author.lab_manager_id) ).scalar_one_or_none() - if lab_manager: - lead = db.session.execute( - db.select(Leads).where( - Leads.lab_manager_id == lab_manager.id, - Leads.opportunity_id == opportunity.id, - ) - ).scalar_one_or_none() - if not lead: - return {"error": "Don't have permission to edit!"}, 401 - else: - return {"error": "Don't have permission to edit!"}, 401 + if leads is None: + abort(400) + + try: + pay = int(request_data["hourlyPay"]) + except: + pay = None + + one = True if "1" in request_data["credits"] else False + two = True if "2" in request_data["credits"] else False + three = True if "3" in request_data["credits"] else False + four = True if "4" in request_data["credits"] else False + + lenum = convert_to_enum(request_data["location"]) + + if lenum is None: + lenum = LocationEnum.TBD # Update fields for opportunity based on the input data - opportunity.name = data["name"] - opportunity.description = data["description"] - opportunity.recommended_experience = data["recommended_experience"] - opportunity.pay = data["pay"] - opportunity.one_credit = data["one_credit"] - opportunity.two_credits = data["two_credits"] - opportunity.three_credits = data["three_credits"] - opportunity.four_credits = data["four_credits"] - opportunity.semester = ( - SemesterEnum[(data["semester"]).upper()] - if "semester" in data - else opportunity.semester + opportunity.name = request_data["title"] + opportunity.description = request_data["description"] + opportunity.recommended_experience = request_data["recommended_experience"] + opportunity.pay = pay + opportunity.one_credit = one + opportunity.two_credits = two + opportunity.three_credits = three + opportunity.four_credits = four + opportunity.application_due = datetime.strptime( + request_data["application_due"], "%Y-%m-%d" ) - opportunity.year = data["year"] - opportunity.application_due = ( - datetime.datetime.strptime(data["application_due"], "%Y-%m-%d") - if "application_due" in data - else opportunity.application_due - ) - opportunity.active = data["active"] - opportunity.location = ( - convert_to_enum(data["location"]) - if "location" in data - else opportunity.location - ) - opportunity.last_updated = datetime.datetime.now() - - # Update related tables for courses, majors, and years - # Clear current recommendations - db.session.query(RecommendsCourses).filter_by( - opportunity_id=opportunity_id - ).delete() - db.session.query(RecommendsMajors).filter_by(opportunity_id=opportunity_id).delete() - db.session.query(RecommendsClassYears).filter_by( - opportunity_id=opportunity_id - ).delete() - - # Re-add new recommendations - for course in data["courses"]: - newCourse = RecommendsCourses(opportunity_id=opportunity.id, course_code=course) - - db.session.add(newCourse) - db.session.commit() - - for major in data["majors"]: - newMajor = RecommendsMajors(opportunity_id=opportunity.id, major_code=major) - db.session.add(newMajor) - db.session.commit() - - for year in data["years"]: - newYear = RecommendsClassYears(opportunity_id=opportunity.id, class_year=year) + # opportunity.active = data["active"] + opportunity.location = lenum + opportunity.last_updated = datetime.now() + + existing_years = { + str(year.class_year) + for year in db.session.execute( + db.select(RecommendsClassYears).where( + RecommendsClassYears.opportunity_id == opportunity_id + ) + ).scalars() + } + new_years = set(request_data["years"]) + + # Years to add + years_to_add = new_years - existing_years + for year in years_to_add: + newYear = RecommendsClassYears() + newYear.opportunity_id = opportunity.id + newYear.class_year = int(year) db.session.add(newYear) - db.session.commit() - # Commit all changes to the database + # Years to remove + years_to_remove = existing_years - new_years + if years_to_remove: + db.session.execute( + db.select(RecommendsClassYears) + .where( + RecommendsClassYears.opportunity_id == opportunity_id, + RecommendsClassYears.class_year.in_(years_to_remove), + ) + .delete(synchronize_session=False) + ) + db.session.commit() return {"data": "Opportunity Updated"}, 200 @@ -873,35 +842,24 @@ def deleteOpportunity(opportunity_id): # TODO: Add check to see if user has permission to delete opportunity user_id = get_jwt_identity() - lab_manager = db.session.execute( - db.select(LabManager) - .join(User, User.lab_manager_id == LabManager.id) - .where(User.email == user_id) + user = db.session.execute( + db.select(User).where(User.email == user_id) ).scalar_one_or_none() - if lab_manager: - lead = db.session.execute( - db.select(Leads).where( - Leads.lab_manager_id == lab_manager.id, - Leads.opportunity_id == opportunity.id, - ) - ).scalar_one_or_none() - if not lead: - return {"error": "Don't have permission to delete!"}, 401 - else: + if not user or not user.lab_manager_id: return {"error": "Don't have permission to delete!"}, 401 - # Delete related records in other tables (e.g., Leads, RecommendsCourses, RecommendsMajors, RecommendsClassYears) - db.session.query(Leads).filter_by(opportunity_id=opportunity_id).delete() - db.session.query(RecommendsCourses).filter_by( - opportunity_id=opportunity_id - ).delete() - db.session.query(RecommendsMajors).filter_by(opportunity_id=opportunity_id).delete() - db.session.query(RecommendsClassYears).filter_by( - opportunity_id=opportunity_id - ).delete() - - # Delete the opportunity itself + leads = db.session.execute( + db.select(Leads) + .where(Leads.opportunity_id == opportunity_id) + .where(Leads.lab_manager_id == user.lab_manager_id) + ).scalar_one_or_none() + + if not leads: + abort(400) + + # Delete the opportunity + # cascading delete will handle all other tables db.session.delete(opportunity) db.session.commit() From 5e061ab08fed6d988e602f91bc2eb7fd466e7140 Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Fri, 15 Nov 2024 17:35:02 -0500 Subject: [PATCH 75/99] Small tweaks --- labconnect/main/opportunity_routes.py | 5 ++--- labconnect/main/routes.py | 14 +------------- 2 files changed, 3 insertions(+), 16 deletions(-) diff --git a/labconnect/main/opportunity_routes.py b/labconnect/main/opportunity_routes.py index aca43b8..4b6c1e8 100644 --- a/labconnect/main/opportunity_routes.py +++ b/labconnect/main/opportunity_routes.py @@ -1,4 +1,5 @@ from datetime import datetime + from flask import abort, request from flask_jwt_extended import get_jwt_identity, jwt_required @@ -9,12 +10,9 @@ Leads, Opportunities, RecommendsClassYears, - RecommendsCourses, - RecommendsMajors, User, ) - from . import main_blueprint @@ -507,6 +505,7 @@ def getOpportunityCards(): # abort(500) + @main_blueprint.get("/staff/opportunities/") def getLabManagerOpportunityCards(rcs_id: str): diff --git a/labconnect/main/routes.py b/labconnect/main/routes.py index 4fdca56..0b5aa7a 100644 --- a/labconnect/main/routes.py +++ b/labconnect/main/routes.py @@ -5,26 +5,14 @@ from labconnect import db from labconnect.models import ( - # ClassYears, - # Courses, LabManager, Leads, - # Majors, Opportunities, - # Participates, - # RecommendsClassYears, - # RecommendsCourses, - # RecommendsMajors, RPIDepartments, - # RPISchools, User, - # UserCourses, - # UserDepartments, - # UserMajors, + ClassYears, ) -# = not currently using - from . import main_blueprint From 69d45aedb49ba9c752e4678dd9e3f2ba8b5fe3cc Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Fri, 15 Nov 2024 18:29:41 -0500 Subject: [PATCH 76/99] fix missing code --- labconnect/main/opportunity_routes.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/labconnect/main/opportunity_routes.py b/labconnect/main/opportunity_routes.py index 423be5b..4d04eb6 100644 --- a/labconnect/main/opportunity_routes.py +++ b/labconnect/main/opportunity_routes.py @@ -609,7 +609,13 @@ def searchLabManagers(query: str): User.email.ilike( f"%{query}%" ) # Case-insensitive partial match on email - lab_managers = [ + ) + ) + ) + + results = db.session.execute(stmt).scalars().all() + + lab_managers = [ { "lab_manager_id": user.lab_manager_id, "first_name": user.first_name, @@ -621,6 +627,7 @@ def searchLabManagers(query: str): return {"lab_managers": lab_managers}, 200 + @main_blueprint.get("/searchCourses/") def searchCourses(query: str): # Perform a search on Courses table by code and name using ILIKE for exact partial matches @@ -726,7 +733,7 @@ def createOpportunity(): db.session.add(newYear) db.session.commit() - + return {"data": "Opportunity Created", "id": newOpportunity.id}, 200 From dec5adc630f009b142a4535c5dc46d878c6bbcf7 Mon Sep 17 00:00:00 2001 From: youssefr26 Date: Fri, 22 Nov 2024 16:19:14 -0500 Subject: [PATCH 77/99] Fixed getOpportunity route --- labconnect/main/opportunity_routes.py | 97 +++++++++++---------------- 1 file changed, 40 insertions(+), 57 deletions(-) diff --git a/labconnect/main/opportunity_routes.py b/labconnect/main/opportunity_routes.py index 4d04eb6..84d6115 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 @@ -108,16 +109,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 +131,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 +150,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,24 +194,36 @@ 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) -# ) +@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 = query.all() + data = query.all() + print(data) -# # check if opportunity exists -# if not data or len(data) == 0: -# abort(404) + # check if opportunity exists + if not data or len(data) == 0: + abort(404) -# data = data[0] -# oppData = packageIndividualOpportunity(data[0]) + data = data[0] + oppData = packageIndividualOpportunity(data[0]) + oppData["recommended_class_years"] = data[1] -# # return data in the below format if opportunity is found -# return {"data": oppData} + # return data in the below format if opportunity is found + return {"data": oppData} # @main_blueprint.get("/opportunity/filter") @@ -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}%" From 9a7063a15905430e17662ef78aa98a99487fed8b Mon Sep 17 00:00:00 2001 From: Mrunal Athaley <112527910+athalm@users.noreply.github.com> Date: Fri, 22 Nov 2024 16:30:07 -0500 Subject: [PATCH 78/99] updated test_opportunity test parameterization --- tests/test_opportunity.py | 384 +++++++++++--------------------------- 1 file changed, 109 insertions(+), 275 deletions(-) diff --git a/tests/test_opportunity.py b/tests/test_opportunity.py index e37f954..b6ade78 100644 --- a/tests/test_opportunity.py +++ b/tests/test_opportunity.py @@ -1,305 +1,139 @@ -""" -Test opportunity routes -""" - import json - -from flask import json +import pytest from flask.testing import FlaskClient -from labconnect import db -from labconnect.helpers import OrJSONProvider, SemesterEnum -from labconnect.models import ( - ClassYears, - Courses, - LabManager, - Leads, - Majors, - Opportunities, - RecommendsClassYears, - RecommendsCourses, - RecommendsMajors, - RPIDepartments, - RPISchools, -) - - -def test_get_opportunity(test_client: FlaskClient) -> None: +def test_get_opportunity_parametrized(test_client: FlaskClient): """ GIVEN a Flask application configured for testing - WHEN the '/opportunity' page is requested (GET) - THEN check that the response is valid + WHEN the '/opportunity' page is requested (GET) with different IDs + THEN check that the responses are valid """ - response1 = test_client.get("/opportunity", json={"id": 1}) - response2 = test_client.get("/opportunity", json={"id": 2}) - - assert response1.status_code == 200 - assert response2.status_code == 200 - - json_data1 = json.loads(response1.data) - json_data2 = json.loads(response2.data) - - lab_manager_opportunities_data = ( - ( - "Automated Cooling System", - "Energy efficient AC system", - "Thermodynamics", - 15.0, - False, - False, - False, - True, - "Spring", - 2024, - True, - ), - ( - "Iphone 15 durability test", - "Scratching the Iphone, drop testing etc.", - "Experienced in getting angry and throwing temper tantrum", - None, - True, - True, - True, - True, - "Spring", - 2024, - True, - ), - ) - - assert json_data1["name"] == lab_manager_opportunities_data[0][0] - assert json_data1["description"] == lab_manager_opportunities_data[0][1] - assert json_data1["recommended_experience"] == lab_manager_opportunities_data[0][2] - assert json_data1["pay"] == lab_manager_opportunities_data[0][3] - assert json_data1["one_credit"] == lab_manager_opportunities_data[0][4] - assert json_data1["two_credits"] == lab_manager_opportunities_data[0][5] - assert json_data1["three_credits"] == lab_manager_opportunities_data[0][6] - assert json_data1["four_credits"] == lab_manager_opportunities_data[0][7] - assert json_data1["semester"] == lab_manager_opportunities_data[0][8] - assert json_data1["year"] == lab_manager_opportunities_data[0][9] - assert json_data1["active"] == lab_manager_opportunities_data[0][10] - - assert json_data2["name"] == lab_manager_opportunities_data[1][0] - assert json_data2["description"] == lab_manager_opportunities_data[1][1] - assert json_data2["recommended_experience"] == lab_manager_opportunities_data[1][2] - assert json_data2["pay"] == lab_manager_opportunities_data[1][3] - assert json_data2["one_credit"] == lab_manager_opportunities_data[1][4] - assert json_data2["two_credits"] == lab_manager_opportunities_data[1][5] - assert json_data2["three_credits"] == lab_manager_opportunities_data[1][6] - assert json_data2["four_credits"] == lab_manager_opportunities_data[1][7] - assert json_data2["semester"] == lab_manager_opportunities_data[1][8] - assert json_data2["year"] == lab_manager_opportunities_data[1][9] - assert json_data2["active"] == lab_manager_opportunities_data[1][10] - - print(json_data2) - - -def test_get_opportunity_no_json(test_client: FlaskClient) -> None: + test_cases = [ + (1, { + "name": "Automated Cooling System", + "description": "Energy efficient AC system", + "recommended_experience": "Thermodynamics", + "pay": 15.0, + "one_credit": False, + "two_credits": False, + "three_credits": False, + "four_credits": True, + "semester": "Spring", + "year": 2024, + "active": True, + }), + (2, { + "name": "Iphone 15 durability test", + "description": "Scratching the Iphone, drop testing etc.", + "recommended_experience": "Experienced in getting angry and throwing temper tantrum", + "pay": None, + "one_credit": True, + "two_credits": True, + "three_credits": True, + "four_credits": True, + "semester": "Spring", + "year": 2024, + "active": True, + }), + ] + + for opportunity_id, expected_data in test_cases: + response = test_client.get("/opportunity", json={"id": opportunity_id}) + assert response.status_code == 200 + + json_data = json.loads(response.data) + for key, value in expected_data.items(): + assert json_data[key] == value + + +def test_get_opportunity_no_json(test_client: FlaskClient): """ GIVEN a Flask application configured for testing - WHEN the '/opportunity' page is requested (GET) - THEN check that the response is valid + WHEN the '/opportunity' page is requested (GET) without JSON payload + THEN check that the response is 400 """ response = test_client.get("/opportunity") - assert response.status_code == 400 -def test_opportunity_incorrect_json(test_client: FlaskClient) -> None: +def test_opportunity_incorrect_json(test_client: FlaskClient): """ GIVEN a Flask application configured for testing - WHEN the '/opportunity' page is requested (GET) - THEN check that the response is valid + WHEN the '/opportunity' page is requested (GET) with incorrect JSON + THEN check that the response is 400 """ response = test_client.get("/opportunity", json={"wrong": "wrong"}) - assert response.status_code == 400 -def test_get_opportunity_meta(test_client: FlaskClient) -> None: +@pytest.mark.parametrize( + "endpoint, expected_keys", + [ + ("/getOpportunityMeta/1", [ + "name", + "description", + "recommended_experience", + "pay", + "credits", + "semester", + "year", + "application_due", + "active", + "courses", + "majors", + "years", + ]), + ("/getOpportunity/2", [ + "id", + "name", + "description", + "recommended_experience", + "author", + "department", + "aboutSection", + ]), + ], +) +def test_opportunity_meta_parametrized(test_client: FlaskClient, endpoint, expected_keys): """ GIVEN a Flask application configured for testing - WHEN the '/getOpportunityMeta' endpoint is requested (GET) with valid data - THEN check that the response is valid and contains expected opportunity data + WHEN specific opportunity endpoints are requested + THEN check that the response contains the expected keys """ - - response = test_client.get("/getOpportunityMeta/1", content_type="application/json") - - # assert response.status_code == 200 - - data = json.loads(response.data) - data = data["data"] - - # Assertions on the expected data - assert "name" in data - assert "description" in data - assert "recommended_experience" in data - assert "pay" in data - assert "credits" in data - assert "semester" in data - assert "year" in data - assert "application_due" in data - assert "active" in data - assert "courses" in data - assert "majors" in data - assert "years" in data - assert "active" in data - - -def test_get_opportunity(test_client: FlaskClient) -> None: - response = test_client.get("/getOpportunity/2") - - assert response.status_code == 200 - - # Load the response data as JSON - data = json.loads(response.data.decode("utf-8")) - data = data["data"] - - # Test that the "name" key exists - assert "id" in data - assert "name" in data - assert "description" in data - assert "recommended_experience" in data - assert "author" in data - assert "department" in data - assert "aboutSection" in data - - for eachSection in data["aboutSection"]: - assert "title" in eachSection - assert "description" in eachSection - - -def test_get_opportunity_professor(test_client: FlaskClient) -> None: - response = test_client.get("/getOpportunityByProfessor/led") - + response = test_client.get(endpoint, content_type="application/json") assert response.status_code == 200 - # Load the response data as JSON - data = json.loads(response.data.decode("utf-8")) - data = data["data"] - - # Test that the "name" key exists - for opportunity in data: - assert "id" in opportunity - assert "name" in opportunity - assert "description" in opportunity - assert "recommended_experience" in opportunity - assert "pay" in opportunity - # assert "credits" in opportunity - assert "semester" in opportunity - assert "year" in opportunity - assert "application_due" in opportunity - assert "active" in opportunity - # assert "professor" in opportunity - # assert "department" in opportunity - - -def test_get_professor_opportunity_cards(test_client: FlaskClient) -> None: - response = test_client.get( - "/getProfessorOpportunityCards/led", content_type="application/json" - ) - - assert response.status_code == 200 - - data = json.loads(response.data.decode("utf-8")) - data = data["data"] - - for eachCard in data: - assert "title" in eachCard - assert "body" in eachCard - assert "attributes" in eachCard - assert "id" in eachCard - - -def test_profile_opportunities(test_client: FlaskClient) -> None: - response = test_client.get( - "/getProfileOpportunities/led", content_type="application/json" - ) - - assert response.status_code == 200 - - data = json.loads(response.data.decode("utf-8")) - data = data["data"] - - for eachCard in data: - assert "id" in eachCard - assert "title" in eachCard - assert "body" in eachCard - assert "attributes" in eachCard - assert "activeStatus" in eachCard - - -def test_create_opportunity(test_client: FlaskClient) -> None: + data = json.loads(response.data) + if "data" in data: + data = data["data"] + + for key in expected_keys: + if isinstance(data, list): + for item in data: + assert key in item + else: + assert key in data + + +@pytest.mark.parametrize( + "endpoint", [ + "/getOpportunityByProfessor/led", + "/getProfessorOpportunityCards/led", + "/getProfileOpportunities/led", + ] +) +def test_professor_related_opportunities(test_client: FlaskClient, endpoint): """ GIVEN a Flask application configured for testing - WHEN the '/createOpportunity' endpoint is requested (POST) with valid data - THEN check that the response is valid and contains expected data + WHEN professor-related endpoints are requested + THEN check that the response contains expected keys in each card """ - - test_data = { - "authorID": "led", - "name": "Some test opportunity", - "description": "Some test description", - "recommended_experience": "Some test experience", - "pay": 25.0, - "credits": ["1", "2", "3", "4"], - "semester": "FALL", - "year": 2024, - "application_due": "2024-03-30", - "active": True, - "courses": ["CSCI4430"], - "majors": ["BIOL"], - "years": [2023, 2024], - "active": True, - "location": "TBD", - } - - response = test_client.post( - "/createOpportunity", - data=json.dumps(test_data), - content_type="application/json", - ) - + response = test_client.get(endpoint, content_type="application/json") assert response.status_code == 200 - # query database to check for new opportunity with the same name - query = db.session.query(Opportunities).filter( - Opportunities.name == "Some test opportunity", - Opportunities.description == "Some test description", - Opportunities.recommended_experience == "Some test experience", - ) - - data = query.first() - assert data is not None - id = data.id - - # delete the opportunity by sending request to deleteOpportunity - response = test_client.post( - "/deleteOpportunity", - data=json.dumps({"id": id}), - content_type="application/json", - ) - - assert response.status_code == 200 - - # check that the opportunity was deleted - query = db.session.query(Opportunities).filter(Opportunities.id == id) - assert query.first() is None - - -def test_professor_opportunity_cards(test_client: FlaskClient) -> None: - - response = test_client.get("/getProfessorOpportunityCards/led") - assert response.status_code == 200 - - # Load the response data as JSON - data = json.loads(response.data.decode("utf-8")) - - # Test that the "name" key exists - assert len(data.keys()) > 0 - for eachCard in data["data"]: - assert "title" in eachCard - assert "body" in eachCard - assert "attributes" in eachCard - assert "id" in eachCard + data = json.loads(response.data)["data"] + for each_card in data: + assert "id" in each_card + assert "title" in each_card or "name" in each_card + assert "body" in each_card or "description" in each_card + assert "attributes" in each_card or "recommended_experience" in each_card From a2e0995c46d15c47012d7749ce88d258364fcac3 Mon Sep 17 00:00:00 2001 From: youssefr26 Date: Fri, 22 Nov 2024 17:05:15 -0500 Subject: [PATCH 79/99] Updated and forated Oppotrunity filter route --- labconnect/main/opportunity_routes.py | 256 +++++++++++++------------- 1 file changed, 128 insertions(+), 128 deletions(-) diff --git a/labconnect/main/opportunity_routes.py b/labconnect/main/opportunity_routes.py index 84d6115..52f9593 100644 --- a/labconnect/main/opportunity_routes.py +++ b/labconnect/main/opportunity_routes.py @@ -13,6 +13,7 @@ RecommendsClassYears, User, Courses, + RecommendsMajors, ) from . import main_blueprint @@ -226,144 +227,143 @@ def getOpportunity(opp_id: int): return {"data": oppData} -# @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 +@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 -##@main_blueprint.route("/opportunity/filter", methods=["POST"]) -##def filterOpportunities(): -# Handle POST requests for filtering opportunities -##json_request_data = request.get_json() +@main_blueprint.post("/opportunity/filter") +def filterOpportunities(): + # Handle POST requests for filtering opportunities + json_request_data = request.get_json() + if not json_request_data: + abort(400) -# if not json_request_data: -# abort(400) + filters = json_request_data.get("filters", None) -# filters = json_request_data.get("filters", None) + data = None -# data = None + if filters is None: + data = db.session.execute(db.select(Opportunities).limit(20)).scalars() -# if filters is None: -# data = db.session.execute(db.select(Opportunities).limit(20)).scalars() + elif not isinstance(filters, list): + abort(400) -# elif not isinstance(filters, list): -# abort(400) + 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) -# else: + result = [opportunity.to_dict() for opportunity in data] -# 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 + return result # @main_blueprint.put("/opportunity") From 41fca530bc4c25b281d34c2cae9e1f95d10ddf01 Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Fri, 22 Nov 2024 18:43:09 -0500 Subject: [PATCH 80/99] clean up db init file --- db_init.py | 163 +++++++++++++++++++++++++++++++++-------------------- 1 file changed, 102 insertions(+), 61 deletions(-) diff --git a/db_init.py b/db_init.py index 798e285..6be7eec 100644 --- a/db_init.py +++ b/db_init.py @@ -49,7 +49,10 @@ ) for row_tuple in rpi_schools_rows: - row = RPISchools(name=row_tuple[0], description=row_tuple[1]) + row = RPISchools() + row.name = row_tuple[0] + row.description = row_tuple[1] + db.session.add(row) db.session.commit() @@ -78,21 +81,24 @@ ) for row_tuple in rpi_departments_rows: - row = RPIDepartments( - name=row_tuple[0], - description=row_tuple[1], - school_id=row_tuple[2], - id=row_tuple[3], - image="https://cdn-icons-png.flaticon.com/512/5310/5310672.png", - website="https://www.rpi.edu", - ) + row = RPIDepartments() + row.name = row_tuple[0] + row.description = row_tuple[1] + row.school_id = row_tuple[2] + row.id = row_tuple[3] + row.image = "https://cdn-icons-png.flaticon.com/512/5310/5310672.png" + row.website = "https://www.rpi.edu" + db.session.add(row) db.session.commit() class_years_rows = (2025, 2026, 2027, 2028, 2029, 2030, 2031) for row_item in class_years_rows: - row = ClassYears(class_year=row_item, active=True) + row = ClassYears() + row.class_year = row_item + row.active = True + db.session.add(row) db.session.commit() @@ -132,42 +138,43 @@ "https://rafaelcenzano.com", ) - lab_manager = LabManager(department_id=raf_test_user[5]) + lab_manager = LabManager() + lab_manager.department_id = raf_test_user[5] db.session.add(lab_manager) db.session.commit() - user = User( - id=raf_test_user[0], - email=raf_test_user[0] + "@rpi.edu", - first_name=raf_test_user[1], - last_name=raf_test_user[2], - preferred_name=raf_test_user[3], - class_year=raf_test_user[4], - lab_manager_id=lab_manager.id, - description=raf_test_user[6], - profile_picture=raf_test_user[7], - website=raf_test_user[8], - ) + user = User() + user.id = raf_test_user[0] + user.email = raf_test_user[0] + "@rpi.edu" + user.first_name = raf_test_user[1] + user.last_name = raf_test_user[2] + user.preferred_name = raf_test_user[3] + user.class_year = raf_test_user[4] + user.lab_manager_id = lab_manager.id + user.description = raf_test_user[6] + user.profile_picture = raf_test_user[7] + user.website = raf_test_user[8] db.session.add(user) db.session.commit() for row_tuple in lab_manager_rows: - lab_manager = LabManager(department_id=row_tuple[3]) + lab_manager = LabManager() + lab_manager.department_id = row_tuple[3] db.session.add(lab_manager) db.session.commit() - user = User( - id=row_tuple[0], - email=row_tuple[0] + "@rpi.edu", - first_name=row_tuple[1], - last_name=row_tuple[2], - lab_manager_id=lab_manager.id, - description=row_tuple[4], - profile_picture="https://www.svgrepo.com/show/206842/professor.svg", - ) + user = User() + user.id = row_tuple[0] + user.email = row_tuple[0] + "@rpi.edu" + user.first_name = row_tuple[1] + user.last_name = row_tuple[2] + user.lab_manager_id = lab_manager.id + user.description = row_tuple[4] + user.profile_picture = "https://www.svgrepo.com/show/206842/professor.svg" + db.session.add(user) db.session.commit() @@ -255,22 +262,22 @@ ) for row_tuple in opportunities_rows: - row = Opportunities( - name=row_tuple[0], - description=row_tuple[1], - recommended_experience=row_tuple[2], - pay=row_tuple[3], - one_credit=row_tuple[4], - two_credits=row_tuple[5], - three_credits=row_tuple[6], - four_credits=row_tuple[7], - semester=row_tuple[8], - year=row_tuple[9], - application_due=row_tuple[10], - active=row_tuple[11], - last_updated=row_tuple[12], - location=row_tuple[13], - ) + row = Opportunities() + row.name = row_tuple[0] + row.description = row_tuple[1] + row.recommended_experience = row_tuple[2] + row.pay = row_tuple[3] + row.one_credit = row_tuple[4] + row.two_credits = row_tuple[5] + row.three_credits = row_tuple[6] + row.four_credits = row_tuple[7] + row.semester = row_tuple[8] + row.year = row_tuple[9] + row.application_due = row_tuple[10] + row.active = row_tuple[11] + row.last_updated = row_tuple[12] + row.location = row_tuple[13] + db.session.add(row) db.session.commit() @@ -282,7 +289,10 @@ ) for row_tuple in courses_rows: - row = Courses(code=row_tuple[0], name=row_tuple[1]) + row = Courses() + row.code = row_tuple[0] + row.name = row_tuple[1] + db.session.add(row) db.session.commit() @@ -296,7 +306,10 @@ ) for row_tuple in majors_rows: - row = Majors(code=row_tuple[0], name=row_tuple[1]) + row = Majors() + row.code = row_tuple[0] + row.name = row_tuple[1] + db.session.add(row) db.session.commit() @@ -313,28 +326,40 @@ ) for r in leads_rows: - row = Leads(lab_manager_id=r[0], opportunity_id=r[1]) + row = Leads() + row.lab_manager_id = r[0] + row.opportunity_id = r[1] + db.session.add(row) db.session.commit() recommends_courses_rows = ((1, "CSCI4430"), (1, "CSCI2961"), (2, "CSCI4390")) for r in recommends_courses_rows: - row = RecommendsCourses(opportunity_id=r[0], course_code=r[1]) + row = RecommendsCourses() + row.opportunity_id = r[0] + row.course_code = r[1] + db.session.add(row) db.session.commit() recommends_majors_rows = ((1, "CSCI"), (1, "PHYS"), (2, "BIOL")) for r in recommends_majors_rows: - row = RecommendsMajors(opportunity_id=r[0], major_code=r[1]) + row = RecommendsMajors() + row.opportunity_id = r[0] + row.major_code = r[1] + db.session.add(row) db.session.commit() recommends_class_years_rows = ((3, 2025), (2, 2025), (2, 2026), (1, 2027)) for r in recommends_class_years_rows: - row = RecommendsClassYears(opportunity_id=r[0], class_year=r[1]) + row = RecommendsClassYears() + row.opportunity_id = r[0] + row.class_year = r[1] + db.session.add(row) db.session.commit() @@ -345,10 +370,19 @@ ) for r in user_majors: - major = UserMajors(user_id=r[0], major_code=r[1]) - department = UserDepartments(user_id=r[0], department_id=r[1]) - db.session.add(major) - db.session.add(department) + row = UserMajors() + row.user_id = r[0] + row.major_code = r[1] + + db.session.add(row) + db.session.commit() + + for r in user_majors: + row = UserDepartments() + row.user_id = r[0] + row.department_id = r[1] + + db.session.add(row) db.session.commit() user_courses = ( @@ -358,7 +392,11 @@ ) for r in user_courses: - row = UserCourses(user_id=r[0], course_code=r[1], in_progress=r[2]) + row = UserCourses() + row.user_id = r[0] + row.course_code = r[1] + row.in_progress = r[2] + db.session.add(row) db.session.commit() @@ -370,7 +408,10 @@ ) for r in participates_rows: - row = Participates(user_id=r[0], opportunity_id=r[1]) + row = Participates() + row.user_id = r[0] + row.opportunity_id = r[1] + db.session.add(row) db.session.commit() From 25137c7c0877a055053128948a73b27ba73178d7 Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Fri, 22 Nov 2024 18:44:00 -0500 Subject: [PATCH 81/99] correct auth routes --- labconnect/main/auth_routes.py | 60 +++++++++++++++++----------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/labconnect/main/auth_routes.py b/labconnect/main/auth_routes.py index c822ac3..2126739 100644 --- a/labconnect/main/auth_routes.py +++ b/labconnect/main/auth_routes.py @@ -4,6 +4,7 @@ from flask import current_app, make_response, redirect, request, abort from flask_jwt_extended import create_access_token from onelogin.saml2.auth import OneLogin_Saml2_Auth +from sqlalchemy import desc from labconnect import db from labconnect.helpers import prepare_flask_request @@ -35,11 +36,11 @@ def generate_temporary_code(user_email: str, registered: bool) -> str: def validate_code_and_get_user_email(code: str) -> tuple[str | None, bool | None]: token_data = temp_codes.get(code, {}) if not token_data: - return None + return None, None user_email = token_data.get("email", None) expire = token_data.get("expires_at", None) - registered = token_data.get("registered", None) + registered = token_data.get("registered", False) if user_email and expire and expire > datetime.now(): # If found, delete the code to prevent reuse @@ -108,49 +109,51 @@ def registerUser(): if not json_data: abort(400) - user = User( - email=json_data.get("email"), - first_name=json_data.get("first_name"), - last_name=json_data.get("last_name"), - preferred_name=json_data.get("preferred_name", ""), - class_year=json_data.get("class_year", ""), - profile_picture=json_data.get( - "profile_picture", "https://www.svgrepo.com/show/206842/professor.svg" - ), - website=json_data.get("website", ""), - description=json_data.get("description", ""), + user = User() + user.email = json_data.get("email") + user.first_name = json_data.get("first_name") + user.last_name = json_data.get("last_name") + user.preferred_name = json_data.get("preferred_name", "") + user.class_year = json_data.get("class_year", "") + user.profile_picture = json_data.get( + "profile_picture", "https://www.svgrepo.com/show/206842/professor.svg" ) + user.website = json_data.get("website", "") + user.description = json_data.get("description", "") db.session.add(user) db.session.commit() # Add UserDepartments if provided if json_data.get("departments"): for department_id in json_data["departments"]: - user_department = UserDepartments( - user_id=user.id, department_id=department_id - ) + user_department = UserDepartments() + user_department.department_id = department_id + user_department.user_id = user.id db.session.add(user_department) # Additional auxiliary records (majors, courses, etc.) if json_data.get("majors"): - for major_id in json_data["majors"]: - user_major = UserMajors(user_id=user.id, major_id=major_id) + for major_code in json_data["majors"]: + user_major = UserMajors() + user_major.user_id = user.id + user_major.major_code = major_code db.session.add(user_major) # Add Courses if provided if json_data.get("courses"): - for course_id in json_data["courses"]: - user_course = UserCourses(user_id=user.id, course_id=course_id) + for course_code in json_data["courses"]: + user_course = UserCourses() + user_course.user_id = user.id + user_course.course_code = course_code db.session.add(user_course) # Add ManagementPermissions if provided if json_data.get("permissions"): permissions = json_data["permissions"] - management_permissions = ManagementPermissions( - user_id=user.id, - super_admin=permissions.get("super_admin", False), - admin=permissions.get("admin", False), - moderator=permissions.get("moderator", False), - ) + management_permissions = ManagementPermissions() + management_permissions.user_id = user.id + management_permissions.super_admin = permissions.get("super_admin", False) + management_permissions.admin = permissions.get("admin", False) + management_permissions.moderator = permissions.get("moderator", False) db.session.add(management_permissions) db.session.commit() @@ -194,8 +197,5 @@ def metadataRoute(): @main_blueprint.get("/logout") def logout(): - if not current_app.config["TESTING"]: - # TODO: add token to blacklist - # current_app.config["TOKEN_BLACKLIST"].add() - pass + # TODO: add token to blacklist return {"msg": "logout successful"} From 6a2cf9639eb8c410e64d67828c96b80f15aec4be Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Fri, 22 Nov 2024 18:44:28 -0500 Subject: [PATCH 82/99] get profile opportunities working --- labconnect/main/opportunity_routes.py | 90 +++++++++++++-------------- 1 file changed, 42 insertions(+), 48 deletions(-) diff --git a/labconnect/main/opportunity_routes.py b/labconnect/main/opportunity_routes.py index 4d04eb6..cb6031b 100644 --- a/labconnect/main/opportunity_routes.py +++ b/labconnect/main/opportunity_routes.py @@ -12,6 +12,7 @@ RecommendsClassYears, User, Courses, + Participates, ) from . import main_blueprint @@ -508,7 +509,7 @@ def getOpportunityCards(): @main_blueprint.get("/staff/opportunities/") -def getLabManagerOpportunityCards(rcs_id: str): +def getLabManagerOpportunityCards(rcs_id: str) -> list[dict[str, str]]: query = ( db.select( @@ -530,61 +531,54 @@ def getLabManagerOpportunityCards(rcs_id: str): data = db.session.execute(query).all() - cards = { - "data": [ - { - "id": row[0], - "title": row[1], - "due": row[2].strftime("%-m/%-d/%y"), - "pay": row[3], - "credits": format_credits(row[4], row[5], row[6], row[7]), - } - for row in data - ] - } + cards = [ + { + "id": row[0], + "title": row[1], + "due": row[2].strftime("%-m/%-d/%y"), + "pay": row[3], + "credits": format_credits(row[4], row[5], row[6], row[7]), + } + for row in data + ] return cards -# @main_blueprint.get("/getProfileOpportunities/") -# def getProfileOpportunities(rcs_id: str): -# # # query database for opportunity - -# query = db.session.execute( -# db.select(Opportunities, Leads) -# .where(Leads.lab_manager_id == rcs_id) -# .join(Opportunities, Leads.opportunity_id == Opportunities.id) -# ) - -# data = query.all() +@main_blueprint.get("/profile/opportunities/") +def getProfileOpportunities(rcs_id: str) -> list[dict[str, str]]: -# cards = {"data": []} - -# for row in data: -# opportunity = row[0] - -# oppData = { -# "id": opportunity.id, -# "title": opportunity.name, -# "body": "Due " + str(opportunity.application_due), -# "attributes": [], -# "activeStatus": opportunity.active, -# } + query = ( + db.select( + Opportunities.id, + Opportunities.name, + Opportunities.application_due, + Opportunities.pay, + Opportunities.one_credit, + Opportunities.two_credits, + Opportunities.three_credits, + Opportunities.four_credits, + ) + .join(Participates, Participates.user_id == rcs_id) + .join(Opportunities, Participates.opportunity_id == Opportunities.id) + .where(User.id == rcs_id) + .select_from(User) + ) -# if opportunity.pay is not None and opportunity.pay > 0: -# oppData["attributes"].append("Paid") -# if ( -# opportunity.one_credit -# or opportunity.two_credits -# or opportunity.three_credits -# or opportunity.four_credits -# ): -# oppData["attributes"].append("Credits") + data = db.session.execute(query).all() -# cards["data"].append(oppData) + cards = [ + { + "id": row[0], + "title": row[1], + "due": row[2].strftime("%-m/%-d/%y"), + "pay": row[3], + "credits": format_credits(row[4], row[5], row[6], row[7]), + } + for row in data + ] -# # return data in the below format if opportunity is found -# return cards + return cards # function to search for lab managers From 9a81cb0865972e32edc25d4a89d23f1d18b7a77e Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Fri, 22 Nov 2024 18:44:48 -0500 Subject: [PATCH 83/99] Complete profile route --- labconnect/main/routes.py | 215 ++++++++------------------------------ 1 file changed, 43 insertions(+), 172 deletions(-) diff --git a/labconnect/main/routes.py b/labconnect/main/routes.py index 0b5aa7a..7c68809 100644 --- a/labconnect/main/routes.py +++ b/labconnect/main/routes.py @@ -6,11 +6,12 @@ from labconnect import db from labconnect.models import ( LabManager, - Leads, Opportunities, RPIDepartments, User, ClassYears, + UserDepartments, + Majors, ) from . import main_blueprint @@ -88,95 +89,49 @@ def departmentDetails(department: str): return result -# @main_blueprint.get("/getSchoolsAndDepartments/") -# def getSchoolsAndDepartments(): -# data = db.session.execute( -# db.select(RPISchools, RPIDepartments).join( -# RPIDepartments, RPISchools.name == RPIDepartments.school_id -# ) -# ).scalars() - -# dictionary = {} -# for item in data: -# if item[0].name not in dictionary: -# dictionary[item[0].name] = [] -# dictionary[item[0].name].append(item[1].name) - -# return dictionary - - -# @main_blueprint.get("/getOpportunitiesRaw/") -# def getOpportunitiesRaw(id: int): -# data = db.session.execute( -# db.select( -# Opportunities, -# Leads, -# LabManager, -# RecommendsMajors, -# RecommendsCourses, -# RecommendsClassYears, -# ) -# .where(Opportunities.id == id) -# .join(Leads, Leads.opportunity_id == Opportunities.id) -# .join(LabManager, Leads.lab_manager_id == LabManager.id) -# .join(RecommendsMajors, RecommendsMajors.opportunity_id == Opportunities.id) -# .join(RecommendsCourses, RecommendsCourses.opportunity_id == Opportunities.id) -# .join( -# RecommendsClassYears, -# RecommendsClassYears.opportunity_id == Opportunities.id, -# ) -# ).scalars() - -# opportunities = [opportunity.to_dict() for opportunity in data] - -# return {"data": opportunities} - - -# @main_blueprint.get("/lab_manager") -# def getLabManagers(): -# if not request.data: -# abort(400) - -# json_request_data = request.get_json() - -# if not json_request_data: -# abort(400) - -# rcs_id = json_request_data.get("rcs_id", None) - -# if not rcs_id: -# abort(400) - -# data = db.first_or_404(db.select(LabManager).where(LabManager.id == rcs_id)) - -# result = data.to_dict() - -# return result - - @main_blueprint.get("/profile") +@jwt_required() def profile(): - request_data = request.get_json() - id = request_data.get("id", None) - # TODO: Fix to a join query - lab_manager = db.first_or_404(db.select(LabManager).where(LabManager.id == id)) - user = db.first_or_404(db.select(User).where(User.lab_manager_id == id)) - - result = lab_manager.to_dict() | user.to_dict() + user_id = get_jwt_identity() data = db.session.execute( - db.select(Opportunities, Leads) - .where(Leads.lab_manager_id == lab_manager.id) - .join(Opportunities, Leads.opportunity_id == Opportunities.id) - ).scalars() + db.select( + User.preferred_name, + User.first_name, + User.last_name, + User.profile_picture, + RPIDepartments.name, + User.description, + User.website, + User.lab_manager_id, + User.id, + ) + .where(User.email == user_id[0]) + .join(UserDepartments, UserDepartments.user_id == User.id) + .join(RPIDepartments, UserDepartments.department_id == RPIDepartments.id) + ).first() + + if not data: + return {"error": "profile not found"}, 404 + + # if data[7]: + # return {"lab_manager": True, "id": data[7]} - result["opportunities"] = [opportunity.to_dict() for opportunity in data] + result = { + "id": data[8], + "name": data[0] + " " + data[2] if data[0] else data[1] + " " + data[2], + "image": data[3], + "department": data[4], + "description": data[5], + "website": data[6], + } return result @main_blueprint.get("/staff/") +@jwt_required() def getProfessorProfile(id: str): data = db.session.execute( @@ -208,68 +163,6 @@ def getProfessorProfile(id: str): return result -# @main_blueprint.get("/lab_manager/opportunities") -# def getLabManagerOpportunityCards() -> dict[Any, list[Any]]: -# if not request.data: -# abort(400) - -# rcs_id = request.get_json().get("rcs_id", None) - -# if not rcs_id: -# abort(400) - -# data = db.session.execute( -# db.select(Opportunities, LabManager) -# .where(LabManager.id == rcs_id) -# .join(Leads, LabManager.id == Leads.lab_manager_id) -# .join(Opportunities, Leads.opportunity_id == Opportunities.id) -# .order_by(Opportunities.id) -# ).scalars() - -# if not data: -# abort(404) - -# result = {rcs_id: [opportunity.to_dict() for opportunity in data]} - -# return result - - -# _______________________________________________________________________________________________# - - -# Editing Opportunities in Profile Page -# @main_blueprint.get("/getProfessorCookies/") -# def getProfessorCookies(id: str): - -# # this is already restricted to "GET" requests - -# # TODO: Use JOIN query -# lab_manager = db.first_or_404(db.select(LabManager).where(LabManager.id == id)) -# user = db.first_or_404(db.select(User).where(User.lab_manager_id == id)) - -# dictionary = lab_manager.to_dict() | user.to_dict() - -# dictionary["role"] = "admin" -# dictionary["researchCenter"] = "AI" -# dictionary["loggedIn"] = True - -# return dictionary - - -# @main_blueprint.get("/getStaff/") -# def getStaff(department: str): -# query = db.session.execute( -# db.select(LabManager).filter(LabManager.department_id == department) -# ) -# data = query.all() -# dictionary = {} -# for item in data: -# dictionary[item[0].rcs_id] = item[0].to_dict() -# dictionary[item[0].rcs_id].pop("rcs_id") - -# return dictionary - - @main_blueprint.post("/changeActiveStatus") def changeActiveStatus() -> dict[str, bool]: data = request.get_json() @@ -313,42 +206,20 @@ def force_error(): # return result -# @main_blueprint.get("/majors") -# def majors() -> list[Any]: - -# if request.data: - -# json_request_data = request.get_json() - -# if not json_request_data: -# abort(400) +@main_blueprint.get("/majors") +def majors() -> list[dict[str, str]]: -# partial_key = json_request_data.get("input", None) + data = db.session.execute(db.select(Majors).order_by(Majors.code)).scalars() -# data = db.session.execute( -# db.select(Majors) -# .order_by(Majors.code) -# .where( -# (Majors.code.ilike(f"%{partial_key}%")) -# | (Majors.name.ilike(f"%{partial_key}%")) -# ) -# ).scalars() - -# if not data: -# abort(404) - -# result = [major.to_dict() for major in data] - -# return result - -# data = db.session.execute(db.select(Majors).order_by(Majors.code)).scalars() + if not data: + abort(404) -# if not data: -# abort(404) + result = [{"code": major.code, "name": major.name} for major in data] -# result = [major.to_dict() for major in data] + if result == []: + abort(404) -# return result + return result @main_blueprint.get("/years") From fa6464aaa6fae8d485dd5368b6cb230c22a8f656 Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Fri, 22 Nov 2024 18:47:46 -0500 Subject: [PATCH 84/99] update diagram --- docs/database_docs/Labconnect_DB.png | Bin 96485 -> 96484 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/database_docs/Labconnect_DB.png b/docs/database_docs/Labconnect_DB.png index b8c8c39c3cd7efdad3aa58d75e9b61b0629fd7eb..bcd496e78d26cf8166061eb6d75d5519120d86e8 100644 GIT binary patch literal 96484 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 E00Eqw9{>OV literal 96485 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 Date: Fri, 22 Nov 2024 18:51:08 -0500 Subject: [PATCH 85/99] remove uneeded import --- labconnect/main/auth_routes.py | 1 - 1 file changed, 1 deletion(-) diff --git a/labconnect/main/auth_routes.py b/labconnect/main/auth_routes.py index 2126739..a251d6c 100644 --- a/labconnect/main/auth_routes.py +++ b/labconnect/main/auth_routes.py @@ -4,7 +4,6 @@ from flask import current_app, make_response, redirect, request, abort from flask_jwt_extended import create_access_token from onelogin.saml2.auth import OneLogin_Saml2_Auth -from sqlalchemy import desc from labconnect import db from labconnect.helpers import prepare_flask_request From 8f97033a66b16d326d807c0adf43d3ea6fa7d4a4 Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Fri, 22 Nov 2024 18:52:25 -0500 Subject: [PATCH 86/99] format with black --- tests/test_departments.py | 13 +++++++------ tests/test_user.py | 22 ++++++++++++++-------- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/tests/test_departments.py b/tests/test_departments.py index 4d3dd49..7f64ac1 100644 --- a/tests/test_departments.py +++ b/tests/test_departments.py @@ -39,7 +39,7 @@ def test_departments_route(test_client: FlaskClient) -> None: ), ( "School of science", - "School of science", + "School of science", "School of engineering", "School of science", "School of engineering", @@ -49,8 +49,7 @@ def test_departments_route(test_client: FlaskClient) -> None: ( "CSCI", "BIOL", - "MTLE" - "MATH", + "MTLE" "MATH", "ENVI", "MANE", "MANE", @@ -78,7 +77,7 @@ def test_departments_route(test_client: FlaskClient) -> None: for department in json_data: assert department["name"] in rpi_departments_data[0] assert department["description"] in rpi_departments_data[1] - #Added + # Added assert department["school_id"] in rpi_departments_data[2] assert department["id"] in rpi_departments_data[3] assert department["image"] in rpi_departments_data[4] @@ -100,9 +99,11 @@ def test_department_route(test_client: FlaskClient) -> None: assert json_data["name"] == "Computer Science" assert json_data["description"] == "DS" assert json_data["school_id"] == "School of Science" - #Added + # Added assert json_data["id"] == "CSCI" - assert json_data["image"] == "https://cdn-icons-png.flaticon.com/512/5310/5310672.png" + assert ( + json_data["image"] == "https://cdn-icons-png.flaticon.com/512/5310/5310672.png" + ) assert json_data["webcite"] == "https://www.rpi.edu" prof_names = ["Duy Le", "Rafael", "Turner", "Kuzmin", "Goldschmidt"] diff --git a/tests/test_user.py b/tests/test_user.py index d1e7d40..122a7c6 100644 --- a/tests/test_user.py +++ b/tests/test_user.py @@ -23,13 +23,16 @@ def test_user_route_with_input_id_1(test_client: FlaskClient) -> None: assert json_data["preferred_name"] == "Raf" assert json_data["last_name"] == "Cenzano" assert json_data["email"] == "cenzar@rpi.edu" - #Added + # Added assert json_data["description"] == "labconnect is the best RCOS project" - assert json_data["profile_picture"] == "https://rafael.sirv.com/Images/rafael.jpeg?thumbnail=350&format=webp&q=90" + assert ( + json_data["profile_picture"] + == "https://rafael.sirv.com/Images/rafael.jpeg?thumbnail=350&format=webp&q=90" + ) assert json_data["website"] == "https://rafaelcenzano.com" - #class year + # class year assert json_data["class_year"] == "2025" - #lab manager id + # lab manager id assert json_data["lab_manager_id"] == 1 departments_data = [ @@ -112,10 +115,13 @@ def test_user_route_with_input_id_2(test_client: FlaskClient) -> None: assert json_data["last_name"] == "RCOS" assert json_data["preferred_name"] is None assert json_data["email"] == "test@rpi.edu" - #Added - assert json_data["description"] is None - assert json_data["profile_picture"] == "https://www.svgrepo.com/show/206842/professor.svg" # Adjust based on your test data - assert json_data["website"] is None + # Added + assert json_data["description"] is None + assert ( + json_data["profile_picture"] + == "https://www.svgrepo.com/show/206842/professor.svg" + ) # Adjust based on your test data + assert json_data["website"] is None assert json_data["class_year"] is None assert json_data["lab_manager_id"] is None From 483131f3e0e89e909690e94a31da295cb3aefb44 Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Fri, 22 Nov 2024 19:03:11 -0500 Subject: [PATCH 87/99] add postgres to pytest gh action --- .github/workflows/pytest.yml | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 91267bc..e4bea05 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -9,6 +9,20 @@ on: jobs: build: runs-on: ubuntu-latest + services: + postgres: + image: postgres:16 + env: + POSTGRES_USER: test_user + POSTGRES_PASSWORD: test_password + POSTGRES_DB: test_db + ports: + - 5432:5432 + options: >- + --health-cmd="pg_isready -U test_user -d test_db" + --health-interval=10s + --health-timeout=5s + --health-retries=3 strategy: matrix: python-version: ["3.12.4"] @@ -22,9 +36,19 @@ jobs: run: | python -m pip install --upgrade pip pip install -r requirements.txt - - name: Setup the Database + - name: Wait for PostgreSQL to be ready + run: | + while ! pg_isready -h localhost -p 5432 -U test_user -d test_db; do + echo "Waiting for PostgreSQL..." + sleep 2 + done + - name: Set up the Database + env: + DATABASE_URL: postgres://test_user:test_password@localhost:5432/test_db run: | python db_init.py create - name: Running pytest + env: + DATABASE_URL: postgres://test_user:test_password@localhost:5432/test_db run: | python -m pytest tests/ From 4c9b8bb354b31811a31f4cf00d1603d0b06e6187 Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Fri, 22 Nov 2024 23:12:04 -0500 Subject: [PATCH 88/99] adjust issues --- .github/workflows/pytest.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index e4bea05..15ce8e6 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -36,12 +36,12 @@ jobs: run: | python -m pip install --upgrade pip pip install -r requirements.txt - - name: Wait for PostgreSQL to be ready - run: | - while ! pg_isready -h localhost -p 5432 -U test_user -d test_db; do - echo "Waiting for PostgreSQL..." - sleep 2 - done + - name: Wait for PostgreSQL to be ready + run: | + while ! pg_isready -h localhost -p 5432 -U test_user -d test_db; do + echo "Waiting for PostgreSQL..." + sleep 2 + done - name: Set up the Database env: DATABASE_URL: postgres://test_user:test_password@localhost:5432/test_db From f5121a14d15131d5ca3e6fe1b75ecf4affde1f71 Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Fri, 22 Nov 2024 23:27:46 -0500 Subject: [PATCH 89/99] test connection --- .github/workflows/pytest.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 15ce8e6..6dbf853 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -42,6 +42,9 @@ jobs: echo "Waiting for PostgreSQL..." sleep 2 done + - name: Test Database Connection + run: | + PGPASSWORD="test_password" psql -h localhost -p 5432 -U test_user -d test_db -c '\conninfo' - name: Set up the Database env: DATABASE_URL: postgres://test_user:test_password@localhost:5432/test_db From 0594ae8c9677d35eb5ac0ce89c3be849cb866c56 Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Fri, 22 Nov 2024 23:38:50 -0500 Subject: [PATCH 90/99] attempt to fix postgres test --- .github/workflows/pytest.yml | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 6dbf853..7033746 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -13,13 +13,13 @@ jobs: postgres: image: postgres:16 env: - POSTGRES_USER: test_user - POSTGRES_PASSWORD: test_password + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres POSTGRES_DB: test_db ports: - 5432:5432 options: >- - --health-cmd="pg_isready -U test_user -d test_db" + --health-cmd="pg_isready -U postgres -d test_db" --health-interval=10s --health-timeout=5s --health-retries=3 @@ -38,20 +38,17 @@ jobs: pip install -r requirements.txt - name: Wait for PostgreSQL to be ready run: | - while ! pg_isready -h localhost -p 5432 -U test_user -d test_db; do + while ! pg_isready -h localhost -p 5432 -U postgres -d test_db; do echo "Waiting for PostgreSQL..." sleep 2 done - - name: Test Database Connection - run: | - PGPASSWORD="test_password" psql -h localhost -p 5432 -U test_user -d test_db -c '\conninfo' - name: Set up the Database env: - DATABASE_URL: postgres://test_user:test_password@localhost:5432/test_db + DATABASE_URL: postgres://postgres:postgres@localhost:5432/test_db run: | python db_init.py create - name: Running pytest env: - DATABASE_URL: postgres://test_user:test_password@localhost:5432/test_db + DATABASE_URL: postgres://postgres:postgres@localhost:5432/test_db run: | python -m pytest tests/ From 1d70cc0406aa2e5ec2f452ab89264aa33930729b Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Fri, 22 Nov 2024 23:43:27 -0500 Subject: [PATCH 91/99] try removing password --- .github/workflows/pytest.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 7033746..2271508 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -14,7 +14,6 @@ jobs: image: postgres:16 env: POSTGRES_USER: postgres - POSTGRES_PASSWORD: postgres POSTGRES_DB: test_db ports: - 5432:5432 @@ -44,11 +43,11 @@ jobs: done - name: Set up the Database env: - DATABASE_URL: postgres://postgres:postgres@localhost:5432/test_db + DATABASE_URL: postgres://postgres@localhost:5432/test_db run: | python db_init.py create - name: Running pytest env: - DATABASE_URL: postgres://postgres:postgres@localhost:5432/test_db + DATABASE_URL: postgres://postgres@localhost:5432/test_db run: | python -m pytest tests/ From 81dd667e9bc56ce9144afdda1e26bc26005c70c8 Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Fri, 22 Nov 2024 23:50:59 -0500 Subject: [PATCH 92/99] fix url --- .github/workflows/pytest.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 2271508..b7fdd24 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -14,11 +14,12 @@ jobs: image: postgres:16 env: POSTGRES_USER: postgres - POSTGRES_DB: test_db + POSTGRES_PASSWORD: postgres_password + POSTGRES_DB: labconnect ports: - 5432:5432 options: >- - --health-cmd="pg_isready -U postgres -d test_db" + --health-cmd="pg_isready -U postgres -d labconnect" --health-interval=10s --health-timeout=5s --health-retries=3 @@ -37,17 +38,17 @@ jobs: pip install -r requirements.txt - name: Wait for PostgreSQL to be ready run: | - while ! pg_isready -h localhost -p 5432 -U postgres -d test_db; do + while ! pg_isready -h localhost -p 5432 -U postgres -d labconnect; do echo "Waiting for PostgreSQL..." sleep 2 done - name: Set up the Database env: - DATABASE_URL: postgres://postgres@localhost:5432/test_db + DATABASE_URL: postgresql+psycopg2://postgres:postgres_password@localhost/labconnect run: | python db_init.py create - name: Running pytest env: - DATABASE_URL: postgres://postgres@localhost:5432/test_db + DATABASE_URL: postgresql+psycopg2://postgres:postgres_password@localhost/labconnect run: | python -m pytest tests/ From 87e918c91acd1b2406f408caad5c4627025094b1 Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Sat, 23 Nov 2024 00:03:10 -0500 Subject: [PATCH 93/99] UpdateTests (#248) small attempt --- .github/workflows/pytest.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index b7fdd24..a131ec8 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -14,7 +14,7 @@ jobs: image: postgres:16 env: POSTGRES_USER: postgres - POSTGRES_PASSWORD: postgres_password + POSTGRES_PASSWORD: postgres POSTGRES_DB: labconnect ports: - 5432:5432 @@ -44,11 +44,11 @@ jobs: done - name: Set up the Database env: - DATABASE_URL: postgresql+psycopg2://postgres:postgres_password@localhost/labconnect + DATABASE_URL: postgresql+psycopg2://postgres:postgres@localhost:5432/labconnect run: | python db_init.py create - name: Running pytest env: - DATABASE_URL: postgresql+psycopg2://postgres:postgres_password@localhost/labconnect + DATABASE_URL: postgresql+psycopg2://postgres:postgres@localhost:5432/labconnect run: | python -m pytest tests/ From b160331587e6d1407db9f3c36815d72669773687 Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Sat, 23 Nov 2024 09:57:04 -0500 Subject: [PATCH 94/99] run black formatter --- tests/test_courses.py | 16 +- tests/test_departments.py | 106 ++++++++---- tests/test_errors.py | 4 +- tests/test_general.py | 15 +- tests/test_lab_manager.py | 47 ++++-- tests/test_majors.py | 8 +- tests/test_opportunities_filtering.py | 65 +++++--- tests/test_opportunity.py | 120 +++++++------ tests/test_user.py | 232 ++++++++++++++------------ 9 files changed, 366 insertions(+), 247 deletions(-) diff --git a/tests/test_courses.py b/tests/test_courses.py index 27d8eec..cb2fd30 100644 --- a/tests/test_courses.py +++ b/tests/test_courses.py @@ -30,14 +30,20 @@ ({"input": "not found"}, 404, None), ], ) -def test_courses_route(test_client: FlaskClient, request_json, expected_status, expected_response) -> None: +def test_courses_route( + test_client: FlaskClient, request_json, expected_status, expected_response +) -> None: """ GIVEN a Flask application configured for testing WHEN the '/courses' page is requested (GET) with various inputs THEN check that the response status and data are as expected """ - response = test_client.get("/courses", json=request_json) if request_json else test_client.get("/courses") - + response = ( + test_client.get("/courses", json=request_json) + if request_json + else test_client.get("/courses") + ) + assert response.status_code == expected_status if expected_response is not None: @@ -65,7 +71,9 @@ def test_courses_route(test_client: FlaskClient, request_json, expected_status, ) ], ) -def test_courses_route_with_specific_input(test_client: FlaskClient, input_name, course_data) -> None: +def test_courses_route_with_specific_input( + test_client: FlaskClient, input_name, course_data +) -> None: """ GIVEN a Flask application configured for testing WHEN the '/courses' page is requested (GET) with specific course input names diff --git a/tests/test_departments.py b/tests/test_departments.py index 866f55c..fbeb88a 100644 --- a/tests/test_departments.py +++ b/tests/test_departments.py @@ -6,6 +6,7 @@ from flask.testing import FlaskClient import pytest + @pytest.mark.parametrize( "endpoint, request_json, expected_status, expected_response_checks", [ @@ -17,41 +18,52 @@ { "field": "name", "values": [ - "Computer Science", "Biology", "Materials Engineering", - "Math", "Environmental Engineering", "Aerospace Engineering", - "Areonautical Engineering" - ] + "Computer Science", + "Biology", + "Materials Engineering", + "Math", + "Environmental Engineering", + "Aerospace Engineering", + "Areonautical Engineering", + ], }, { "field": "description", "values": [ - "DS", "life", "also pretty cool", "quick maths", "water", - "space, the final frontier", "flying, need for speed" - ] + "DS", + "life", + "also pretty cool", + "quick maths", + "water", + "space, the final frontier", + "flying, need for speed", + ], }, { "field": "school_id", "values": [ - "School of science", "School of science", "School of engineering", - "School of science", "School of engineering", "School of engineering", - "School of engineering" - ] + "School of science", + "School of science", + "School of engineering", + "School of science", + "School of engineering", + "School of engineering", + "School of engineering", + ], }, { "field": "id", - "values": ["CSCI", "BIOL", "MTLE", "MATH", "ENVI", "MANE", "MANE"] + "values": ["CSCI", "BIOL", "MTLE", "MATH", "ENVI", "MANE", "MANE"], }, { "field": "image", "values": [ "https://cdn-icons-png.flaticon.com/512/5310/5310672.png" - ] * 7 + ] + * 7, }, - { - "field": "webcite", - "values": ["https://www.rpi.edu"] * 7 - } - ] + {"field": "webcite", "values": ["https://www.rpi.edu"] * 7}, + ], ), ( "/department", @@ -64,36 +76,66 @@ {"field": "id", "values": ["CSCI"]}, { "field": "image", - "values": ["https://cdn-icons-png.flaticon.com/512/5310/5310672.png"] + "values": [ + "https://cdn-icons-png.flaticon.com/512/5310/5310672.png" + ], }, {"field": "webcite", "values": ["https://www.rpi.edu"]}, { "field": "professors", "subfields": [ - {"subfield": "name", "values": ["Duy Le", "Rafael", "Turner", "Kuzmin", "Goldschmidt"]}, - {"subfield": "rcs_id", "values": ["led", "cenzar", "turner", "kuzmin", "goldd"]} - ] + { + "subfield": "name", + "values": [ + "Duy Le", + "Rafael", + "Turner", + "Kuzmin", + "Goldschmidt", + ], + }, + { + "subfield": "rcs_id", + "values": ["led", "cenzar", "turner", "kuzmin", "goldd"], + }, + ], }, { "field": "opportunities", "subfields": [ {"subfield": "id", "values": [1, 2]}, - {"subfield": "name", "values": ["Automated Cooling System", "Iphone 15 durability test"]} - ] - } - ] + { + "subfield": "name", + "values": [ + "Automated Cooling System", + "Iphone 15 durability test", + ], + }, + ], + }, + ], ), ("/department", None, 400, None), - ("/department", {"wrong": "wrong"}, 400, None) - ] + ("/department", {"wrong": "wrong"}, 400, None), + ], ) -def test_department_routes(test_client: FlaskClient, endpoint, request_json, expected_status, expected_response_checks) -> None: +def test_department_routes( + test_client: FlaskClient, + endpoint, + request_json, + expected_status, + expected_response_checks, +) -> None: """ GIVEN a Flask application configured for testing WHEN various '/departments' or '/department' routes are requested (GET) THEN check that the response status and data are as expected """ - response = test_client.get(endpoint, json=request_json) if request_json else test_client.get(endpoint) + response = ( + test_client.get(endpoint, json=request_json) + if request_json + else test_client.get(endpoint) + ) assert response.status_code == expected_status if expected_response_checks: @@ -106,4 +148,6 @@ def test_department_routes(test_client: FlaskClient, endpoint, request_json, exp else: for item in json_data.get(check["field"], []): for subfield_check in check["subfields"]: - assert item[subfield_check["subfield"]] in subfield_check["values"] + assert ( + item[subfield_check["subfield"]] in subfield_check["values"] + ) diff --git a/tests/test_errors.py b/tests/test_errors.py index d44acaa..d09edc6 100644 --- a/tests/test_errors.py +++ b/tests/test_errors.py @@ -20,7 +20,9 @@ ), ], ) -def test_error_pages(test_client: FlaskClient, route, expected_status, expected_response) -> None: +def test_error_pages( + test_client: FlaskClient, route, expected_status, expected_response +) -> None: """ GIVEN a Flask application configured for testing WHEN the specified error route is requested (GET) diff --git a/tests/test_general.py b/tests/test_general.py index e69a222..71d19ee 100644 --- a/tests/test_general.py +++ b/tests/test_general.py @@ -41,11 +41,14 @@ def test_discover_route(test_client: FlaskClient) -> None: @pytest.mark.parametrize( "input_id, expected_profile", [ - (1, { - "id": "cenzar", - "first_name": "Rafael", - "opportunities": [ ... ] # Replace with expected opportunities data - }) + ( + 1, + { + "id": "cenzar", + "first_name": "Rafael", + "opportunities": [...], # Replace with expected opportunities data + }, + ) ], ) def test_profile_page(test_client: FlaskClient, input_id, expected_profile) -> None: @@ -115,7 +118,7 @@ def test_professor_profile(test_client: FlaskClient) -> None: THEN check that the response is valid """ response = test_client.get("/getProfessorProfile/1") - + assert response.status_code == 200 # Load the response data as JSON diff --git a/tests/test_lab_manager.py b/tests/test_lab_manager.py index 562f6b2..5d54c2c 100644 --- a/tests/test_lab_manager.py +++ b/tests/test_lab_manager.py @@ -10,20 +10,26 @@ @pytest.mark.parametrize( "input_json, expected_status, expected_response", [ - ({"rcs_id": "cenzar"}, 200, { - "website": None, - "rcs_id": "cenzar", - "name": "Rafael", - "alt_email": None, - "phone_number": None, - "email": None, - "description": None, - }), + ( + {"rcs_id": "cenzar"}, + 200, + { + "website": None, + "rcs_id": "cenzar", + "name": "Rafael", + "alt_email": None, + "phone_number": None, + "email": None, + "description": None, + }, + ), (None, 400, None), # No input JSON case - ({"wrong": "wrong"}, 400, None) # Incorrect JSON structure case - ] + ({"wrong": "wrong"}, 400, None), # Incorrect JSON structure case + ], ) -def test_lab_manager_route(test_client: FlaskClient, input_json, expected_status, expected_response) -> None: +def test_lab_manager_route( + test_client: FlaskClient, input_json, expected_status, expected_response +) -> None: """ GIVEN a Flask application configured for testing WHEN the '/lab_manager' page is requested (GET) with different JSON inputs @@ -42,10 +48,12 @@ def test_lab_manager_route(test_client: FlaskClient, input_json, expected_status [ ({"rcs_id": "cenzar"}, 200), (None, 400), # No input JSON case - ({"wrong": "wrong"}, 400) # Incorrect JSON structure case - ] + ({"wrong": "wrong"}, 400), # Incorrect JSON structure case + ], ) -def test_lab_manager_opportunity_cards(test_client: FlaskClient, input_json, expected_status) -> None: +def test_lab_manager_opportunity_cards( + test_client: FlaskClient, input_json, expected_status +) -> None: """ GIVEN a Flask application configured for testing WHEN the '/lab_manager/opportunities' page is requested (GET) with different JSON inputs @@ -79,8 +87,13 @@ def test_lab_manager_opportunity_cards(test_client: FlaskClient, input_json, exp for i, item in enumerate(json_data["cenzar"]): assert item["name"] == lab_manager_opportunities_data[i]["name"] - assert item["description"] == lab_manager_opportunities_data[i]["description"] - assert item["recommended_experience"] == lab_manager_opportunities_data[i]["recommended_experience"] + assert ( + item["description"] == lab_manager_opportunities_data[i]["description"] + ) + assert ( + item["recommended_experience"] + == lab_manager_opportunities_data[i]["recommended_experience"] + ) assert item["pay"] == lab_manager_opportunities_data[i]["pay"] assert item["semester"] == lab_manager_opportunities_data[i]["semester"] assert item["year"] == lab_manager_opportunities_data[i]["year"] diff --git a/tests/test_majors.py b/tests/test_majors.py index b4c89d8..d7d6df8 100644 --- a/tests/test_majors.py +++ b/tests/test_majors.py @@ -54,7 +54,9 @@ def test_majors_route(test_client: FlaskClient, expected_majors) -> None: ), ], ) -def test_majors_route_with_input_name(test_client: FlaskClient, input_data, expected_majors) -> None: +def test_majors_route_with_input_name( + test_client: FlaskClient, input_data, expected_majors +) -> None: """ GIVEN a Flask application configured for testing WHEN the '/majors' page is requested (GET) @@ -87,7 +89,9 @@ def test_majors_route_with_input_name(test_client: FlaskClient, input_data, expe ), ], ) -def test_majors_route_with_input_code(test_client: FlaskClient, input_data, expected_majors) -> None: +def test_majors_route_with_input_code( + test_client: FlaskClient, input_data, expected_majors +) -> None: """ GIVEN a Flask application configured for testing WHEN the '/majors' page is requested (GET) diff --git a/tests/test_opportunities_filtering.py b/tests/test_opportunities_filtering.py index 6610b25..1c06701 100644 --- a/tests/test_opportunities_filtering.py +++ b/tests/test_opportunities_filtering.py @@ -6,70 +6,89 @@ from flask import json from flask.testing import FlaskClient + @pytest.mark.parametrize( "filters, expected_opportunities", [ ( [{"field": "pay", "value": {"min": 14.9, "max": 21}}], - ["Automated Cooling System"] + ["Automated Cooling System"], ), ( [{"field": "departments", "value": ["Material Science"]}], - ["Checking out cubes"] + ["Checking out cubes"], ), ( - [{"field": "departments", "value": ["Computer Science", "Material Science"]}], - ["Iphone 15 durability test", "Checking out cubes", "Automated Cooling System"] + [ + { + "field": "departments", + "value": ["Computer Science", "Material Science"], + } + ], + [ + "Iphone 15 durability test", + "Checking out cubes", + "Automated Cooling System", + ], ), ( [{"field": "majors", "value": ["BIOL"]}], - ["Iphone 15 durability test", "Checking out cubes", "Automated Cooling System"] + [ + "Iphone 15 durability test", + "Checking out cubes", + "Automated Cooling System", + ], ), ( [{"field": "majors", "value": ["CSCI", "BIOL"]}], - ["Iphone 15 durability test", "Checking out cubes", "Automated Cooling System"] + [ + "Iphone 15 durability test", + "Checking out cubes", + "Automated Cooling System", + ], ), ( [{"field": "credits", "value": [1]}], - ["Iphone 15 durability test", "Checking out cubes"] + ["Iphone 15 durability test", "Checking out cubes"], ), ( [{"field": "credits", "value": [2, 4]}], - ["Iphone 15 durability test", "Checking out cubes", "Automated Cooling System", "Test the water"] - ), - ( - [{"field": "class_year", "value": [2025]}], - ["Iphone 15 durability test"] + [ + "Iphone 15 durability test", + "Checking out cubes", + "Automated Cooling System", + "Test the water", + ], ), + ([{"field": "class_year", "value": [2025]}], ["Iphone 15 durability test"]), ( [{"field": "class_year", "value": [2025, 2027]}], - ["Iphone 15 durability test", "Automated Cooling System"] - ), - ( - [{"field": "location", "value": "Remote"}], - ["Automated Cooling System"] + ["Iphone 15 durability test", "Automated Cooling System"], ), + ([{"field": "location", "value": "Remote"}], ["Automated Cooling System"]), ( [{"field": "location", "value": "In-Person"}], - ["Iphone 15 durability test", "Checking out cubes", "Test the water"] + ["Iphone 15 durability test", "Checking out cubes", "Test the water"], ), ( [ {"field": "location", "value": "In-Person"}, - {"field": "departments", "value": ["Computer Science"]} + {"field": "departments", "value": ["Computer Science"]}, ], - ["Iphone 15 durability test"] + ["Iphone 15 durability test"], ), ( [ {"field": "credits", "value": [2, 4]}, - {"field": "departments", "value": ["Computer Science"]} + {"field": "departments", "value": ["Computer Science"]}, ], - ["Iphone 15 durability test", "Automated Cooling System"] + ["Iphone 15 durability test", "Automated Cooling System"], ), ], ) -def test_opportunity_filter(test_client: FlaskClient, filters, expected_opportunities) -> None: +def test_opportunity_filter( + test_client: FlaskClient, filters, expected_opportunities +) -> None: """ GIVEN a Flask application configured for testing WHEN the '/opportunity/filter' page is requested (GET) diff --git a/tests/test_opportunity.py b/tests/test_opportunity.py index b6ade78..bd0e9da 100644 --- a/tests/test_opportunity.py +++ b/tests/test_opportunity.py @@ -2,6 +2,7 @@ import pytest from flask.testing import FlaskClient + def test_get_opportunity_parametrized(test_client: FlaskClient): """ GIVEN a Flask application configured for testing @@ -9,32 +10,38 @@ def test_get_opportunity_parametrized(test_client: FlaskClient): THEN check that the responses are valid """ test_cases = [ - (1, { - "name": "Automated Cooling System", - "description": "Energy efficient AC system", - "recommended_experience": "Thermodynamics", - "pay": 15.0, - "one_credit": False, - "two_credits": False, - "three_credits": False, - "four_credits": True, - "semester": "Spring", - "year": 2024, - "active": True, - }), - (2, { - "name": "Iphone 15 durability test", - "description": "Scratching the Iphone, drop testing etc.", - "recommended_experience": "Experienced in getting angry and throwing temper tantrum", - "pay": None, - "one_credit": True, - "two_credits": True, - "three_credits": True, - "four_credits": True, - "semester": "Spring", - "year": 2024, - "active": True, - }), + ( + 1, + { + "name": "Automated Cooling System", + "description": "Energy efficient AC system", + "recommended_experience": "Thermodynamics", + "pay": 15.0, + "one_credit": False, + "two_credits": False, + "three_credits": False, + "four_credits": True, + "semester": "Spring", + "year": 2024, + "active": True, + }, + ), + ( + 2, + { + "name": "Iphone 15 durability test", + "description": "Scratching the Iphone, drop testing etc.", + "recommended_experience": "Experienced in getting angry and throwing temper tantrum", + "pay": None, + "one_credit": True, + "two_credits": True, + "three_credits": True, + "four_credits": True, + "semester": "Spring", + "year": 2024, + "active": True, + }, + ), ] for opportunity_id, expected_data in test_cases: @@ -69,32 +76,40 @@ def test_opportunity_incorrect_json(test_client: FlaskClient): @pytest.mark.parametrize( "endpoint, expected_keys", [ - ("/getOpportunityMeta/1", [ - "name", - "description", - "recommended_experience", - "pay", - "credits", - "semester", - "year", - "application_due", - "active", - "courses", - "majors", - "years", - ]), - ("/getOpportunity/2", [ - "id", - "name", - "description", - "recommended_experience", - "author", - "department", - "aboutSection", - ]), + ( + "/getOpportunityMeta/1", + [ + "name", + "description", + "recommended_experience", + "pay", + "credits", + "semester", + "year", + "application_due", + "active", + "courses", + "majors", + "years", + ], + ), + ( + "/getOpportunity/2", + [ + "id", + "name", + "description", + "recommended_experience", + "author", + "department", + "aboutSection", + ], + ), ], ) -def test_opportunity_meta_parametrized(test_client: FlaskClient, endpoint, expected_keys): +def test_opportunity_meta_parametrized( + test_client: FlaskClient, endpoint, expected_keys +): """ GIVEN a Flask application configured for testing WHEN specific opportunity endpoints are requested @@ -116,11 +131,12 @@ def test_opportunity_meta_parametrized(test_client: FlaskClient, endpoint, expec @pytest.mark.parametrize( - "endpoint", [ + "endpoint", + [ "/getOpportunityByProfessor/led", "/getProfessorOpportunityCards/led", "/getProfileOpportunities/led", - ] + ], ) def test_professor_related_opportunities(test_client: FlaskClient, endpoint): """ diff --git a/tests/test_user.py b/tests/test_user.py index 0e9ee86..2b6744e 100644 --- a/tests/test_user.py +++ b/tests/test_user.py @@ -6,62 +6,64 @@ from flask import json from flask.testing import FlaskClient -@pytest.mark.parametrize("input_data, expected_status, expected_output", [ - ( - {"id": "1"}, - 200, - { - "id": 1, - "first_name": "Rafael", - "preferred_name": "Raf", - "last_name": "Cenzano", - "email": "cenzar@rpi.edu", - "description": "labconnect is the best RCOS project", - "profile_picture": "https://rafael.sirv.com/Images/rafael.jpeg?thumbnail=350&format=webp&q=90", - "website": "https://rafaelcenzano.com", - "class_year": "2025", - "lab_manager_id": 1, - "departments": [ - {"user_id": 1, "department_id": "Computer Science"}, - {"user_id": 1, "department_id": "Math"} - ], - "majors": [ - {"user_id": 1, "major_code": "CSCI"}, - {"user_id": 1, "major_code": "MATH"} - ], - "courses": [ - {"in_progress": False, "user_id": 1, "course_code": "CSCI2300"}, - {"in_progress": True, "user_id": 1, "course_code": "CSCI4430"} - ] - } - ), - ( - {"id": "2"}, - 200, - { - "id": 2, - "first_name": "RCOS", - "preferred_name": None, - "last_name": "RCOS", - "email": "test@rpi.edu", - "description": None, - "profile_picture": "https://www.svgrepo.com/show/206842/professor.svg", - "website": None, - "class_year": None, - "lab_manager_id": None, - "departments": [ - {"user_id": 2, "department_id": "Computer Science"} - ], - "majors": [ - {"user_id": 2, "major_code": "CSCI"} - ], - "courses": [ - {"in_progress": False, "user_id": 2, "course_code": "CSCI2300"} - ] - } - ) -]) -def test_user_route(test_client: FlaskClient, input_data, expected_status, expected_output) -> None: + +@pytest.mark.parametrize( + "input_data, expected_status, expected_output", + [ + ( + {"id": "1"}, + 200, + { + "id": 1, + "first_name": "Rafael", + "preferred_name": "Raf", + "last_name": "Cenzano", + "email": "cenzar@rpi.edu", + "description": "labconnect is the best RCOS project", + "profile_picture": "https://rafael.sirv.com/Images/rafael.jpeg?thumbnail=350&format=webp&q=90", + "website": "https://rafaelcenzano.com", + "class_year": "2025", + "lab_manager_id": 1, + "departments": [ + {"user_id": 1, "department_id": "Computer Science"}, + {"user_id": 1, "department_id": "Math"}, + ], + "majors": [ + {"user_id": 1, "major_code": "CSCI"}, + {"user_id": 1, "major_code": "MATH"}, + ], + "courses": [ + {"in_progress": False, "user_id": 1, "course_code": "CSCI2300"}, + {"in_progress": True, "user_id": 1, "course_code": "CSCI4430"}, + ], + }, + ), + ( + {"id": "2"}, + 200, + { + "id": 2, + "first_name": "RCOS", + "preferred_name": None, + "last_name": "RCOS", + "email": "test@rpi.edu", + "description": None, + "profile_picture": "https://www.svgrepo.com/show/206842/professor.svg", + "website": None, + "class_year": None, + "lab_manager_id": None, + "departments": [{"user_id": 2, "department_id": "Computer Science"}], + "majors": [{"user_id": 2, "major_code": "CSCI"}], + "courses": [ + {"in_progress": False, "user_id": 2, "course_code": "CSCI2300"} + ], + }, + ), + ], +) +def test_user_route( + test_client: FlaskClient, input_data, expected_status, expected_output +) -> None: """ GIVEN a Flask application configured for testing WHEN the '/user' page is requested (GET) with input data @@ -72,55 +74,61 @@ def test_user_route(test_client: FlaskClient, input_data, expected_status, expec json_data = json.loads(response.data) assert json_data == expected_output -@pytest.mark.parametrize("input_data, expected_opportunities", [ - ( - {"id": 1}, - [ - { - "name": "Automated Cooling System", - "description": "Energy efficient AC system", - "recommended_experience": "Thermodynamics", - "pay": 15.0, - "semester": "Spring", - "year": 2024, - "active": True - }, - { - "name": "Iphone 15 durability test", - "description": "Scratching the Iphone, drop testing etc.", - "recommended_experience": "Experienced in getting angry and throwing temper tantrum", - "pay": None, - "semester": "Spring", - "year": 2024, - "active": True - } - ] - ), - ( - {"id": 2}, - [ - { - "name": "Checking out cubes", - "description": "Material Sciences", - "recommended_experience": "Experienced in materials.", - "pay": None, - "semester": "Fall", - "year": 2024, - "active": True - }, - { - "name": "Test the water", - "description": "Testing the quality of water in Troy pipes", - "recommended_experience": "Understanding of lead poisioning", - "pay": None, - "semester": "Summer", - "year": 2024, - "active": True - } - ] - ) -]) -def test_user_opportunity_cards(test_client: FlaskClient, input_data, expected_opportunities) -> None: + +@pytest.mark.parametrize( + "input_data, expected_opportunities", + [ + ( + {"id": 1}, + [ + { + "name": "Automated Cooling System", + "description": "Energy efficient AC system", + "recommended_experience": "Thermodynamics", + "pay": 15.0, + "semester": "Spring", + "year": 2024, + "active": True, + }, + { + "name": "Iphone 15 durability test", + "description": "Scratching the Iphone, drop testing etc.", + "recommended_experience": "Experienced in getting angry and throwing temper tantrum", + "pay": None, + "semester": "Spring", + "year": 2024, + "active": True, + }, + ], + ), + ( + {"id": 2}, + [ + { + "name": "Checking out cubes", + "description": "Material Sciences", + "recommended_experience": "Experienced in materials.", + "pay": None, + "semester": "Fall", + "year": 2024, + "active": True, + }, + { + "name": "Test the water", + "description": "Testing the quality of water in Troy pipes", + "recommended_experience": "Understanding of lead poisioning", + "pay": None, + "semester": "Summer", + "year": 2024, + "active": True, + }, + ], + ), + ], +) +def test_user_opportunity_cards( + test_client: FlaskClient, input_data, expected_opportunities +) -> None: """ GIVEN a Flask application configured for testing WHEN the '/user' page is requested (GET) with input data @@ -133,12 +141,14 @@ def test_user_opportunity_cards(test_client: FlaskClient, input_data, expected_o for i, item in enumerate(json_data["opportunities"]): assert item == expected_opportunities[i] -@pytest.mark.parametrize("input_data, expected_status", [ - (None, 400), - ({"wrong": "wrong"}, 400), - ({"id": "not found"}, 404) -]) -def test_user_route_edge_cases(test_client: FlaskClient, input_data, expected_status) -> None: + +@pytest.mark.parametrize( + "input_data, expected_status", + [(None, 400), ({"wrong": "wrong"}, 400), ({"id": "not found"}, 404)], +) +def test_user_route_edge_cases( + test_client: FlaskClient, input_data, expected_status +) -> None: """ GIVEN a Flask application configured for testing WHEN the '/user' page is requested (GET) with various edge case inputs From 4693db36a0a427c24c66dacd16b801fdfe74cedf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Dec 2024 10:24:02 +0000 Subject: [PATCH 95/99] Bump psycopg2 from 2.9.9 to 2.9.10 Bumps [psycopg2](https://github.com/psycopg/psycopg2) from 2.9.9 to 2.9.10. - [Changelog](https://github.com/psycopg/psycopg2/blob/master/NEWS) - [Commits](https://github.com/psycopg/psycopg2/compare/2.9.9...2.9.10) --- updated-dependencies: - dependency-name: psycopg2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 10b7f84..33ab25d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -19,7 +19,7 @@ MarkupSafe==3.0.2 orjson==3.10.10 packaging==24.1 pluggy==1.5.0 -psycopg2==2.9.9 +psycopg2==2.9.10 psycopg2-binary==2.9.9 PyJWT==2.9.0 pytest==8.3.3 From 1b5ebf28b00a7599d2e60b21f2e1652a03e01c9b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Dec 2024 17:49:54 +0000 Subject: [PATCH 96/99] Bump packaging from 24.1 to 24.2 Bumps [packaging](https://github.com/pypa/packaging) from 24.1 to 24.2. - [Release notes](https://github.com/pypa/packaging/releases) - [Changelog](https://github.com/pypa/packaging/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pypa/packaging/compare/24.1...24.2) --- updated-dependencies: - dependency-name: packaging dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 33ab25d..a2edf92 100644 --- a/requirements.txt +++ b/requirements.txt @@ -17,7 +17,7 @@ lxml==5.3.0 Mako==1.3.6 MarkupSafe==3.0.2 orjson==3.10.10 -packaging==24.1 +packaging==24.2 pluggy==1.5.0 psycopg2==2.9.10 psycopg2-binary==2.9.9 From ee41913e0024fd1fe39d7364f293bfe46e20a642 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Dec 2024 23:52:22 -0800 Subject: [PATCH 97/99] Bump pyjwt from 2.9.0 to 2.10.1 (#253) Bumps [pyjwt](https://github.com/jpadilla/pyjwt) from 2.9.0 to 2.10.1. - [Release notes](https://github.com/jpadilla/pyjwt/releases) - [Changelog](https://github.com/jpadilla/pyjwt/blob/master/CHANGELOG.rst) - [Commits](https://github.com/jpadilla/pyjwt/compare/2.9.0...2.10.1) --- updated-dependencies: - dependency-name: pyjwt dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index a2edf92..f35c927 100644 --- a/requirements.txt +++ b/requirements.txt @@ -21,7 +21,7 @@ packaging==24.2 pluggy==1.5.0 psycopg2==2.9.10 psycopg2-binary==2.9.9 -PyJWT==2.9.0 +PyJWT==2.10.1 pytest==8.3.3 pytest-cov==5.0.0 python3-saml==1.16.0 From 9aee71dd08abfeeee47d5604f44431390cf6a1d8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Dec 2024 23:54:30 -0800 Subject: [PATCH 98/99] Bump flask-jwt-extended from 4.6.0 to 4.7.1 (#249) Bumps [flask-jwt-extended](https://github.com/vimalloc/flask-jwt-extended) from 4.6.0 to 4.7.1. - [Release notes](https://github.com/vimalloc/flask-jwt-extended/releases) - [Commits](https://github.com/vimalloc/flask-jwt-extended/compare/4.6.0...4.7.1) --- updated-dependencies: - dependency-name: flask-jwt-extended dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index f35c927..f3dee7e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,7 +5,7 @@ click==8.1.7 coverage==7.6.1 Flask==3.0.3 Flask-Cors==5.0.0 -Flask-JWT-Extended==4.6.0 +Flask-JWT-Extended==4.7.1 Flask-Migrate==4.0.7 Flask-SQLAlchemy==3.1.1 gunicorn==23.0.0 From e047b3042887f22107e901116528787837759b5b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Dec 2024 00:01:57 -0800 Subject: [PATCH 99/99] Bump pytest-cov from 5.0.0 to 6.0.0 (#252) Bumps [pytest-cov](https://github.com/pytest-dev/pytest-cov) from 5.0.0 to 6.0.0. - [Changelog](https://github.com/pytest-dev/pytest-cov/blob/master/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/pytest-cov/compare/v5.0.0...v6.0.0) --- updated-dependencies: - dependency-name: pytest-cov dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index f3dee7e..38173e6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -23,7 +23,7 @@ psycopg2==2.9.10 psycopg2-binary==2.9.9 PyJWT==2.10.1 pytest==8.3.3 -pytest-cov==5.0.0 +pytest-cov==6.0.0 python3-saml==1.16.0 pytz==2024.2 sentry-sdk==2.17.0