allow adding markers and authors to exams in collections
This commit is contained in:
@@ -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)
|
||||
@@ -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)
|
||||
|
||||
@@ -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 %}
|
||||
Executable
+12
@@ -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>
|
||||
Executable
+12
@@ -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
@@ -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",
|
||||
|
||||
@@ -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")
|
||||
Reference in New Issue
Block a user