Add exam collection link to the navigation menu and clean up dropdown toggle
This commit is contained in:
@@ -4709,6 +4709,67 @@ class ExamCollectionClone(CreateView, AuthorRequiredMixin):
|
||||
|
||||
object.author.set(self.author)
|
||||
object.save()
|
||||
|
||||
# Clone exams linked to the original collection into the new one.
|
||||
# For each supported exam app, find exams related to the old collection
|
||||
# and create shallow copies (questions/authors re-applied, but
|
||||
# active/archive/publish flags cleared).
|
||||
if hasattr(self, "initial_object") and self.initial_object:
|
||||
for _label, rel_name, ExamModel in GROUP_TYPES:
|
||||
try:
|
||||
old_exams = list(getattr(self.initial_object, rel_name).all())
|
||||
except Exception:
|
||||
old_exams = []
|
||||
|
||||
for old_exam in old_exams:
|
||||
# Build a dict of field values excluding the PK
|
||||
data = model_to_dict(old_exam, exclude=["id"])
|
||||
|
||||
# Clear group membership and flags for cloned exams
|
||||
data["valid_user_users"] = [] if "valid_user_users" in data else []
|
||||
data["valid_cid_users"] = [] if "valid_cid_users" in data else []
|
||||
data["cid_user_groups"] = [] if "cid_user_groups" in data else []
|
||||
data["user_user_groups"] = [] if "user_user_groups" in data else []
|
||||
|
||||
data["active"] = False
|
||||
# some models use `archive` or `archived` - try both safely
|
||||
if "archive" in data:
|
||||
data["archive"] = False
|
||||
if "archived" in data:
|
||||
data["archived"] = False
|
||||
data["publish_results"] = False if "publish_results" in data else data.get("publish_results", False)
|
||||
|
||||
# Keep a copy of M2M fields to reapply after create
|
||||
m2m_backup = {}
|
||||
for m2m_field in ("exam_questions", "author", "markers", "valid_user_users", "valid_cid_users", "cid_user_groups", "user_user_groups"):
|
||||
if m2m_field in data:
|
||||
m2m_backup[m2m_field] = data.pop(m2m_field)
|
||||
|
||||
# Set the new examcollection foreign key to the newly created collection
|
||||
# model_to_dict returns the FK id; replace with instance for create()
|
||||
data["examcollection"] = object
|
||||
|
||||
try:
|
||||
new_exam = ExamModel.objects.create(**data)
|
||||
except Exception:
|
||||
# If creation failed for any model-specific field, skip cloning this exam
|
||||
continue
|
||||
|
||||
# Reapply M2M relationships where possible
|
||||
for field_name, ids in m2m_backup.items():
|
||||
try:
|
||||
getattr(new_exam, field_name).set(ids)
|
||||
except Exception:
|
||||
# If the field doesn't exist on this model, ignore
|
||||
pass
|
||||
|
||||
try:
|
||||
# Some exam models provide an ordering helper
|
||||
if hasattr(new_exam, "order_questions"):
|
||||
new_exam.order_questions()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return HttpResponseRedirect(object.get_absolute_url())
|
||||
|
||||
|
||||
|
||||
+5
-3
@@ -201,7 +201,7 @@
|
||||
<a class="nav-link active" href="{% url 'atlas:index' %}">Atlas</a>
|
||||
</li>
|
||||
<li class="nav-item dropdown pt-0">
|
||||
<a class="nav-link dropdown-toggle active" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
FRCR
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
@@ -223,6 +223,9 @@
|
||||
<li>
|
||||
<a class="dropdown-item" href="{% url 'sbas:index' %}">SBAs</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="dropdown-item" href="{% url 'generic:examcollection_list' %}">Exam Collection</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
{% if request.user|has_group:"cid_user_manager" %}
|
||||
@@ -334,7 +337,6 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
//}
|
||||
// fallback to any table on the page that looks like it has selection
|
||||
var any = document.querySelector('table.js-row-selectable') //|| Array.from(document.querySelectorAll('table')).find(function(t){ return t.querySelector && (t.querySelector('input[name="selection"]') || t.querySelector('input[type="checkbox"]')); });
|
||||
console.log('findTableForControl fallback', any);
|
||||
return any || null;
|
||||
}
|
||||
|
||||
@@ -375,7 +377,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
container.parentNode.insertBefore(wrapper, container);
|
||||
}
|
||||
|
||||
//// Create controls for any table that looks selectable but lacks a control block
|
||||
// Create controls for any table that looks selectable but lacks a control block
|
||||
Array.from(document.querySelectorAll('table')).forEach(function(t){
|
||||
if (t.querySelector && (t.querySelector('input[name="selection"]') || t.querySelector('input[type="checkbox"]'))) {
|
||||
ensureControlsForTable(t);
|
||||
|
||||
Reference in New Issue
Block a user