Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions app/api/endpoints/registration.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,41 @@ async def unregister_registration(
)

return await registration_model.unregister_registration(registration_id, current_user.entity_id)

@router.put("/check-in/{volunteer_id}", response_model=Registration)
async def check_in_registration(
event_id: str,
volunteer_id: str,
current_user: Annotated[User, Depends(get_current_user)],
) -> Registration:

if current_user.user_type not in [UserType.ORGANIZATION, UserType.ADMIN]:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Only organizations can check in volunteers",
)

volunteer = await volunteer_model.get_volunteer_by_id(volunteer_id)
if not volunteer:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Volunteer not found")

return await registration_model.check_in_registration(volunteer_id, event_id)

@router.put("/check-out/{volunteer_id}", response_model=Registration)
async def check_out_registration(
event_id: str,
volunteer_id: str,
current_user: Annotated[User, Depends(get_current_user)],
) -> Registration:

if current_user.user_type not in [UserType.ORGANIZATION, UserType.ADMIN]:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Only organizations can check out volunteers",
)

volunteer = await volunteer_model.get_volunteer_by_id(volunteer_id)
if not volunteer:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Volunteer not found")

return await registration_model.check_out_registration(volunteer_id, event_id)
15 changes: 3 additions & 12 deletions app/models/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from app.schemas.data_types import Location
from app.services.event import EventService
from app.services.volunteer import VolunteerService
from app.services.registration import RegistrationService
from app.models.volunteer import volunteer_model
from app.models.user import user_model

Expand All @@ -17,6 +18,7 @@ class EventModel:
def __init__(self):
self.event_service = EventService()
self.volunteer_service = VolunteerService()
self.registration_service = RegistrationService()
self.collection: AsyncIOMotorCollection = db["events"]

async def create_event(self, event: CreateEventRequest, user_id: str) -> Event:
Expand Down Expand Up @@ -75,22 +77,11 @@ async def update_event_status(
event_data.update(updated_data)

if event_data["status"] == Status.COMPLETED:
await self.update_event_status_completed(event_data)
await self.registration_service.update_not_checked_out_volunteers(event_id)

return self.to_event(event_data)
raise HTTPException(status_code=404, detail="No event with this ID was found")

async def update_event_status_completed(self, event: Event) -> None:
duration = event["end_date_time"] - event["start_date_time"]
exp = duration.total_seconds() / 36 # 3600 seconds in an hour * 100 exp per hour
volunteers = await volunteer_model.get_volunteers_by_event(event["id"])
for volunteer in volunteers:
await volunteer_model.update_volunteer(volunteer["id"], {"exp": volunteer["exp"] + exp})
await volunteer_model.update_volunteer(
volunteer["id"], {"coins": volunteer["coins"] + event["coins"]}
)
await self.volunteer_service.check_level_up(volunteer)

async def delete_event_by_id(self, event_id: str) -> None:
event = await self.collection.find_one({"_id": ObjectId(event_id)})
if not event:
Expand Down
33 changes: 33 additions & 0 deletions app/models/registration.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,14 @@
from app.models.event import event_model
from app.schemas.event import Event
from app.schemas.registration import CreateRegistrationRequest, Registration, RegistrationStatus
from app.models.volunteer import volunteer_model
from app.services.volunteer import VolunteerService


class RegistrationModel:
def __init__(self):
self.registrations: AsyncIOMotorCollection = db["registrations"]
self.volunteer_service = VolunteerService()

async def get_volunteers_by_event(self, event_id: str) -> list[Registration]:
event = await event_model.get_event_by_id(event_id)
Expand Down Expand Up @@ -132,6 +135,36 @@ async def unregister_registration(
updated_doc = await self.registrations.find_one({"_id": ObjectId(registration_id)})
return self._to_registration(updated_doc)

async def check_in_registration(self, volunteer_id: str, event_id: str) -> Registration:
await self.registrations.update_one(
{"volunteer_id": ObjectId(volunteer_id), "event_id": ObjectId(event_id)},
{"$set": {"clocked_in": datetime.now()}},
)
updated_doc = await self.registrations.find_one(
{"volunteer_id": ObjectId(volunteer_id), "event_id": ObjectId(event_id)}
)
return self._to_registration(updated_doc)

async def check_out_registration(self, volunteer_id: str, event_id: str) -> Registration:
event = await event_model.get_event_by_id(event_id)
volunteer = await volunteer_model.get_volunteer_by_id(volunteer_id)
registration = await self.registrations.update_one(
{"volunteer_id": ObjectId(volunteer_id), "event_id": ObjectId(event_id)},
{"$set": {"clocked_out": datetime.now()}},
)

duration = registration["clocked_out"] - registration["clocked_in"]
exp = duration.total_seconds() / 36 # 3600 seconds in an hour * 100 exp per hour
await volunteer_model.update_volunteer(volunteer_id, {"exp": volunteer["exp"] + exp})
await volunteer_model.update_volunteer(
volunteer_id, {"coins": volunteer["coins"] + event["coins"]}
)
await self.volunteer_service.check_level_up(volunteer)
updated_doc = await self.registrations.find_one(
{"volunteer_id": ObjectId(volunteer_id), "event_id": ObjectId(event_id)}
)
return self._to_registration(updated_doc)

def _to_registration(self, doc) -> Registration:
registration_data = doc.copy()
registration_data["id"] = str(registration_data["_id"])
Expand Down
4 changes: 2 additions & 2 deletions app/schemas/registration.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ class Registration(BaseModel):
volunteer_id: str
registered_at: datetime
registration_status: RegistrationStatus
clocked_in: bool
clocked_out: bool
clocked_in: datetime | None
clocked_out: datetime | None

class Config:
from_attributes = True
Expand Down
16 changes: 16 additions & 0 deletions app/services/registration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from datetime import datetime
from app.models.registration import registration_model


class RegistrationService:
def __init__(self, model=None):
self.model = registration_model

async def update_not_checked_out_volunteers(self, event_id: str) -> None:
volunteers = await self.model.get_volunteers_by_event(event_id)
for volunteer in volunteers:
if volunteer["clocked_out"] is None:
volunteer["clocked_out"] = datetime.now()
await self.model.update_registration(
volunteer["id"], {"clocked_out": volunteer["clocked_out"]}
)