From 2bdddc696224ca17de17a8193070129f8e5e467a Mon Sep 17 00:00:00 2001 From: Yiran Li Date: Sun, 10 Mar 2024 16:20:52 +1100 Subject: [PATCH 01/10] Creating a new endpoint as GET http method to get all the unavailability of a person in the database --- controllers/v2/unavailability/api.py | 18 ++++++------ repository/volunteer_unavailability_v2.py | 35 +++++++++++++++++++++++ 2 files changed, 44 insertions(+), 9 deletions(-) diff --git a/controllers/v2/unavailability/api.py b/controllers/v2/unavailability/api.py index 23a223a4..ac63bea4 100644 --- a/controllers/v2/unavailability/api.py +++ b/controllers/v2/unavailability/api.py @@ -16,8 +16,8 @@ class SpecificVolunteerUnavailabilityV2(Resource): - @requires_auth - @is_user_or_has_role(None, UserType.ROOT_ADMIN) + #@requires_auth + #@is_user_or_has_role(None, UserType.ROOT_ADMIN) def put(self, user_id, event_id): args = edit_parser.parse_args() with session_scope() as session: @@ -29,8 +29,8 @@ def put(self, user_id, event_id): else: return {"message": "Unexpected Error Occurred"}, 400 - @requires_auth - @is_user_or_has_role(None, UserType.ROOT_ADMIN) + #@requires_auth + #@is_user_or_has_role(None, UserType.ROOT_ADMIN) def delete(self, user_id, event_id): with session_scope() as session: try: @@ -48,19 +48,19 @@ def delete(self, user_id, event_id): class VolunteerUnavailabilityV2(Resource): - @requires_auth + #@requires_auth @marshal_with(volunteer_unavailability_time) - @is_user_or_has_role(None, UserType.ROOT_ADMIN) + #@is_user_or_has_role(None, UserType.ROOT_ADMIN) def get(self, user_id): with session_scope() as session: - volunteer_unavailability_record = fetch_event(session, user_id) + volunteer_unavailability_record = get_event(session, user_id) if volunteer_unavailability_record is not None: return volunteer_unavailability_record else: return jsonify({'userID': user_id, 'success': False}), 400 - @requires_auth - @is_user_or_has_role(None, UserType.ROOT_ADMIN) + #@requires_auth + #@is_user_or_has_role(None, UserType.ROOT_ADMIN) def post(self, user_id): try: args = edit_parser.parse_args() diff --git a/repository/volunteer_unavailability_v2.py b/repository/volunteer_unavailability_v2.py index e717e372..633af4c0 100644 --- a/repository/volunteer_unavailability_v2.py +++ b/repository/volunteer_unavailability_v2.py @@ -1,7 +1,12 @@ import logging +from flask import jsonify + from repository.unavailability_repository import * +from domain import UnavailabilityTime +from datetime import timezone + def edit_event(session, userId, eventId, title=None, start=None, end=None, periodicity=None): try: @@ -23,3 +28,33 @@ def edit_event(session, userId, eventId, title=None, start=None, end=None, perio session.rollback() logging.error(e) return None + +def get_event(session, userId): + """ + get all the non-availability events of the given user + :param session: session + :param userId: Integer, user id, who want to query the events + """ + try: + events = session.query(UnavailabilityTime).filter( + UnavailabilityTime.userId == userId, UnavailabilityTime.status == 1).all() + session.expunge_all() + '''for event in events: + print(f"Debug: Event ID: {event.eventId}, Start: {event.start}, End: {event.end}") + if events is not None: + event_records = [{ + "eventId": event.eventId, + "userId": event.userId, + "title": event.title, + "startTime": event.start.astimezone(timezone.utc).isoformat() if event.start else None, + "endTime": event.end.astimezone(timezone.utc).isoformat() if event.end else None, + "periodicity": event.periodicity + } for event in events] + print(event_records) + return event_records + else: + return None''' + return events + except Exception as e: + logging.error(e) + return None \ No newline at end of file From d6bb446d076e8887aa6c53d94172a2ebfae69a12 Mon Sep 17 00:00:00 2001 From: Yiran Li Date: Sun, 10 Mar 2024 16:27:56 +1100 Subject: [PATCH 02/10] remove comments --- controllers/v2/unavailability/api.py | 16 ++++++++-------- repository/volunteer_unavailability_v2.py | 18 ------------------ 2 files changed, 8 insertions(+), 26 deletions(-) diff --git a/controllers/v2/unavailability/api.py b/controllers/v2/unavailability/api.py index ac63bea4..9f970245 100644 --- a/controllers/v2/unavailability/api.py +++ b/controllers/v2/unavailability/api.py @@ -16,8 +16,8 @@ class SpecificVolunteerUnavailabilityV2(Resource): - #@requires_auth - #@is_user_or_has_role(None, UserType.ROOT_ADMIN) + @requires_auth + @is_user_or_has_role(None, UserType.ROOT_ADMIN) def put(self, user_id, event_id): args = edit_parser.parse_args() with session_scope() as session: @@ -29,8 +29,8 @@ def put(self, user_id, event_id): else: return {"message": "Unexpected Error Occurred"}, 400 - #@requires_auth - #@is_user_or_has_role(None, UserType.ROOT_ADMIN) + @requires_auth + @is_user_or_has_role(None, UserType.ROOT_ADMIN) def delete(self, user_id, event_id): with session_scope() as session: try: @@ -48,9 +48,9 @@ def delete(self, user_id, event_id): class VolunteerUnavailabilityV2(Resource): - #@requires_auth + @requires_auth @marshal_with(volunteer_unavailability_time) - #@is_user_or_has_role(None, UserType.ROOT_ADMIN) + @is_user_or_has_role(None, UserType.ROOT_ADMIN) def get(self, user_id): with session_scope() as session: volunteer_unavailability_record = get_event(session, user_id) @@ -59,8 +59,8 @@ def get(self, user_id): else: return jsonify({'userID': user_id, 'success': False}), 400 - #@requires_auth - #@is_user_or_has_role(None, UserType.ROOT_ADMIN) + @requires_auth + @is_user_or_has_role(None, UserType.ROOT_ADMIN) def post(self, user_id): try: args = edit_parser.parse_args() diff --git a/repository/volunteer_unavailability_v2.py b/repository/volunteer_unavailability_v2.py index 633af4c0..2b0e30fe 100644 --- a/repository/volunteer_unavailability_v2.py +++ b/repository/volunteer_unavailability_v2.py @@ -1,11 +1,8 @@ import logging -from flask import jsonify - from repository.unavailability_repository import * from domain import UnavailabilityTime -from datetime import timezone def edit_event(session, userId, eventId, title=None, start=None, end=None, periodicity=None): @@ -39,21 +36,6 @@ def get_event(session, userId): events = session.query(UnavailabilityTime).filter( UnavailabilityTime.userId == userId, UnavailabilityTime.status == 1).all() session.expunge_all() - '''for event in events: - print(f"Debug: Event ID: {event.eventId}, Start: {event.start}, End: {event.end}") - if events is not None: - event_records = [{ - "eventId": event.eventId, - "userId": event.userId, - "title": event.title, - "startTime": event.start.astimezone(timezone.utc).isoformat() if event.start else None, - "endTime": event.end.astimezone(timezone.utc).isoformat() if event.end else None, - "periodicity": event.periodicity - } for event in events] - print(event_records) - return event_records - else: - return None''' return events except Exception as e: logging.error(e) From 40cc8b904c6297b7729ea5c8c8e4f57eede18744 Mon Sep 17 00:00:00 2001 From: Yiran Li Date: Sun, 10 Mar 2024 17:23:39 +1100 Subject: [PATCH 03/10] Creating a new endpoint as GET http method to get all the unavailability of a person in the database --- controllers/v2/unavailability/api.py | 18 +++++++++--------- repository/volunteer_unavailability_v2.py | 23 +++++++++++++++++++++-- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/controllers/v2/unavailability/api.py b/controllers/v2/unavailability/api.py index 9f970245..785b5163 100644 --- a/controllers/v2/unavailability/api.py +++ b/controllers/v2/unavailability/api.py @@ -16,8 +16,8 @@ class SpecificVolunteerUnavailabilityV2(Resource): - @requires_auth - @is_user_or_has_role(None, UserType.ROOT_ADMIN) + #@requires_auth + #@is_user_or_has_role(None, UserType.ROOT_ADMIN) def put(self, user_id, event_id): args = edit_parser.parse_args() with session_scope() as session: @@ -29,8 +29,8 @@ def put(self, user_id, event_id): else: return {"message": "Unexpected Error Occurred"}, 400 - @requires_auth - @is_user_or_has_role(None, UserType.ROOT_ADMIN) + #@requires_auth + #@is_user_or_has_role(None, UserType.ROOT_ADMIN) def delete(self, user_id, event_id): with session_scope() as session: try: @@ -48,9 +48,9 @@ def delete(self, user_id, event_id): class VolunteerUnavailabilityV2(Resource): - @requires_auth - @marshal_with(volunteer_unavailability_time) - @is_user_or_has_role(None, UserType.ROOT_ADMIN) + #@requires_auth + #@marshal_with(volunteer_unavailability_time) + #@is_user_or_has_role(None, UserType.ROOT_ADMIN) def get(self, user_id): with session_scope() as session: volunteer_unavailability_record = get_event(session, user_id) @@ -59,8 +59,8 @@ def get(self, user_id): else: return jsonify({'userID': user_id, 'success': False}), 400 - @requires_auth - @is_user_or_has_role(None, UserType.ROOT_ADMIN) + #@requires_auth + #@is_user_or_has_role(None, UserType.ROOT_ADMIN) def post(self, user_id): try: args = edit_parser.parse_args() diff --git a/repository/volunteer_unavailability_v2.py b/repository/volunteer_unavailability_v2.py index 2b0e30fe..d7fd8ac3 100644 --- a/repository/volunteer_unavailability_v2.py +++ b/repository/volunteer_unavailability_v2.py @@ -1,6 +1,9 @@ import logging +from flask import jsonify + from repository.unavailability_repository import * +from datetime import datetime from domain import UnavailabilityTime @@ -32,11 +35,27 @@ def get_event(session, userId): :param session: session :param userId: Integer, user id, who want to query the events """ + now = datetime.now() try: + # only show the unavailability time that is end in the future events = session.query(UnavailabilityTime).filter( - UnavailabilityTime.userId == userId, UnavailabilityTime.status == 1).all() + UnavailabilityTime.userId == userId, UnavailabilityTime.status == 1, UnavailabilityTime.end > now).all() session.expunge_all() - return events + event_records = [] + for event in events: + # if the start time is earlier than now, then show from now to the end time + start_time = max(event.start, now) + event_record = { + "eventId": event.eventId, + "userId": event.userId, + "title": event.title, + "startTime": start_time.isoformat(), + "endTime": event.end.isoformat(), + "periodicity": event.periodicity + } + event_records.append(event_record) + + return jsonify(event_records) except Exception as e: logging.error(e) return None \ No newline at end of file From 5e3992365e9244e5164d32251ce585c36d124cd3 Mon Sep 17 00:00:00 2001 From: Yiran Li Date: Mon, 11 Mar 2024 11:44:07 +1100 Subject: [PATCH 04/10] modified the message --- controllers/v2/unavailability/api.py | 20 +++++++------- repository/volunteer_unavailability_v2.py | 33 ++++++++++++----------- 2 files changed, 27 insertions(+), 26 deletions(-) diff --git a/controllers/v2/unavailability/api.py b/controllers/v2/unavailability/api.py index 785b5163..99729f32 100644 --- a/controllers/v2/unavailability/api.py +++ b/controllers/v2/unavailability/api.py @@ -16,8 +16,8 @@ class SpecificVolunteerUnavailabilityV2(Resource): - #@requires_auth - #@is_user_or_has_role(None, UserType.ROOT_ADMIN) + @requires_auth + @is_user_or_has_role(None, UserType.ROOT_ADMIN) def put(self, user_id, event_id): args = edit_parser.parse_args() with session_scope() as session: @@ -29,8 +29,8 @@ def put(self, user_id, event_id): else: return {"message": "Unexpected Error Occurred"}, 400 - #@requires_auth - #@is_user_or_has_role(None, UserType.ROOT_ADMIN) + @requires_auth + @is_user_or_has_role(None, UserType.ROOT_ADMIN) def delete(self, user_id, event_id): with session_scope() as session: try: @@ -48,19 +48,19 @@ def delete(self, user_id, event_id): class VolunteerUnavailabilityV2(Resource): - #@requires_auth - #@marshal_with(volunteer_unavailability_time) - #@is_user_or_has_role(None, UserType.ROOT_ADMIN) + @requires_auth + @marshal_with(volunteer_unavailability_time) + @is_user_or_has_role(None, UserType.ROOT_ADMIN) def get(self, user_id): with session_scope() as session: volunteer_unavailability_record = get_event(session, user_id) if volunteer_unavailability_record is not None: return volunteer_unavailability_record else: - return jsonify({'userID': user_id, 'success': False}), 400 + return {"message": "No unavailability record found."}, 400 - #@requires_auth - #@is_user_or_has_role(None, UserType.ROOT_ADMIN) + @requires_auth + @is_user_or_has_role(None, UserType.ROOT_ADMIN) def post(self, user_id): try: args = edit_parser.parse_args() diff --git a/repository/volunteer_unavailability_v2.py b/repository/volunteer_unavailability_v2.py index d7fd8ac3..deea2178 100644 --- a/repository/volunteer_unavailability_v2.py +++ b/repository/volunteer_unavailability_v2.py @@ -40,22 +40,23 @@ def get_event(session, userId): # only show the unavailability time that is end in the future events = session.query(UnavailabilityTime).filter( UnavailabilityTime.userId == userId, UnavailabilityTime.status == 1, UnavailabilityTime.end > now).all() - session.expunge_all() - event_records = [] - for event in events: - # if the start time is earlier than now, then show from now to the end time - start_time = max(event.start, now) - event_record = { - "eventId": event.eventId, - "userId": event.userId, - "title": event.title, - "startTime": start_time.isoformat(), - "endTime": event.end.isoformat(), - "periodicity": event.periodicity - } - event_records.append(event_record) - - return jsonify(event_records) + if events: + event_records = [] + for event in events: + # if the start time is earlier than now, then show from now to the end time + start_time = max(event.start, now) + event_record = { + "eventId": event.eventId, + "userId": event.userId, + "title": event.title, + "startTime": start_time.isoformat(), + "endTime": event.end.isoformat(), + "periodicity": event.periodicity + } + event_records.append(event_record) + return jsonify(event_records) + else: + return None except Exception as e: logging.error(e) return None \ No newline at end of file From 9c6ac094183a7689b65fd05572d120f5ee2909a9 Mon Sep 17 00:00:00 2001 From: Yiran Li Date: Wed, 13 Mar 2024 06:04:24 +1100 Subject: [PATCH 05/10] wrap in EventRepository class and inject it through the constructor of the unavailability api resource --- controllers/v2/unavailability/api.py | 28 ++++-- repository/volunteer_unavailability_v2.py | 105 +++++++++++----------- 2 files changed, 74 insertions(+), 59 deletions(-) diff --git a/controllers/v2/unavailability/api.py b/controllers/v2/unavailability/api.py index 99729f32..945ae9f8 100644 --- a/controllers/v2/unavailability/api.py +++ b/controllers/v2/unavailability/api.py @@ -3,7 +3,8 @@ from .response_models import volunteer_unavailability_time from domain import session_scope, UserType -from repository.volunteer_unavailability_v2 import * +from repository.volunteer_unavailability_v2 import EventRepository +from repository.unavailability_repository import * from services.jwk import requires_auth, is_user_or_has_role from controllers.v2.v2_blueprint import v2_api @@ -16,12 +17,17 @@ class SpecificVolunteerUnavailabilityV2(Resource): + def __init__(self, event_repository): + self.event_repository = event_repository + @requires_auth @is_user_or_has_role(None, UserType.ROOT_ADMIN) def put(self, user_id, event_id): args = edit_parser.parse_args() with session_scope() as session: - success = edit_event(session, user_id, event_id, **args) + event_repository = EventRepository(session) + success = event_repository.edit_event(user_id, event_id, **args) + # success = edit_event(session, user_id, event_id, **args) if success is True: return {"message": "Updated successfully"}, 200 elif success is False: @@ -48,12 +54,17 @@ def delete(self, user_id, event_id): class VolunteerUnavailabilityV2(Resource): + def __init__(self, event_repository): + self.event_repository = event_repository + @requires_auth @marshal_with(volunteer_unavailability_time) @is_user_or_has_role(None, UserType.ROOT_ADMIN) def get(self, user_id): with session_scope() as session: - volunteer_unavailability_record = get_event(session, user_id) + event_repository = EventRepository(session) + volunteer_unavailability_record = event_repository.get_event(user_id) + # volunteer_unavailability_record = get_event(session, user_id) if volunteer_unavailability_record is not None: return volunteer_unavailability_record else: @@ -80,9 +91,10 @@ def post(self, user_id): except Exception as e: return {"description": "Internal server error", "error": str(e)}, 500 # HTTP 500 Internal Server Error +with session_scope() as session: + event_repository = EventRepository(session) + v2_api.add_resource(SpecificVolunteerUnavailabilityV2, '/v2/volunteers/', + '/v2/volunteers//unavailability/', resource_class_args=[event_repository]) -v2_api.add_resource(SpecificVolunteerUnavailabilityV2, '/v2/volunteers/', - '/v2/volunteers//unavailability/') - -v2_api.add_resource(VolunteerUnavailabilityV2, '/v2/volunteers/', - '/v2/volunteers//unavailability') + v2_api.add_resource(VolunteerUnavailabilityV2, '/v2/volunteers/', + '/v2/volunteers//unavailability', resource_class_args=[event_repository]) diff --git a/repository/volunteer_unavailability_v2.py b/repository/volunteer_unavailability_v2.py index deea2178..7fa9368c 100644 --- a/repository/volunteer_unavailability_v2.py +++ b/repository/volunteer_unavailability_v2.py @@ -2,61 +2,64 @@ from flask import jsonify -from repository.unavailability_repository import * from datetime import datetime from domain import UnavailabilityTime -def edit_event(session, userId, eventId, title=None, start=None, end=None, periodicity=None): - try: - event = session.query(UnavailabilityTime).filter(UnavailabilityTime.eventId == eventId, - UnavailabilityTime.userId == userId).first() - if event is None: - return False - if title is not None: - event.title = title - if start is not None: - event.start = start - if end is not None: - event.end = end - if end is not None: - event.periodicity = periodicity - session.commit() - return True - except Exception as e: - session.rollback() - logging.error(e) - return None +class EventRepository: + def __init__(self, session): + self.session = session -def get_event(session, userId): - """ - get all the non-availability events of the given user - :param session: session - :param userId: Integer, user id, who want to query the events - """ - now = datetime.now() - try: - # only show the unavailability time that is end in the future - events = session.query(UnavailabilityTime).filter( - UnavailabilityTime.userId == userId, UnavailabilityTime.status == 1, UnavailabilityTime.end > now).all() - if events: - event_records = [] - for event in events: - # if the start time is earlier than now, then show from now to the end time - start_time = max(event.start, now) - event_record = { - "eventId": event.eventId, - "userId": event.userId, - "title": event.title, - "startTime": start_time.isoformat(), - "endTime": event.end.isoformat(), - "periodicity": event.periodicity - } - event_records.append(event_record) - return jsonify(event_records) - else: + def edit_event(self, userId, eventId, title=None, start=None, end=None, periodicity=None): + try: + event = self.session.query(UnavailabilityTime).filter(UnavailabilityTime.eventId == eventId, + UnavailabilityTime.userId == userId).first() + if event is None: + return False + if title is not None: + event.title = title + if start is not None: + event.start = start + if end is not None: + event.end = end + if end is not None: + event.periodicity = periodicity + self.session.commit() + return True + except Exception as e: + self.session.rollback() + logging.error(e) return None - except Exception as e: - logging.error(e) - return None \ No newline at end of file + + def get_event(self, userId): + """ + get all the non-availability events of the given user + :param session: session + :param userId: Integer, user id, who want to query the events + """ + now = datetime.now() + try: + # only show the unavailability time that is end in the future + events = self.session.query(UnavailabilityTime).filter( + UnavailabilityTime.userId == userId, UnavailabilityTime.status == 1, UnavailabilityTime.end > now).all() + if events: + event_records = [] + for event in events: + # if the start time is earlier than now, then show from now to the end time + start_time = max(event.start, now) + event_record = { + "eventId": event.eventId, + "userId": event.userId, + "title": event.title, + "startTime": start_time.isoformat(), + "endTime": event.end.isoformat(), + "periodicity": event.periodicity + } + event_records.append(event_record) + return jsonify(event_records) + else: + return None + except Exception as e: + logging.error(e) + return None \ No newline at end of file From 5b9c6d40581cc3bc3b72e7c1c9a76c040b19d11c Mon Sep 17 00:00:00 2001 From: Yiran Li Date: Wed, 13 Mar 2024 06:54:20 +1100 Subject: [PATCH 06/10] add delete and create function in EventRepository class --- controllers/v2/unavailability/api.py | 16 +++----- repository/volunteer_unavailability_v2.py | 48 ++++++++++++++++++++++- 2 files changed, 53 insertions(+), 11 deletions(-) diff --git a/controllers/v2/unavailability/api.py b/controllers/v2/unavailability/api.py index 470f9cf4..7d4070db 100644 --- a/controllers/v2/unavailability/api.py +++ b/controllers/v2/unavailability/api.py @@ -8,7 +8,6 @@ from .response_models import volunteer_unavailability_time from domain import session_scope, UserType from repository.volunteer_unavailability_v2 import EventRepository -from repository.unavailability_repository import * from services.jwk import requires_auth, is_user_or_has_role from controllers.v2.v2_blueprint import v2_api @@ -44,7 +43,9 @@ def put(self, user_id, event_id): def delete(self, user_id, event_id): with session_scope() as session: try: - success = remove_event(session, user_id, event_id) + event_repository = EventRepository(session) + success = event_repository.remove_event(user_id, event_id) + #success = remove_event(session, user_id, event_id) if success: # If the event is successfully removed, return HTTP 200 OK. return {"message": "Unavailability event removed successfully."}, 200 @@ -84,13 +85,8 @@ def post(self, user_id): return {"message": "Start time must be earlier than end time"}, 400 # HTTP 400 Bad Request with session_scope() as session: - # checks if new time frame overlaps with any existing in the database for specific userId - overlapping_events = session.query(UnavailabilityTime).filter( - UnavailabilityTime.userId == user_id, - UnavailabilityTime.start < args['end'], - UnavailabilityTime.end > args['start'], - UnavailabilityTime.periodicity == args['periodicity'] - ).all() + event_repository = EventRepository(session) + overlapping_events = event_repository.check_overlapping_events(user_id, args['start'], args['end'], args['periodicity']) if overlapping_events: overlapping_details = [] for event in overlapping_events: @@ -99,7 +95,7 @@ def post(self, user_id): return {"message": "Time frames overlap with existing events", "overlapping_events": overlapping_details}, 400 # HTTP 400 Bad Request - eventId = create_event( + eventId = event_repository.create_event( session, user_id, args['title'], diff --git a/repository/volunteer_unavailability_v2.py b/repository/volunteer_unavailability_v2.py index 7fa9368c..d84a1422 100644 --- a/repository/volunteer_unavailability_v2.py +++ b/repository/volunteer_unavailability_v2.py @@ -62,4 +62,50 @@ def get_event(self, userId): return None except Exception as e: logging.error(e) - return None \ No newline at end of file + return None + + # copy from repository.unavailability_repository.py + def create_event(self, userId, title, startTime, endTime, periodicity): + """ + Function to create an event + :param session: session + :param userId: Integer, user id + :param title: String, reason why unavailable + :param startTime: DateTime, from what time is unavailable + :param endTime: DateTime, to what time is unavailable + :param periodicity: Integer, Daily = 1, Weekly = 2, One-Off = 3 + """ + event = UnavailabilityTime(userId=userId, title=title, start=startTime, end=endTime, + periodicity=periodicity) + self.session.add(event) + # session.expunge(question) + self.session.flush() + return event.eventId + + # copy from repository.unavailability_repository.py + def remove_event(self, userId, eventId): + """ + Function to remove an event + :param session: session + :param userId: Integer, user id, who want to remove an event + :param eventId: Integer, event id want to remove + :return: True: remove successful + False: remove failed + """ + existing = self.session.query(UnavailabilityTime).filter(UnavailabilityTime.userId == userId, + UnavailabilityTime.eventId == eventId).first() + if existing is not None and existing.status is True: + existing.status = False + return True + return False + + # copy from post function in api.py written by Steven + def check_overlapping_events(self, userId, startTime, endTime, periodicity): + # checks if new time frame overlaps with any existing in the database for specific userId + overlapping_events = self.session.query(UnavailabilityTime).filter( + UnavailabilityTime.userId == userId, + UnavailabilityTime.start < endTime, + UnavailabilityTime.end > startTime, + UnavailabilityTime.periodicity == periodicity + ).all() + return overlapping_events \ No newline at end of file From 0b7284ab169b39e717f040b0d2e3f0be4fd8c7ce Mon Sep 17 00:00:00 2001 From: Yiran Li Date: Thu, 14 Mar 2024 05:57:49 +1100 Subject: [PATCH 07/10] fix some error --- controllers/v2/unavailability/api.py | 42 +++++++++++++--------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/controllers/v2/unavailability/api.py b/controllers/v2/unavailability/api.py index 7d4070db..52ebaf01 100644 --- a/controllers/v2/unavailability/api.py +++ b/controllers/v2/unavailability/api.py @@ -20,17 +20,16 @@ class SpecificVolunteerUnavailabilityV2(Resource): - def __init__(self, event_repository): - self.event_repository = event_repository + def __init__(self): + self.event_repository = None @requires_auth @is_user_or_has_role(None, UserType.ROOT_ADMIN) def put(self, user_id, event_id): args = edit_parser.parse_args() with session_scope() as session: - event_repository = EventRepository(session) - success = event_repository.edit_event(user_id, event_id, **args) - # success = edit_event(session, user_id, event_id, **args) + self.event_repository = EventRepository(session) + success = self.event_repository.edit_event(user_id, event_id, **args) if success is True: return {"message": "Updated successfully"}, 200 elif success is False: @@ -43,9 +42,8 @@ def put(self, user_id, event_id): def delete(self, user_id, event_id): with session_scope() as session: try: - event_repository = EventRepository(session) - success = event_repository.remove_event(user_id, event_id) - #success = remove_event(session, user_id, event_id) + self.event_repository = EventRepository(session) + success = self.event_repository.remove_event(user_id, event_id) if success: # If the event is successfully removed, return HTTP 200 OK. return {"message": "Unavailability event removed successfully."}, 200 @@ -59,17 +57,16 @@ def delete(self, user_id, event_id): class VolunteerUnavailabilityV2(Resource): - def __init__(self, event_repository): - self.event_repository = event_repository + def __init__(self): + self.event_repository = None @requires_auth @marshal_with(volunteer_unavailability_time) @is_user_or_has_role(None, UserType.ROOT_ADMIN) def get(self, user_id): with session_scope() as session: - event_repository = EventRepository(session) - volunteer_unavailability_record = event_repository.get_event(user_id) - # volunteer_unavailability_record = get_event(session, user_id) + self.event_repository = EventRepository(session) + volunteer_unavailability_record = self.event_repository.get_event(user_id) if volunteer_unavailability_record is not None: return volunteer_unavailability_record else: @@ -85,8 +82,8 @@ def post(self, user_id): return {"message": "Start time must be earlier than end time"}, 400 # HTTP 400 Bad Request with session_scope() as session: - event_repository = EventRepository(session) - overlapping_events = event_repository.check_overlapping_events(user_id, args['start'], args['end'], args['periodicity']) + self.event_repository = EventRepository(session) + overlapping_events = self.event_repository.check_overlapping_events(user_id, args['start'], args['end'], args['periodicity']) if overlapping_events: overlapping_details = [] for event in overlapping_events: @@ -95,8 +92,7 @@ def post(self, user_id): return {"message": "Time frames overlap with existing events", "overlapping_events": overlapping_details}, 400 # HTTP 400 Bad Request - eventId = event_repository.create_event( - session, + eventId = self.event_repository.create_event( user_id, args['title'], args['start'], @@ -110,10 +106,10 @@ def post(self, user_id): except Exception as e: return {"description": "Internal server error", "error": str(e)}, 500 # HTTP 500 Internal Server Error -with session_scope() as session: - event_repository = EventRepository(session) - v2_api.add_resource(SpecificVolunteerUnavailabilityV2, '/v2/volunteers/', - '/v2/volunteers//unavailability/', resource_class_args=[event_repository]) - v2_api.add_resource(VolunteerUnavailabilityV2, '/v2/volunteers/', - '/v2/volunteers//unavailability', resource_class_args=[event_repository]) + +v2_api.add_resource(SpecificVolunteerUnavailabilityV2, '/v2/volunteers/', + '/v2/volunteers//unavailability/') + +v2_api.add_resource(VolunteerUnavailabilityV2, '/v2/volunteers/', + '/v2/volunteers//unavailability') From 021fbe14b38fedacf9b9b41adc24ec93bdc31112 Mon Sep 17 00:00:00 2001 From: Yiran Li Date: Sat, 16 Mar 2024 08:52:03 +1100 Subject: [PATCH 08/10] modified to pass EventRepository in through the constructor --- controllers/v2/unavailability/api.py | 105 ++++++++---------- repository/volunteer_unavailability_v2.py | 128 +++++++++++----------- 2 files changed, 112 insertions(+), 121 deletions(-) diff --git a/controllers/v2/unavailability/api.py b/controllers/v2/unavailability/api.py index 52ebaf01..c306691e 100644 --- a/controllers/v2/unavailability/api.py +++ b/controllers/v2/unavailability/api.py @@ -1,12 +1,7 @@ -import json -import uuid - -from flask import jsonify from flask_restful import reqparse, Resource, marshal_with, inputs -from domain.entity import unavailability_time from .response_models import volunteer_unavailability_time -from domain import session_scope, UserType +from domain import UserType from repository.volunteer_unavailability_v2 import EventRepository from services.jwk import requires_auth, is_user_or_has_role from controllers.v2.v2_blueprint import v2_api @@ -21,56 +16,50 @@ class SpecificVolunteerUnavailabilityV2(Resource): def __init__(self): - self.event_repository = None + self.event_repository = EventRepository() @requires_auth @is_user_or_has_role(None, UserType.ROOT_ADMIN) def put(self, user_id, event_id): args = edit_parser.parse_args() - with session_scope() as session: - self.event_repository = EventRepository(session) - success = self.event_repository.edit_event(user_id, event_id, **args) - if success is True: - return {"message": "Updated successfully"}, 200 - elif success is False: - return {"message": "Event not found"}, 404 - else: - return {"message": "Unexpected Error Occurred"}, 400 + success = self.event_repository.edit_event(user_id, event_id, **args) + if success is True: + return {"message": "Updated successfully"}, 200 + elif success is False: + return {"message": "Event not found"}, 404 + else: + return {"message": "Unexpected Error Occurred"}, 400 @requires_auth @is_user_or_has_role(None, UserType.ROOT_ADMIN) def delete(self, user_id, event_id): - with session_scope() as session: - try: - self.event_repository = EventRepository(session) - success = self.event_repository.remove_event(user_id, event_id) - if success: - # If the event is successfully removed, return HTTP 200 OK. - return {"message": "Unavailability event removed successfully."}, 200 - else: - # If the event does not exist or could not be removed, return HTTP 404 Not Found. - return {"message": "Unavailability event not found."}, 404 - except Exception as e: - # HTTP 500 Internal Server Error - return {"message": "Internal server error", "error": str(e)}, 500 + try: + success = self.event_repository.remove_event(user_id, event_id) + if success: + # If the event is successfully removed, return HTTP 200 OK. + return {"message": "Unavailability event removed successfully."}, 200 + else: + # If the event does not exist or could not be removed, return HTTP 404 Not Found. + return {"message": "Unavailability event not found."}, 404 + except Exception as e: + # HTTP 500 Internal Server Error + return {"message": "Internal server error", "error": str(e)}, 500 class VolunteerUnavailabilityV2(Resource): def __init__(self): - self.event_repository = None + self.event_repository = EventRepository() @requires_auth @marshal_with(volunteer_unavailability_time) @is_user_or_has_role(None, UserType.ROOT_ADMIN) def get(self, user_id): - with session_scope() as session: - self.event_repository = EventRepository(session) - volunteer_unavailability_record = self.event_repository.get_event(user_id) - if volunteer_unavailability_record is not None: - return volunteer_unavailability_record - else: - return {"message": "No unavailability record found."}, 400 + volunteer_unavailability_record = self.event_repository.get_event(user_id) + if volunteer_unavailability_record is not None: + return volunteer_unavailability_record + else: + return {"message": "No unavailability record found."}, 400 @requires_auth @is_user_or_has_role(None, UserType.ROOT_ADMIN) @@ -81,28 +70,26 @@ def post(self, user_id): if args['start'] >= args['end']: return {"message": "Start time must be earlier than end time"}, 400 # HTTP 400 Bad Request - with session_scope() as session: - self.event_repository = EventRepository(session) - overlapping_events = self.event_repository.check_overlapping_events(user_id, args['start'], args['end'], args['periodicity']) - if overlapping_events: - overlapping_details = [] - for event in overlapping_events: - overlapping_details.append({ - "eventId": event.eventId}) - return {"message": "Time frames overlap with existing events", - "overlapping_events": overlapping_details}, 400 # HTTP 400 Bad Request - - eventId = self.event_repository.create_event( - user_id, - args['title'], - args['start'], - args['end'], - args['periodicity'] - ) - if eventId is not None: - return {"eventId": eventId}, 200 # HTTP 200 OK - else: - return {"description": "Failed to create event"}, 400 # HTTP 400 Bad Request + overlapping_events = self.event_repository.check_overlapping_events(user_id, args['start'], args['end'], args['periodicity']) + if overlapping_events: + overlapping_details = [] + for event in overlapping_events: + overlapping_details.append({ + "eventId": event.eventId}) + return {"message": "Time frames overlap with existing events", + "overlapping_events": overlapping_details}, 400 # HTTP 400 Bad Request + + eventId = self.event_repository.create_event( + user_id, + args['title'], + args['start'], + args['end'], + args['periodicity'] + ) + if eventId is not None: + return {"eventId": eventId}, 200 # HTTP 200 OK + else: + return {"description": "Failed to create event"}, 400 # HTTP 400 Bad Request except Exception as e: return {"description": "Internal server error", "error": str(e)}, 500 # HTTP 500 Internal Server Error diff --git a/repository/volunteer_unavailability_v2.py b/repository/volunteer_unavailability_v2.py index d84a1422..f5ed69a5 100644 --- a/repository/volunteer_unavailability_v2.py +++ b/repository/volunteer_unavailability_v2.py @@ -4,33 +4,33 @@ from datetime import datetime -from domain import UnavailabilityTime +from domain import UnavailabilityTime, session_scope class EventRepository: - def __init__(self, session): - self.session = session - + def __init__(self): + pass def edit_event(self, userId, eventId, title=None, start=None, end=None, periodicity=None): - try: - event = self.session.query(UnavailabilityTime).filter(UnavailabilityTime.eventId == eventId, + with session_scope() as session: + try: + event = session.query(UnavailabilityTime).filter(UnavailabilityTime.eventId == eventId, UnavailabilityTime.userId == userId).first() - if event is None: - return False - if title is not None: - event.title = title - if start is not None: - event.start = start - if end is not None: - event.end = end - if end is not None: - event.periodicity = periodicity - self.session.commit() - return True - except Exception as e: - self.session.rollback() - logging.error(e) - return None + if event is None: + return False + if title is not None: + event.title = title + if start is not None: + event.start = start + if end is not None: + event.end = end + if end is not None: + event.periodicity = periodicity + session.commit() + return True + except Exception as e: + session.rollback() + logging.error(e) + return None def get_event(self, userId): """ @@ -39,30 +39,31 @@ def get_event(self, userId): :param userId: Integer, user id, who want to query the events """ now = datetime.now() - try: - # only show the unavailability time that is end in the future - events = self.session.query(UnavailabilityTime).filter( - UnavailabilityTime.userId == userId, UnavailabilityTime.status == 1, UnavailabilityTime.end > now).all() - if events: - event_records = [] - for event in events: - # if the start time is earlier than now, then show from now to the end time - start_time = max(event.start, now) - event_record = { - "eventId": event.eventId, - "userId": event.userId, - "title": event.title, - "startTime": start_time.isoformat(), - "endTime": event.end.isoformat(), - "periodicity": event.periodicity - } - event_records.append(event_record) - return jsonify(event_records) - else: + with session_scope() as session: + try: + # only show the unavailability time that is end in the future + events = session.query(UnavailabilityTime).filter( + UnavailabilityTime.userId == userId, UnavailabilityTime.status == 1, UnavailabilityTime.end > now).all() + if events: + event_records = [] + for event in events: + # if the start time is earlier than now, then show from now to the end time + start_time = max(event.start, now) + event_record = { + "eventId": event.eventId, + "userId": event.userId, + "title": event.title, + "startTime": start_time.isoformat(), + "endTime": event.end.isoformat(), + "periodicity": event.periodicity + } + event_records.append(event_record) + return jsonify(event_records) + else: + return None + except Exception as e: + logging.error(e) return None - except Exception as e: - logging.error(e) - return None # copy from repository.unavailability_repository.py def create_event(self, userId, title, startTime, endTime, periodicity): @@ -77,10 +78,11 @@ def create_event(self, userId, title, startTime, endTime, periodicity): """ event = UnavailabilityTime(userId=userId, title=title, start=startTime, end=endTime, periodicity=periodicity) - self.session.add(event) - # session.expunge(question) - self.session.flush() - return event.eventId + with session_scope() as session: + session.add(event) + # session.expunge(question) + session.flush() + return event.eventId # copy from repository.unavailability_repository.py def remove_event(self, userId, eventId): @@ -92,20 +94,22 @@ def remove_event(self, userId, eventId): :return: True: remove successful False: remove failed """ - existing = self.session.query(UnavailabilityTime).filter(UnavailabilityTime.userId == userId, - UnavailabilityTime.eventId == eventId).first() - if existing is not None and existing.status is True: - existing.status = False - return True - return False + with session_scope() as session: + existing = session.query(UnavailabilityTime).filter(UnavailabilityTime.userId == userId, + UnavailabilityTime.eventId == eventId).first() + if existing is not None and existing.status is True: + existing.status = False + return True + return False # copy from post function in api.py written by Steven def check_overlapping_events(self, userId, startTime, endTime, periodicity): - # checks if new time frame overlaps with any existing in the database for specific userId - overlapping_events = self.session.query(UnavailabilityTime).filter( - UnavailabilityTime.userId == userId, - UnavailabilityTime.start < endTime, - UnavailabilityTime.end > startTime, - UnavailabilityTime.periodicity == periodicity - ).all() + with session_scope() as session: + # checks if new time frame overlaps with any existing in the database for specific userId + overlapping_events = session.query(UnavailabilityTime).filter( + UnavailabilityTime.userId == userId, + UnavailabilityTime.start < endTime, + UnavailabilityTime.end > startTime, + UnavailabilityTime.periodicity == periodicity + ).all() return overlapping_events \ No newline at end of file From 917cbae66587058645fdf45f563e47f9729349a8 Mon Sep 17 00:00:00 2001 From: Tai Ha Date: Fri, 15 Mar 2024 00:42:33 +1100 Subject: [PATCH 09/10] remove bug in testing code. Using inmemory database instead of real database to avoid unwanted behaviour. Need further testing --- domain/base.py | 13 +++-- domain/entity/diet_requirement.py | 2 +- domain/entity/question.py | 3 +- domain/entity/unavailability_time.py | 2 +- tests/conftest.py | 68 ++++++++++++++++++++----- tests/functional/test_unavailability.py | 28 +++++----- 6 files changed, 81 insertions(+), 35 deletions(-) diff --git a/domain/base.py b/domain/base.py index 7e838ce9..0b6ee756 100644 --- a/domain/base.py +++ b/domain/base.py @@ -12,11 +12,14 @@ # Configure Session Session = sessionmaker() -Engine = create_engine('mysql+mysqldb://{0}:{1}@{2}:{3}/{4}'.format(os.environ.get('username'), - os.environ.get('password'), - os.environ.get('host'), - os.environ.get('port'), - os.environ.get('dbname')), echo=False) +if os.environ.get("SQLALCHEMY_DATABASE_URI"): + Engine = create_engine(os.environ.get("SQLALCHEMY_DATABASE_URI")) +else: + Engine = create_engine('mysql+mysqldb://{0}:{1}@{2}:{3}/{4}'.format(os.environ.get('username'), + os.environ.get('password'), + os.environ.get('host'), + os.environ.get('port'), + os.environ.get('dbname')), echo=False) Session.configure(bind=Engine) # Configure Declarative Base for ORM diff --git a/domain/entity/diet_requirement.py b/domain/entity/diet_requirement.py index fef1246f..0edf7128 100644 --- a/domain/entity/diet_requirement.py +++ b/domain/entity/diet_requirement.py @@ -8,7 +8,7 @@ class DietRequirement(Base): __tablename__ = 'diet_requirement' diet_id = Column(Integer, primary_key=True, autoincrement=True) - user_id = Column(Integer, ForeignKey('user.id'), primary_key=True, nullable=False) + user_id = Column(Integer, ForeignKey('user.id'), nullable=False) halal = Column(Boolean, nullable=False, default=0) vegetarian = Column(Boolean, nullable=False, default=0) vegan = Column(Boolean, nullable=False, default=0) diff --git a/domain/entity/question.py b/domain/entity/question.py index adeb4b38..3490e0ca 100644 --- a/domain/entity/question.py +++ b/domain/entity/question.py @@ -1,6 +1,5 @@ from datetime import datetime from sqlalchemy import Column, Integer, String, DateTime, Boolean, Enum, Text -from sqlalchemy.dialects.mysql import TINYINT from domain.base import Base from domain.type import QuestionType @@ -14,7 +13,7 @@ class Question(Base): role = Column(String(256), nullable=True) description = Column(String(1024), nullable=False) choice = Column(Text, nullable=False) - difficulty = Column(TINYINT, default=1, nullable=False) + difficulty = Column(Integer, default=1, nullable=False) answer = Column(String(20), nullable=False) status = Column(Boolean, default=True, nullable=False) answered_time = Column(Integer, default=0, nullable=False) diff --git a/domain/entity/unavailability_time.py b/domain/entity/unavailability_time.py index d4358209..67759b12 100644 --- a/domain/entity/unavailability_time.py +++ b/domain/entity/unavailability_time.py @@ -6,7 +6,7 @@ class UnavailabilityTime(Base): __tablename__ = 'unavailability_time' eventId = Column(Integer, primary_key=True, autoincrement=True) - userId = Column(Integer, ForeignKey('user.id'), primary_key=True, nullable=False) + userId = Column(Integer, ForeignKey('user.id'), nullable=False) title = Column(String(256), nullable=True, default=None) periodicity = Column(Integer, nullable=False, default=1) start = Column(DateTime, nullable=False, default=datetime.now()) diff --git a/tests/conftest.py b/tests/conftest.py index 13828e27..3581e5fd 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,34 +1,76 @@ import os -os.environ.setdefault('username', 'user') -os.environ.setdefault('password', 'password') -os.environ.setdefault('host', '127.0.0.1') -os.environ.setdefault('port', '3306') -os.environ.setdefault('dbname', 'db') +os.environ.setdefault("SQLALCHEMY_DATABASE_URI", 'sqlite:///:memory:') import pytest from application import app +from domain.base import Engine, Base, Session +from domain.entity.user import User +from domain.type.user_type import UserType +from datetime import datetime + + +@pytest.fixture(scope='session', autouse=True) +def create_test_database(): + Base.metadata.drop_all(bind=Engine) + Base.metadata.create_all(bind=Engine) + yield + Base.metadata.drop_all(bind=Engine) + + +@pytest.fixture(autouse=True) +def transactional_test(create_test_database, request): + connection = Engine.connect() + transaction = connection.begin() + + try: + nested = connection.begin_nested() + + Session.configure(bind=connection) + yield + + finally: + nested.rollback() + transaction.rollback() + connection.close() @pytest.fixture(scope='module') def test_client(): - # Set the Testing configuration prior to creating the Flask application - with app.test_client() as testing_client: - # Establish an application context with app.app_context(): yield testing_client +@pytest.fixture(scope='module') +def create_user(): + session = Session() + test_user = User( + role=UserType.ROOT_ADMIN, + first_name="admin", + last_name="admin", + mobile_number="1234567890", + email="admin", + update_date_time=datetime.utcnow(), + insert_date_time=datetime.utcnow(), + password="$2a$12$BEOqNVY7cHlMztWNra87nuHAHqvex/ZgFfPmq5ZNNi4DxFHyflHau" + ) + session.add(test_user) + session.commit() + user_id = test_user.id + yield user_id + session.delete(test_user) + session.commit() + session.close() + + @pytest.fixture(scope='module') def auth_token(test_client): - # Login with predefined admin credentials - login_payload = { # admin account details - 'email': 'admin', - 'password': 'admin' + login_payload = { + "email": "admin", + "password": "admin" } response = test_client.post('/authentication/login', json=login_payload) assert response.status_code == 200, "Failed to log in with the given credential" - print(response.json) token = response.json['access_token'] return token diff --git a/tests/functional/test_unavailability.py b/tests/functional/test_unavailability.py index 060ac788..d5ea56db 100644 --- a/tests/functional/test_unavailability.py +++ b/tests/functional/test_unavailability.py @@ -1,5 +1,5 @@ -def test_create_unavailability_consecutive_event_id(test_client): - user_id = 49 # admin id +def test_create_unavailability_consecutive_event_id(test_client, create_user): + user_id = create_user payload_1 = { "title": "All Day Event", "periodicity": 0, @@ -23,8 +23,8 @@ def test_create_unavailability_consecutive_event_id(test_client): assert response_2.json["eventId"] - response.json["eventId"] == 1 -def test_create_unavailability_same_time_interval(test_client): - user_id = 49 +def test_create_unavailability_same_time_interval(test_client, create_user): + user_id = create_user payload = { "title": "All Day Event", "periodicity": 0, @@ -37,6 +37,8 @@ def test_create_unavailability_same_time_interval(test_client): response_2 = test_client.post(f"/v2/volunteers/{user_id}/unavailability", json=payload ) + print(response.json) + assert response.status_code == 200 assert response_2.status_code == 400 @@ -52,11 +54,11 @@ def test_create_unavailability_nonexistent_user_id(test_client): response = test_client.post(f"/v2/volunteers/{user_id}/unavailability", json=payload ) - response.status_code = 404 + assert response.status_code == 404 -def test_create_unavailability_end_before_start(test_client): - user_id = 49 +def test_create_unavailability_end_before_start(test_client, create_user): + user_id = create_user payload = { "title": "All Day Event", "periodicity": 0, @@ -69,8 +71,8 @@ def test_create_unavailability_end_before_start(test_client): assert response.status_code == 400 -def test_create_unavailability_overlapped_time(test_client): - user_id = 49 +def test_create_unavailability_overlapped_time(test_client, create_user): + user_id = create_user payload_1 = { "title": "All Day Event", "periodicity": 0, @@ -93,8 +95,8 @@ def test_create_unavailability_overlapped_time(test_client): assert response_2.status_code == 400 -def test_merge_overlapping_unavailability_intervals(test_client): - user_id = 49 +def test_merge_overlapping_unavailability_intervals(test_client, create_user): + user_id = create_user payload_1 = { "title": "Morning Event", "periodicity": 0, @@ -115,8 +117,8 @@ def test_merge_overlapping_unavailability_intervals(test_client): assert response.json["mergedIntervals"][0]["end"] == "2024-03-05T15:00:00Z" -def test_merge_adjacent_unavailability_intervals(test_client): - user_id = 49 +def test_merge_adjacent_unavailability_intervals(test_client, create_user): + user_id = create_user payload_1 = { "title": "Morning Shift", "periodicity": 0, From a8a1489feff7e4cf0dcbfa5363fc5563d8e255c0 Mon Sep 17 00:00:00 2001 From: Tai Ha Date: Sat, 16 Mar 2024 23:32:08 +1100 Subject: [PATCH 10/10] remove register creation bug and enforce foreign key constraint on testing sqlite database --- domain/base.py | 8 ++++++++ services/authentication.py | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/domain/base.py b/domain/base.py index 0b6ee756..9727a54b 100644 --- a/domain/base.py +++ b/domain/base.py @@ -14,6 +14,14 @@ Session = sessionmaker() if os.environ.get("SQLALCHEMY_DATABASE_URI"): Engine = create_engine(os.environ.get("SQLALCHEMY_DATABASE_URI")) + + + def enable_fk_listener(dbapi_connection, connection_record): # enabling foreign key constraint in the test database + dbapi_connection.execute('pragma foreign_keys=ON') + + + event.listen(Engine, 'connect', enable_fk_listener) + else: Engine = create_engine('mysql+mysqldb://{0}:{1}@{2}:{3}/{4}'.format(os.environ.get('username'), os.environ.get('password'), diff --git a/services/authentication.py b/services/authentication.py index a369f3e8..f1b7d6ab 100644 --- a/services/authentication.py +++ b/services/authentication.py @@ -59,7 +59,7 @@ def register(session: Session, email: str, password: str, given_name: str, last_ # Everything seems fine, so we go ahead and create the user & the linked account. password_hash = passwordService.hash(password) new_user = User(role=UserType.VOLUNTEER, password=password_hash, first_name=given_name, last_name=last_name, - mobile_number=phone, email=email, preferred_hours={}, experience_years=0, possibleRoles=["Basic"], + mobile_number=phone, email=email, preferred_hours=None, experience_years=0, possibleRoles=["Basic"], qualifications=[], availabilities={"Friday": [], "Monday": [], "Sunday": [], "Tuesday": [], "Saturday": [], "Thursday": [], "Wednesday": []},