Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bulk volunteer deactivation page #186

Merged
merged 1 commit into from
Sep 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions ceuk-marking/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,11 @@
volunteers.BulkAssignVolunteer.as_view(),
name="bulk_assign_volunteer",
),
path(
"volunteers/deactivate/",
volunteers.DeactivateVolunteers.as_view(),
name="deactivate_volunteers",
),
path(
"volunteers/<user_id>/assign/",
volunteers.VolunteerAssignmentView.as_view(),
Expand Down
8 changes: 8 additions & 0 deletions crowdsourcer/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -506,3 +506,11 @@ def clean(self):
raise ValidationError(errors)

self.volunteer_df = df


class VolunteerDeactivateForm(Form):
stage = ChoiceField(required=True, choices=[])

def __init__(self, stage_choices, **kwargs):
super().__init__(**kwargs)
self.fields["stage"].choices = stage_choices
20 changes: 20 additions & 0 deletions crowdsourcer/templates/crowdsourcer/volunteers/deactivate.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{% extends 'crowdsourcer/base.html' %}

{% load crowdsourcer_tags django_bootstrap5 %}

{% block content %}
{% if show_login %}
<h1 class="mb-4">Sign in</h1>
<a href="{% url 'login' %}">Sign in</a>
{% else %}
<h1 class="mb-4">Deactivate Volunteers</h1>


<form enctype="multipart/form-data" action="" method="post">
{% csrf_token %}
{% bootstrap_form form %}
<input type="submit" value="Deactivate">
</form>

{% endif %}
{% endblock %}
1 change: 1 addition & 0 deletions crowdsourcer/templates/crowdsourcer/volunteers/list.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ <h1 class="mb-4">Sign in</h1>
<div class="float-end">
<a href="{% session_url 'add_volunteer' %}">Add volunteer</a>
<a href="{% session_url 'bulk_assign_volunteer' %}">Bulk assignment</a>
<a href="{% session_url 'deactivate_volunteers' %}">Stage deactivate</a>
</div>
<h1 class="mb-4">Volunteers</h1>
<table class="table">
Expand Down
67 changes: 66 additions & 1 deletion crowdsourcer/tests/test_volunteer_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from django.test import TestCase
from django.urls import reverse

from crowdsourcer.models import Assigned, MarkingSession, ResponseType, Section
from crowdsourcer.models import Assigned, Marker, MarkingSession, ResponseType, Section


class BaseTestCase(TestCase):
Expand Down Expand Up @@ -386,3 +386,68 @@ def test_assignments_already_made_error(self):
)

self.assertEqual(Assigned.objects.count(), 6)


class TestDeactivateVolunteers(BaseTestCase):
def test_deactivate(self):
url = reverse("deactivate_volunteers")
response = self.client.get(url)

self.assertEqual(User.objects.filter(is_active=False).count(), 0)
u = User.objects.get(email="marker@example.org")
self.assertTrue(u.is_active)
response = self.client.post(
url,
data={"stage": "First Mark"},
)

self.assertRedirects(response, f"/Default{reverse('list_volunteers')}")
self.assertEqual(User.objects.filter(is_active=False).count(), 1)

u = User.objects.get(email="marker@example.org")
self.assertFalse(u.is_active)

def test_ignores_staff(self):
url = reverse("deactivate_volunteers")
response = self.client.get(url)

rt = ResponseType.objects.get(type="First Mark")
session = MarkingSession.objects.get(label="Default")

self.assertEqual(User.objects.filter(is_active=False).count(), 0)
u = User.objects.get(email="admin@example.org")
self.assertTrue(u.is_active)
m = Marker.objects.create(user=u, response_type=rt)
m.marking_session.set([session])
response = self.client.post(
url,
data={"stage": "First Mark"},
)

self.assertRedirects(response, f"/Default{reverse('list_volunteers')}")
self.assertEqual(User.objects.filter(is_active=False).count(), 1)
u = User.objects.get(email="admin@example.org")
self.assertTrue(u.is_active)

def test_respects_session(self):
url = reverse("deactivate_volunteers")
url = "/Second%20Session" + url
response = self.client.get(url)

self.assertEqual(User.objects.filter(is_active=False).count(), 0)
u = User.objects.get(email="marker@example.org")
self.assertTrue(u.is_active)
u2 = User.objects.get(email="other_marker@example.org")
self.assertTrue(u2.is_active)
response = self.client.post(
url,
data={"stage": "First Mark"},
)

self.assertRedirects(response, f"/Second%20Session{reverse('list_volunteers')}")
self.assertEqual(User.objects.filter(is_active=False).count(), 1)

u = User.objects.get(email="marker@example.org")
self.assertTrue(u.is_active)
u2 = User.objects.get(email="other_marker@example.org")
self.assertFalse(u2.is_active)
30 changes: 29 additions & 1 deletion crowdsourcer/views/volunteers.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
UserForm,
VolunteerAssignmentFormset,
VolunteerBulkAssignForm,
VolunteerDeactivateForm,
)
from crowdsourcer.models import (
Assigned,
Expand All @@ -24,7 +25,7 @@
ResponseType,
Section,
)
from crowdsourcer.volunteers import send_registration_email
from crowdsourcer.volunteers import deactivate_stage_volunteers, send_registration_email

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -259,6 +260,33 @@ def render_to_response(self, context, **response_kwargs):
return JsonResponse({"results": data})


class DeactivateVolunteers(VolunteerAccessMixin, FormView):
template_name = "crowdsourcer/volunteers/deactivate.html"
form_class = VolunteerDeactivateForm

def get_form(self, form_class=None):
if form_class is None:
form_class = self.form_class

return form_class(
[(rt.type, rt.type) for rt in ResponseType.objects.all()],
**self.get_form_kwargs()
)

def get_success_url(self):
return reverse(
"session_urls:list_volunteers",
kwargs={"marking_session": self.request.current_session.label},
)

def form_valid(self, form):
ms = self.request.current_session
rt = ResponseType.objects.get(type=form.cleaned_data.get("stage"))

deactivate_stage_volunteers(rt, ms)
return super().form_valid(form)


class BulkAssignVolunteer(VolunteerAccessMixin, FormView):
template_name = "crowdsourcer/volunteers/bulk_assign.html"
form_class = VolunteerBulkAssignForm
Expand Down
16 changes: 15 additions & 1 deletion crowdsourcer/volunteers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@

from django.conf import settings
from django.contrib.auth.forms import PasswordResetForm
from django.contrib.auth.models import User
from django.db.models import Q
from django.http import HttpRequest

import pandas as pd

from crowdsourcer.models import Assigned, PublicAuthority, Section
from crowdsourcer.models import Assigned, Marker, PublicAuthority, Section


def check_bulk_assignments(df, rt, ms, num_assignments, always_assign=False):
Expand Down Expand Up @@ -99,3 +101,15 @@ def send_registration_email(user, server_name):
subject_template_name=subject_template,
email_template_name=email_template,
)


def deactivate_stage_volunteers(stage, session):
users = User.objects.filter(
id__in=Marker.objects.filter(
marking_session=session, response_type=stage
).values_list("user_id"),
).exclude(Q(is_staff=True) | Q(is_superuser=True))

for user in users:
user.is_active = False
user.save()
Loading