Further user management improvements
This commit is contained in:
@@ -6,7 +6,10 @@
|
||||
|
||||
- Improve documentation
|
||||
- Test coverage
|
||||
- Privacy policy
|
||||
- Cookie policy
|
||||
|
||||
|
||||
# Future
|
||||
- Clean up user results / score pages
|
||||
- Clean up user results / score pages
|
||||
- Remove external javascript dependencies
|
||||
@@ -902,4 +902,9 @@ tr:has(.errorlist){
|
||||
|
||||
.inline-form {
|
||||
display: inline-grid;
|
||||
}
|
||||
|
||||
form .submit-button {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
+18
-14
@@ -143,6 +143,22 @@ class QuestionNoteForm(ModelForm):
|
||||
|
||||
|
||||
class CidUserForm(ModelForm):
|
||||
|
||||
class Meta:
|
||||
model = CidUser
|
||||
fields = [
|
||||
"passcode",
|
||||
"active",
|
||||
"internal_candidate",
|
||||
"name",
|
||||
"email",
|
||||
"supervisor",
|
||||
"login_email_sent",
|
||||
"results_email_sent",
|
||||
"group",
|
||||
]
|
||||
|
||||
class CidUserExamForm(ModelForm):
|
||||
def __init__(self, *args, **kwargs):
|
||||
if kwargs.get("instance"):
|
||||
# We get the 'initial' keyword argument or initialize it
|
||||
@@ -169,7 +185,7 @@ class CidUserForm(ModelForm):
|
||||
|
||||
ModelForm.__init__(self, *args, **kwargs)
|
||||
|
||||
super(CidUserForm, self).__init__(*args, **kwargs)
|
||||
super(CidUserExamForm, self).__init__(*args, **kwargs)
|
||||
|
||||
self.fields["physics_exams"] = ModelMultipleChoiceField(
|
||||
required=False,
|
||||
@@ -244,21 +260,9 @@ class CidUserForm(ModelForm):
|
||||
self.save_m2m()
|
||||
|
||||
return instance
|
||||
|
||||
class Meta:
|
||||
model = CidUser
|
||||
fields = [
|
||||
"passcode",
|
||||
"active",
|
||||
"internal_candidate",
|
||||
"name",
|
||||
"email",
|
||||
"supervisor",
|
||||
"login_email_sent",
|
||||
"results_email_sent",
|
||||
"group",
|
||||
]
|
||||
|
||||
fields = []
|
||||
|
||||
class CidUserGroupModelChoiceField(ModelMultipleChoiceField):
|
||||
def label_from_instance(self, obj):
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
from collections import defaultdict
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.db import models
|
||||
from django.http import HttpRequest
|
||||
@@ -619,6 +620,13 @@ class CidUserExam(models.Model):
|
||||
# TODO switch to json field?
|
||||
results_emailed_status = models.CharField(max_length=255, blank=True)
|
||||
|
||||
CID_GROUP_EXAMS = (
|
||||
("SBAs", "sba_cid_user_groups"),
|
||||
("Physics", "physics_cid_user_groups"),
|
||||
("Anatomy", "anatomy_cid_user_groups"),
|
||||
("Rapids", "rapid_cid_user_groups"),
|
||||
("Longs", "longs_cid_user_groups"),
|
||||
)
|
||||
|
||||
class CidUserGroup(models.Model):
|
||||
name = models.CharField(blank=True, max_length=50)
|
||||
@@ -633,8 +641,19 @@ class CidUserGroup(models.Model):
|
||||
s = ", ".join([f"{user.id} - {user.name}" for user in cid_users])
|
||||
return s
|
||||
|
||||
def GetGroupExams(self):
|
||||
exams = defaultdict(list)
|
||||
for t, rel in CID_GROUP_EXAMS:
|
||||
exam_rel = getattr(self, rel)
|
||||
if exam_rel.exists():
|
||||
exams[t].extend(exam_rel.all())
|
||||
|
||||
return dict(exams)
|
||||
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse("generic:cid_group_update", kwargs={"pk": self.pk})
|
||||
|
||||
|
||||
|
||||
class UserUserGroup(models.Model):
|
||||
|
||||
@@ -2,22 +2,36 @@
|
||||
|
||||
{% block content %}
|
||||
<h2>Group: {{group.name}}</h2>
|
||||
Count: {{users|length}}
|
||||
<ul>
|
||||
{% for user in users %}
|
||||
<li>{{user.email}} / CID: {{user.cid}} / Passcode: {{user.passcode}}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr><th>Email</th><th>CID</th><th>Passcode</th></tr>
|
||||
</thead>
|
||||
{% for user in users %}
|
||||
<tr><td>{{user.email}}</td><td>{{user.cid}}</td><td>{{user.passcode}}</td></tr>
|
||||
<h3>Users</h3>
|
||||
<p>Count: {{users|length}}</p>
|
||||
|
||||
{% if users %}
|
||||
<table>
|
||||
<thead>
|
||||
<tr><th>Email</th><th>CID</th><th>Passcode</th></tr>
|
||||
</thead>
|
||||
{% for user in users %}
|
||||
<tr><td>{{user.email}}</td><td>{{user.cid}}</td><td>{{user.passcode}}</td></tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% else %}
|
||||
This group has no users. They can be created (or added) <a href="{% url 'generic:manage_cids' %}">here</a>
|
||||
{% 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 %}
|
||||
</table>
|
||||
{% endwith %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
|
||||
@@ -29,14 +29,34 @@
|
||||
<summary>
|
||||
<h3>Add/Edit CID users</h3>
|
||||
</summary>
|
||||
<button id="add-exams-selected-cids">Add selected exams</button>
|
||||
<button id="change-exams-selected-cids">Change selected exams</button>
|
||||
<button id="clear-exams-selected-cids">Clear selected exams</button>
|
||||
<div>
|
||||
Groups<br />
|
||||
<select id="cid-groups">
|
||||
<option value="">----</option>
|
||||
{% for name, id in cid_user_groups %}
|
||||
<option value="{{id}}">{{name}}</option>
|
||||
{% endfor %}
|
||||
|
||||
</select>
|
||||
</div>
|
||||
<h4>Edit existing users</h4>
|
||||
<p>Users can be edited using the below buttons once they have been selected in the table. If you need to add a group to a user(s) select it above. Once a CID user is part of a group they can be added to exams via the exam candidate page.</p>
|
||||
<button id="activate-selected-cids">Activate selected</button>
|
||||
<button id="deactivate-selected-cids">Deactivate selected</button>
|
||||
<button id="delete-selected-cids">Delete selected</button>
|
||||
<button id="toggle-internal">Toggle internal</button>
|
||||
<button id="add-group">Add Group to users</button>
|
||||
<h4>Create New Users</h4>
|
||||
<p>New CID users can be created by the two below buttons. If you want to create blank users you can specify the number in the associated box and click the relevant button. If you have a list of email addresses you can enter them in the relevant box and click "Add New Users From Email" and a new user will be created for each user (you do not need to specify the number of users). Ideally you will have already created a <a href="{% url 'generic:cid_group_view' %}">CID user group</a> that you can add to the newly generated users using the above select box.</p>
|
||||
<button id="add-new-cids" title="This will create N new users">Add New (Blank) Users</button>
|
||||
<input type="number" id="add-number" value="number to add" placeholder="Number of new users"><br />
|
||||
<p>or</p>
|
||||
<button id="add-new-emails" title="This will create users from a list of email addresses">Add New Users From Email</button>
|
||||
<textarea id="emails-input" name="emails" rows="4" cols="50" placeholder="Enter emails here (single email per line)"></textarea>
|
||||
|
||||
<details>
|
||||
<summary>Edit CID exams</summary>
|
||||
<p>This should be done via the exams pages one via group management.</p>
|
||||
<p>Select exams below to add user(s) to (or edit existing user(s)).</p>
|
||||
<div class="exam-selectors">
|
||||
<span>
|
||||
@@ -96,21 +116,11 @@
|
||||
|
||||
|
||||
</div>
|
||||
<div>
|
||||
Groups<br />
|
||||
<select id="cid-groups">
|
||||
<option value="">----</option>
|
||||
{% for name, id in cid_user_groups %}
|
||||
<option value="{{id}}">{{name}}</option>
|
||||
{% endfor %}
|
||||
|
||||
</select>
|
||||
</div>
|
||||
<h3>Create New Users</h3>
|
||||
<button id="add-new-cids" title="This will create N new users">Add New (Blank) Users</button>
|
||||
<input type="number" id="add-number" value="number to add"><br />
|
||||
<button id="add-new-emails" title="This will create users from a list of email addresses">Add New Users From Email</button>
|
||||
<textarea id="emails-input" name="emails" rows="4" cols="50" placeholder="Enter emails here (single email per line)"></textarea>
|
||||
<button id="add-exams-selected-cids">Add selected exams</button>
|
||||
<button id="change-exams-selected-cids">Change selected exams</button>
|
||||
<button id="clear-exams-selected-cids">Clear selected exams</button>
|
||||
|
||||
</details>
|
||||
</details>
|
||||
|
||||
{% endblock %}
|
||||
@@ -299,6 +309,9 @@
|
||||
});
|
||||
</script>
|
||||
<style>
|
||||
#cid-groups {
|
||||
margin: 20px;
|
||||
}
|
||||
.exam-selectors {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
{% extends "generic/base.html" %}
|
||||
<!-- {% load static from static %} -->
|
||||
|
||||
{% load crispy_forms_tags %}
|
||||
|
||||
{% block css %}
|
||||
{% endblock %}
|
||||
{% block js %}
|
||||
@@ -18,9 +20,19 @@ Use this form to edit a CID user.
|
||||
<form action="" method="post" enctype="multipart/form-data" id="condition-form">
|
||||
{% csrf_token %}
|
||||
|
||||
<table>
|
||||
{{ form.as_table }}
|
||||
</table>
|
||||
{{ form|crispy }}
|
||||
<input type="submit" class="submit-button" value="Submit" name="submit">
|
||||
</form>
|
||||
|
||||
<h2>Exams</h2>
|
||||
<p>The user is currently part of the following exams</p>
|
||||
|
||||
<p>
|
||||
{{ object.get_cid_exams }}
|
||||
</p>
|
||||
|
||||
<p>
|
||||
These should be edited via the exam candidate page. If you need to manually toggle you can do so <a href="{% url 'generic:update_cid_exams' object.pk %}">here</a> (you shouldn't)
|
||||
</p>
|
||||
|
||||
{% endblock %}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
{% extends "generic/base.html" %}
|
||||
<!-- {% load static from static %} -->
|
||||
|
||||
{% load crispy_forms_tags %}
|
||||
|
||||
{% block css %}
|
||||
{% endblock %}
|
||||
{% block js %}
|
||||
<!--<script type="text/javascript" src="/admin/jsi18n/"></script>-->
|
||||
{{form.media}}
|
||||
|
||||
<script type="text/javascript">
|
||||
</script>
|
||||
|
||||
<!-- {{ form.media }} -->
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<h2>Edit CID User {{ciduser.cid}} Exams</h2>
|
||||
Use this form to edit a CID user exams (only do so if required - it shouldn't be).
|
||||
<form action="" method="post" enctype="multipart/form-data" id="condition-form">
|
||||
{% csrf_token %}
|
||||
{{ form|crispy }}
|
||||
<input type="submit" class="submit-button" value="Submit" name="submit">
|
||||
</form>
|
||||
{% endblock %}
|
||||
@@ -3,6 +3,9 @@
|
||||
<h3>CID Users</h3>
|
||||
{% if groups %}
|
||||
Users from the following groups are available: {% for group in groups %}{{group}}, {% endfor %} .
|
||||
{% else %}
|
||||
This exam is not associated with any user groups. <a href="{% url exam.app_name|add:':exam_update' exam.pk %}">Edit and add a group</a> to enable user management.
|
||||
{% endif %}
|
||||
<ol>
|
||||
{% for cid in current_cid_users %}
|
||||
|
||||
@@ -19,14 +22,16 @@
|
||||
|
||||
{% endfor %}
|
||||
</ol>
|
||||
{% else %}
|
||||
This exam is not associated with any user groups. <a href="{% url exam.app_name|add:':exam_update' exam.pk %}">Edit and add a group</a> to enable user management.
|
||||
{% endif %}
|
||||
|
||||
<p><button class="toggle-all-btn">Toggle all</button></p>
|
||||
|
||||
<script>
|
||||
$(document).ready(() => {
|
||||
$(".toggle-all-btn").click((el) => {
|
||||
$(".toggle-btn").click();
|
||||
});
|
||||
$(".toggle-btn").click((el) => {
|
||||
parent = $(el.target).parent()
|
||||
let parent = $(el.target).parent()
|
||||
$.ajax({
|
||||
url: "{% url exam.app_name|add:':exam_json_edit' exam.pk %}",
|
||||
data: {
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
<h3>Users</h3>
|
||||
{% if groups %}
|
||||
Users from the following groups are available: {% for group in groups %}<a href='{{group.get_absolute_url}}'>{{group}}</a>, {% endfor %} .
|
||||
{% else %}
|
||||
This exam is not associated with any user groups. <a href="{% url exam.app_name|add:':exam_update' exam.pk %}">Edit and add a group</a> to enable user management.
|
||||
{% endif %}
|
||||
<ol>
|
||||
{% for user in current_user_users %}
|
||||
|
||||
@@ -18,12 +21,14 @@
|
||||
|
||||
{% endfor %}
|
||||
</ol>
|
||||
{% else %}
|
||||
This exam is not associated with any user groups. <a href="{% url exam.app_name|add:':exam_update' exam.pk %}">Edit and add a group</a> to enable user management.
|
||||
{% endif %}
|
||||
|
||||
<p><button class="toggle-all-btn">Toggle all</button></p>
|
||||
|
||||
<script>
|
||||
$(document).ready(() => {
|
||||
$(".toggle-all-btn").click((el) => {
|
||||
$(".toggle-btn").click();
|
||||
});
|
||||
$(".toggle-btn").click((el) => {
|
||||
parent = $(el.target).parent()
|
||||
$.ajax({
|
||||
|
||||
@@ -29,6 +29,9 @@ urlpatterns = [
|
||||
path(
|
||||
"cids/manage/<int:pk>/update", views.CidUserUpdate.as_view(), name="update_cid"
|
||||
),
|
||||
path(
|
||||
"cids/manage/<int:pk>/update/exams", views.CidUserExamUpdate.as_view(), name="update_cid_exams"
|
||||
),
|
||||
path(
|
||||
"cids/manage/<int:cid>/email_results",
|
||||
views.candidate_email_results,
|
||||
|
||||
@@ -50,6 +50,7 @@ from generic.tables import CidUserExamTable, CidUserTable
|
||||
|
||||
from .forms import (
|
||||
CidUserForm,
|
||||
CidUserExamForm,
|
||||
ExaminationForm,
|
||||
CidUserGroupForm,
|
||||
SupervisorForm,
|
||||
@@ -2432,6 +2433,15 @@ class CidUserUpdate(CidManagerRequiredMixin, UpdateView):
|
||||
model = CidUser
|
||||
form_class = CidUserForm
|
||||
|
||||
class CidUserExamUpdate(CidManagerRequiredMixin, UpdateView):
|
||||
model = CidUser
|
||||
form_class = CidUserExamForm
|
||||
template_name = "generic/ciduserexam_form.html"
|
||||
|
||||
#def get_context_data(self, *args, **kwargs):
|
||||
# context = super().get_context_data(**kwargs)
|
||||
# context["test"] = "HELLO"
|
||||
# return context
|
||||
|
||||
class CidUserGroupDelete(RevisionMixin, CidManagerRequiredMixin, DeleteView):
|
||||
model = CidUserGroup
|
||||
|
||||
+32
-1
@@ -3,6 +3,37 @@
|
||||
{% block content %}
|
||||
<div class="anatomy">
|
||||
<h1>Privacy Policy</h1>
|
||||
Under construction
|
||||
<p>We aim to store the minimum information required to enable delivery of the required service on the platform. What is stored depends on the service being provided.</p>
|
||||
|
||||
<h3>CID candidates</h3>
|
||||
<p>Candidates who receive a CID number may have the following information stored on the server.</p>
|
||||
<ul>
|
||||
<li>Name</li>
|
||||
<li>Email address</li>
|
||||
</ul>
|
||||
<p>These details will be linked (via a CID) with any answers given in the course of using the platform.
|
||||
|
||||
<h3>User accounts</h3>
|
||||
<p>User accounts may have the following information stored on the server.</p>
|
||||
<ul>
|
||||
<li>Name</li>
|
||||
<li>Email address</li>
|
||||
<li>Supervisor</li>
|
||||
<li>Professional registration number</li>
|
||||
<li>Grade</li>
|
||||
</ul>
|
||||
<p>These details will be linked (via a the user account) with any answers given in the course of using the platform.
|
||||
|
||||
<h3>Supervisors</h3>
|
||||
<p>A supervisor may have a user account in which case all of the above (under the "User accounts" section) may apply</p>
|
||||
|
||||
<p>In addition the following information may be stored</p>
|
||||
<ul>
|
||||
<li>Name</li>
|
||||
<li>Email address</li>
|
||||
<li>Trainee(s)</li>
|
||||
<li>Site</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user