Skip to content

Commit

Permalink
Add export anonymized application submissions feature for Wharton Cou…
Browse files Browse the repository at this point in the history
…ncil cycles
  • Loading branch information
julianweng committed Feb 15, 2024
1 parent e70ced7 commit 7be2ddf
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 21 deletions.
2 changes: 1 addition & 1 deletion backend/clubs/permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ def has_permission(self, request, view):

class WhartonApplicationPermission(permissions.BasePermission):
"""
Grants permission is the user is an officer of Wharton Council
Grants permission if the user is an officer of Wharton Council
"""

WHARTON_COUNCIL_CLUB_CODE = "wharton-council"
Expand Down
104 changes: 85 additions & 19 deletions backend/clubs/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
from django.core.serializers.json import DjangoJSONEncoder
from django.core.validators import validate_email
from django.db.models import (
Case,
CharField,
Count,
DurationField,
ExpressionWrapper,
Expand All @@ -37,6 +39,7 @@
Q,
TextField,
Value,
When,
)
from django.db.models.functions import SHA1, Concat, Lower, Trunc
from django.db.models.query import prefetch_related_objects
Expand Down Expand Up @@ -2424,11 +2427,13 @@ def get_queryset(self):
.prefetch_related(
Prefetch(
"club__badges",
queryset=Badge.objects.filter(
fair__id=self.request.query_params.get("fair")
)
if "fair" in self.request.query_params
else Badge.objects.filter(visible=True),
queryset=(
Badge.objects.filter(
fair__id=self.request.query_params.get("fair")
)
if "fair" in self.request.query_params
else Badge.objects.filter(visible=True)
),
)
)
.order_by("start_time")
Expand Down Expand Up @@ -4069,12 +4074,14 @@ def post(self, request):
return Response(
{
"success": out.ok,
"detail": "Your Zoom meeting has been updated. "
"The following accounts have been made hosts:"
f" {', '.join(alt_hosts)}"
if out.ok
else "Your Zoom meeting has not been updated. "
"Are you the owner of the meeting?",
"detail": (
"Your Zoom meeting has been updated. "
"The following accounts have been made hosts:"
f" {', '.join(alt_hosts)}"
if out.ok
else "Your Zoom meeting has not been updated. "
"Are you the owner of the meeting?"
),
}
)

Expand Down Expand Up @@ -4186,9 +4193,11 @@ def post(self, request):
return Response(
{
"success": response.ok,
"detail": "Your user settings have been updated on Zoom."
if response.ok
else "Failed to update Zoom user settings.",
"detail": (
"Your user settings have been updated on Zoom."
if response.ok
else "Failed to update Zoom user settings."
),
}
)

Expand Down Expand Up @@ -4858,6 +4867,7 @@ class WhartonCyclesView(viewsets.ModelViewSet):
patch: Update application cycle and WC applications with cycle
clubs: list clubs with cycle
add_clubs: add clubs to cycle
applications: list application submissions for cycle
remove_clubs_from_all: remove clubs from all cycles
"""

Expand Down Expand Up @@ -5105,6 +5115,60 @@ def remove_clubs_from_exception(self, *args, **kwargs):
)
return Response([])

@action(detail=True, methods=["GET"])
def applications(self, *args, **kwargs):
"""
Retrieve applications for given cycle
---
requestBody: {}
responses:
"200":
content: {}
---
"""
cycle = self.get_object()
data = (
ApplicationSubmission.objects.filter(
application__is_wharton_council=True,
application__application_cycle=cycle,
)
.select_related(
"user__profile", "application", "application__application_cycle"
)
.annotate(
annotated_name=F("application__name"),
annotated_committee=F("committee__name"),
annotated_club=F("application__club__name"),
annotated_grad_year=F("user__profile__graduation_year"),
annotated_school=F("user__profile__school__name"),
status_name=Case(
When(status=1, then=Value("Pending")),
When(status=2, then=Value("Rejected after written application")),
When(status=3, then=Value("Rejected after interview(s)")),
When(status=4, then=Value("Accepted")),
default=Value("Unknown"),
output_field=CharField(),
),
)
.values(
"annotated_name",
"application",
"annotated_committee",
"annotated_club",
"annotated_grad_year",
"annotated_school",
"status_name",
"user",
)
)
df = pd.DataFrame(data)
resp = HttpResponse(
content_type="text/csv",
headers={"Content-Disposition": "attachment;filename=submissions.csv"},
)
df.to_csv(index=True, path_or_buf=resp)
return resp


class WhartonApplicationAPIView(viewsets.ModelViewSet):
"""
Expand Down Expand Up @@ -5793,11 +5857,13 @@ def add_argument(self, *args, **kwargs):
default = kwargs.get("default")
typ = kwargs.get(
"type",
bool
if kwargs.get("action") == "store_true"
else type(default)
if default is not None
else str,
(
bool
if kwargs.get("action") == "store_true"
else type(default)
if default is not None
else str
),
)
pos = -1
if not args[0].startswith("-"):
Expand Down
8 changes: 7 additions & 1 deletion frontend/components/Settings/WhartonApplicationCycles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import Select from 'react-select'
import styled from 'styled-components'

import { ClubApplication } from '~/types'
import { doApiRequest } from '~/utils'
import { doApiRequest, getApiUrl } from '~/utils'

import { Checkbox, Icon, Loading, Modal, Subtitle, Text } from '../common'
import { DateTimeField, TextField } from '../FormComponents'
Expand Down Expand Up @@ -207,6 +207,12 @@ const WhartonApplicationCycles = (): ReactElement => {
>
Extensions
</button>
<a
href={getApiUrl(`/cycles/${object.id}/applications`)}
className="button is-info is-small"
>
Export Applications
</a>
</>
)}
/>
Expand Down

0 comments on commit 7be2ddf

Please sign in to comment.