Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Yiran li/feature/get unavailability #178

Merged
merged 11 commits into from
Mar 18, 2024
119 changes: 55 additions & 64 deletions controllers/v2/unavailability/api.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
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 repository.volunteer_unavailability_v2 import *
from repository.unavailability_repository import *
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

Expand All @@ -20,49 +14,53 @@


class SpecificVolunteerUnavailabilityV2(Resource):
event_repository: EventRepository

def __init__(self, event_repository: EventRepository = EventRepository()):
emilymclean marked this conversation as resolved.
Show resolved Hide resolved
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)
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:
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
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 = 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:
volunteer_unavailability_record = fetch_event(session, user_id)
if volunteer_unavailability_record is not None:
return volunteer_unavailability_record
else:
return jsonify({'userID': user_id, 'success': False}), 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)
Expand All @@ -73,40 +71,33 @@ 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:
# 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()
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 = create_event(
session,
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



v2_api.add_resource(SpecificVolunteerUnavailabilityV2, '/v2/volunteers/',
'/v2/volunteers/<user_id>/unavailability/<event_id>')
'/v2/volunteers/<user_id>/unavailability/<event_id>')

v2_api.add_resource(VolunteerUnavailabilityV2, '/v2/volunteers/',
'/v2/volunteers/<user_id>/unavailability')
'/v2/volunteers/<user_id>/unavailability')
130 changes: 110 additions & 20 deletions repository/volunteer_unavailability_v2.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,115 @@
import logging

from repository.unavailability_repository import *
from flask import jsonify

from datetime import datetime

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:
from domain import UnavailabilityTime, session_scope


class EventRepository:
def __init__(self):
pass
def edit_event(self, userId, eventId, title=None, start=None, end=None, periodicity=None):
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
session.commit()
return True
except Exception as e:
session.rollback()
logging.error(e)
return None

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()
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

# 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)
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):
"""
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
"""
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
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

# copy from post function in api.py written by Steven
def check_overlapping_events(self, userId, startTime, endTime, periodicity):
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
Loading