From 9ec583cfc439556f5b1e2e64484a8b90015f7e9c Mon Sep 17 00:00:00 2001 From: Jeff Triplett Date: Mon, 19 Jun 2023 20:32:56 -0500 Subject: [PATCH 1/3] :sparkles: Adds ProgramApplicantsCsv --- grants/models.py | 1 + grants/views/program.py | 53 +++++++++++++++++++++++++++++++ grorg/urls.py | 1 + templates/program-applicants.html | 1 + 4 files changed, 56 insertions(+) diff --git a/grants/models.py b/grants/models.py index 43e8ca0..3ce4ce6 100644 --- a/grants/models.py +++ b/grants/models.py @@ -33,6 +33,7 @@ class urls(Urls): questions = "{view}questions/" applicants = "{view}applicants/" applicants_bulk = "{view}applicants/bulk/" + applicants_csv = "{view}applicants/csv/" scores_bulk = "{view}applicants/bulk_scores/" resources = "{view}resources/" users = "{view}users/" diff --git a/grants/views/program.py b/grants/views/program.py index f6df1f4..2365609 100644 --- a/grants/views/program.py +++ b/grants/views/program.py @@ -1,10 +1,12 @@ from __future__ import annotations import collections +import csv from django import forms from django.db.models import Q from django.http import Http404 +from django.http import HttpResponse from django.shortcuts import redirect, render from django.utils import timezone from django.views.generic import FormView, ListView, TemplateView, UpdateView, View @@ -201,6 +203,57 @@ def get_context_data(self): return context +class ProgramApplicantsCsv(ProgramMixin, ListView): + """ + Shows applications to the program. + """ + + context_object_name = "applicants" + + def get(self, request, *args, **kwargs): + # Work out sort + if self.request.GET.get("sort", None) == "score": + self.sort = "score" + else: + self.sort = "applied" + # Fetch applicants + # but don't let a user see their own request + applicants = list( + self.program.applicants.exclude(email=self.request.user.email) + .prefetch_related("scores") + .order_by("-applied") + ) + for applicant in applicants: + applicant.has_scored = applicant.scores.filter( + user=self.request.user + ).exists() + if applicant.has_scored: + applicant.average_score = applicant.average_score() + else: + applicant.average_score = -1 + if self.sort == "score": + applicants.sort(key=lambda a: a.average_score, reverse=True) + + # Prepare CSV response + response = HttpResponse(content_type="text/csv") + response["Content-Disposition"] = 'attachment; filename="applicants.csv"' + + writer = csv.writer(response) + writer.writerow(["Email", "Has Scored", "Average Score"]) # Write headers + + for applicant in applicants: + writer.writerow( + [applicant.email, applicant.has_scored, applicant.average_score] + ) + + return response + + def get_context_data(self): + context = super().get_context_data() + context["sort"] = self.sort + return context + + class ProgramApplicantView(ProgramMixin, TemplateView): """ Shows an individual application. diff --git a/grorg/urls.py b/grorg/urls.py index 1aa4361..a3ce201 100644 --- a/grorg/urls.py +++ b/grorg/urls.py @@ -31,6 +31,7 @@ "/applicants/bulk_scores/", bulk_load.BulkLoadScores.as_view(), ), + path("/applicants/csv/", program.ProgramApplicantsCsv.as_view()), path( "/applicants/random-unscored/", program.RandomUnscoredApplicant.as_view(), diff --git a/templates/program-applicants.html b/templates/program-applicants.html index a4d0734..c215caa 100644 --- a/templates/program-applicants.html +++ b/templates/program-applicants.html @@ -54,6 +54,7 @@

Applicants

{% endblock %} From 0d5998c5cc099a488268d641df5875bc49e54aab Mon Sep 17 00:00:00 2001 From: Jeff Triplett Date: Mon, 19 Jun 2023 20:33:13 -0500 Subject: [PATCH 2/3] :shirt: Lints --- README.md | 4 ++-- pyproject.toml | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9a1e541..e3df5f2 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,8 @@ Check out our [deploy.yml](https://github.com/djangocon/grorg/blob/main/.github/ ## Want to use ours? -File an issue https://github.com/djangocon/grorg/issues and we can build an issue program ID for your event. +File an issue https://github.com/djangocon/grorg/issues and we can build an issue program ID for your event. -## Kudos +## Kudos Created by andrew@aeracode.org diff --git a/pyproject.toml b/pyproject.toml index aa95ad5..349fb39 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,4 +1,3 @@ - [tool.pytest.ini_options] # addopts = "--cov=. --durations=1 --nomigrations --reuse-db -vv" addopts = "--nomigrations --reuse-db -vv" From cb14ed39c98311dfd70a0da8be0d1e2200a7c83c Mon Sep 17 00:00:00 2001 From: Jeff Triplett Date: Mon, 19 Jun 2023 20:34:44 -0500 Subject: [PATCH 3/3] :arrow_up: Updates bumpver --- requirements.in | 1 + requirements.txt | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/requirements.in b/requirements.in index 4be1263..36540bf 100644 --- a/requirements.in +++ b/requirements.in @@ -1,3 +1,4 @@ +bumpver django-allauth Django<5.0 environs[django] diff --git a/requirements.txt b/requirements.txt index 46dc956..9be76ba 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,6 +8,10 @@ asgiref==3.5.2 \ --hash=sha256:1d2880b792ae8757289136f1db2b7b99100ce959b2aa57fd69dab783d05afac4 \ --hash=sha256:4a29362a6acebe09bf1d6640db38c1dc3d9217c68e6f9f6204d72667fc19a424 # via django +bumpver==2023.1124 \ + --hash=sha256:81ef4c969adfdb14eb3a029d46998fbb72eb7bb533073ad3468f0ecec2f4c09c \ + --hash=sha256:e5632c9da189c12b16da568f0c9b5e6d7c7786a4361c150f99fb0d24fd1b7910 + # via -r ./requirements.in certifi==2022.12.7 \ --hash=sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3 \ --hash=sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18 @@ -155,6 +159,14 @@ charset-normalizer==3.1.0 \ --hash=sha256:f8303414c7b03f794347ad062c0516cee0e15f7a612abd0ce1e25caf6ceb47df \ --hash=sha256:fca62a8301b605b954ad2e9c3666f9d97f63872aa4efcae5492baca2056b74ab # via requests +click==8.1.3 \ + --hash=sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e \ + --hash=sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48 + # via bumpver +colorama==0.4.6 \ + --hash=sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44 \ + --hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6 + # via bumpver cryptography==40.0.2 \ --hash=sha256:05dc219433b14046c476f6f09d7636b92a1c3e5808b9a6536adf4932b3b2c440 \ --hash=sha256:0dcca15d3a19a66e63662dc8d30f8036b07be851a8680eda92d079868f106288 \ @@ -213,6 +225,14 @@ idna==3.4 \ --hash=sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4 \ --hash=sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2 # via requests +lexid==2021.1006 \ + --hash=sha256:509a3a4cc926d3dbf22b203b18a4c66c25e6473fb7c0e0d30374533ac28bafe5 \ + --hash=sha256:5526bb5606fd74c7add23320da5f02805bddd7c77916f2dc1943e6bada8605ed + # via bumpver +looseversion==1.2.0 \ + --hash=sha256:0b30eaca26506135c1109dbed582384f8503dee8fcfe07b85fd949f69f077977 \ + --hash=sha256:c64e71c0b29030683b4ea75aee431db2d25c4e6e533590e52129f1d9e51de204 + # via bumpver marshmallow==3.16.0 \ --hash=sha256:53a1e0ee69f79e1f3e80d17393b25cfc917eda52f859e8183b4af72c3390c1f1 \ --hash=sha256:a762c1d8b2bcb0e5c8e964850d03f9f3bffd6a12b626f3c14b9d6b1841999af5 @@ -225,6 +245,10 @@ packaging==21.3 \ --hash=sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb \ --hash=sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522 # via marshmallow +pathlib2==2.3.7.post1 \ + --hash=sha256:5266a0fd000452f1b3467d782f079a4343c63aaa119221fbdc4e39577489ca5b \ + --hash=sha256:9fe0edad898b83c0c3e199c842b27ed216645d2e177757b2dd67384d4113c641 + # via bumpver psycopg2-binary==2.9.3 \ --hash=sha256:01310cf4cf26db9aea5158c217caa92d291f0500051a6469ac52166e1a16f5b7 \ --hash=sha256:083a55275f09a62b8ca4902dd11f4b33075b743cf0d360419e2051a8a5d5ff76 \ @@ -320,10 +344,18 @@ requests-oauthlib==1.3.1 \ --hash=sha256:2577c501a2fb8d05a304c09d090d6e47c306fef15809d102b327cf8364bddab5 \ --hash=sha256:75beac4a47881eeb94d5ea5d6ad31ef88856affe2332b9aafb52c6452ccf0d7a # via django-allauth +six==1.16.0 \ + --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \ + --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 + # via pathlib2 sqlparse==0.4.2 \ --hash=sha256:0c00730c74263a94e5a9919ade150dfc3b19c574389985446148402998287dae \ --hash=sha256:48719e356bb8b42991bdbb1e8b83223757b93789c00910a616a071910ca4a64d # via django +toml==0.10.2 \ + --hash=sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b \ + --hash=sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f + # via bumpver urllib3==2.0.2 \ --hash=sha256:61717a1095d7e155cdb737ac7bb2f4324a858a1e2e6466f6d03ff630ca68d3cc \ --hash=sha256:d055c2f9d38dc53c808f6fdc8eab7360b6fdbbde02340ed25cfbcd817c62469e