From dc15c0f768224f1b11b8c16640edafa3364ace47 Mon Sep 17 00:00:00 2001 From: Mustafa Abdulrahman Date: Thu, 17 Oct 2024 01:16:45 -0400 Subject: [PATCH 1/6] Add support for RSVP --- .../event/jinja2/event/dashboard_base.html | 87 ++++++++++++++++--- hackathon_site/event/serializers.py | 10 +-- hackathon_site/event/views.py | 30 ++++++- hackathon_site/hackathon_site/jinja2.py | 1 + .../hackathon_site/settings/__init__.py | 1 + hackathon_site/registration/admin.py | 2 + hackathon_site/registration/forms.py | 46 ++++++++++ hackathon_site/registration/urls.py | 1 + hackathon_site/registration/views.py | 69 +++++++++++++++ hackathon_site/review/admin.py | 1 + .../review/emails/accepted_email_body.html | 2 +- hackathon_site/review/views.py | 3 + 12 files changed, 234 insertions(+), 19 deletions(-) diff --git a/hackathon_site/event/jinja2/event/dashboard_base.html b/hackathon_site/event/jinja2/event/dashboard_base.html index 08d1d532..c0b0c0f0 100644 --- a/hackathon_site/event/jinja2/event/dashboard_base.html +++ b/hackathon_site/event/jinja2/event/dashboard_base.html @@ -15,16 +15,7 @@

Dashboard

{% if application is none %} - {% if is_registration_open() and not is_application_open() %} -

Applications are not open yet

-

{{ hackathon_name }} applications will open soon! Please follow our Instagram for the latest updates.

-
-

Note: We are sorry to inform, but due to logistical changes, we will be updating our application form. To those that have previously submitted an application, you would need to refill a new one - when applications re-open. We will be sending an email soon to all those that are affected. Apologies for the inconvenience!

-
-

If you have any questions or concerns, please contact us.

- - {% elif not is_application_open() %} + {% if not is_registration_open() %}

Applications have closed

Unfortunately, the deadline to apply for {{ hackathon_name }} was {{ localtime(registration_close_date).strftime("%B %-d, %Y") }}.


@@ -44,10 +35,82 @@

Complete your application

{% elif application is not none and review is not none %}
{% if review.status == "Accepted" %} -

Congratulations! You've been accepted into {{ hackathon_name }}!

-

Make sure you read the participant package for all the info regarding + {% if application.rsvp and using_rsvp %} +

Thanks for RSVP'ing! See you at {{ hackathon_name }}!

+ {% elif application.rsvp is sameas false and using_rsvp%} +

Thanks for letting us know. Hope to see you next year at {{ hackathon_name }}

+ {% else %} +

Congratulations! You've been accepted into {{ hackathon_name }}!

+ {% endif %} + + {% if using_rsvp %} +

+ Status:  + {% if application.rsvp is sameas false %} + + highlight_off + + {% elif application.rsvp %} + + check_circle_outline + + {% endif %} + {{ status }} +

+
+ {% if not rsvp_passed %} + {% if application.rsvp is none %} +

To confirm your attendance at {{ hackathon_name }}, please RSVP using the accept or decline buttons below.


+

RSVP by {{ rsvp_deadline }}, otherwise your spot will be given to other applicants. + Alternatively you can decline the offer. You can change your response at any time before {{ rsvp_deadline }}. +


+ {% else %} +

You can change your response at any time before {{ rsvp_deadline }}.


+ {% endif %} + {% endif %} + {% endif %} + + {% if (application.rsvp and using_rsvp) or not using_rsvp %} +

Make sure you read the participant package for all the info regarding the event, and join our {{ chat_room_name }}. Stay tuned for more updates regarding detailed event logistics, and we hope to see you soon!


+ + {% endif %}

If you have questions, read the FAQ, or feel free to contact us.


+ + {% if using_rsvp %} + {% if not rsvp_passed %} +
+ {% if application.rsvp is sameas false or application.rsvp is none %} + + Will Attend (Accept) + + {% endif %} + {% if application.rsvp or application.rsvp is none %} + + Cannot Attend (Decline) + + {% endif %} +
+ + {% elif rsvp_passed and application.rsvp %} +

The RSVP deadline has passed. Thanks for confirming your position at {{ hackathon_name }}! We look forward to seeing you there. Note that you cannot change your RSVP at this time.

+ {% elif rsvp_passed and application.rsvp is sameas false %} +

The RSVP deadline has passed. We regret to see that you will not be joining us this year at {{ hackathon_name }}. Unfortunately you cannot change your RSVP at this time.

+ {% else %} +

It appears you haven't RSVPed. Unfortunately the RSVP deadline has passed and you cannot change your RSVP at this time.

+ {% endif %} + {% endif %} + {% elif review.status == "Waitlisted" %}

You've been waitlisted for {{ hackathon_name }}

The {{ hackathon_name }} team has reviewed your application, and have decided not to grant you a guaranteed spot diff --git a/hackathon_site/event/serializers.py b/hackathon_site/event/serializers.py index 5df367f6..a92bc2b0 100644 --- a/hackathon_site/event/serializers.py +++ b/hackathon_site/event/serializers.py @@ -104,11 +104,11 @@ def create(self, validated_data): ) if not is_test_user: try: - application = Application.objects.get(user=current_user) - # if not rsvp_status: - # raise serializers.ValidationError( - # "User has not RSVP'd to the hackathon. Please RSVP to access the Hardware Signout Site" - # ) + rsvp_status = Application.objects.get(user=current_user).rsvp + if not rsvp_status and settings.RSVP: + raise serializers.ValidationError( + "User has not RSVP'd to the hackathon. Please RSVP to access the Hardware Signout Site" + ) except Application.DoesNotExist: raise serializers.ValidationError( "User has not completed their application to the hackathon. Please do so to access the Hardware Signout Site" diff --git a/hackathon_site/event/views.py b/hackathon_site/event/views.py index f457f187..06354071 100644 --- a/hackathon_site/event/views.py +++ b/hackathon_site/event/views.py @@ -47,10 +47,15 @@ def get_context_data(self, **kwargs): class DashboardView(LoginRequiredMixin, FormView): - template_name = "event/dashboard_base.html" # Form submits should take the user back to the dashboard success_url = reverse_lazy("event:dashboard") + # TODO: QR Scanner CODE + def get_template_names(self): + # if self.request.user.is_staff: + # return "event/dashboard_admin.html" + return "event/dashboard_base.html" + def get_form(self, form_class=None): """ The dashboard can have different forms, but not at the same time: @@ -117,6 +122,19 @@ def get_context_data(self, **kwargs): review = self.request.user.application.review context["review"] = review + if settings.RSVP: + context[ + "rsvp_passed" + ] = _now().date() > review.decision_sent_date + timedelta( + days=settings.RSVP_DAYS + ) + rsvp_deadline = datetime.combine( + review.decision_sent_date + timedelta(days=settings.RSVP_DAYS), + datetime.max.time(), # 11:59PM + ) + context["rsvp_deadline"] = settings.TZ_INFO.localize( + rsvp_deadline + ).strftime("%B %-d, %Y, %-I:%M %p %Z") else: context["review"] = None @@ -134,6 +152,12 @@ def get_context_data(self, **kwargs): and self.request.user.application.review.decision_sent_date is None ): context["status"] = "Application Complete" + elif ( + hasattr(self.request.user.application, "review") + and self.request.user.application.review.status == "Accepted" + and self.request.user.application.rsvp is None + ): + context["status"] = "Accepted, awaiting RSVP" elif ( hasattr(self.request.user.application, "review") and self.request.user.application.review.status == "Waitlisted" @@ -144,6 +168,10 @@ def get_context_data(self, **kwargs): and self.request.user.application.review.status == "Rejected" ): context["status"] = "Rejected" + elif self.request.user.application.rsvp: + context["status"] = "Will Attend (Accepted)" + elif not self.request.user.application.rsvp: + context["status"] = "Cannot Attend (Declined)" else: context["status"] = "Unknown" diff --git a/hackathon_site/hackathon_site/jinja2.py b/hackathon_site/hackathon_site/jinja2.py index d636a56e..c359a57e 100644 --- a/hackathon_site/hackathon_site/jinja2.py +++ b/hackathon_site/hackathon_site/jinja2.py @@ -38,6 +38,7 @@ def environment(**options): "chat_room_name": settings.CHAT_ROOM[0], "chat_room_link": settings.CHAT_ROOM[1], "using_teams": settings.TEAMS, + "using_rsvp": settings.RSVP, } ) return env diff --git a/hackathon_site/hackathon_site/settings/__init__.py b/hackathon_site/hackathon_site/settings/__init__.py index 74225ba8..0d0d7809 100644 --- a/hackathon_site/hackathon_site/settings/__init__.py +++ b/hackathon_site/hackathon_site/settings/__init__.py @@ -384,6 +384,7 @@ # Enable/Disable certain Features TEAMS = True +RSVP = True # HSS Testing TEST_USER_GROUP = "HSS Test Users" diff --git a/hackathon_site/registration/admin.py b/hackathon_site/registration/admin.py index 6dff7eae..305f9527 100644 --- a/hackathon_site/registration/admin.py +++ b/hackathon_site/registration/admin.py @@ -57,6 +57,7 @@ class Meta: "email_agree", "resume_sharing", "review__status", + "rsvp", "created_at", "updated_at", ) @@ -84,6 +85,7 @@ class Meta: "email_agree", "resume_sharing", "review__status", + "rsvp", "created_at", "updated_at", ) diff --git a/hackathon_site/registration/forms.py b/hackathon_site/registration/forms.py index e02557d2..39c390a7 100644 --- a/hackathon_site/registration/forms.py +++ b/hackathon_site/registration/forms.py @@ -369,3 +369,49 @@ def clean_team_code(self): raise forms.ValidationError(_(f"Team {team_code} is full.")) return team_code + +class SignInForm(forms.Form): + email = forms.EmailField() + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.label_suffix = "" + self.error_css_class = "invalid" + + def clean(self): + if not is_hackathon_happening(): + raise forms.ValidationError( + _("You cannot sign in outside of the hackathon period."), + code="invalid_sign_in_time", + ) + + return super().clean() + + def clean_email(self): + email = self.cleaned_data["email"] + + try: + user = User.objects.get(email__exact=email) + application = Application.objects.get(user__exact=user) + review = Review.objects.get(application__exact=application) + if review.status == "Accepted": + if settings.RSVP and application.rsvp is None: + raise forms.ValidationError( + _(f"User {email} has not RSVP'd to the hackathon") + ) + else: + raise forms.ValidationError( + _( + f"User {email} has not been Accepted to attend {settings.HACKATHON_NAME}" + ) + ) + except User.DoesNotExist: + raise forms.ValidationError(_(f"User {email} does not exist.")) + except Application.DoesNotExist: + raise forms.ValidationError( + _(f"User {email} has not applied to {settings.HACKATHON_NAME}") + ) + except Exception as e: + raise e + + return email \ No newline at end of file diff --git a/hackathon_site/registration/urls.py b/hackathon_site/registration/urls.py index 001a4075..2be84724 100644 --- a/hackathon_site/registration/urls.py +++ b/hackathon_site/registration/urls.py @@ -24,4 +24,5 @@ ), path("application/", views.ApplicationView.as_view(), name="application"), path("leave_team/", views.LeaveTeamView.as_view(), name="leave-team"), + re_path("rsvp/(?Pyes|no)/$", views.RSVPView.as_view(), name="rsvp"), ] diff --git a/hackathon_site/registration/views.py b/hackathon_site/registration/views.py index 6255e086..a735b8b5 100644 --- a/hackathon_site/registration/views.py +++ b/hackathon_site/registration/views.py @@ -209,3 +209,72 @@ def get(self, request, *args, **kwargs): response["Content-Encoding"] = encoding return response + + +class RSVPView(LoginRequiredMixin, View): + """ + This page checks if the RSVP deadline has passed and then does one of + the following: + 1. If the deadline has passed, redirect to the dashboard + 2. Otherwise if their decision was a 'yes', we note that and + create a profile for them + 3. Otherwise if their decision was a 'no', we note that and remove + their profile and team if they had one. + + Finally we redirect to the dashboard. + """ + + def get(self, request, *args, **kwargs): + decision = kwargs["rsvp"] + + # Check for nulls + user = self.request.user + if not hasattr(user, "application"): + return HttpResponseBadRequest( + "You have not submitted an application.".encode(encoding="utf-8") + ) + + application = user.application + if not hasattr(application, "review"): + return HttpResponseBadRequest( + "Your application has not yet been reviewed.".encode(encoding="utf-8") + ) + + review = application.review + if not review.status == "Accepted": + return HttpResponseBadRequest( + "You cannot RSVP since your application has not yet been accepted.".encode( + encoding="utf-8" + ) + ) + + # Check if RSVP deadline has passed + if _now().date() > review.decision_sent_date + timedelta( + days=settings.RSVP_DAYS + ): + return redirect(reverse_lazy("event:dashboard")) + + # Check decision + else: + if decision == "yes" and not application.rsvp: + application.rsvp = True + application.save() + + # TODO: decide whether to create profile when rsvp + # profile = Profile(user=user, team=EventTeam.objects.create()) + # profile.save() + + elif decision == "no" and (application.rsvp or application.rsvp is None): + application.rsvp = False + application.save() + + # Delete the profile + if hasattr(request.user, "profile"): + team = user.profile.team + user.profile.delete() + + # Delete the team if it is empty + if not team.profiles.exists(): + team.delete() + + return redirect(reverse_lazy("event:dashboard")) \ No newline at end of file diff --git a/hackathon_site/review/admin.py b/hackathon_site/review/admin.py index c22abebd..b1148fd4 100644 --- a/hackathon_site/review/admin.py +++ b/hackathon_site/review/admin.py @@ -111,6 +111,7 @@ class ApplicationInline(admin.TabularInline): "ethnicity", "phone_number", "resume", + "rsvp", "conduct_agree", "data_agree", ) diff --git a/hackathon_site/review/jinja2/review/emails/accepted_email_body.html b/hackathon_site/review/jinja2/review/emails/accepted_email_body.html index 124ef1ce..9c61a295 100644 --- a/hackathon_site/review/jinja2/review/emails/accepted_email_body.html +++ b/hackathon_site/review/jinja2/review/emails/accepted_email_body.html @@ -55,7 +55,7 @@

If you have already RSVP'd please ignore the following.

- To confirm your attendance, visit your dashboard to RSVP by November 3rd, 2023 otherwise your spot will be given to other applicants. Alternatively, you can press the "Cannot attend" button. + To confirm your attendance, visit your dashboard to RSVP by {{ rsvp_deadline }} otherwise your spot will be given to other applicants. Alternatively, you can press the "Cannot attend" button.

Read our participant package for all the info regarding the event, and join our {{ chat_room_name }}. Stay tuned for more updates regarding detailed event logistics, and we hope to see you soon! If you have questions, read the FAQ on your dashboard or feel free to contact us.

diff --git a/hackathon_site/review/views.py b/hackathon_site/review/views.py index 3d25ef8d..809612c5 100644 --- a/hackathon_site/review/views.py +++ b/hackathon_site/review/views.py @@ -61,6 +61,9 @@ def form_valid(self, form, **kwargs): render_to_string_context = { "user": review.application.user, "request": self.request, + "rsvp_deadline": ( + current_date + timedelta(days=settings.RSVP_DAYS) + ).strftime("%B %-d %Y"), } review.application.user.email_user( From 049e55ac5d4175a5c64ddfc5d1f25ae377f8c19e Mon Sep 17 00:00:00 2001 From: Mustafa Abdulrahman Date: Thu, 17 Oct 2024 01:19:36 -0400 Subject: [PATCH 2/6] ran black --- hackathon_site/registration/forms.py | 3 ++- hackathon_site/registration/views.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/hackathon_site/registration/forms.py b/hackathon_site/registration/forms.py index 39c390a7..950cbbe9 100644 --- a/hackathon_site/registration/forms.py +++ b/hackathon_site/registration/forms.py @@ -370,6 +370,7 @@ def clean_team_code(self): return team_code + class SignInForm(forms.Form): email = forms.EmailField() @@ -414,4 +415,4 @@ def clean_email(self): except Exception as e: raise e - return email \ No newline at end of file + return email diff --git a/hackathon_site/registration/views.py b/hackathon_site/registration/views.py index a735b8b5..574a8013 100644 --- a/hackathon_site/registration/views.py +++ b/hackathon_site/registration/views.py @@ -277,4 +277,4 @@ def get(self, request, *args, **kwargs): if not team.profiles.exists(): team.delete() - return redirect(reverse_lazy("event:dashboard")) \ No newline at end of file + return redirect(reverse_lazy("event:dashboard")) From 4f0b093134eebe58320ca4af93b043df35effa86 Mon Sep 17 00:00:00 2001 From: carmen-chau <80921817+carmen-chau@users.noreply.github.com> Date: Thu, 17 Oct 2024 22:05:04 -0400 Subject: [PATCH 3/6] added 2024 participant pkg --- hackathon_site/hackathon_site/settings/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hackathon_site/hackathon_site/settings/__init__.py b/hackathon_site/hackathon_site/settings/__init__.py index 0d0d7809..96581be7 100644 --- a/hackathon_site/hackathon_site/settings/__init__.py +++ b/hackathon_site/hackathon_site/settings/__init__.py @@ -375,7 +375,7 @@ # Links # TODO: NEED TO REPLACE THIS WITH NEW LINK (for acceptance email) -PARTICIPANT_PACKAGE_LINK = "https://docs.google.com/document/d/1AkinPac_KS9_wA9P7H-7wOBfJ5xgIciIGwpU3D1UGu0/edit?usp=sharing" +PARTICIPANT_PACKAGE_LINK = "https://docs.google.com/document/d/1AmgarLDeE8e8oirdG-uY-fdyOwfUomhA4jjU6o-Q2MM/edit?usp=sharing" # Note this is in the form (chat_room_name, chat_room_link) # Chat room name is such as the following: Slack, Discord From 48849aaab3f54a1dcafdb81705ba4e78afb2387e Mon Sep 17 00:00:00 2001 From: carmen-chau <80921817+carmen-chau@users.noreply.github.com> Date: Sat, 19 Oct 2024 21:19:08 -0400 Subject: [PATCH 4/6] revised rsvp date --- hackathon_site/hackathon_site/settings/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hackathon_site/hackathon_site/settings/__init__.py b/hackathon_site/hackathon_site/settings/__init__.py index 96581be7..88371f4e 100644 --- a/hackathon_site/hackathon_site/settings/__init__.py +++ b/hackathon_site/hackathon_site/settings/__init__.py @@ -322,7 +322,7 @@ HARDWARE_SIGN_OUT_START_DATE = datetime(2024, 10, 28, 23, 59, 0, tzinfo=TZ_INFO) HARDWARE_SIGN_OUT_END_DATE = EVENT_END_DATE -RSVP_DAYS = 10 +RSVP_DAYS = 2 # sign in times must be between EVENT_START_DATE and EVENT_END_DATE and in chronological order # the number of sign in times MUST MATCH the number of columns in UserActivityTable From d70757b80d24b5be58124fa9c54327ca9d5719dd Mon Sep 17 00:00:00 2001 From: carmen-chau <80921817+carmen-chau@users.noreply.github.com> Date: Sat, 19 Oct 2024 21:39:05 -0400 Subject: [PATCH 5/6] changed discord link --- hackathon_site/hackathon_site/settings/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hackathon_site/hackathon_site/settings/__init__.py b/hackathon_site/hackathon_site/settings/__init__.py index 88371f4e..ed2c95e2 100644 --- a/hackathon_site/hackathon_site/settings/__init__.py +++ b/hackathon_site/hackathon_site/settings/__init__.py @@ -380,7 +380,7 @@ # Note this is in the form (chat_room_name, chat_room_link) # Chat room name is such as the following: Slack, Discord # TODO: NEED TO REPLACE THIS WITH NEW LINK (for acceptance email) -CHAT_ROOM = ("Discord", "https://discord.gg/cqW93CMu") +CHAT_ROOM = ("Discord", "https://discord.gg/TQZ7aCs24r") # Enable/Disable certain Features TEAMS = True From d57ddfa6624c07576569c8a46760f64f0bb0a04b Mon Sep 17 00:00:00 2001 From: carmen-chau <80921817+carmen-chau@users.noreply.github.com> Date: Sat, 19 Oct 2024 21:39:43 -0400 Subject: [PATCH 6/6] removed comments --- hackathon_site/hackathon_site/settings/__init__.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/hackathon_site/hackathon_site/settings/__init__.py b/hackathon_site/hackathon_site/settings/__init__.py index ed2c95e2..d1f18b9f 100644 --- a/hackathon_site/hackathon_site/settings/__init__.py +++ b/hackathon_site/hackathon_site/settings/__init__.py @@ -374,12 +374,10 @@ FINAL_REVIEW_RESPONSE_DATE = REGISTRATION_CLOSE_DATE + timedelta(days=7) # Links -# TODO: NEED TO REPLACE THIS WITH NEW LINK (for acceptance email) PARTICIPANT_PACKAGE_LINK = "https://docs.google.com/document/d/1AmgarLDeE8e8oirdG-uY-fdyOwfUomhA4jjU6o-Q2MM/edit?usp=sharing" # Note this is in the form (chat_room_name, chat_room_link) # Chat room name is such as the following: Slack, Discord -# TODO: NEED TO REPLACE THIS WITH NEW LINK (for acceptance email) CHAT_ROOM = ("Discord", "https://discord.gg/TQZ7aCs24r") # Enable/Disable certain Features