diff --git a/backend/config/urls.py b/backend/config/urls.py index 09c71db..d1d3590 100644 --- a/backend/config/urls.py +++ b/backend/config/urls.py @@ -19,11 +19,13 @@ from django.urls import path from hoagiecalendar.api.event_views import EventDetailView, EventView +from hoagiecalendar.api.user_event_attending_view import UserEventAttendingView from hoagiecalendar.api.user_events_view import UserEventsView urlpatterns = [ path("admin/", admin.site.urls), path("event/", EventView.as_view(), name="event"), path("event//", EventDetailView.as_view(), name="event-detail"), - path("user/events/", UserEventsView.as_view(), name="user-events"), + path("user/events/created", UserEventsView.as_view(), name="user-events"), + path("user/events/attending", UserEventAttendingView.as_view(), name="user-events-attending"), ] diff --git a/backend/hoagiecalendar/api/event_views.py b/backend/hoagiecalendar/api/event_views.py index 02ab148..d56a8c9 100644 --- a/backend/hoagiecalendar/api/event_views.py +++ b/backend/hoagiecalendar/api/event_views.py @@ -37,6 +37,11 @@ class EventSerializer(serializers.ModelSerializer): }, ) + attending_count = serializers.SerializerMethodField(read_only=True) + + def get_attending_count(self, obj: Event) -> int: + return obj.attending_count() + class Meta: model = Event fields = [ @@ -50,9 +55,9 @@ class Meta: "owner", "category", "from_mail", - "ordering", + "attending_count", ] - read_only_fields = ["id", "owner", "created_at", "updated_at"] + read_only_fields = ["id", "owner", "created_at", "updated_at", "attending_count"] class EventView(APIView): diff --git a/backend/hoagiecalendar/api/user_event_attending_view.py b/backend/hoagiecalendar/api/user_event_attending_view.py new file mode 100644 index 0000000..1176dbe --- /dev/null +++ b/backend/hoagiecalendar/api/user_event_attending_view.py @@ -0,0 +1,49 @@ +from rest_framework import status +from rest_framework.request import Request +from rest_framework.response import Response +from rest_framework.views import APIView + +from hoagiecalendar.models.user import User + +from ..models.event import Event +from .event_views import EventSerializer + + +def add_or_remove_attendee_from_event(event_id: str | None, user: User, add: bool) -> Response: + if not event_id: + return Response({"error": "invalid request: no event_id provided"}, status=status.HTTP_400_BAD_REQUEST) + + try: + event = Event.objects.get(pk=event_id) + if add: + event.attendees.add(user) + serializer = EventSerializer(event) + + return Response({"event": serializer.data}, status=status.HTTP_200_OK) + else: + event.attendees.remove(user) + + return Response(status=status.HTTP_204_NO_CONTENT) + except ValueError: + return Response({"error": "invalid event_id"}, status=status.HTTP_400_BAD_REQUEST) + except Event.DoesNotExist: + return Response({"error": "event not found"}, status=status.HTTP_404_NOT_FOUND) + except Exception as _: + # TODO: Log exception once logging is set up + return Response({"error": "an internal error has occurred"}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) + + +class UserEventAttendingView(APIView): + def post(self, request: Request) -> Response: + return add_or_remove_attendee_from_event( + event_id=request.query_params.get("event_id"), + user=request.user, + add=True, + ) + + def delete(self, request: Request) -> Response: + return add_or_remove_attendee_from_event( + event_id=request.query_params.get("event_id"), + user=request.user, + add=False, + ) diff --git a/backend/hoagiecalendar/models/event.py b/backend/hoagiecalendar/models/event.py index 1abcfe4..1bb2526 100644 --- a/backend/hoagiecalendar/models/event.py +++ b/backend/hoagiecalendar/models/event.py @@ -25,6 +25,10 @@ class Event(models.Model): from_mail = models.BooleanField(default=False) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) + attendees = models.ManyToManyField(User, related_name="events_attending", blank=True) + + def attending_count(self) -> int: + return self.attendees.count() def __str__(self) -> str: return self.name