diff --git a/backend/djangoindia/api/serializers/event.py b/backend/djangoindia/api/serializers/event.py index 5c53cae..33fac65 100644 --- a/backend/djangoindia/api/serializers/event.py +++ b/backend/djangoindia/api/serializers/event.py @@ -55,6 +55,23 @@ class EventRegistrationSerializer(serializers.Serializer): other_links = serializers.URLField(required=False, allow_blank=True) rsvp = serializers.BooleanField(default=False) include_in_attendee_list = serializers.BooleanField(default=False) + first_time_attendee = serializers.BooleanField(default= True) + attendee_type = serializers.ChoiceField(choices=EventRegistration.AttendeeType) + + class EventAttendeeSerializer(serializers.ModelSerializer): + full_name = serializers.SerializerMethodField() + + class Meta: + model = EventRegistration + fields = [ + 'full_name', 'professional_status', 'organization', + 'linkedin', 'github', 'twitter', 'first_time_attendee', + 'attendee_type' + ] def create(self, validated_data): return EventRegistration.objects.create(**validated_data) + + def get_full_name(self, obj): + return f"{obj.first_name} {obj.last_name}" + diff --git a/backend/djangoindia/api/urls/event.py b/backend/djangoindia/api/urls/event.py index 5dc46a6..f2e2be7 100644 --- a/backend/djangoindia/api/urls/event.py +++ b/backend/djangoindia/api/urls/event.py @@ -1,8 +1,8 @@ from django.urls import path - -from djangoindia.api.views.event import EventAPIView +from djangoindia.api.views.event import EventAPIView,EventAttendeeViewSet # URL conf urlpatterns = [ path("events/", EventAPIView.as_view({"get":"list"}), name="list_events"), path("events//", EventAPIView.as_view({"get":"retrieve","post":"post"}), name="get_event"), + path("events//attendees/", EventAttendeeViewSet.as_view({"get": "list"}), name="get_event_attendee"), ] \ No newline at end of file diff --git a/backend/djangoindia/api/views/.cph/.event.py_d9370a604011efc5b3d32a44afd21dc9.prob b/backend/djangoindia/api/views/.cph/.event.py_d9370a604011efc5b3d32a44afd21dc9.prob new file mode 100644 index 0000000..8154167 --- /dev/null +++ b/backend/djangoindia/api/views/.cph/.event.py_d9370a604011efc5b3d32a44afd21dc9.prob @@ -0,0 +1 @@ +{"name":"Local: event","url":"c:\\Users\\apala\\OneDrive\\Desktop\\ContribDj\\djangoindia.org\\backend\\djangoindia\\api\\views\\event.py","tests":[{"id":1729355817490,"input":"","output":""}],"interactive":false,"memoryLimit":1024,"timeLimit":3000,"srcPath":"c:\\Users\\apala\\OneDrive\\Desktop\\ContribDj\\djangoindia.org\\backend\\djangoindia\\api\\views\\event.py","group":"local","local":true} \ No newline at end of file diff --git a/backend/djangoindia/api/views/__init__.py b/backend/djangoindia/api/views/__init__.py index 05ea605..8ece5d7 100644 --- a/backend/djangoindia/api/views/__init__.py +++ b/backend/djangoindia/api/views/__init__.py @@ -1,3 +1,3 @@ -from .event import EventAPIView +from .event import EventAPIView,EventAttendeeViewSet from .communication import SubscriberAPIView, ContactUsAPIView from .partner_and_sponsor import CommunityPartnerAndSponsorAPIView \ No newline at end of file diff --git a/backend/djangoindia/api/views/event.py b/backend/djangoindia/api/views/event.py index 984d94d..4a794f9 100644 --- a/backend/djangoindia/api/views/event.py +++ b/backend/djangoindia/api/views/event.py @@ -1,3 +1,4 @@ +from django.shortcuts import get_object_or_404 from djangoindia.api.serializers.event import ( EventRegistrationSerializer, EventSerializer, @@ -5,7 +6,7 @@ ) from djangoindia.bg_tasks.event_registration import registration_confirmation_email_task from djangoindia.db.models import Event, EventRegistration,Volunteer, Sponsorship,CommunityPartner -from rest_framework import generics, status, viewsets +from rest_framework import generics, status, viewsets,mixins from rest_framework.mixins import CreateModelMixin, ListModelMixin, RetrieveModelMixin from rest_framework.response import Response @@ -13,6 +14,33 @@ from django.db.models import Prefetch from django.utils import timezone +class EventAttendeeViewSet( + mixins.ListModelMixin, + viewsets.GenericViewSet +): + serializer_class = EventRegistrationSerializer + + def get_queryset(self): + event_id = self.kwargs.get('event_id') + return EventRegistration.objects.filter( + event_id=event_id, + # include_in_attendee_list=True + ).select_related('event').order_by('first_name', 'last_name') + + def list(self, request, *args, **kwargs): + event_id = self.kwargs.get('event_id') + event = get_object_or_404(Event, id=event_id) + queryset = self.get_queryset() + serializer = self.get_serializer(queryset, many=True) + + response_data = { + 'event_name': event.name, + 'total_attendees': queryset.count(), + 'first_time_attendees': queryset.filter(first_time_attendee=True).count(), + 'attendees': serializer.data + } + + return Response(response_data) # Create your views here. class EventAPIView( viewsets.ModelViewSet diff --git a/backend/djangoindia/db/admin.py b/backend/djangoindia/db/admin.py index 98fa1fc..6e711d6 100644 --- a/backend/djangoindia/db/admin.py +++ b/backend/djangoindia/db/admin.py @@ -54,15 +54,14 @@ class EventAdmin(admin.ModelAdmin): class EventRegistrationResource(resources.ModelResource): - class Meta: model = EventRegistration @admin.register(EventRegistration) class EventRegistrationAdmin(ImportExportModelAdmin): - list_display = ('event', 'first_name', 'email', 'created_at') - readonly_fields = ('created_at', 'updated_at') - list_filter = ('event__name',) - search_fields=['email','event__name','first_name','last_name',] + list_display = ('event', 'first_name', 'email', 'created_at','attendee_type','first_time_attendee') + readonly_fields = ('created_at', 'updated_at','first_time_attendee','attendee_type') + list_filter = ('event__name','attendee_type','first_time_attendee') + search_fields=['email','event__name','first_name','last_name','first_time_attendee','attendee_type'] actions = [send_email_to_selected_users] resource_class = EventRegistrationResource diff --git a/backend/djangoindia/db/migrations/0011_eventregistration_attendee_type_and_more.py b/backend/djangoindia/db/migrations/0011_eventregistration_attendee_type_and_more.py new file mode 100644 index 0000000..2715398 --- /dev/null +++ b/backend/djangoindia/db/migrations/0011_eventregistration_attendee_type_and_more.py @@ -0,0 +1,23 @@ +# Generated by Django 5.1.2 on 2024-10-16 18:42 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('db', '0010_communitypartner_event_max_seats_event_seats_left_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='eventregistration', + name='attendee_type', + field=models.CharField(choices=[('guest', 'Guest'), ('host', 'Host'), ('speaker', 'Speaker'), ('volunteer', 'Volunteer')], default='guest', max_length=10), + ), + migrations.AddField( + model_name='eventregistration', + name='first_time_attendee', + field=models.BooleanField(default=True), + ), + ] diff --git a/backend/djangoindia/db/migrations/0012_alter_eventregistration_attendee_type.py b/backend/djangoindia/db/migrations/0012_alter_eventregistration_attendee_type.py new file mode 100644 index 0000000..bb9d65c --- /dev/null +++ b/backend/djangoindia/db/migrations/0012_alter_eventregistration_attendee_type.py @@ -0,0 +1,18 @@ +# Generated by Django 5.1.2 on 2024-10-19 17:02 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('db', '0011_eventregistration_attendee_type_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='eventregistration', + name='attendee_type', + field=models.CharField(choices=[('guest', 'Guest'), ('host', 'Host'), ('speaker', 'Speaker'), ('volunteer', 'Volunteer')], default='guest', max_length=20), + ), + ] diff --git a/backend/djangoindia/db/models/event.py b/backend/djangoindia/db/models/event.py index f21691a..6011fcb 100644 --- a/backend/djangoindia/db/models/event.py +++ b/backend/djangoindia/db/models/event.py @@ -64,6 +64,13 @@ class Gender(models.TextChoices): FEMALE = "female" OTHER = "other" + class AttendeeType(models.TextChoices): + GUEST = "guest", "Guest" + HOST = "host", "Host" + SPEAKER = "speaker", "Speaker" + VOLUNTEER = "volunteer", "Volunteer" + + event = models.ForeignKey( "db.Event", on_delete=models.CASCADE, @@ -89,6 +96,14 @@ class Gender(models.TextChoices): # TODO: imnplement this (RSVP mailing + RSVP submission link) rsvp = models.BooleanField(default=False) + + first_time_attendee = models.BooleanField(default=True) + attendee_type = models.CharField( + max_length=20, + choices=AttendeeType.choices, + default=AttendeeType.GUEST + ) + class Meta: constraints = [ models.UniqueConstraint( @@ -99,6 +114,9 @@ class Meta: def save(self, *args, **kwargs): # This is a new registration if self._state.adding: + user_has_registered_before = EventRegistration.objects.filter(email=self.email).exists() + self.first_time_attendee = not user_has_registered_before + if self.event.seats_left > 0: self.event.seats_left -= 1 self.event.save() diff --git a/backend/djangoindia/settings/base.py b/backend/djangoindia/settings/base.py index e17eaf7..ce3fe77 100644 --- a/backend/djangoindia/settings/base.py +++ b/backend/djangoindia/settings/base.py @@ -21,7 +21,7 @@ # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent.parent -DOCKERIZED = int(os.environ.get("DOCKERIZED", 0)) == 1 +DOCKERIZED = (os.environ.get("DOCKERIZED", 0)) == 1 # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/ diff --git a/backend/djangoindia/urls.py b/backend/djangoindia/urls.py index dc37c87..f0197c9 100644 --- a/backend/djangoindia/urls.py +++ b/backend/djangoindia/urls.py @@ -23,7 +23,6 @@ SpectacularAPIView, SpectacularSwaggerView, ) - urlpatterns = [ path(f"api/{settings.ADMIN_URL}", admin.site.urls), path("api/v1/", include("djangoindia.api.urls")),