From ce7de7c5e03813182da8a4987f8922f647f56c92 Mon Sep 17 00:00:00 2001 From: aldo Date: Wed, 20 Nov 2024 15:39:41 -0600 Subject: [PATCH 01/19] backend is now logging the feedback; a bit of work is need on the front end to ensure the write at is selected --- BackEndFlask/controller/Routes/Rating_routes.py | 6 ++++-- .../ViewCompletedAssessmentTasks.js | 12 ++++++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/BackEndFlask/controller/Routes/Rating_routes.py b/BackEndFlask/controller/Routes/Rating_routes.py index aebe91c32..29aeb40cf 100644 --- a/BackEndFlask/controller/Routes/Rating_routes.py +++ b/BackEndFlask/controller/Routes/Rating_routes.py @@ -61,8 +61,10 @@ def student_view_feedback(): used to calculate lag time. """ try: - user_id = request.json["user_id"] - completed_assessment_id = request.json["completed_assessment_id"] + with open("zfile.txt", 'w') as out: + print(request.json, file=out) + user_id = request.json.get("user_id") + completed_assessment_id = request.json.get("completed_assessment_id") exists = check_feedback_exists(user_id, completed_assessment_id) if exists: diff --git a/FrontEndReact/src/View/Student/View/CompletedAssessmentTask/ViewCompletedAssessmentTasks.js b/FrontEndReact/src/View/Student/View/CompletedAssessmentTask/ViewCompletedAssessmentTasks.js index 9728b156f..3d3f63625 100644 --- a/FrontEndReact/src/View/Student/View/CompletedAssessmentTask/ViewCompletedAssessmentTasks.js +++ b/FrontEndReact/src/View/Student/View/CompletedAssessmentTask/ViewCompletedAssessmentTasks.js @@ -3,7 +3,7 @@ import 'bootstrap/dist/css/bootstrap.css'; import CustomDataTable from "../../../Components/CustomDataTable"; import { IconButton } from "@mui/material"; import VisibilityIcon from '@mui/icons-material/Visibility'; -import { getHumanReadableDueDate } from "../../../../utility"; +import { genericResourcePOST, getHumanReadableDueDate } from "../../../../utility"; @@ -95,7 +95,15 @@ class ViewCompletedAssessmentTasks extends Component { { navbar.setAssessmentTaskInstructions(assessmentTasks, atId, completedAssessments, { readOnly: true }); - }} + genericResourcePOST( + `/rating`, + this, + JSON.stringify({ + "user_id" : this.userId, + "completed_assessment_id": 1, + }), + ); + }} aria-label="completedAssessmentTasksViewIconButton" > From c4a24c31c523685b3e75dbaf3801bcd08d4c033e Mon Sep 17 00:00:00 2001 From: aldo Date: Thu, 21 Nov 2024 13:53:23 -0600 Subject: [PATCH 02/19] Seems to now be saving and displaying correctly. I need to do some more testing to ensure info is being fully saved --- BackEndFlask/controller/Routes/Rating_routes.py | 4 ++-- .../ViewCompletedAssessmentTasks.js | 8 ++++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/BackEndFlask/controller/Routes/Rating_routes.py b/BackEndFlask/controller/Routes/Rating_routes.py index 29aeb40cf..688ec4d6a 100644 --- a/BackEndFlask/controller/Routes/Rating_routes.py +++ b/BackEndFlask/controller/Routes/Rating_routes.py @@ -71,8 +71,8 @@ def student_view_feedback(): return create_bad_response(f"Feedback already exists", "feedbacks", 409) feedback_data = request.json - feedback_time = datetime.now() - feedback_data["feedback_time"] = feedback_time.strftime('%Y-%m-%dT%H:%M:%S') + string_format ='%Y-%m-%dT%H:%M:%S.%fZ' + feedback_data["feedback_time"] = datetime.now().strftime(string_format) feedback = create_feedback(feedback_data) diff --git a/FrontEndReact/src/View/Student/View/CompletedAssessmentTask/ViewCompletedAssessmentTasks.js b/FrontEndReact/src/View/Student/View/CompletedAssessmentTask/ViewCompletedAssessmentTasks.js index 3d3f63625..fbce13e9b 100644 --- a/FrontEndReact/src/View/Student/View/CompletedAssessmentTask/ViewCompletedAssessmentTasks.js +++ b/FrontEndReact/src/View/Student/View/CompletedAssessmentTask/ViewCompletedAssessmentTasks.js @@ -95,12 +95,16 @@ class ViewCompletedAssessmentTasks extends Component { { navbar.setAssessmentTaskInstructions(assessmentTasks, atId, completedAssessments, { readOnly: true }); + var singluarCompletedAssessment = null; + if (completedAssessments) { + singluarCompletedAssessment = completedAssessments.find(completedAssessment => completedAssessment.assessment_task_id === atId) ?? null; + } genericResourcePOST( `/rating`, this, JSON.stringify({ - "user_id" : this.userId, - "completed_assessment_id": 1, + "user_id" : singluarCompletedAssessment.user_id, + "completed_assessment_id": singluarCompletedAssessment.completed_assessment_id, }), ); }} From 46375731935a55cc81cf40767d3b062ce09665c7 Mon Sep 17 00:00:00 2001 From: aldo Date: Thu, 21 Nov 2024 14:03:11 -0600 Subject: [PATCH 03/19] removing debugging --- BackEndFlask/controller/Routes/Rating_routes.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/BackEndFlask/controller/Routes/Rating_routes.py b/BackEndFlask/controller/Routes/Rating_routes.py index 5a65a3088..0b62faa22 100644 --- a/BackEndFlask/controller/Routes/Rating_routes.py +++ b/BackEndFlask/controller/Routes/Rating_routes.py @@ -67,8 +67,6 @@ def student_view_feedback(): used to calculate lag time. """ try: - with open("zfile.txt", 'w') as out: - print(request.json, file=out) user_id = request.json.get("user_id") completed_assessment_id = request.json.get("completed_assessment_id") From b8d2e5a14bfa05a7a6b46702e8e7ea54f237ac08 Mon Sep 17 00:00:00 2001 From: aldo Date: Thu, 21 Nov 2024 17:05:01 -0600 Subject: [PATCH 04/19] changes nothing fixed --- .../controller/Routes/Assessment_task_routes.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/BackEndFlask/controller/Routes/Assessment_task_routes.py b/BackEndFlask/controller/Routes/Assessment_task_routes.py index 814b6a313..2953f751f 100644 --- a/BackEndFlask/controller/Routes/Assessment_task_routes.py +++ b/BackEndFlask/controller/Routes/Assessment_task_routes.py @@ -209,6 +209,7 @@ def update_assessment_task(): one_assessment_task = get_assessment_task(assessment_task_id) # Trigger an error if not exists + if one_assessment_task.notification_sent == None: list_of_completed_assessments = get_completed_assessments_by_assessment_task_id(assessment_task_id) @@ -230,11 +231,11 @@ def update_assessment_task(): notification_date ) - return create_good_response( - assessment_task_schema.dump(one_assessment_task), - 201, - "assessment_tasks" - ) + return create_good_response( + assessment_task_schema.dump(one_assessment_task), + 201, + "assessment_tasks" + ) assessment_task_id = request.args.get("assessment_task_id") From d23233029ab536224572195be93df6e55eb3a932 Mon Sep 17 00:00:00 2001 From: aldo Date: Thu, 21 Nov 2024 21:12:03 -0600 Subject: [PATCH 05/19] saving some changes to jump to another branch --- .../controller/Routes/Assessment_task_routes.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/BackEndFlask/controller/Routes/Assessment_task_routes.py b/BackEndFlask/controller/Routes/Assessment_task_routes.py index 2953f751f..77e7065ce 100644 --- a/BackEndFlask/controller/Routes/Assessment_task_routes.py +++ b/BackEndFlask/controller/Routes/Assessment_task_routes.py @@ -231,11 +231,11 @@ def update_assessment_task(): notification_date ) - return create_good_response( - assessment_task_schema.dump(one_assessment_task), - 201, - "assessment_tasks" - ) + return create_good_response( + assessment_task_schema.dump(one_assessment_task), + 201, + "assessment_tasks" + ) assessment_task_id = request.args.get("assessment_task_id") From f2930acd8283c878cdad319aafba478eedf46707 Mon Sep 17 00:00:00 2001 From: aldo Date: Fri, 22 Nov 2024 16:23:08 -0600 Subject: [PATCH 06/19] new route created to begin teasing out the complex functionality stuffed in one put route --- .../Routes/Assessment_task_routes.py | 2 - .../controller/Routes/notification_routes.py | 67 +++++++++++++++++++ BackEndFlask/controller/__init__.py | 1 + .../ViewCompleteIndividualAssessmentTasks.js | 3 +- 4 files changed, 69 insertions(+), 4 deletions(-) create mode 100644 BackEndFlask/controller/Routes/notification_routes.py diff --git a/BackEndFlask/controller/Routes/Assessment_task_routes.py b/BackEndFlask/controller/Routes/Assessment_task_routes.py index 77e7065ce..934d6bc27 100644 --- a/BackEndFlask/controller/Routes/Assessment_task_routes.py +++ b/BackEndFlask/controller/Routes/Assessment_task_routes.py @@ -192,7 +192,6 @@ def add_assessment_task(): ) - @bp.route('/assessment_task', methods = ['PUT']) @jwt_required() @bad_token_check() @@ -209,7 +208,6 @@ def update_assessment_task(): one_assessment_task = get_assessment_task(assessment_task_id) # Trigger an error if not exists - if one_assessment_task.notification_sent == None: list_of_completed_assessments = get_completed_assessments_by_assessment_task_id(assessment_task_id) diff --git a/BackEndFlask/controller/Routes/notification_routes.py b/BackEndFlask/controller/Routes/notification_routes.py new file mode 100644 index 000000000..8dfaae020 --- /dev/null +++ b/BackEndFlask/controller/Routes/notification_routes.py @@ -0,0 +1,67 @@ +#------------------------------------------------------------ +# This is file holds the routes that handle sending +# notifications to individuals. +# +# Explanation of how Assessment.notification_sent will be +# used: +# If a completed assessments last update is after +# assessment.notification_sent, then they are +# considered to be new and elligble to send a msg +# to agian. Any more complex feture will require +# another table or trigger table to be added. +#------------------------------------------------------------ + +from flask import request +from flask_sqlalchemy import * +from controller import bp +from models.assessment_task import * +from models.course import get_course +from models.user import get_user +from models.team import get_team +from models.role import get_role +from controller.Route_response import * +from models.user_course import get_user_courses_by_user_id + +from flask_jwt_extended import jwt_required +from controller.security.CustomDecorators import ( + AuthCheck, bad_token_check, + admin_check +) + +@bp.route('/mass_notification', methods = ['PUT']) +@jwt_required() +@bad_token_check() +@AuthCheck() +@admin_check() +def mass_notify_new_ca_users(): + """ + Description: + This route will email individuals/teams of a related AT; + New/updated completed ATs will be notified upon successive + use. + + Parameters(from the json): + assessment_task_id: str (AT) + team: bool (is the at team based) + notification_message: str (message to send over in the email) + + Exceptions: + None all should be caught and handled + """ + try: + at_id = int(request.args.get('assessment_task_id')) + is_teams = bool(request.args.get('team')) + + msg_to_students = request.json["notification_message"] + + one_assessment_task = get_assessment_task(at_id) # Trigger an error if not exists + + return create_good_response( + "Message Sent", + 201, + "Mass notified" + ) + except Exception as e: + return create_bad_response( + f"An error occurred emailing users: {e}", "mass notified", 400 + ) \ No newline at end of file diff --git a/BackEndFlask/controller/__init__.py b/BackEndFlask/controller/__init__.py index f438f9180..8752a90c7 100644 --- a/BackEndFlask/controller/__init__.py +++ b/BackEndFlask/controller/__init__.py @@ -21,6 +21,7 @@ from controller.Routes import Feedback_routes from controller.Routes import Refresh_route from controller.Routes import Csv_routes +from controller.Routes import notification_routes from controller.security import utility from controller.security import CustomDecorators from controller.security import blacklist \ No newline at end of file diff --git a/FrontEndReact/src/View/Admin/View/ViewCompleteAssessmentTasks/ViewCompleteIndividualAssessmentTasks.js b/FrontEndReact/src/View/Admin/View/ViewCompleteAssessmentTasks/ViewCompleteIndividualAssessmentTasks.js index c98af7e48..d7e8e613e 100644 --- a/FrontEndReact/src/View/Admin/View/ViewCompleteAssessmentTasks/ViewCompleteIndividualAssessmentTasks.js +++ b/FrontEndReact/src/View/Admin/View/ViewCompleteAssessmentTasks/ViewCompleteIndividualAssessmentTasks.js @@ -70,9 +70,8 @@ class ViewCompleteIndividualAssessmentTasks extends Component { } genericResourcePUT( - `/assessment_task?assessment_task_id=${chosenAssessmentTask["assessment_task_id"]}¬ification=${true}`, + `/mass_notification?assessment_task_id=${chosenAssessmentTask["assessment_task_id"]}&team=${false}`, this, JSON.stringify({ - "notification_date": date, "notification_message": notes }) ).then((result) => { From 94aef66ead14759597d53aff4c8fb2bcd15bff2f Mon Sep 17 00:00:00 2001 From: aldo Date: Fri, 22 Nov 2024 20:06:21 -0600 Subject: [PATCH 07/19] figuring out some datetime things --- .../controller/Routes/notification_routes.py | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/BackEndFlask/controller/Routes/notification_routes.py b/BackEndFlask/controller/Routes/notification_routes.py index 8dfaae020..6b58dafad 100644 --- a/BackEndFlask/controller/Routes/notification_routes.py +++ b/BackEndFlask/controller/Routes/notification_routes.py @@ -14,15 +14,12 @@ from flask import request from flask_sqlalchemy import * from controller import bp -from models.assessment_task import * -from models.course import get_course -from models.user import get_user -from models.team import get_team -from models.role import get_role +from models.assessment_task import get_assessment_task from controller.Route_response import * from models.user_course import get_user_courses_by_user_id - from flask_jwt_extended import jwt_required +import datetime + from controller.security.CustomDecorators import ( AuthCheck, bad_token_check, admin_check @@ -41,9 +38,9 @@ def mass_notify_new_ca_users(): use. Parameters(from the json): - assessment_task_id: str (AT) - team: bool (is the at team based) - notification_message: str (message to send over in the email) + assessment_task_id: r (AT) + team: (is the at team based) + notification_message: (message to send over in the email) Exceptions: None all should be caught and handled @@ -51,17 +48,23 @@ def mass_notify_new_ca_users(): try: at_id = int(request.args.get('assessment_task_id')) is_teams = bool(request.args.get('team')) - msg_to_students = request.json["notification_message"] - one_assessment_task = get_assessment_task(at_id) # Trigger an error if not exists + # Raises InvalidAssessmentTaskID if non-existant AT. + at_time = get_assessment_task(at_id).notification_sent + + # Lowest possible time for easier comparisons. + if at_time == None : at_time = datetime.datetime(1,1,1,0,0,0,0) + + with open("ap.txt", 'w') as out: + print(at_time, file=out) return create_good_response( "Message Sent", 201, - "Mass notified" + "Mass_notified" ) except Exception as e: return create_bad_response( - f"An error occurred emailing users: {e}", "mass notified", 400 + f"An error occurred emailing users: {e}", "mass_not_notified", 400 ) \ No newline at end of file From b1fd67a8a9c011bd54e8b814118406b8c52d99d2 Mon Sep 17 00:00:00 2001 From: aldo Date: Mon, 25 Nov 2024 14:43:25 -0600 Subject: [PATCH 08/19] sending mass notifications for ats without teams works now. --- .../controller/Routes/notification_routes.py | 17 ++++++++-- BackEndFlask/models/queries.py | 34 +++++++++++++++++-- BackEndFlask/models/utility.py | 2 ++ .../ViewCompleteIndividualAssessmentTasks.js | 3 +- .../ViewCompleteTeamAssessmentTasks.js | 4 +-- 5 files changed, 51 insertions(+), 9 deletions(-) diff --git a/BackEndFlask/controller/Routes/notification_routes.py b/BackEndFlask/controller/Routes/notification_routes.py index 6b58dafad..60d7d4335 100644 --- a/BackEndFlask/controller/Routes/notification_routes.py +++ b/BackEndFlask/controller/Routes/notification_routes.py @@ -14,10 +14,11 @@ from flask import request from flask_sqlalchemy import * from controller import bp -from models.assessment_task import get_assessment_task +from models.assessment_task import get_assessment_task, toggle_notification_sent_to_true from controller.Route_response import * -from models.user_course import get_user_courses_by_user_id +from models.queries import get_students_for_emailing from flask_jwt_extended import jwt_required +from models.utility import email_students_feedback_is_ready_to_view import datetime from controller.security.CustomDecorators import ( @@ -49,6 +50,7 @@ def mass_notify_new_ca_users(): at_id = int(request.args.get('assessment_task_id')) is_teams = bool(request.args.get('team')) msg_to_students = request.json["notification_message"] + date = request.json["date"] # Raises InvalidAssessmentTaskID if non-existant AT. at_time = get_assessment_task(at_id).notification_sent @@ -56,8 +58,17 @@ def mass_notify_new_ca_users(): # Lowest possible time for easier comparisons. if at_time == None : at_time = datetime.datetime(1,1,1,0,0,0,0) + students = get_students_for_emailing(at_id) + + left_to_notifiy = [singular_student for singular_student in students if singular_student.last_update > at_time] + + email_students_feedback_is_ready_to_view(left_to_notifiy, msg_to_students) + + #update the at noti time + toggle_notification_sent_to_true(at_id, date) + with open("ap.txt", 'w') as out: - print(at_time, file=out) + print(left_to_notifiy, file=out) return create_good_response( "Message Sent", diff --git a/BackEndFlask/models/queries.py b/BackEndFlask/models/queries.py index f66838a7b..2ee340af0 100644 --- a/BackEndFlask/models/queries.py +++ b/BackEndFlask/models/queries.py @@ -1083,8 +1083,6 @@ def get_course_name_by_at_id(at_id:int) -> str : return course_name[0][0] - - def get_completed_assessment_ratio(course_id: int, assessment_task_id: int) -> int: """ Description: @@ -1126,4 +1124,34 @@ def is_admin_by_user_id(user_id: int) -> bool: if is_admin[0][0]: return True - return False \ No newline at end of file + return False + +def get_students_for_emailing(at_id: int) -> tuple[dict[str],dict[str]]: + """ + Description: + Returns the needed data for emailing students who should be reciving the notification from + their professors. + + Parameters: + at_id: (AT id) + + Returns: + tuple[dict[str],dict[str]] (The students information such as first_name, last_name, last_update, and email) + + Exceptions: + None raise by me except the database my raise some. + """ + # Note a similar function exists but its a select * query which hinders prefomance. + student_info = db.session.query( + CompletedAssessment.last_update, + User.first_name, + User.last_name, + User.email + ).join( + User, + User.user_id == CompletedAssessment.user_id + ).filter( + CompletedAssessment.assessment_task_id == at_id + ).all() + + return student_info \ No newline at end of file diff --git a/BackEndFlask/models/utility.py b/BackEndFlask/models/utility.py index 942ea62b0..27f538ea6 100644 --- a/BackEndFlask/models/utility.py +++ b/BackEndFlask/models/utility.py @@ -48,11 +48,13 @@ def email_students_feedback_is_ready_to_view(students: list, notification_messag send_email(student.email, subject, message) +##############################################################Rest the excepttion before commiting def send_email(address: str, subject: str, content: str): try: yag = yagmail.SMTP("skillbuilder02", PASSWORD) yag.send(address, subject, content) except: + return raise EmailFailureException def generate_random_password(length: int): diff --git a/FrontEndReact/src/View/Admin/View/ViewCompleteAssessmentTasks/ViewCompleteIndividualAssessmentTasks.js b/FrontEndReact/src/View/Admin/View/ViewCompleteAssessmentTasks/ViewCompleteIndividualAssessmentTasks.js index d7e8e613e..0e0d485cb 100644 --- a/FrontEndReact/src/View/Admin/View/ViewCompleteAssessmentTasks/ViewCompleteIndividualAssessmentTasks.js +++ b/FrontEndReact/src/View/Admin/View/ViewCompleteAssessmentTasks/ViewCompleteIndividualAssessmentTasks.js @@ -72,7 +72,8 @@ class ViewCompleteIndividualAssessmentTasks extends Component { genericResourcePUT( `/mass_notification?assessment_task_id=${chosenAssessmentTask["assessment_task_id"]}&team=${false}`, this, JSON.stringify({ - "notification_message": notes + "notification_message": notes, + "date" : date }) ).then((result) => { if (result !== undefined && result.errorMessage === null) { diff --git a/FrontEndReact/src/View/Admin/View/ViewCompleteAssessmentTasks/ViewCompleteTeamAssessmentTasks.js b/FrontEndReact/src/View/Admin/View/ViewCompleteAssessmentTasks/ViewCompleteTeamAssessmentTasks.js index bf3d6afe5..2e36b51a5 100644 --- a/FrontEndReact/src/View/Admin/View/ViewCompleteAssessmentTasks/ViewCompleteTeamAssessmentTasks.js +++ b/FrontEndReact/src/View/Admin/View/ViewCompleteAssessmentTasks/ViewCompleteTeamAssessmentTasks.js @@ -70,9 +70,9 @@ class ViewCompleteTeamAssessmentTasks extends Component { } genericResourcePUT( - `/assessment_task?assessment_task_id=${chosenAssessmentTask["assessment_task_id"]}¬ification=${true}`, + `/mass_notification?assessment_task_id=${chosenAssessmentTask["assessment_task_id"]}&team=${true}`, this, JSON.stringify({ - "notification_date": date, + "date": date, "notification_message": notes }) ).then((result) => { From 5d53c77dbf8a6810076922cfb26385302f2f0665 Mon Sep 17 00:00:00 2001 From: aldo Date: Mon, 25 Nov 2024 16:59:54 -0600 Subject: [PATCH 09/19] The send notification button can now be used on both individuals and teams --- .../controller/Routes/notification_routes.py | 11 +++----- BackEndFlask/models/queries.py | 28 ++++++++++++++----- .../ViewCompleteIndividualAssessmentTasks.js | 2 +- 3 files changed, 26 insertions(+), 15 deletions(-) diff --git a/BackEndFlask/controller/Routes/notification_routes.py b/BackEndFlask/controller/Routes/notification_routes.py index 60d7d4335..e19552776 100644 --- a/BackEndFlask/controller/Routes/notification_routes.py +++ b/BackEndFlask/controller/Routes/notification_routes.py @@ -48,7 +48,7 @@ def mass_notify_new_ca_users(): """ try: at_id = int(request.args.get('assessment_task_id')) - is_teams = bool(request.args.get('team')) + is_teams = request.args.get('team') == "true" msg_to_students = request.json["notification_message"] date = request.json["date"] @@ -58,18 +58,15 @@ def mass_notify_new_ca_users(): # Lowest possible time for easier comparisons. if at_time == None : at_time = datetime.datetime(1,1,1,0,0,0,0) - students = get_students_for_emailing(at_id) + collection = get_students_for_emailing(at_id, is_teams) - left_to_notifiy = [singular_student for singular_student in students if singular_student.last_update > at_time] + left_to_notifiy = [singular_student for singular_student in collection if singular_student.last_update > at_time] email_students_feedback_is_ready_to_view(left_to_notifiy, msg_to_students) - #update the at noti time + # Updating AT notification time toggle_notification_sent_to_true(at_id, date) - with open("ap.txt", 'w') as out: - print(left_to_notifiy, file=out) - return create_good_response( "Message Sent", 201, diff --git a/BackEndFlask/models/queries.py b/BackEndFlask/models/queries.py index 2ee340af0..0183b3190 100644 --- a/BackEndFlask/models/queries.py +++ b/BackEndFlask/models/queries.py @@ -1126,7 +1126,7 @@ def is_admin_by_user_id(user_id: int) -> bool: return True return False -def get_students_for_emailing(at_id: int) -> tuple[dict[str],dict[str]]: +def get_students_for_emailing(at_id: int, is_teams: bool) -> tuple[dict[str],dict[str]]: """ Description: Returns the needed data for emailing students who should be reciving the notification from @@ -1134,6 +1134,7 @@ def get_students_for_emailing(at_id: int) -> tuple[dict[str],dict[str]]: Parameters: at_id: (AT id) + is_teams: (are we looking for students associated to a team?) Returns: tuple[dict[str],dict[str]] (The students information such as first_name, last_name, last_update, and email) @@ -1147,11 +1148,24 @@ def get_students_for_emailing(at_id: int) -> tuple[dict[str],dict[str]]: User.first_name, User.last_name, User.email - ).join( - User, - User.user_id == CompletedAssessment.user_id - ).filter( + ) + + if is_teams: + student_info = student_info.join( + TeamUser, + TeamUser.team_id == CompletedAssessment.team_id + ).join( + User, + User.user_id == TeamUser.user_id + ) + else: + student_info = student_info.join( + User, + User.user_id == CompletedAssessment.user_id + ) + + student_info = student_info.filter( CompletedAssessment.assessment_task_id == at_id - ).all() + ) - return student_info \ No newline at end of file + return student_info.all() \ No newline at end of file diff --git a/FrontEndReact/src/View/Admin/View/ViewCompleteAssessmentTasks/ViewCompleteIndividualAssessmentTasks.js b/FrontEndReact/src/View/Admin/View/ViewCompleteAssessmentTasks/ViewCompleteIndividualAssessmentTasks.js index 0e0d485cb..1ff8a2028 100644 --- a/FrontEndReact/src/View/Admin/View/ViewCompleteAssessmentTasks/ViewCompleteIndividualAssessmentTasks.js +++ b/FrontEndReact/src/View/Admin/View/ViewCompleteAssessmentTasks/ViewCompleteIndividualAssessmentTasks.js @@ -72,7 +72,7 @@ class ViewCompleteIndividualAssessmentTasks extends Component { genericResourcePUT( `/mass_notification?assessment_task_id=${chosenAssessmentTask["assessment_task_id"]}&team=${false}`, this, JSON.stringify({ - "notification_message": notes, + "notification_message": notes, "date" : date }) ).then((result) => { From 385ca17e68df9d486d10059c0333c52547694642 Mon Sep 17 00:00:00 2001 From: aldo Date: Mon, 25 Nov 2024 17:00:32 -0600 Subject: [PATCH 10/19] I mean that it works on mass sending to individuals at or team ats --- BackEndFlask/models/queries.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BackEndFlask/models/queries.py b/BackEndFlask/models/queries.py index 0183b3190..e4649332c 100644 --- a/BackEndFlask/models/queries.py +++ b/BackEndFlask/models/queries.py @@ -1168,4 +1168,4 @@ def get_students_for_emailing(at_id: int, is_teams: bool) -> tuple[dict[str],dic CompletedAssessment.assessment_task_id == at_id ) - return student_info.all() \ No newline at end of file + return student_info.all() \ No newline at end of file From 2f9eb8aae0485eac975460ba5ff98e0b13949702 Mon Sep 17 00:00:00 2001 From: aldo Date: Mon, 25 Nov 2024 18:01:36 -0600 Subject: [PATCH 11/19] might want to rework the single email sender to make code reuse a thing for email sending between single and mass notifications --- .../controller/Routes/notification_routes.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/BackEndFlask/controller/Routes/notification_routes.py b/BackEndFlask/controller/Routes/notification_routes.py index e19552776..8dd1fd707 100644 --- a/BackEndFlask/controller/Routes/notification_routes.py +++ b/BackEndFlask/controller/Routes/notification_routes.py @@ -42,6 +42,7 @@ def mass_notify_new_ca_users(): assessment_task_id: r (AT) team: (is the at team based) notification_message: (message to send over in the email) + date: (date to record things) Exceptions: None all should be caught and handled @@ -75,4 +76,15 @@ def mass_notify_new_ca_users(): except Exception as e: return create_bad_response( f"An error occurred emailing users: {e}", "mass_not_notified", 400 - ) \ No newline at end of file + ) + + +@bp.route('/send_single_email', methods = ['POST']) +@jwt_required() +@bad_token_check() +@AuthCheck() +@admin_check() +def send_single_email(): + """ + """ + return \ No newline at end of file From 40b53d6cf957cd5149d9b27b65d43239a28f9d44 Mon Sep 17 00:00:00 2001 From: aldo Date: Tue, 26 Nov 2024 20:13:58 -0600 Subject: [PATCH 12/19] added a new button and added the single message route in the backend. Both are still in progress --- .../controller/Routes/notification_routes.py | 34 ++++++++++++++++++- .../ViewCompleteIndividualAssessmentTasks.js | 21 ++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/BackEndFlask/controller/Routes/notification_routes.py b/BackEndFlask/controller/Routes/notification_routes.py index 8dd1fd707..1b2b5e132 100644 --- a/BackEndFlask/controller/Routes/notification_routes.py +++ b/BackEndFlask/controller/Routes/notification_routes.py @@ -43,6 +43,7 @@ def mass_notify_new_ca_users(): team: (is the at team based) notification_message: (message to send over in the email) date: (date to record things) + user_id: (who is requested the route[The decorators need it]) Exceptions: None all should be caught and handled @@ -86,5 +87,36 @@ def mass_notify_new_ca_users(): @admin_check() def send_single_email(): """ + Description: + Parameters: + user_id: (who requested the route {decorators uses it}) + is_team: (is this a team or individual msg) + targeted_id: (intended student/team for the message) + msg: (The message the team or individual should recive) + + Returns: + Good or bad Response + + Exceptions: + None """ - return \ No newline at end of file + + try: + is_teams = request.args.get('team') == "true" + targeted_id = request.args.get('targeted_id') + msg = request.json['msg'] + + # Find the students to email. Need first_name, last_name, and email. + + # Put into a compreshion list and call emailing funciton(same func at above) + + + return create_good_response( + "Message Sent", + 201, + "Individual/Team notified" + ) + except Exception as e: + return create_bad_response( + f"An error occurred emailing user/s: {e}", "Individual/Team not notified", 400 + ) \ No newline at end of file diff --git a/FrontEndReact/src/View/Admin/View/ViewCompleteAssessmentTasks/ViewCompleteIndividualAssessmentTasks.js b/FrontEndReact/src/View/Admin/View/ViewCompleteAssessmentTasks/ViewCompleteIndividualAssessmentTasks.js index 1ff8a2028..f8772c15c 100644 --- a/FrontEndReact/src/View/Admin/View/ViewCompleteAssessmentTasks/ViewCompleteIndividualAssessmentTasks.js +++ b/FrontEndReact/src/View/Admin/View/ViewCompleteAssessmentTasks/ViewCompleteIndividualAssessmentTasks.js @@ -255,6 +255,27 @@ class ViewCompleteIndividualAssessmentTasks extends Component { } } } + }, + { + name: "Student/Team Id", + label: " ", + options: { + filter: false, + sort: false, + setCellHeaderProps: () => { return { align:"center", className:"button-column-alignment"}}, + setCellProps: () => { return { align:"center", className:"button-column-alignment"} }, + customBodyRender: (completedAssessmentId) => { + return ( + + ) + } + } } ]; From b48e4b8c9def91a2fa232118afb25118739085a2 Mon Sep 17 00:00:00 2001 From: aldo Date: Wed, 27 Nov 2024 14:01:05 -0600 Subject: [PATCH 13/19] front end button can now distinguish who is calling it. Need to work on which completed assessment is calling it --- .../controller/Routes/notification_routes.py | 9 ++- .../ViewCompleteIndividualAssessmentTasks.js | 57 +++++++++++++------ 2 files changed, 46 insertions(+), 20 deletions(-) diff --git a/BackEndFlask/controller/Routes/notification_routes.py b/BackEndFlask/controller/Routes/notification_routes.py index 1b2b5e132..499844798 100644 --- a/BackEndFlask/controller/Routes/notification_routes.py +++ b/BackEndFlask/controller/Routes/notification_routes.py @@ -103,8 +103,8 @@ def send_single_email(): try: is_teams = request.args.get('team') == "true" - targeted_id = request.args.get('targeted_id') - msg = request.json['msg'] + completed_assessment_id = request.args.get('completed_assessment_id') + msg = request.json['notification_message'] # Find the students to email. Need first_name, last_name, and email. @@ -117,6 +117,11 @@ def send_single_email(): "Individual/Team notified" ) except Exception as e: + return create_good_response( + "Message Sent", + 201, + "Individual/Team notified" + ) return create_bad_response( f"An error occurred emailing user/s: {e}", "Individual/Team not notified", 400 ) \ No newline at end of file diff --git a/FrontEndReact/src/View/Admin/View/ViewCompleteAssessmentTasks/ViewCompleteIndividualAssessmentTasks.js b/FrontEndReact/src/View/Admin/View/ViewCompleteAssessmentTasks/ViewCompleteIndividualAssessmentTasks.js index f8772c15c..f83306467 100644 --- a/FrontEndReact/src/View/Admin/View/ViewCompleteAssessmentTasks/ViewCompleteIndividualAssessmentTasks.js +++ b/FrontEndReact/src/View/Admin/View/ViewCompleteAssessmentTasks/ViewCompleteIndividualAssessmentTasks.js @@ -6,7 +6,7 @@ import IconButton from '@mui/material/IconButton'; import VisibilityIcon from '@mui/icons-material/Visibility'; import { Box, Typography } from "@mui/material"; import CustomButton from "../../../Student/View/Components/CustomButton"; -import { genericResourcePUT } from "../../../../utility"; +import { genericResourcePOST, genericResourcePUT } from "../../../../utility"; import ResponsiveNotification from "../../../Components/SendNotification"; import CourseInfo from "../../../Components/CourseInfo"; @@ -23,6 +23,7 @@ class ViewCompleteIndividualAssessmentTasks extends Component { showDialog: false, notes: '', notificationSent: false, + singleMessage: false, errors: { notes:'' @@ -42,9 +43,10 @@ class ViewCompleteIndividualAssessmentTasks extends Component { }); }; - handleDialog = () => { + handleDialog = (isSingleMessage) => { this.setState({ showDialog: this.state.showDialog === false ? true : false, + singleMessage: isSingleMessage, }) } @@ -68,21 +70,39 @@ class ViewCompleteIndividualAssessmentTasks extends Component { return; } - - genericResourcePUT( - `/mass_notification?assessment_task_id=${chosenAssessmentTask["assessment_task_id"]}&team=${false}`, - this, JSON.stringify({ - "notification_message": notes, - "date" : date - }) - ).then((result) => { - if (result !== undefined && result.errorMessage === null) { - this.setState({ - showDialog: false, - notificationSent: date, + if(this.state.singleMessage) { + this.setState({singleMessage: false}, () => { + genericResourcePOST( + `/send_single_email?team=${false}&completed_assessment_id=${1}`, + this, JSON.stringify({ + "notification_message": notes, + }) + ).then((result) => { + if(result !== undefined && result.errorMessage === null){ + this.setState({ + showDialog: false, + notificationSent: date, + }); + } }); - } - }); + }); + } else { + genericResourcePUT( + `/mass_notification?assessment_task_id=${chosenAssessmentTask["assessment_task_id"]}&team=${false}`, + this, JSON.stringify({ + "notification_message": notes, + "date" : date + }) + ).then((result) => { + if (result !== undefined && result.errorMessage === null) { + this.setState({ + showDialog: false, + notificationSent: date, + }); + } + }); + } + }; render() { @@ -258,7 +278,7 @@ class ViewCompleteIndividualAssessmentTasks extends Component { }, { name: "Student/Team Id", - label: " ", + label: "Message", options: { filter: false, sort: false, @@ -267,6 +287,7 @@ class ViewCompleteIndividualAssessmentTasks extends Component { customBodyRender: (completedAssessmentId) => { return ( this.handleDialog(true)} label="Message" align="center" isOutlined={true} @@ -315,7 +336,7 @@ class ViewCompleteIndividualAssessmentTasks extends Component { this.handleDialog(false)} isOutlined={false} disabled={notificationSent} aria-label="viewCompletedAssessmentSendNotificationButton" From 42144ce7fdde12774ab6952952411b87ffd2f25c Mon Sep 17 00:00:00 2001 From: aldo Date: Wed, 27 Nov 2024 20:22:07 -0600 Subject: [PATCH 14/19] There undefiened error i need to find --- .../ViewCompleteIndividualAssessmentTasks.js | 48 +++++++++++-------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/FrontEndReact/src/View/Admin/View/ViewCompleteAssessmentTasks/ViewCompleteIndividualAssessmentTasks.js b/FrontEndReact/src/View/Admin/View/ViewCompleteAssessmentTasks/ViewCompleteIndividualAssessmentTasks.js index f83306467..faf4cb479 100644 --- a/FrontEndReact/src/View/Admin/View/ViewCompleteAssessmentTasks/ViewCompleteIndividualAssessmentTasks.js +++ b/FrontEndReact/src/View/Admin/View/ViewCompleteAssessmentTasks/ViewCompleteIndividualAssessmentTasks.js @@ -23,7 +23,8 @@ class ViewCompleteIndividualAssessmentTasks extends Component { showDialog: false, notes: '', notificationSent: false, - singleMessage: false, + isSingleMsg: false, + compATId: null, errors: { notes:'' @@ -43,15 +44,17 @@ class ViewCompleteIndividualAssessmentTasks extends Component { }); }; - handleDialog = (isSingleMessage) => { + handleDialog = (isSingleMessage, singleCompletedAT) => { + console.log(singleCompletedAT); this.setState({ showDialog: this.state.showDialog === false ? true : false, - singleMessage: isSingleMessage, - }) + isSingleMsg: isSingleMessage, + compATId: singleCompletedAT, + }); } handleSendNotification = () => { - var notes = this.state.notes; + var notes = this.state.notes; var navbar = this.props.navbar; @@ -70,10 +73,10 @@ class ViewCompleteIndividualAssessmentTasks extends Component { return; } - if(this.state.singleMessage) { - this.setState({singleMessage: false}, () => { + if(this.state.isSingleMsg) { + this.setState({isSingleMsg: false}, () => { genericResourcePOST( - `/send_single_email?team=${false}&completed_assessment_id=${1}`, + `/send_single_email?team=${false}&completed_assessment_id=${this.state.compATId}`, this, JSON.stringify({ "notification_message": notes, }) @@ -279,25 +282,32 @@ class ViewCompleteIndividualAssessmentTasks extends Component { { name: "Student/Team Id", label: "Message", + at: this.state.compATId, options: { filter: false, sort: false, setCellHeaderProps: () => { return { align:"center", className:"button-column-alignment"}}, setCellProps: () => { return { align:"center", className:"button-column-alignment"} }, customBodyRender: (completedAssessmentId) => { - return ( - this.handleDialog(true)} - label="Message" - align="center" - isOutlined={true} - disabled={notificationSent} - aria-label="viewCompletedAssessmentSendNotificationButton" - /> - ) + if (completedAssessmentId) { + return ( + this.handleDialog(true, completedAssessmentId)} + label="Message" + align="center" + isOutlined={true} + disabled={notificationSent} + aria-label="Send individual messages" + /> + ) + }else{ + return( +

{''}

+ ) + } } } - } + }, ]; const options = { From f216ad1bf4a2d4b6e26848f10fef94cd597cd677 Mon Sep 17 00:00:00 2001 From: aldo Date: Fri, 29 Nov 2024 14:26:25 -0600 Subject: [PATCH 15/19] frontend msg buttons are now in working order --- .../ViewCompleteIndividualAssessmentTasks.js | 20 ++--- .../ViewCompleteTeamAssessmentTasks.js | 90 +++++++++++++++---- 2 files changed, 82 insertions(+), 28 deletions(-) diff --git a/FrontEndReact/src/View/Admin/View/ViewCompleteAssessmentTasks/ViewCompleteIndividualAssessmentTasks.js b/FrontEndReact/src/View/Admin/View/ViewCompleteAssessmentTasks/ViewCompleteIndividualAssessmentTasks.js index faf4cb479..b83652f6f 100644 --- a/FrontEndReact/src/View/Admin/View/ViewCompleteAssessmentTasks/ViewCompleteIndividualAssessmentTasks.js +++ b/FrontEndReact/src/View/Admin/View/ViewCompleteAssessmentTasks/ViewCompleteIndividualAssessmentTasks.js @@ -45,7 +45,6 @@ class ViewCompleteIndividualAssessmentTasks extends Component { }; handleDialog = (isSingleMessage, singleCompletedAT) => { - console.log(singleCompletedAT); this.setState({ showDialog: this.state.showDialog === false ? true : false, isSingleMsg: isSingleMessage, @@ -282,14 +281,16 @@ class ViewCompleteIndividualAssessmentTasks extends Component { { name: "Student/Team Id", label: "Message", - at: this.state.compATId, options: { filter: false, sort: false, setCellHeaderProps: () => { return { align:"center", className:"button-column-alignment"}}, setCellProps: () => { return { align:"center", className:"button-column-alignment"} }, - customBodyRender: (completedAssessmentId) => { - if (completedAssessmentId) { + customBodyRender: (completedAssessmentId, completeAssessmentTasks) => { + const rowIndex = completeAssessmentTasks.rowIndex; + const completedATIndex = 5; + completedAssessmentId = completeAssessmentTasks.tableData[rowIndex][completedATIndex]; + if (completedAssessmentId !== null) { return ( this.handleDialog(true, completedAssessmentId)} @@ -355,13 +356,12 @@ class ViewCompleteIndividualAssessmentTasks extends Component { - + - ); } diff --git a/FrontEndReact/src/View/Admin/View/ViewCompleteAssessmentTasks/ViewCompleteTeamAssessmentTasks.js b/FrontEndReact/src/View/Admin/View/ViewCompleteAssessmentTasks/ViewCompleteTeamAssessmentTasks.js index 2e36b51a5..b2fa72f1b 100644 --- a/FrontEndReact/src/View/Admin/View/ViewCompleteAssessmentTasks/ViewCompleteTeamAssessmentTasks.js +++ b/FrontEndReact/src/View/Admin/View/ViewCompleteAssessmentTasks/ViewCompleteTeamAssessmentTasks.js @@ -6,7 +6,7 @@ import IconButton from '@mui/material/IconButton'; import VisibilityIcon from '@mui/icons-material/Visibility'; import { Box, Typography } from "@mui/material"; import CustomButton from "../../../Student/View/Components/CustomButton"; -import { genericResourcePUT } from "../../../../utility"; +import { genericResourcePUT, genericResourcePOST } from "../../../../utility"; import ResponsiveNotification from "../../../Components/SendNotification"; import CourseInfo from "../../../Components/CourseInfo"; @@ -23,6 +23,8 @@ class ViewCompleteTeamAssessmentTasks extends Component { showDialog: false, notes: '', notificationSent: false, + isSingleMsg: false, + compATId: null, errors: { notes:'' @@ -42,10 +44,12 @@ class ViewCompleteTeamAssessmentTasks extends Component { }); }; - handleDialog = () => { + handleDialog = (isSingleMessage, singleCompletedAT) => { this.setState({ showDialog: this.state.showDialog === false ? true : false, - }) + isSingleMsg: isSingleMessage, + compATId: singleCompletedAT, + }); } handleSendNotification = () => { @@ -69,20 +73,39 @@ class ViewCompleteTeamAssessmentTasks extends Component { return; } - genericResourcePUT( - `/mass_notification?assessment_task_id=${chosenAssessmentTask["assessment_task_id"]}&team=${true}`, - this, JSON.stringify({ - "date": date, - "notification_message": notes - }) - ).then((result) => { - if (result !== undefined && result.errorMessage === null) { - this.setState({ - showDialog: false, - notificationSent: date, + if(this.state.isSingleMsg){ + this.setState({isSingleMsg: false}, () => { + genericResourcePOST( + `/send_single_email?team=${true}&completed_assessment_id=${this.state.compATId}`, + this, JSON.stringify({ + "notification_message": notes, + }) + ).then((result) => { + if(result !== undefined && result.errorMessage === null){ + this.setState({ + showDialog: false, + notificationSent: date, + }); + } }); - } - }); + }); + }else{ + genericResourcePUT( + `/mass_notification?assessment_task_id=${chosenAssessmentTask["assessment_task_id"]}&team=${true}`, + this, JSON.stringify({ + "date": date, + "notification_message": notes + }) + ).then((result) => { + if (result !== undefined && result.errorMessage === null) { + this.setState({ + showDialog: false, + notificationSent: date, + }); + } + }); + } + }; render() { @@ -255,7 +278,38 @@ class ViewCompleteTeamAssessmentTasks extends Component { } } } - } + }, + { + name: "Student/Team Id", + label: "Message", + options: { + filter: false, + sort: false, + setCellHeaderProps: () => { return { align:"center", className:"button-column-alignment"}}, + setCellProps: () => { return { align:"center", className:"button-column-alignment"} }, + customBodyRender: (completedAssessmentId, completeAssessmentTasks) => { + const rowIndex = completeAssessmentTasks.rowIndex; + const completedATIndex = 5; + completedAssessmentId = completeAssessmentTasks.tableData[rowIndex][completedATIndex]; + if (completedAssessmentId !== null) { + return ( + this.handleDialog(true, completedAssessmentId)} + label="Message" + align="center" + isOutlined={true} + disabled={notificationSent} + aria-label="Send individual messages" + /> + ) + }else{ + return( +

{''}

+ ) + } + } + } + }, ]; const options = { @@ -294,7 +348,7 @@ class ViewCompleteTeamAssessmentTasks extends Component { this.handleDialog(false)} isOutlined={false} disabled={notificationSent} aria-label="viewCompletedAssessmentSendNotificationButton" From 5df054804293ed3b4108b87c2f1b58de1862bf3e Mon Sep 17 00:00:00 2001 From: aldo Date: Fri, 29 Nov 2024 14:56:29 -0600 Subject: [PATCH 16/19] modified query for finding students to email --- .../controller/Routes/notification_routes.py | 2 +- BackEndFlask/models/queries.py | 26 +++++++++++++------ 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/BackEndFlask/controller/Routes/notification_routes.py b/BackEndFlask/controller/Routes/notification_routes.py index 499844798..efc0ff369 100644 --- a/BackEndFlask/controller/Routes/notification_routes.py +++ b/BackEndFlask/controller/Routes/notification_routes.py @@ -60,7 +60,7 @@ def mass_notify_new_ca_users(): # Lowest possible time for easier comparisons. if at_time == None : at_time = datetime.datetime(1,1,1,0,0,0,0) - collection = get_students_for_emailing(at_id, is_teams) + collection = get_students_for_emailing(is_teams, at_id=at_id) left_to_notifiy = [singular_student for singular_student in collection if singular_student.last_update > at_time] diff --git a/BackEndFlask/models/queries.py b/BackEndFlask/models/queries.py index e4649332c..6911fcc42 100644 --- a/BackEndFlask/models/queries.py +++ b/BackEndFlask/models/queries.py @@ -1126,23 +1126,28 @@ def is_admin_by_user_id(user_id: int) -> bool: return True return False -def get_students_for_emailing(at_id: int, is_teams: bool) -> tuple[dict[str],dict[str]]: +def get_students_for_emailing(is_teams: bool, completed_at_id: int = None, at_id: int = None) -> tuple[dict[str],dict[str]]: """ Description: Returns the needed data for emailing students who should be reciving the notification from - their professors. + their professors. Note that it can also work for it you have a at_id or completed_at_id. Parameters: - at_id: (AT id) is_teams: (are we looking for students associated to a team?) - + at_id: (assessment Id) + completed_at_id: (Completed assessment Id) + Returns: tuple[dict[str],dict[str]] (The students information such as first_name, last_name, last_update, and email) Exceptions: - None raise by me except the database my raise some. + TypeError if completed_id and at_id are None. """ # Note a similar function exists but its a select * query which hinders prefomance. + + if at_id is None and completed_at_id is None: + raise TypeError("Both at_id and completed_at_id can not be .") + student_info = db.session.query( CompletedAssessment.last_update, User.first_name, @@ -1164,8 +1169,13 @@ def get_students_for_emailing(at_id: int, is_teams: bool) -> tuple[dict[str],dic User.user_id == CompletedAssessment.user_id ) - student_info = student_info.filter( - CompletedAssessment.assessment_task_id == at_id - ) + if at_id is not None: + student_info = student_info.filter( + CompletedAssessment.assessment_task_id == at_id + ) + else: + student_info = student_info.filter( + CompletedAssessment.completed_assessment_id == completed_at_id + ) return student_info.all() \ No newline at end of file From 0b56aff7d7927bf332f653e490df0f4cea77f564 Mon Sep 17 00:00:00 2001 From: aldo Date: Fri, 29 Nov 2024 15:06:15 -0600 Subject: [PATCH 17/19] backend and frontend single messaging are now hooked up --- BackEndFlask/controller/Routes/notification_routes.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/BackEndFlask/controller/Routes/notification_routes.py b/BackEndFlask/controller/Routes/notification_routes.py index efc0ff369..8372e8ddf 100644 --- a/BackEndFlask/controller/Routes/notification_routes.py +++ b/BackEndFlask/controller/Routes/notification_routes.py @@ -106,10 +106,12 @@ def send_single_email(): completed_assessment_id = request.args.get('completed_assessment_id') msg = request.json['notification_message'] - # Find the students to email. Need first_name, last_name, and email. + collection = get_students_for_emailing(is_teams, completed_at_id= completed_assessment_id) - # Put into a compreshion list and call emailing funciton(same func at above) + # Putting into a list as thats what the function wants. + left_to_notifiy = [singular_student for singular_student in collection] + email_students_feedback_is_ready_to_view(left_to_notifiy, msg) return create_good_response( "Message Sent", @@ -117,11 +119,6 @@ def send_single_email(): "Individual/Team notified" ) except Exception as e: - return create_good_response( - "Message Sent", - 201, - "Individual/Team notified" - ) return create_bad_response( f"An error occurred emailing user/s: {e}", "Individual/Team not notified", 400 ) \ No newline at end of file From 743efb12df43e0cd6afb5b8bc1c4c806dbfa2bb0 Mon Sep 17 00:00:00 2001 From: aldo Date: Fri, 29 Nov 2024 18:15:52 -0600 Subject: [PATCH 18/19] updated documentation --- BackEndFlask/controller/Routes/notification_routes.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/BackEndFlask/controller/Routes/notification_routes.py b/BackEndFlask/controller/Routes/notification_routes.py index 8372e8ddf..a651d31d9 100644 --- a/BackEndFlask/controller/Routes/notification_routes.py +++ b/BackEndFlask/controller/Routes/notification_routes.py @@ -45,6 +45,9 @@ def mass_notify_new_ca_users(): date: (date to record things) user_id: (who is requested the route[The decorators need it]) + Returns: + Bad or good response. + Exceptions: None all should be caught and handled """ @@ -88,6 +91,9 @@ def mass_notify_new_ca_users(): def send_single_email(): """ Description: + This function sends emails to select single students or teams based on a completed_assessment_id. + The function was teased out from the above function to allow the addition of new features. + Parameters: user_id: (who requested the route {decorators uses it}) is_team: (is this a team or individual msg) From a45a1dfda9a34a405d5d282a388aefcd1582ea52 Mon Sep 17 00:00:00 2001 From: aldo Date: Sun, 1 Dec 2024 12:31:38 -0600 Subject: [PATCH 19/19] Allowing email to raise the proper errors again. --- BackEndFlask/models/utility.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/BackEndFlask/models/utility.py b/BackEndFlask/models/utility.py index 27f538ea6..942ea62b0 100644 --- a/BackEndFlask/models/utility.py +++ b/BackEndFlask/models/utility.py @@ -48,13 +48,11 @@ def email_students_feedback_is_ready_to_view(students: list, notification_messag send_email(student.email, subject, message) -##############################################################Rest the excepttion before commiting def send_email(address: str, subject: str, content: str): try: yag = yagmail.SMTP("skillbuilder02", PASSWORD) yag.send(address, subject, content) except: - return raise EmailFailureException def generate_random_password(length: int):