allow adding markers and authors to exams in collections

This commit is contained in:
Ross
2025-01-06 20:11:57 +00:00
parent 9bb4d8bc08
commit 9d4487b7f5
8 changed files with 162 additions and 4 deletions
+14
View File
@@ -807,3 +807,17 @@ class ExamCollectionCloneForm(ModelForm):
class Meta:
model = ExamCollection
fields = ("name", "date")
from autocomplete import widgets as htmx_widgets, Autocomplete, AutocompleteWidget, ModelAutocomplete, register as autocomplete_register
class UserAutocomplete(ModelAutocomplete):
model = User
search_attrs = ["first_name", "last_name", "username"]
class UsersAutocompleteForm(Form):
users = ModelChoiceField(queryset=User.objects.all(), widget=AutocompleteWidget(
ac_class=UserAutocomplete, options={"multiselect": True}
))
autocomplete_register(UserAutocomplete)
+4
View File
@@ -51,6 +51,10 @@ class AuthorMixin():
return "None"
return authors
def add_authors(self, users : List[User]):
"""Add an author to the object"""
self.author.add(*users)
def add_author(self, user: User):
"""Add an author to the object"""
self.author.add(user)
+43
View File
@@ -882,6 +882,12 @@ class ExamOrCollectionGenericBase(models.Model, AuthorMixin):
return cloned_model
def add_markers(self, users):
self.markers.add(*users)
def add_marker(self, user):
self.markers.add(user)
class ExamBase(ExamOrCollectionGenericBase):
exam_mode = models.BooleanField(
@@ -1747,6 +1753,43 @@ class ExamCollection(models.Model, AuthorMixin):
def get_absolute_url(self):
return reverse("generic:examcollection_detail", kwargs={"pk": self.pk})
def get_exams(self):
return {
"anatomy": self.anatomy_exams.filter(archive=False),
"longs": self.longs_exams.filter(archive=False),
"physics": self.physics_exams.filter(archive=False),
"rapids": self.rapids_exams.filter(archive=False),
"sbas": self.sbas_exams.filter(archive=False),
}
def add_author_to_exams(self, users, exam_types: None | list[str] =None):
for exam_type, exams in self.get_exams().items():
if exam_types is None:
pass
elif exam_type not in exam_types:
continue
else:
raise ValueError(f"Invalid exam type {exam_type}")
for exam in exams:
exam.add_authors(users)
#return True
def add_marker_to_exams(self, users, exam_types: None | list[str] =None):
for exam_type, exams in self.get_exams().items():
if exam_types is None:
pass
elif exam_type not in exam_types:
continue
else:
pass
for exam in exams:
exam.add_markers(users)
#return True
#class Presentation(models.Model, AuthorMixin):
#
@@ -29,6 +29,11 @@
{% endwith %}
<a href="{% url 'anatomy:exam_list_collection' object.pk %}">View exam list</a>
<div class="add-marker">
<button class="btn-sm add-marker-button" hx-get="{% url 'generic:exam_collection_add_marker' object.pk 'anatomy' %}" hx-target=".add-marker" hx-swap="innerHTML">Add marker</button>
</div>
{% endif %}
{% if object.longs_exams.all %}
@@ -37,6 +42,9 @@
{% include "exam_list.html#exam-list" %}
{% endwith %}
<a href="{% url 'longs:exam_list_collection' object.pk %}">View exam list</a>
<div class="add-marker">
<button class="btn-sm add-marker-button" hx-get="{% url 'generic:exam_collection_add_marker' object.pk 'longs' %}" hx-target=".add-marker" hx-swap="innerHTML">Add marker</button>
</div>
{% endif %}
{% if object.rapids_exams.all %}
@@ -45,6 +53,9 @@
{% include "exam_list.html#exam-list" %}
{% endwith %}
<a href="{% url 'rapids:exam_list_collection' object.pk %}">View exam list</a>
<div class="add-marker">
<button class="btn-sm add-marker-button" hx-get="{% url 'generic:exam_collection_add_marker' object.pk 'rapids' %}" hx-target=".add-marker" hx-swap="innerHTML">Add marker</button>
</div>
{% endif %}
{% if object.physics_exams.all %}
@@ -63,11 +74,19 @@
<a href="{% url 'sbas:exam_list_collection' object.pk %}">View exam list</a>
{% endif %}
<br/>
<div id="add-user">
<button hx-get="{% url 'generic:exam_collection_add_author' object.pk %}" hx-target="#add-user" hx-swap="innerHTML">Add author</button>
</div>
{% include 'exam_overview_js.html' %}
{% endblock %}
{% block js %}
{% endblock %}
{% block css %}
<style>
.add-marker-button {
opacity: 0.5;
}
</style>
{% endblock %}
+12
View File
@@ -0,0 +1,12 @@
{% load crispy_forms_tags %}
{{form.media}}
<form action="" method="post" enctype="multipart/form-data" id="marker-form" class="inline-form">
{% csrf_token %}
{{ form|crispy }}
{% comment %} <input type="submit" class="submit-button" value="Submit" name="submit"> {% endcomment %}
<button hx-post="{% url 'generic:exam_collection_add_marker' collection_id exam_type %}" hx-target=".add-marker" hx-swap="innerHTML" class="btn btn-primary">Add marker to exams</button>
</form>
+12
View File
@@ -0,0 +1,12 @@
{% load crispy_forms_tags %}
{{form.media}}
<form action="" method="post" enctype="multipart/form-data" id="user-form" class="inline-form">
{% csrf_token %}
{{ form|crispy }}
{% comment %} <input type="submit" class="submit-button" value="Submit" name="submit"> {% endcomment %}
<button hx-post="{% url 'generic:exam_collection_add_author' collection_id %}" hx-target="#add-user" hx-swap="innerHTML" class="btn btn-primary">Submit</button>
</form>
+3 -1
View File
@@ -236,6 +236,8 @@ urlpatterns = [
views.ExamCollectionDelete.as_view(),
name="examcollection_delete",
),
path("collection/<int:collection_id>/add_author", views.exam_collection_add_author, name="exam_collection_add_author"),
path("collection/<int:collection_id>/add_marker/<str:exam_type>", views.exam_collection_add_marker, name="exam_collection_add_marker"),
path(
"share_with_supervisor_toggle/<int:pk>/",
views.toggle_share_with_supervisor,
@@ -395,7 +397,7 @@ def generic_exam_urls(generic_exam_view: GenericExamViews):
name="exam_answers_submit",
),
path("exam/", generic_exam_view.exam_list, name="exam_list"),
path("exam/<int:collection_id>/collection", generic_exam_view.exam_list_collection, name="exam_list_collection"),
path("collection/<int:collection_id>/", generic_exam_view.exam_list_collection, name="exam_list_collection"),
path("exam/all", generic_exam_view.exam_list_all, name="exam_list_all"),
path(
"exam/<int:exam_id>/order_questions",
+52
View File
@@ -77,6 +77,7 @@ from .forms import (
CidGroupExamForm,
UserUserForm,
UserUserGroupForm,
UsersAutocompleteForm, # Added import
)
from .models import (
@@ -769,6 +770,7 @@ class ExamViews(View, LoginRequiredMixin):
return self.exam_list(request, all=True, collection=collection)
@method_decorator(login_required)
def exam_list(self, request, all=False, collection=None):
if collection is None:
@@ -4032,3 +4034,53 @@ def toggle_share_with_supervisor(request, pk):
)
else:
raise PermissionDenied()
def exam_collection_add_author(request, collection_id):
if request.method != "POST":
form = UsersAutocompleteForm()
return render(
request,
"generic/user_form.html",
{"form": form, "collection_id": collection_id},
)
return
collection = get_object_or_404(ExamCollection, pk=collection_id)
if not request.user in collection.author.all():
raise PermissionDenied
#user = get_object_or_404(User, pk=request.POST.get("user"))
users = User.objects.filter(pk__in=request.POST.getlist("users"))
collection.add_author_to_exams(users)
return HttpResponse("Author added to all exams")
def exam_collection_add_marker(request, collection_id, exam_type):
if request.method != "POST":
form = UsersAutocompleteForm()
return render(
request,
"generic/marker_form.html",
{"form": form, "collection_id": collection_id, "exam_type": exam_type},
)
return
collection = get_object_or_404(ExamCollection, pk=collection_id)
if not request.user in collection.author.all():
raise PermissionDenied
#user = get_object_or_404(User, pk=request.POST.get("user"))
users = User.objects.filter(pk__in=request.POST.getlist("users"))
collection.add_marker_to_exams(users, exam_types=(exam_type,))
return HttpResponse("Marker added to exams")