allow adding users to exams by group

This commit is contained in:
Ross
2024-09-02 12:16:37 +01:00
parent cf9b514597
commit 4f60440ea1
4 changed files with 129 additions and 57 deletions
+49 -45
View File
@@ -68,6 +68,7 @@ from django.forms.utils import from_current_timezone, to_current_timezone
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Submit
class SplitDateTimeFieldDefaultTime(SplitDateTimeField):
def compress(self, data_list):
if data_list:
@@ -79,9 +80,9 @@ class SplitDateTimeFieldDefaultTime(SplitDateTimeField):
)
if data_list[1] in self.empty_values:
data_list[1] = datetime.time(0, 1)
#raise ValidationError(
# raise ValidationError(
# self.error_messages["invalid_time"], code="invalid_time"
#)
# )
result = datetime.datetime.combine(*data_list)
return from_current_timezone(result)
return None
@@ -98,9 +99,9 @@ class SplitDateTimeFieldDefaultTimeEnd(SplitDateTimeField):
)
if data_list[1] in self.empty_values:
data_list[1] = datetime.time(23, 59)
#raise ValidationError(
# raise ValidationError(
# self.error_messages["invalid_time"], code="invalid_time"
#)
# )
result = datetime.datetime.combine(*data_list)
return from_current_timezone(result)
return None
@@ -111,29 +112,28 @@ class ExamFormMixin:
super(ModelForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_id = 'id-exam-form'
self.helper.form_class = 'exam-form'
self.helper.form_method = 'post'
self.helper.form_action = 'submit'
self.helper.form_id = "id-exam-form"
self.helper.form_class = "exam-form"
self.helper.form_method = "post"
self.helper.form_action = "submit"
self.helper.add_input(Submit("submit", "Submit"))
self.helper.add_input(Submit('submit', 'Submit'))
#if user.is_superuser or user.groups.filter(name="cid_user_manager").exists():
# if user.is_superuser or user.groups.filter(name="cid_user_manager").exists():
# cid_user_group_queryset = CidUserGroup.objects.filter(archive=False)
# user_user_group_queryset = UserUserGroup.objects.filter(archive=False)
#else:
# else:
# cid_user_group_queryset = CidUserGroup.objects.none()
# user_user_group_queryset = UserUserGroup.objects.none()
#self.fields["cid_user_groups"] = ModelMultipleChoiceField(
# self.fields["cid_user_groups"] = ModelMultipleChoiceField(
# required=False,
# queryset=cid_user_group_queryset,
#)
#self.fields["user_user_groups"] = ModelMultipleChoiceField(
# )
# self.fields["user_user_groups"] = ModelMultipleChoiceField(
# required=False,
# queryset=user_user_group_queryset,
#)
# )
self.fields["start_date"] = SplitDateTimeFieldDefaultTime(
widget=SplitDateTimeWidget(
date_attrs={"type": "date", "class": "datepicker"},
@@ -169,8 +169,8 @@ class ExamFormMixin:
"active",
"publish_results",
"archive",
#"cid_user_groups",
#"user_user_groups",
# "cid_user_groups",
# "user_user_groups",
# "author",
]
@@ -199,6 +199,7 @@ class ExamAuthorFormMixin(ModelForm):
widget=FilteredSelectMultiple(verbose_name="Authors", is_stacked=False),
)
class ExamMarkerFormMixin(ModelForm):
class Meta:
fields = ["markers"]
@@ -213,37 +214,41 @@ class ExamMarkerFormMixin(ModelForm):
class ExamGroupsFormMixin(ModelForm):
class Meta:
#model = ExamCollection
fields = ("cid_user_groups", "user_user_groups")
class Meta:
# model = ExamCollection
fields = ("cid_user_groups", "user_user_groups")
def __init__(self, *args, user, **kwargs) -> None:
super(ModelForm, self).__init__(*args, **kwargs)
def __init__(self, *args, user, **kwargs) -> None:
super(ModelForm, self).__init__(*args, **kwargs)
# TODO: decide how we should handle managing user groups
# i.e who should be able to access a list of all users?
# TODO: decide how we should handle managing user groups
# i.e who should be able to access a list of all users?
if user.is_superuser or user.groups.filter(name="cid_user_manager").exists():
cid_user_group_queryset = CidUserGroup.objects.filter(archive=False)
user_user_group_queryset = UserUserGroup.objects.filter(archive=False)
else:
cid_user_group_queryset = CidUserGroup.objects.filter(archive=False, open_access=True)
user_user_group_queryset = UserUserGroup.objects.none(archive=False, open_access=True)
#cid_user_group_queryset = CidUserGroup.objects.none()
#user_user_group_queryset = UserUserGroup.objects.none()
self.fields["cid_user_groups"] = ModelMultipleChoiceField(
required=False,
queryset=cid_user_group_queryset,
label="CID User Groups",
if user.is_superuser or user.groups.filter(name="cid_user_manager").exists():
cid_user_group_queryset = CidUserGroup.objects.filter(archive=False)
user_user_group_queryset = UserUserGroup.objects.filter(archive=False)
else:
cid_user_group_queryset = CidUserGroup.objects.filter(
archive=False, open_access=True
)
self.fields["user_user_groups"] = ModelMultipleChoiceField(
required=False,
queryset=user_user_group_queryset,
label="User Groups",
user_user_group_queryset = UserUserGroup.objects.none(
archive=False, open_access=True
)
self.fields["cid_user_groups"].widget.attrs["size"] = 8
self.fields["user_user_groups"].widget.attrs["size"] = 8
# cid_user_group_queryset = CidUserGroup.objects.none()
# user_user_group_queryset = UserUserGroup.objects.none()
self.fields["cid_user_groups"] = ModelMultipleChoiceField(
required=False,
queryset=cid_user_group_queryset,
label="CID User Groups",
)
self.fields["user_user_groups"] = ModelMultipleChoiceField(
required=False,
queryset=user_user_group_queryset,
label="User Groups",
)
self.fields["cid_user_groups"].widget.attrs["size"] = 8
self.fields["user_user_groups"].widget.attrs["size"] = 8
class ExaminationForm(ModelForm):
@@ -751,4 +756,3 @@ class ExamCollectionCloneForm(ModelForm):
class Meta:
model = ExamCollection
fields = ("name", "date")
@@ -39,44 +39,67 @@
{% endif %}
{% endif %}
<h3>Exams</h3>
The group is currently associated with the following exams.
The group is currently associated with the following exams. This allows the users within the group to be easily added to the exam. It will not automatically give members of the group access to the exam.
{% if group_type == "cid" %}
Add more <a href='{% url "generic:cid_group_exams" group.pk %}'>here</a>.
{% else %}
Add more <a href='{% url "generic:user_group_exams" group.pk %}'>here</a>.
{% endif %}
<p>It is possible to quickly add or remove all group candidates from an exam by clicking the buttons below. This will only affect the <b>{{users|length}}</b> candidates in this group. You will need to refresh the page to see updated candidate counts.</p>
{% with group.GetGroupExams as exam_map %}
{% for key, value in exam_map.items %}
<h4>{{key}}</h4>
<ul>
<div>
{% for exam in value %}
<li>
<a href="{{exam.get_absolute_url}}">{{exam}}</a>
<div class="d-flex">
<a href="{{exam.get_absolute_url}}" class="px-2">{{exam}}</a>
{% if group_type == "cid" %}
<a href="{{exam.get_cid_edit_url}}" class="edit-link">Edit candidates</a>
<a href="{{exam.get_cid_edit_url}}" class="edit-link" px-2>Edit candidates</a>
{% comment %} <button>Add group candidates</button>
<button>Remove group candidates</button> {% endcomment %}
{% else %}
<a href="{{exam.get_user_edit_url}}" class="edit-link">Edit candidates</a>
<a href="{{exam.get_user_edit_url}}" class="edit-link px-2">Edit candidates</a>
<form>
<input type="hidden" name="exam_id" value="{{exam.pk}}">
<input type="hidden" name="exam_type" value="{{exam.app_name}}">
<button
class="btn btn-sm px-2"
hx-post="{% url 'generic:user_group_add_candidates_to_exams' group.pk %}"
title="Add all group candidates to this exam"
name="action"
value="add"
>Add group candidates</button>
<button
hx-post="{% url 'generic:user_group_add_candidates_to_exams' group.pk %}"
title="Remove all group candidates to this exam"
class="btn btn-sm px-2"
name="action"
value="remove"
>Remove group candidates</button>
</form>
{% endif %}
<span class="cid-number">
<div class="px-2 ms-auto ">
{% if group_type == "cid" %}
(Cid candidate count: {{exam.valid_cid_users.count}})
{% else %}
(User candidate count: {{exam.valid_user_users.count}})
{% endif %}
</span>
</li>
</div>
</div>
{% endfor %}
</ul>
</div>
{% endfor %}
{% endwith %}
{% endblock %}
{% block js %}
<style>
td, th { padding-left: 10px }
.cid-number {float: right}
.edit-link {
font-size: smaller;
opacity: 60%;
+10
View File
@@ -120,6 +120,16 @@ urlpatterns = [
views.user_group_view_detail,
name="user_group_detail",
),
path(
"user/group/<int:group_id>/add",
views.user_group_add_candidates_to_exams,
name="user_group_add_candidates_to_exams",
),
path(
"user/group/<int:group_id>/",
views.user_group_view_detail,
name="user_group_detail",
),
path(
"user/group/<int:pk>/exams",
views.UserGroupExamUpdate.as_view(),
+35
View File
@@ -133,6 +133,17 @@ class CidManagerRequiredMixin(UserPassesTestMixin):
# return obj
# raise PermissionDenied() # or Http404
def get_exam_model_from_app_name(app_name: str) -> ExamBase:
EXAM_MAP = {
"physics": PhysicsExam,
"anatomy": AnatomyExam,
"rapids": RapidsExam,
"longs": LongsExam,
"sbas": SbasExam,
}
return EXAM_MAP[app_name]
def normaliseRapidsScore(score):
if score == 49:
@@ -2709,6 +2720,30 @@ def cid_group_view_all(request):
{"groups": groups, "view_all": True},
)
@user_is_cid_user_manager
def user_group_add_candidates_to_exams(request, group_id):
if request.htmx:
group = get_object_or_404(UserUserGroup, pk=group_id)
exam_id = request.POST.get("exam_id")
exam_type = request.POST.get("exam_type")
ExamModel = get_exam_model_from_app_name(exam_type)
exam = get_object_or_404(ExamModel, pk=exam_id)
if request.POST.get("action") == "remove":
exam.valid_user_users.remove(*group.users.all())
return HttpResponse(f"Candidates removed")
else:
exam.valid_user_users.add(*group.users.all())
return HttpResponse(f"Candidates added")
#exam.save()
raise PermissionDenied() # or Http404
pass
@user_is_cid_user_manager
def user_group_view_detail(request, group_id):