Skip to content

Commit

Permalink
Merge branch 'master' into wc-application-admin
Browse files Browse the repository at this point in the history
  • Loading branch information
julianweng authored Jan 6, 2024
2 parents 0b34b7e + 6c26b15 commit a3db4e1
Show file tree
Hide file tree
Showing 16 changed files with 371 additions and 157 deletions.
2 changes: 2 additions & 0 deletions backend/clubs/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
Advisor,
ApplicationCommittee,
ApplicationCycle,
ApplicationExtension,
ApplicationMultipleChoice,
ApplicationQuestion,
ApplicationQuestionResponse,
Expand Down Expand Up @@ -412,6 +413,7 @@ class ApplicationSubmissionAdmin(admin.ModelAdmin):

admin.site.register(Asset)
admin.site.register(ApplicationCommittee)
admin.site.register(ApplicationExtension)
admin.site.register(ApplicationMultipleChoice)
admin.site.register(ApplicationQuestion)
admin.site.register(ApplicationQuestionResponse)
Expand Down
47 changes: 47 additions & 0 deletions backend/clubs/migrations/0091_applicationextension.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Generated by Django 3.2.18 on 2023-11-25 03:58

import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
("clubs", "0090_auto_20230106_1443"),
]

operations = [
migrations.CreateModel(
name="ApplicationExtension",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("end_time", models.DateTimeField()),
(
"application",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="extensions",
to="clubs.clubapplication",
),
),
(
"user",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to=settings.AUTH_USER_MODEL,
),
),
],
options={"unique_together": {("user", "application")}},
),
]
40 changes: 40 additions & 0 deletions backend/clubs/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -1593,6 +1593,40 @@ def validate_template(cls, template):
return all(t in cls.VALID_TEMPLATE_TOKENS for t in tokens)


class ApplicationExtension(models.Model):
"""
Represents an individual club application extension.
"""

user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
application = models.ForeignKey(
ClubApplication, related_name="extensions", on_delete=models.CASCADE
)
end_time = models.DateTimeField()

def send_extension_mail(self):
context = {
"name": self.user.first_name,
"application_name": self.application.name,
"end_time": self.end_time,
"club": self.application.club.name,
"url": (
f"https://pennclubs.com/club/{self.application.club.code}"
f"/application/{self.application.pk}/"
),
}

send_mail_helper(
name="application_extension",
subject=f"Application Extension for {self.application.name}",
emails=[self.user.email],
context=context,
)

class Meta:
unique_together = (("user", "application"),)


class ApplicationCommittee(models.Model):
"""
Represents a committee for a particular club application. Each application
Expand Down Expand Up @@ -1696,6 +1730,9 @@ class ApplicationSubmission(models.Model):
def __str__(self):
return f"{self.user.first_name}: {self.application.name}"

class Meta:
unique_together = (("user", "application", "committee"),)


class ApplicationQuestionResponse(models.Model):
"""
Expand Down Expand Up @@ -1724,6 +1761,9 @@ class ApplicationQuestionResponse(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)

class Meta:
unique_together = (("question", "submission"),)


class QuestionResponse(models.Model):
"""
Expand Down
81 changes: 81 additions & 0 deletions backend/clubs/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
Advisor,
ApplicationCommittee,
ApplicationCycle,
ApplicationExtension,
ApplicationMultipleChoice,
ApplicationQuestion,
ApplicationQuestionResponse,
Expand Down Expand Up @@ -2443,6 +2444,86 @@ class Meta:
fields = ("text", "multiple_choice", "question_type", "question")


class ApplicationExtensionSerializer(serializers.ModelSerializer):
first_name = serializers.CharField(source="user.first_name", read_only=True)
last_name = serializers.CharField(source="user.last_name", read_only=True)
username = serializers.CharField(source="user.username", read_only=False)
graduation_year = serializers.CharField(
source="user.profile.graduation_year", read_only=True
)

class Meta:
model = ApplicationExtension
fields = (
"id",
"username",
"first_name",
"last_name",
"graduation_year",
"end_time",
)

def create(self, validated_data):
username = validated_data.get("user").pop("username")
validated_data["user"] = get_user_model().objects.get(username=username)

application_pk = self.context["view"].kwargs.get("application_pk")
validated_data["application"] = ClubApplication.objects.filter(
pk=application_pk
).first()

return super().create(validated_data)

def update(self, instance, validated_data):
if user_field := validated_data.pop("user", None):
username = user_field.pop("username")
user = get_user_model().objects.get(username=username)
instance.user = user
return super().update(instance, validated_data)

def validate(self, data):
username = None
if user_field := data.get("user") or not self.instance:
username = user_field.get("username")
user = get_user_model().objects.filter(username=username).first()
if not user:
raise serializers.ValidationError("Please provide a valid username!")

application_pk = self.context["view"].kwargs.get("application_pk")
application = ClubApplication.objects.filter(pk=application_pk).first()

if not application:
raise serializers.ValidationError("Invalid application id!")

extension_exists = ApplicationExtension.objects.filter(
user=user, application=application
).exists()
modify_username = not self.instance or (
username and self.instance.user.username != username
)

if modify_username and extension_exists:
raise serializers.ValidationError(
"An extension for this user and application already exists!"
)

extension_end_time = data.get("end_time")
if (
extension_end_time
and extension_end_time <= application.application_end_time
):
raise serializers.ValidationError(
"Extension end time must be greater than the application end time!"
)

return data

def save(self):
extension_obj = super().save()
extension_obj.send_extension_mail()
return extension_obj


class ApplicationSubmissionSerializer(serializers.ModelSerializer):
committee = ApplicationCommitteeSerializer(required=False, read_only=True)
responses = ApplicationQuestionResponseSerializer(
Expand Down
5 changes: 5 additions & 0 deletions backend/clubs/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from clubs.views import (
AdminNoteViewSet,
AdvisorViewSet,
ApplicationExtensionViewSet,
ApplicationQuestionViewSet,
ApplicationSubmissionUserViewSet,
ApplicationSubmissionViewSet,
Expand Down Expand Up @@ -120,6 +121,10 @@
basename="club-application-submissions",
)

applications_router.register(
r"extensions", ApplicationExtensionViewSet, basename="club-application-extensions"
)

router.register(r"booths", ClubBoothsViewSet, basename="club-booth")

urlpatterns = [
Expand Down
Loading

0 comments on commit a3db4e1

Please sign in to comment.