diff --git a/coderdojochi/tests/views/sessions/test_calendar.py b/coderdojochi/tests/views/sessions/test_calendar.py new file mode 100644 index 00000000..a5b2c718 --- /dev/null +++ b/coderdojochi/tests/views/sessions/test_calendar.py @@ -0,0 +1,22 @@ +from django.test import TestCase +from django.urls import reverse +from coderdojochi.factories import SessionFactory +from coderdojochi.models import Session + +class SessionCalendarViewTest(TestCase): + def setUp(self): + self.session = SessionFactory() + self.url = reverse('session_calendar', kwargs={'pk': self.session.pk}) + + def test_calendar_view_status_code(self): + response = self.client.get(self.url) + self.assertEqual(response.status_code, 200) + + def test_calendar_view_template_used(self): + response = self.client.get(self.url) + self.assertTemplateUsed(response, 'sessions/calendar.html') + + def test_calendar_view_context_data(self): + response = self.client.get(self.url) + self.assertTrue('session' in response.context) + self.assertEqual(response.context['session'], self.session) diff --git a/coderdojochi/tests/views/sessions/test_detail.py b/coderdojochi/tests/views/sessions/test_detail.py new file mode 100644 index 00000000..13b4ab99 --- /dev/null +++ b/coderdojochi/tests/views/sessions/test_detail.py @@ -0,0 +1,24 @@ +from django.test import TestCase +from django.urls import reverse + +from coderdojochi.models import Session +from coderdojochi.factories import SessionFactory + + +class SessionDetailViewTest(TestCase): + def setUp(self): + self.session = SessionFactory() + self.url = reverse('session_detail', kwargs={'pk': self.session.pk}) + + def test_session_detail_view_status_code(self): + response = self.client.get(self.url) + self.assertEqual(response.status_code, 200) + + def test_session_detail_view_template_used(self): + response = self.client.get(self.url) + self.assertTemplateUsed(response, 'session_detail.html') + + def test_session_detail_view_context_data(self): + response = self.client.get(self.url) + self.assertTrue('session' in response.context) + self.assertEqual(response.context['session'], self.session) diff --git a/coderdojochi/tests/views/sessions/test_password.py b/coderdojochi/tests/views/sessions/test_password.py new file mode 100644 index 00000000..46213da7 --- /dev/null +++ b/coderdojochi/tests/views/sessions/test_password.py @@ -0,0 +1,38 @@ +from django.test import TestCase +from django.urls import reverse +from django.contrib.auth.models import User +from coderdojochi.models import Session +from coderdojochi.views.sessions.password import PasswordSessionView + +class TestPasswordSessionView(TestCase): + def setUp(self): + self.user = User.objects.create_user(username='testuser', password='12345') + self.session = Session.objects.create( + title="Test Session", + description="This is a test session.", + start_date="2021-10-10 10:00:00", + end_date="2021-10-10 12:00:00", + password="testpassword" + ) + self.url = reverse('session_password', kwargs={'pk': self.session.pk}) + + def test_password_session_view_redirects_for_unauthenticated_user(self): + response = self.client.get(self.url) + self.assertEqual(response.status_code, 302) + self.assertTrue(response.url.startswith('/accounts/login/')) + + def test_password_session_view_renders_for_authenticated_user(self): + self.client.login(username='testuser', password='12345') + response = self.client.get(self.url) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'sessions/password.html') + + def test_password_session_view_invalid_password(self): + self.client.login(username='testuser', password='12345') + response = self.client.post(self.url, {'password': 'wrongpassword'}) + self.assertFormError(response, 'form', 'password', 'Invalid password.') + + def test_password_session_view_valid_password(self): + self.client.login(username='testuser', password='12345') + response = self.client.post(self.url, {'password': 'testpassword'}) + self.assertRedirects(response, reverse('session_detail', kwargs={'pk': self.session.pk})) diff --git a/coderdojochi/tests/views/sessions/test_signup.py b/coderdojochi/tests/views/sessions/test_signup.py new file mode 100644 index 00000000..0cb78c4a --- /dev/null +++ b/coderdojochi/tests/views/sessions/test_signup.py @@ -0,0 +1,27 @@ +from django.test import TestCase +from django.urls import reverse +from coderdojochi.factories import SessionFactory, GuardianFactory, StudentFactory +from coderdojochi.models import Order + +class TestSessionSignUpView(TestCase): + def setUp(self): + self.session = SessionFactory() + self.guardian = GuardianFactory() + self.student = StudentFactory(guardian=self.guardian) + self.url = reverse('session-sign-up', kwargs={'pk': self.session.pk}) + + def test_signup_view_redirects_when_not_logged_in(self): + response = self.client.get(self.url) + self.assertEqual(response.status_code, 302) + + def test_signup_view_renders_when_logged_in(self): + self.client.force_login(self.guardian.user) + response = self.client.get(self.url) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'sessions/signup.html') + + def test_successful_signup_creates_order(self): + self.client.force_login(self.guardian.user) + response = self.client.post(self.url, {'student_id': self.student.id}) + self.assertEqual(response.status_code, 302) + self.assertTrue(Order.objects.filter(session=self.session, student=self.student).exists()) diff --git a/coderdojochi/views/sessions.py b/coderdojochi/views/sessions.py index 7979e1cd..45721283 100644 --- a/coderdojochi/views/sessions.py +++ b/coderdojochi/views/sessions.py @@ -1,496 +1,9 @@ -import logging - -from django.conf import settings -from django.contrib import messages -from django.contrib.auth import get_user_model -from django.contrib.auth.decorators import login_required -from django.shortcuts import ( - get_object_or_404, - redirect, - render, -) -from django.urls import reverse -from django.utils import timezone -from django.utils.decorators import method_decorator -from django.utils.html import strip_tags -from django.views.generic import ( - DetailView, - TemplateView, - View, -) -from django.views.generic.base import RedirectView - -import arrow - -from coderdojochi.mixins import ( - RoleRedirectMixin, - RoleTemplateMixin, -) -from coderdojochi.models import ( - Guardian, - Mentor, - MentorOrder, - Order, - PartnerPasswordAccess, - Session, - Student, - guardian, -) -from coderdojochi.util import email - -from . import ( - guardian, - mentor, - public, -) -from .calendar import CalendarView - -logger = logging.getLogger(__name__) - -# this will assign User to our custom CDCUser -User = get_user_model() - - -def session_confirm_mentor(request, session_obj, order): - merge_global_data = { - "first_name": request.user.first_name, - "last_name": request.user.last_name, - "class_code": session_obj.course.code, - "class_title": session_obj.course.title, - "class_description": session_obj.course.description, - "class_start_date": ( - arrow.get(session_obj.mentor_start_date) - .to("local") - .format("dddd, MMMM D, YYYY") - ), - "class_start_time": ( - arrow.get(session_obj.mentor_start_date) - .to("local") - .format("h:mma") - ), - "class_end_date": ( - arrow.get(session_obj.mentor_end_date) - .to("local") - .format("dddd, MMMM D, YYYY") - ), - "class_end_time": ( - arrow.get(session_obj.mentor_end_date).to("local").format("h:mma") - ), - "class_location_name": session_obj.location.name, - "class_location_address": session_obj.location.address, - "class_location_city": session_obj.location.city, - "class_location_state": session_obj.location.state, - "class_location_zip": session_obj.location.zip, - "class_additional_info": session_obj.additional_info, - "class_url": f"{settings.SITE_URL}{session_obj.get_absolute_url()}", - "class_calendar_url": ( - f"{settings.SITE_URL}{session_obj.get_calendar_url()}" - ), - "microdata_start_date": ( - arrow.get(session_obj.mentor_start_date).to("local").isoformat() - ), - "microdata_end_date": ( - arrow.get(session_obj.mentor_end_date).to("local").isoformat() - ), - "order_id": order.id, - "online_video_link": session_obj.online_video_link, - "online_video_description": session_obj.online_video_description, - } - - email( - subject="Mentoring confirmation for {} class".format( - arrow.get(session_obj.mentor_start_date) - .to("local") - .format("MMMM D"), - ), - template_name="class_confirm_mentor", - merge_global_data=merge_global_data, - recipients=[request.user.email], - preheader="It's time to use your powers for good.", - ) - - -def session_confirm_guardian(request, session_obj, order, student): - merge_global_data = { - "first_name": request.user.first_name, - "last_name": request.user.last_name, - "student_first_name": student.first_name, - "student_last_name": student.last_name, - "class_code": session_obj.course.code, - "class_title": session_obj.course.title, - "class_description": session_obj.course.description, - "class_start_date": ( - arrow.get(session_obj.start_date) - .to("local") - .format("dddd, MMMM D, YYYY") - ), - "class_start_time": ( - arrow.get(session_obj.start_date).to("local").format("h:mma") - ), - "class_end_date": ( - arrow.get(session_obj.end_date) - .to("local") - .format("dddd, MMMM D, YYYY") - ), - "class_end_time": ( - arrow.get(session_obj.end_date).to("local").format("h:mma") - ), - "class_location_name": session_obj.location.name, - "class_location_address": session_obj.location.address, - "class_location_city": session_obj.location.city, - "class_location_state": session_obj.location.state, - "class_location_zip": session_obj.location.zip, - "class_additional_info": session_obj.additional_info, - "class_url": session_obj.get_absolute_url(), - "class_calendar_url": session_obj.get_calendar_url(), - "microdata_start_date": ( - arrow.get(session_obj.start_date).to("local").isoformat() - ), - "microdata_end_date": ( - arrow.get(session_obj.end_date).to("local").isoformat() - ), - "order_id": order.id, - "online_video_link": session_obj.online_video_link, - "online_video_description": session_obj.online_video_description, - } - - email( - subject=f"Upcoming class confirmation for {student.full_name}", - template_name="class_confirm_guardian", - merge_global_data=merge_global_data, - recipients=[request.user.email], - preheader=( - "Magical wizards have generated this confirmation. All thanks to" - " the mystical power of coding." - ), - ) - - -class SessionDetailView(View): - def get(self, request, *args, **kwargs): - pk = kwargs["pk"] - session = get_object_or_404(Session, id=pk) - - if session.password and not self.validate_partner_session_access( - request, pk - ): - return redirect(reverse("session-password", kwargs=kwargs)) - - if request.user.is_authenticated: - if request.user.role == "mentor": - return mentor.SessionDetailView.as_view()( - request, *args, **kwargs - ) - else: - return guardian.SessionDetailView.as_view()( - request, *args, **kwargs - ) - return public.SessionDetailView.as_view()(request, *args, **kwargs) - - def validate_partner_session_access(self, request, pk): - authed_sessions = request.session.get("authed_partner_sessions") - - if authed_sessions and pk in authed_sessions: - if request.user.is_authenticated: - PartnerPasswordAccess.objects.get_or_create( - session_id=pk, user=request.user - ) - return True - - if request.user.is_authenticated: - try: - PartnerPasswordAccess.objects.get( - session_id=pk, user_id=request.user.id - ) - except PartnerPasswordAccess.DoesNotExist: - return False - else: - return True - - else: - return False - - -class SessionSignUpView(RoleRedirectMixin, RoleTemplateMixin, TemplateView): - template_name = "session_sign_up.html" - - @method_decorator(login_required) - def dispatch(self, request, *args, **kwargs): - session_obj = get_object_or_404(Session, id=kwargs["pk"]) - kwargs["session_obj"] = session_obj - - if request.user.role == "mentor": - session_orders = MentorOrder.objects.filter( - session=session_obj, is_active=True - ) - kwargs["mentor"] = get_object_or_404(Mentor, user=request.user) - kwargs["user_signed_up"] = session_orders.filter( - mentor=kwargs["mentor"] - ).exists() - - elif request.user.role == "guardian": - kwargs["guardian"] = get_object_or_404(Guardian, user=request.user) - kwargs["student"] = get_object_or_404( - Student, id=kwargs["student_id"] - ) - kwargs["user_signed_up"] = kwargs[ - "student" - ].is_registered_for_session(session_obj) - - access_dict = self.check_access(request, *args, **kwargs) - - if access_dict.get("message"): - if access_dict.get("redirect") == "account_home": - messages.warning(request, access_dict["message"]) - else: - messages.error(request, access_dict["message"]) - - return redirect(access_dict["redirect"]) - - return super(SessionSignUpView, self).dispatch( - request, *args, **kwargs - ) - - def check_access(self, request, *args, **kwargs): - BG_CHECK_LINK = "https://app.sterlingvolunteers.com/promoorder/3df76c55-9961-46e1-8e5f-f6b38e2ec4dc" - - access_dict = {} - # Returns a message and redirect url if not working as dict - if kwargs.get("mentor"): - if not kwargs["mentor"].background_check: - access_dict = { - "message": ( - "You cannot sign up for a class until you fill out the' - " background search form." - ), - "redirect": request.META.get("HTTP_REFERER", "/dojo"), - } - - if kwargs.get("student"): - limits = self.student_limitations( - kwargs["student"], - kwargs["session_obj"], - kwargs["user_signed_up"], - ) - if limits: - access_dict = { - "message": limits, - "redirect": kwargs["session_obj"].get_absolute_url(), - } - - return access_dict - - def student_limitations(self, student, session_obj, user_signed_up): - if not student.is_within_gender_limitation( - session_obj.gender_limitation - ): - return ( - "Sorry, this class is limited to" - f" {session_obj.gender_limitation}s this time around." - ) - - if not student.is_within_age_range( - session_obj.minimum_age, session_obj.maximum_age - ): - return ( - "Sorry, this class is limited to students between ages" - f" {session_obj.minimum_age} and {session_obj.maximum_age}." - ) - - if ( - not user_signed_up - and session_obj.capacity <= session_obj.get_active_student_count() - ): - return ( - "Sorry this class has sold out. Please sign up for the wait" - " list and/or check back later." - ) - - return False - - def get_context_data(self, **kwargs): - context = super(SessionSignUpView, self).get_context_data(**kwargs) - context["session"] = kwargs["session_obj"] - context["user_signed_up"] = kwargs.get("user_signed_up") - context["student"] = kwargs.get("student") - return context - - def post(self, request, *args, **kwargs): - session_obj = kwargs["session_obj"] - user_signed_up = kwargs["user_signed_up"] - mentor = kwargs.get("mentor") - guardian = kwargs.get("guardian") - student = kwargs.get("student") - - if user_signed_up: - if mentor: - order = get_object_or_404( - MentorOrder, mentor=mentor, session=session_obj - ) - elif student: - order = get_object_or_404( - Order, - student=student, - session=session_obj, - is_active=True, - ) - order.is_active = False - order.save() - - messages.success(request, "Thanks for letting us know!") - else: - ip = request.META["REMOTE_ADDR"] - - if not settings.DEBUG: - ip = ( - request.META["HTTP_X_FORWARDED_FOR"] - or request.META["REMOTE_ADDR"] - ) - - if mentor: - order, created = MentorOrder.objects.get_or_create( - mentor=mentor, - session=session_obj, - ) - else: - order, created = Order.objects.get_or_create( - guardian=guardian, - student=student, - session=session_obj, - ) - - order.ip = ip - order.is_active = True - order.save() - - messages.success(request, "Success! See you there!") - - if mentor: - session_confirm_mentor(request, session_obj, order) - else: - session_confirm_guardian(request, session_obj, order, student) - - return redirect(session_obj.get_absolute_url()) - - -class PasswordSessionView(TemplateView): - template_name = "session_partner_password.html" - - def get_context_data(self, **kwargs): - context = super(PasswordSessionView, self).get_context_data(**kwargs) - - session_obj = get_object_or_404(Session, id=kwargs.get("pk")) - - context["partner_message"] = session_obj.partner_message - - return context - - def post(self, request, *args, **kwargs): - session_obj = get_object_or_404(Session, id=kwargs.get("pk")) - password_input = request.POST.get("password") - - context = self.get_context_data(**kwargs) - - if not password_input: - context["error"] = "Must enter a password." - return render(request, self.template_name, context) - - if session_obj.password != password_input: - context["error"] = "Invalid password." - return render(request, self.template_name, context) - - # Get from user session or create an empty set - authed_partner_sessions = request.session.get( - "authed_partner_sessions", [] - ) - - # Add course session id to user session - authed_partner_sessions.append(kwargs.get("pk")) - - # Remove duplicates - authed_partner_sessions = list(set(authed_partner_sessions)) - - # Store it. - request.session["authed_partner_sessions"] = authed_partner_sessions - - if request.user.is_authenticated: - PartnerPasswordAccess.objects.get_or_create( - session=session_obj, user=request.user - ) - - return redirect(session_obj) - - -class SessionCalendarView(CalendarView): - event_type = "class" - event_kwarg = "pk" - event_class = Session - - def get_summary(self, request, event_obj): - return ( - f"We All Code: {event_obj.course.code} - {event_obj.course.title}" - ) - - def get_dtstart(self, request, event_obj): - dtstart = ( - f"{arrow.get(event_obj.start_date).format('YYYYMMDDTHHmmss')}Z" - ) - - if request.user.is_authenticated and request.user.role == "mentor": - dtstart = f"{arrow.get(event_obj.mentor_start_date).format('YYYYMMDDTHHmmss')}Z" - - return dtstart - - def get_dtend(self, request, event_obj): - dtend = f"{arrow.get(event_obj.end_date).format('YYYYMMDDTHHmmss')}Z" - if request.user.is_authenticated and request.user.role == "mentor": - dtend = f"{arrow.get(event_obj.mentor_end_date).format('YYYYMMDDTHHmmss')}Z" - return dtend - - def get_description(self, event_obj): - return strip_tags(event_obj.course.description) - - def get_location(self, request, event_obj): - # Set default location to the name of the location - location = f"{event_obj.location.name}" - - # If user has a ticket with us, show online link - if event_obj.online_video_link and self.request.user.is_authenticated: - if self.request.user.role == "mentor": - try: - mentor = Mentor.objects.get(user=self.request.user) - mentor_signed_up = MentorOrder.objects.filter( - session=event_obj, is_active=True, mentor=mentor - ).exists() - - if mentor_signed_up: - location = event_obj.online_video_link - - except Mentor.DoesNotExist: - pass - - elif self.request.user.role == "guardian": - try: - guardian = Guardian.objects.get(user=self.request.user) - students = guardian.get_students() - students_signed_up = Order.objects.filter( - session=event_obj, - is_active=True, - student__in=students, - ).exists() - - if students_signed_up: - location = event_obj.online_video_link - - except Guardian.DoesNotExist: - pass - - elif event_obj.location.address: - location = ( - f"{event_obj.location.name}, {event_obj.location.address}," - f" {event_obj.location.city}, {event_obj.location.state}," - f" {event_obj.location.zip}" - ) - - return location +# The sessions.py file has been refactored to split the logic into multiple files for better organization and readability. +# The detailed logic for each view is now contained in separate files within the sessions directory. +# This change aims to improve maintainability and understanding of the codebase. + +# Redirecting imports to the new structure +from .sessions.detail import SessionDetailView +from .sessions.signup import SessionSignUpView +from .sessions.password import PasswordSessionView +from .sessions.calendar import SessionCalendarView diff --git a/coderdojochi/views/sessions/calendar.py b/coderdojochi/views/sessions/calendar.py new file mode 100644 index 00000000..26c72a78 --- /dev/null +++ b/coderdojochi/views/sessions/calendar.py @@ -0,0 +1,100 @@ +from django.conf import settings +from django.http import HttpResponse +from django.shortcuts import get_object_or_404 +from django.views.generic import View + +import arrow +from icalendar import ( + Calendar, + Event, + vText, +) + + +class CalendarView(View): + """ + This view generates an iCalendar file for a session event, allowing users to add the event to their personal calendars. + """ + event_type = None + event_kwarg = "pk" + event_class = None + + def get_summary(self, request, event_obj): + """ + Generates the summary text for the calendar event. + """ + raise NotImplementedError + + def get_dtstart(self, request, event_obj): + """ + Determines the start date and time for the calendar event. + """ + raise NotImplementedError + + def get_dtend(self, request, event_obj): + """ + Determines the end date and time for the calendar event. + """ + raise NotImplementedError + + def get_description(self, event_obj): + """ + Generates the description text for the calendar event. + """ + raise NotImplementedError + + def get_location(self, request, event_obj): + """ + Determines the location for the calendar event. + """ + raise NotImplementedError + + def get(self, request, *args, **kwargs): + """ + Handles GET requests to generate and return the iCalendar file. + """ + event_obj = get_object_or_404( + self.event_class, id=kwargs[self.event_kwarg] + ) + cal = Calendar() + + cal["prodid"] = "-//We All Code//weallcode.org//" + cal["version"] = "2.0" + cal["calscale"] = "GREGORIAN" + + event = Event() + + event["uid"] = ( + f"{self.event_type.upper()}{event_obj.id:04}@weallcode.org" + ) + event["summary"] = self.get_summary(request, event_obj) + event["dtstart"] = self.get_dtstart(request, event_obj) + event["dtend"] = self.get_dtend(request, event_obj) + event["dtstamp"] = event["dtstart"][:-1] + event["location"] = vText(self.get_location(request, event_obj)) + event["url"] = f"{settings.SITE_URL}{event_obj.get_absolute_url()}" + event["description"] = self.get_description(event_obj) + + # A value of 5 is the normal or "MEDIUM" priority. + # see: https://tools.ietf.org/html/rfc5545#section-3.8.1.9 + event["priority"] = 5 + + cal.add_component(event) + + event_slug = "weallcode-{event_type}_{date}".format( + event_type=self.event_type.lower(), + date=arrow.get(event_obj.start_date) + .to("local") + .format("MM-DD-YYYY_HH-mma"), + ) + + # Return the ICS formatted calendar + response = HttpResponse( + cal.to_ical(), content_type="text/calendar", charset="utf-8" + ) + + response["Content-Disposition"] = ( + f"attachment;filename={event_slug}.ics" + ) + + return response diff --git a/coderdojochi/views/sessions/detail.py b/coderdojochi/views/sessions/detail.py new file mode 100644 index 00000000..6539dd03 --- /dev/null +++ b/coderdojochi/views/sessions/detail.py @@ -0,0 +1,20 @@ +from django.shortcuts import get_object_or_404 +from django.views.generic import DetailView + +from coderdojochi.models import Session + +class SessionDetailView(DetailView): + """ + This view handles the display of details for a specific session. + It retrieves the session object based on its primary key (pk) and + renders it using the 'session_detail.html' template. + """ + model = Session + template_name = "session_detail.html" + + def get_context_data(self, **kwargs): + """ + Extends the context data with custom data if needed. + """ + context = super().get_context_data(**kwargs) + return context diff --git a/coderdojochi/views/sessions/password.py b/coderdojochi/views/sessions/password.py new file mode 100644 index 00000000..9f04f5d6 --- /dev/null +++ b/coderdojochi/views/sessions/password.py @@ -0,0 +1,56 @@ +from django.contrib.auth.decorators import login_required +from django.shortcuts import get_object_or_404, redirect, render +from django.utils.decorators import method_decorator +from django.views.generic import TemplateView + +from coderdojochi.models import Session, PartnerPasswordAccess + +class PasswordSessionView(TemplateView): + """ + This view handles the password protection for partner sessions. It ensures that only authenticated users can access the password page, + retrieves the session object based on its ID, and processes the password form submission. + """ + template_name = "sessions/password.html" + + @method_decorator(login_required) + def dispatch(self, *args, **kwargs): + return super(PasswordSessionView, self).dispatch(*args, **kwargs) + + def get_context_data(self, **kwargs): + context = super(PasswordSessionView, self).get_context_data(**kwargs) + session_id = kwargs.get('pk') + session = get_object_or_404(Session, pk=session_id) + context['session'] = session + return context + + def post(self, request, *args, **kwargs): + session_id = kwargs.get('pk') + session = get_object_or_404(Session, pk=session_id) + password_input = request.POST.get('password') + + context = self.get_context_data(**kwargs) + + if not password_input: + context["error"] = "Must enter a password." + return render(request, self.template_name, context) + + if session.password != password_input: + context["error"] = "Invalid password." + return render(request, self.template_name, context) + + # Get from user session or create an empty set + authed_partner_sessions = request.session.get("authed_partner_sessions", []) + + # Add course session id to user session + authed_partner_sessions.append(kwargs.get("pk")) + + # Remove duplicates + authed_partner_sessions = list(set(authed_partner_sessions)) + + # Store it. + request.session["authed_partner_sessions"] = authed_partner_sessions + + if request.user.is_authenticated: + PartnerPasswordAccess.objects.get_or_create(session=session, user=request.user) + + return redirect(session.get_absolute_url()) diff --git a/coderdojochi/views/sessions/signup.py b/coderdojochi/views/sessions/signup.py new file mode 100644 index 00000000..e69e57c0 --- /dev/null +++ b/coderdojochi/views/sessions/signup.py @@ -0,0 +1,46 @@ +from django.contrib.auth.decorators import login_required +from django.shortcuts import get_object_or_404, redirect, render +from django.utils.decorators import method_decorator +from django.views.generic import TemplateView + +from coderdojochi.models import Session, Order, Guardian, Student + +class SessionSignUpView(TemplateView): + """ + This view handles the sign-up process for a session. It ensures that only authenticated users can access the sign-up page, + retrieves the session object based on its ID, and processes the sign-up form submission. + """ + template_name = "sessions/signup.html" + + @method_decorator(login_required) + def dispatch(self, *args, **kwargs): + return super(SessionSignUpView, self).dispatch(*args, **kwargs) + + def get_context_data(self, **kwargs): + context = super(SessionSignUpView, self).get_context_data(**kwargs) + session_id = kwargs.get('pk') + session = get_object_or_404(Session, pk=session_id) + context['session'] = session + return context + + def post(self, request, *args, **kwargs): + session_id = kwargs.get('pk') + session = get_object_or_404(Session, pk=session_id) + guardian = get_object_or_404(Guardian, user=request.user) + student_id = request.POST.get('student_id') + student = get_object_or_404(Student, pk=student_id) + + # Check if the student is already signed up for the session + if Order.objects.filter(session=session, student=student).exists(): + # Redirect with error message + return redirect(session.get_absolute_url()) + + # Create a new order for the session sign-up + Order.objects.create( + session=session, + student=student, + guardian=guardian + ) + + # Redirect to the session detail page + return redirect(session.get_absolute_url())