Improve group management

This commit is contained in:
Ross
2023-01-09 11:31:48 +00:00
parent af52658e44
commit a8f710f4aa
8 changed files with 134 additions and 89 deletions
-1
View File
@@ -8,7 +8,6 @@
- Test coverage
- Privacy policy
- Cookie policy
- Cloning exams should include authors
# Future
+6
View File
@@ -178,6 +178,12 @@ class ExamBase(models.Model):
def get_absolute_url(self):
return reverse("{}:exam_overview".format(self.app_name), kwargs={"pk": self.pk})
def get_cid_edit_url(self):
return reverse("{}:exam_cids_edit".format(self.app_name), kwargs={"exam_id": self.pk})
def get_user_edit_url(self):
return reverse("{}:exam_users_edit".format(self.app_name), kwargs={"exam_id": self.pk})
def get_take_url(self):
return f"{settings.REMOTE_URL}/rts"
@@ -3,20 +3,40 @@
{% block content %}
<h2>Group: {{group.name}}</h2>
<details>
<summary>Help</summary>
<p>This page shows an overview of the candidates and exams that are associated with the group.</p>
<p>Once a candidate has been added to a group and the group has been added to an exam individual candidates can be allocated to the exam. Please note: simply adding the group to the exam will not automatically give the group candidates access to that exam, they will have to be added individually/as a group.</p>
</details>
<h3>Users</h3>
<p>Count: {{users|length}}</p>
<p title="The number of users that have been added to this group">Count: {{users|length}}</p>
{% if users %}
<table>
<thead>
<tr><th>Email</th><th>CID</th><th>Passcode</th></tr>
{% if group_type == "cid" %}
<tr><th>Email</th><th>CID</th><th>Passcode</th></tr>
{% else %}
<tr><th>User</th></tr>
{% endif %}
</thead>
{% for user in users %}
<tr><td>{{user.email}}</td><td>{{user.cid}}</td><td>{{user.passcode}}</td></tr>
{% if group_type == "cid" %}
<tr><td>{{user.email}}</td><td>{{user.cid}}</td><td>{{user.passcode}}</td></tr>
{% else %}
<tr><td>{{user.username}}</td></tr>
{% endif %}
{% endfor %}
</table>
{% else %}
This group has no users. They can be created (or added) <a href="{% url 'generic:manage_cids' %}">here</a>
This group has no users.
{% if group_type == "cid" %}
They can be created (or added) <a href="{% url 'generic:manage_cids' %}">here</a>
{% endif %}
{% endif %}
<h3>Exams</h3>
The group is currently associated with the following exams
@@ -27,17 +47,34 @@
{% for exam in value %}
<li>
<a href="{{exam.get_absolute_url}}">{{exam}}</a>
{% if group_type == "cid" %}
<a href="{{exam.get_cid_edit_url}}" class="edit-link">Edit candidates</a>
{% else %}
<a href="{{exam.get_user_edit_url}}" class="edit-link">Edit candidates</a>
{% endif %}
<span class="cid-number">
{% if group_type == "cid" %}
(Cid candidate count: {{exam.valid_cid_users.count}})
{% else %}
(User candidate count: {{exam.valid_user_users.count}})
{% endif %}
</span>
</li>
{% endfor %}
</ul>
{% endfor %}
{% endwith %}
{% endblock %}
{% block js %}
<style>
td, th { padding-left: 10px }
.cid-number {float: right}
.edit-link {
font-size: smaller;
opacity: 60%;
}
</style>
{% endblock %}
@@ -23,7 +23,10 @@
{% endfor %}
</ol>
<p><button class="toggle-all-btn">Toggle all</button></p>
{% comment %} Hide the toggle button if there are no users (to add or remove) {% endcomment %}
{% if current_cid_users or available_cid_users %}
<p><button class="toggle-all-btn">Toggle all</button></p>
{% endif %}
<script>
$(document).ready(() => {
@@ -13,15 +13,25 @@
{% if exam.recreate_json %}
<div class="alert alert-warning" role="alert">
Exam JSON is out of date.
Exam JSON may be out of date.
<a href="{% url app_name|add:':exam_json_recreate' pk=exam.pk %}">Click here to force refresh</a>
</div>
{% endif %}
This exam has {{question_number}} questions. Time limit: {{exam.time_limit}} seconds.
{% if exam.exam_mode %}
{% if not candidate_count.0 and not candidate_count.1 %}
<div class="alert alert-danger" role="alert">
This exam does not have any candidates.
</div>
{% endif %}
{% endif %}
This exam has {{question_number}} questions. Time limit: {{exam.time_limit}} seconds.
Exam mode: {{ exam.exam_mode }}<br />
Candidates - cid: {{candidate_count.0}}, users: {{candidate_count.1}}<br />
Open access: {{ exam.open_access }}<br />
<div class="parent-help" title="Click to enable / disable the exam">
@@ -1,43 +0,0 @@
{% extends 'generic/base.html' %}
{% block content %}
<h2>Group: {{group.name}}</h2>
<h3>Users</h3>
<p>Count: {{users|length}}</p>
{% if users %}
<table>
<thead>
<tr><th>User</th></tr>
</thead>
{% for user in users %}
<tr><td>{{user.username}}</td></tr>
{% endfor %}
</table>
{% else %}
This group has no users.
{% endif %}
<h3>Exams</h3>
The group is currently associated with the following exams
{% with group.GetGroupExams as exam_map %}
{% for key, value in exam_map.items %}
<h4>{{key}}</h4>
<ul>
{% for exam in value %}
<li>
<a href="{{exam.get_absolute_url}}">{{exam}}</a>
</li>
{% endfor %}
</ul>
{% endfor %}
{% endwith %}
{% endblock %}
{% block js %}
<style>
td, th { padding-left: 10px }
</style>
{% endblock %}
+7 -3
View File
@@ -829,6 +829,9 @@ class ExamViews(View, LoginRequiredMixin):
question_number = len(questions)
cid_candidates = exam.valid_cid_users.count()
users_candidates = exam.valid_user_users.count()
return render(
request,
"{}/exam_overview.html".format(self.app_name),
@@ -839,6 +842,7 @@ class ExamViews(View, LoginRequiredMixin):
"can_edit": can_edit,
"notes": notes,
"app_name": self.app_name,
"candidate_count": (cid_candidates, users_candidates)
},
)
@@ -2242,7 +2246,7 @@ def cid_group_view_detail(request, group_id):
return render(
request,
"generic/cid_group_view_detail.html",
{"group": group, "users": users},
{"group": group, "users": users, "group_type": "cid"},
)
@user_is_cid_user_manager
@@ -2263,8 +2267,8 @@ def user_group_view_detail(request, group_id):
return render(
request,
"generic/user_group_view_detail.html",
{"group": group, "users": users},
"generic/cid_group_view_detail.html",
{"group": group, "users": users, "group_type": "user"},
)
@user_is_cid_user_manager
+62 -33
View File
@@ -2,43 +2,72 @@
{% block content %}
{% load thumbnail %}
<div class="physics">
{% include 'generic/exam_overview_headers.html' %}
{% load thumbnail %}
<div class="physics">
{% include 'generic/exam_overview_headers.html' %}
This exam will be available to take <a href="{% url 'physics:exam_start' pk=exam.pk %}">here</a> (when active).
This exam will be available to take <a href="{% url 'physics:exam_start' pk=exam.pk %}">here</a> (when active).
{% autoescape off %}
<ol id="full-question-list-physics">
{% for question in questions.all %}
{% autoescape off %}
<ol id="full-question-list-physics">
{% for question in questions.all %}
<li>
{{ question.stem }}
<ol type="a" class="abcde">
<li>
{{ question.a }}: {{ question.a_answer }}
</li>
<li>
{{ question.b }}: {{ question.b_answer }}
</li>
<li>
{{ question.c }}: {{ question.c_answer }}
</li>
<li>
{{ question.d }}: {{ question.d_answer }}
</li>
<li>
{{ question.e }}: {{ question.e_answer }}
</li>
<li>
{{ question.stem }}
<ol type="a" class="abcde">
<li class="question-a">
<span class="question-text">{{ question.a }}</span>: <span class="question-answer">{{ question.a_answer }}</span>
{% if question.a_feedback %}
<span class="question-feedback">{{question.a_feedback}}</span>
{% endif %}
</li>
<li class="question-b">
<span class="question-text">{{ question.b }}</span>: <span class="question-answer">{{ question.b_answer }}</span>
{% if question.b_feedback %}
<span class="question-feedback">{{question.b_feedback}}</span>
{% endif %}
</li>
<li class="question-c">
<span class="question-text">{{ question.c }}</span>: <span class="question-answer">{{ question.c_answer }}</span>
{% if question.c_feedback %}
<span class="question-feedback">{{question.c_feedback}}</span>
{% endif %}
</li>
<li class="question-d">
<span class="question-text">{{ question.d }}</span>: <span class="question-answer">{{ question.d_answer }}</span>
{% if question.d_feedback %}
<span class="question-feedback">{{question.d_feedback}}</span>
{% endif %}
</li>
<li class="question-e">
<span class="question-text">{{ question.e }}</span>: <span class="question-answer">{{ question.e_answer }}</span>
{% if question.e_feedback %}
<span class="question-feedback">{{question.e_feedback}}</span>
{% endif %}
</li>
</ol>
Category: {{ question.category }}, <a href="{% url 'physics:question_detail' pk=question.pk %}">View [id: {{question.pk}}]</a> <a
href="{% url 'admin:physics_question_change' question.id %}">Edit</a>
</li>
{% endfor %}
</ol>
Category: {{ question.category }}, <a href="{% url 'physics:question_detail' pk=question.pk %}">View [id: {{question.pk}}]</a> <a
href="{% url 'admin:physics_question_change' question.id %}">Edit</a>
{% endautoescape %}
</li>
{% endfor %}
</ol>
{% endautoescape %}
</div>
</div>
{% include 'exam_overview_js.html' %}
{% endblock %}
{% block css %}
<style>
.question-answer {
font-weight: bolder;
}
.question-feedback {
opacity: 50%;
float: right
}
.question-feedback::before {
content: "Feedback: ";
}
</style>
{% endblock %}