From d414d3baa2a25f0ecbfc659232fe1c5165999816 Mon Sep 17 00:00:00 2001 From: Ross Date: Mon, 20 Nov 2023 11:55:49 +0000 Subject: [PATCH] improve group management --- generic/forms.py | 193 +++++++++++++++++- generic/templates/generic/cid_group_base.html | 30 +++ .../generic/cid_group_view_detail.html | 9 +- generic/templates/generic/ciduser_form.html | 2 +- .../templates/generic/cidusergroup_form.html | 2 +- generic/urls.py | 2 + generic/views.py | 30 +++ 7 files changed, 261 insertions(+), 7 deletions(-) create mode 100644 generic/templates/generic/cid_group_base.html diff --git a/generic/forms.py b/generic/forms.py index 006b93d8..2457c733 100755 --- a/generic/forms.py +++ b/generic/forms.py @@ -69,7 +69,6 @@ class ExamFormMixin: else: cid_user_group_queryset = CidUserGroup.objects.none() user_user_group_queryset = UserUserGroup.objects.none() - self.fields["cid_user_groups"] = ModelMultipleChoiceField( required=False, @@ -79,6 +78,7 @@ class ExamFormMixin: required=False, queryset=user_user_group_queryset, ) + class Meta: fields = [ "name", @@ -129,9 +129,11 @@ class ExaminationForm(ModelForm): model = Examination fields = ["examination", "modality"] + class ExaminationMergeForm(Form): examination_to_merge_into = ModelChoiceField(queryset=Examination.objects.all()) + class QuestionNoteForm(ModelForm): class Meta: model = QuestionNote @@ -172,7 +174,6 @@ class QuestionNoteForm(ModelForm): class CidUserForm(ModelForm): - class Meta: model = CidUser fields = [ @@ -187,6 +188,7 @@ class CidUserForm(ModelForm): "group", ] + class CidUserExamForm(ModelForm): def __init__(self, *args, **kwargs): if kwargs.get("instance"): @@ -289,17 +291,18 @@ class CidUserExamForm(ModelForm): self.save_m2m() return instance + class Meta: model = CidUser fields = [] + class CidUserGroupModelChoiceField(ModelMultipleChoiceField): def label_from_instance(self, obj): return f"{obj.cid} [{obj.email}]" class CidUserGroupForm(ModelForm): - class Meta: model = CidUserGroup fields = ["name", "archive"] @@ -322,6 +325,190 @@ class UserUserGroupForm(ModelForm): fields = ["name", "archive", "users"] +class UserGroupExamForm(ModelForm): + GROUP_TYPES = [ + "anatomy_user_user_groups", + "rapid_user_user_groups", + "longs_user_user_groups", + "physics_user_user_groups", + "sba_user_user_groups", + ] + # users = UserUserGroupModelChoiceField( + # required=False, + # queryset=User.objects.all(), + # widget=FilteredSelectMultiple(verbose_name="Users", is_stacked=False), + # ) + def __init__(self, *args, **kwargs): + if kwargs.get("instance"): + # We get the 'initial' keyword argument or initialize it + # as a dict if it didn't exist. + initial = kwargs.setdefault("initial", {}) + # The widget for a ModelMultipleChoiceField expects + # a list of primary key for the selected data. + for groups in self.GROUP_TYPES: + #instance.anatomy_cid_user_groups.clear() + #obj = getattr(instance,groups) + initial[groups] = [ + t.pk for t in getattr(kwargs["instance"],groups).all() + ] + + ModelForm.__init__(self, *args, **kwargs) + + super(UserGroupExamForm, self).__init__(*args, **kwargs) + + self.fields["anatomy_user_user_groups"] = ModelMultipleChoiceField( + required=False, + queryset=AnatomyExam.objects.filter(archive=False), + widget=FilteredSelectMultiple( + verbose_name="Anatomy Exams", is_stacked=False + ), + ) + self.fields["rapid_user_user_groups"] = ModelMultipleChoiceField( + required=False, + queryset=RapidsExam.objects.filter(archive=False), + widget=FilteredSelectMultiple(verbose_name="Rapid Exams", is_stacked=False), + ) + self.fields["longs_user_user_groups"] = ModelMultipleChoiceField( + required=False, + queryset=LongsExam.objects.filter(archive=False), + widget=FilteredSelectMultiple(verbose_name="Longs Exams", is_stacked=False), + ) + self.fields["physics_user_user_groups"] = ModelMultipleChoiceField( + required=False, + queryset=PhysicsExam.objects.filter(archive=False), + widget=FilteredSelectMultiple( + verbose_name="Physics Exams", is_stacked=False + ), + ) + self.fields["sba_user_user_groups"] = ModelMultipleChoiceField( + required=False, + queryset=SbasExam.objects.filter(archive=False), + widget=FilteredSelectMultiple(verbose_name="Sbas Exams", is_stacked=False), + ) + + class Meta: + model = UserUserGroup + fields = [] + + def save(self, commit=True): + # Get the unsaved Long instance + instance = ModelForm.save(self, False) + + # Prepare a 'save_m2m' method for the form, + old_save_m2m = self.save_m2m + + def save_m2m(): + old_save_m2m() + + for groups in self.GROUP_TYPES: + #instance.anatomy_cid_user_groups.clear() + obj = getattr(instance,groups) + obj.clear() + for exam in self.cleaned_data[groups]: + obj.add(exam.pk) + + self.save_m2m = save_m2m + + # Do we need to save all changes now? + # if commit: + instance.save() + self.save_m2m() + + return instance + + +class CidGroupExamForm(ModelForm): + GROUP_TYPES = [ + "anatomy_cid_user_groups", + "rapid_cid_user_groups", + "longs_cid_user_groups", + "physics_cid_user_groups", + "sba_cid_user_groups", + ] + + # users = CidUserGroupModelChoiceField( + # required=False, + # queryset=User.objects.all(), + # widget=FilteredSelectMultiple(verbose_name="Users", is_stacked=False), + def __init__(self, *args, **kwargs): + if kwargs.get("instance"): + # We get the 'initial' keyword argument or initialize it + # as a dict if it didn't exist. + initial = kwargs.setdefault("initial", {}) + # The widget for a ModelMultipleChoiceField expects + # a list of primary key for the selected data. + for groups in self.GROUP_TYPES: + #instance.anatomy_cid_user_groups.clear() + #obj = getattr(instance,groups) + initial[groups] = [ + t.pk for t in getattr(kwargs["instance"],groups).all() + ] + + ModelForm.__init__(self, *args, **kwargs) + + super(CidGroupExamForm, self).__init__(*args, **kwargs) + + self.fields["anatomy_cid_user_groups"] = ModelMultipleChoiceField( + required=False, + queryset=AnatomyExam.objects.filter(archive=False), + widget=FilteredSelectMultiple( + verbose_name="Anatomy Exams", is_stacked=False + ), + ) + self.fields["rapid_cid_user_groups"] = ModelMultipleChoiceField( + required=False, + queryset=RapidsExam.objects.filter(archive=False), + widget=FilteredSelectMultiple(verbose_name="Rapid Exams", is_stacked=False), + ) + self.fields["longs_cid_user_groups"] = ModelMultipleChoiceField( + required=False, + queryset=LongsExam.objects.filter(archive=False), + widget=FilteredSelectMultiple(verbose_name="Longs Exams", is_stacked=False), + ) + self.fields["physics_cid_user_groups"] = ModelMultipleChoiceField( + required=False, + queryset=PhysicsExam.objects.filter(archive=False), + widget=FilteredSelectMultiple( + verbose_name="Physics Exams", is_stacked=False + ), + ) + self.fields["sba_cid_user_groups"] = ModelMultipleChoiceField( + required=False, + queryset=SbasExam.objects.filter(archive=False), + widget=FilteredSelectMultiple(verbose_name="Sbas Exams", is_stacked=False), + ) + + class Meta: + model = CidUserGroup + fields = [] + + def save(self, commit=True): + # Get the unsaved Long instance + instance = ModelForm.save(self, False) + + # Prepare a 'save_m2m' method for the form, + old_save_m2m = self.save_m2m + + def save_m2m(): + old_save_m2m() + + for groups in self.GROUP_TYPES: + #instance.anatomy_cid_user_groups.clear() + obj = getattr(instance,groups) + obj.clear() + for exam in self.cleaned_data[groups]: + obj.add(exam.pk) + + self.save_m2m = save_m2m + + # Do we need to save all changes now? + # if commit: + instance.save() + self.save_m2m() + + return instance + + # class UserForm(ModelForm): # class Meta: # model = User diff --git a/generic/templates/generic/cid_group_base.html b/generic/templates/generic/cid_group_base.html new file mode 100644 index 00000000..bb1c837f --- /dev/null +++ b/generic/templates/generic/cid_group_base.html @@ -0,0 +1,30 @@ +{% extends 'generic/base.html' %} + + +{% block navigation %} + {{block.super}} +
+ Group: {{group.name}}-> + {% if group_type == "cid" %} + + {% if not group %} + Group / + Edit Users / + Edit Exams / + Delete + + {% else %} + Group / + Edit Users / + Edit Exams / + Delete + {% endif %} + + {% else %} + Group / + Edit Users / + Edit Exams / + Delete + {% endif %} + +{% endblock %} \ No newline at end of file diff --git a/generic/templates/generic/cid_group_view_detail.html b/generic/templates/generic/cid_group_view_detail.html index dce2aadb..727d27f8 100755 --- a/generic/templates/generic/cid_group_view_detail.html +++ b/generic/templates/generic/cid_group_view_detail.html @@ -1,4 +1,4 @@ -{% extends 'generic/base.html' %} +{% extends 'generic/cid_group_base.html' %} {% block content %}

Group: {{group.name}}

@@ -39,7 +39,12 @@ {% endif %} {% endif %}

Exams

- The group is currently associated with the following exams + The group is currently associated with the following exams. + {% if group_type == "cid" %} + Add more here. + {% else %} + Add more here. + {% endif %} {% with group.GetGroupExams as exam_map %} {% for key, value in exam_map.items %}

{{key}}

diff --git a/generic/templates/generic/ciduser_form.html b/generic/templates/generic/ciduser_form.html index d20a18f2..65ffa193 100755 --- a/generic/templates/generic/ciduser_form.html +++ b/generic/templates/generic/ciduser_form.html @@ -25,7 +25,7 @@

Exams

-

The user is currently part of the following exams

+ The group is currently associated with the following exams.

{% with object.get_cid_exams as exam_map %} diff --git a/generic/templates/generic/cidusergroup_form.html b/generic/templates/generic/cidusergroup_form.html index 6c534a23..87df0c35 100755 --- a/generic/templates/generic/cidusergroup_form.html +++ b/generic/templates/generic/cidusergroup_form.html @@ -1,4 +1,4 @@ -{% extends "generic/base.html" %} +{% extends 'generic/cid_group_base.html' %} {% block css %} diff --git a/generic/urls.py b/generic/urls.py index 5dad80f7..e83be7ee 100755 --- a/generic/urls.py +++ b/generic/urls.py @@ -60,6 +60,7 @@ urlpatterns = [ name="cid_group_detail", ), path("cids/group//email", views.group_email, name="group_email"), + path("cids/group//exams", views.CidGroupExamUpdate.as_view(), name="cid_group_exams"), path( "cids/group//email_results", views.group_email_results, @@ -105,6 +106,7 @@ urlpatterns = [ views.user_group_view_detail, name="user_group_detail", ), + path("user/group//exams", views.UserGroupExamUpdate.as_view(), name="user_group_exams"), path( "user/group//update", views.UserUserGroupUpdate.as_view(), diff --git a/generic/views.py b/generic/views.py index 0fda623e..9c1feb32 100644 --- a/generic/views.py +++ b/generic/views.py @@ -3,6 +3,7 @@ from pathlib import Path import secrets import statistics import threading +from typing import Any from dal import autocomplete from django.contrib.auth.models import User from django.contrib.contenttypes.models import ContentType @@ -51,12 +52,15 @@ from generic.tables import CidUserExamTable, CidUserTable, ExaminationTable from generic.mixins import SuperuserRequiredMixin from .forms import ( + CidGroupExamForm, CidUserForm, CidUserExamForm, ExaminationForm, CidUserGroupForm, ExaminationMergeForm, SupervisorForm, + UserGroupExamForm, + CidGroupExamForm, UserUserForm, UserUserGroupForm, ) @@ -2963,6 +2967,11 @@ class CidUserGroupUpdate(RevisionMixin, CidManagerRequiredMixin, UpdateView): model = CidUserGroup form_class = CidUserGroupForm + def get_context_data(self, **kwargs: Any) -> dict[str, Any]: + context = super().get_context_data(**kwargs) + context["group_type"] = "cid" + return context + class UserUserGroupCreate(RevisionMixin, CidManagerRequiredMixin, CreateView): model = UserUserGroup @@ -2973,12 +2982,33 @@ class UserUserGroupUpdate(RevisionMixin, CidManagerRequiredMixin, UpdateView): model = UserUserGroup form_class = UserUserGroupForm + def get_context_data(self, **kwargs: Any) -> dict[str, Any]: + context = super().get_context_data(**kwargs) + context["group_type"] = "user" + return context class UserUserGroupDelete(RevisionMixin, CidManagerRequiredMixin, DeleteView): model = UserUserGroup template_name = "confirm_delete.html" success_url = reverse_lazy("generic:user_group_view") +class UserGroupExamUpdate(CidManagerRequiredMixin, UpdateView): + model = UserUserGroup + form_class = UserGroupExamForm + + def get_context_data(self, **kwargs: Any) -> dict[str, Any]: + context = super().get_context_data(**kwargs) + context["group_type"] = "user" + return context + +class CidGroupExamUpdate(CidManagerRequiredMixin, UpdateView): + model = CidUserGroup + form_class = CidGroupExamForm + + def get_context_data(self, **kwargs: Any) -> dict[str, Any]: + context = super().get_context_data(**kwargs) + context["group_type"] = "cid" + return context class ExamCreateBase(RevisionMixin, LoginRequiredMixin, CreateView): template_name = "exam_create_form.html"