Complete supervisor model and start improving forms
This commit is contained in:
@@ -6,3 +6,7 @@
|
|||||||
|
|
||||||
- Improve documentation
|
- Improve documentation
|
||||||
- Test coverage
|
- Test coverage
|
||||||
|
|
||||||
|
|
||||||
|
# Future
|
||||||
|
- Clean up user results / score pages
|
||||||
@@ -453,6 +453,15 @@ td.user-answer-score-2.rapid-ans::after {
|
|||||||
padding-top: 10px;
|
padding-top: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.submitted-user-answer:hover::after {
|
||||||
|
content: " Submitted answer";
|
||||||
|
opacity: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.question-stem-text {
|
||||||
|
font-weight: bolder;
|
||||||
|
}
|
||||||
|
|
||||||
.parent-help:hover .help-text {
|
.parent-help:hover .help-text {
|
||||||
opacity: 50%;
|
opacity: 50%;
|
||||||
}
|
}
|
||||||
@@ -871,3 +880,26 @@ tr:has(.errorlist){
|
|||||||
background-color: red;
|
background-color: red;
|
||||||
color: darkblue;
|
color: darkblue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Form styling */
|
||||||
|
|
||||||
|
.control-group {
|
||||||
|
padding-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.help-block {
|
||||||
|
float: right;
|
||||||
|
opacity: 25%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-group:hover .help-block{
|
||||||
|
opacity: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-group {
|
||||||
|
padding-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inline-form {
|
||||||
|
display: inline-grid;
|
||||||
|
}
|
||||||
@@ -13,9 +13,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="anatomy">
|
<div class="anatomy">
|
||||||
<h2>Exam: {{ exam.name }}</h2>
|
{% include 'user_score_header.html' %}
|
||||||
<h3>Candidate: {{ cid|default_if_none:request.user.username }}</h3>
|
|
||||||
Answers:
|
|
||||||
<ul class="score-answer-list">{% for ans, score, correct_answer in answers_and_marks %}
|
<ul class="score-answer-list">{% for ans, score, correct_answer in answers_and_marks %}
|
||||||
<li class="user-answer-li">Question {{forloop.counter}} - Correct answer: <span class="correct-answer">{{correct_answer }}</span></li>
|
<li class="user-answer-li">Question {{forloop.counter}} - Correct answer: <span class="correct-answer">{{correct_answer }}</span></li>
|
||||||
<span class="user-answer-score user-answer-score-{{score}} physics-ans">
|
<span class="user-answer-score user-answer-score-{{score}} physics-ans">
|
||||||
@@ -24,12 +22,7 @@
|
|||||||
<span class="view-question-link" data-qn={{forloop.counter0}}>View</span>
|
<span class="view-question-link" data-qn={{forloop.counter0}}>View</span>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
<br /> Total mark: {{ total_score }} / {{max_score}}
|
{% include 'user_scores_footer.html' %}
|
||||||
<div>
|
|
||||||
{% if cid %}
|
|
||||||
<a href="{% url 'cid_scores' cid passcode %}">Other exams</a>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block js %}
|
{% block js %}
|
||||||
|
|||||||
+60
-17
@@ -7,14 +7,22 @@ from django.forms import (
|
|||||||
CharField,
|
CharField,
|
||||||
HiddenInput,
|
HiddenInput,
|
||||||
EmailField,
|
EmailField,
|
||||||
IntegerField
|
IntegerField,
|
||||||
|
|
||||||
)
|
)
|
||||||
from django.forms import inlineformset_factory
|
from django.forms import inlineformset_factory
|
||||||
from atlas.models import CaseCollection
|
from atlas.models import CaseCollection
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
|
|
||||||
from generic.models import CidUser, CidUserGroup, Examination, QuestionNote, Supervisor, UserGrades, UserProfile, UserUserGroup
|
from generic.models import (
|
||||||
|
CidUser,
|
||||||
|
CidUserGroup,
|
||||||
|
Examination,
|
||||||
|
QuestionNote,
|
||||||
|
Supervisor,
|
||||||
|
UserGrades,
|
||||||
|
UserProfile,
|
||||||
|
UserUserGroup,
|
||||||
|
)
|
||||||
|
|
||||||
from django.contrib.admin.widgets import FilteredSelectMultiple
|
from django.contrib.admin.widgets import FilteredSelectMultiple
|
||||||
from django.forms.widgets import RadioSelect, TextInput, Textarea
|
from django.forms.widgets import RadioSelect, TextInput, Textarea
|
||||||
@@ -50,6 +58,7 @@ from sbas.models import CidUserAnswer as SbasCidUserAnswer
|
|||||||
from sbas.models import Exam as SbasExam
|
from sbas.models import Exam as SbasExam
|
||||||
from sbas.models import Question as SbasQuestion
|
from sbas.models import Question as SbasQuestion
|
||||||
|
|
||||||
|
|
||||||
class ExamFormMixin:
|
class ExamFormMixin:
|
||||||
class Meta:
|
class Meta:
|
||||||
fields = [
|
fields = [
|
||||||
@@ -64,7 +73,7 @@ class ExamFormMixin:
|
|||||||
"archive",
|
"archive",
|
||||||
"cid_user_groups",
|
"cid_user_groups",
|
||||||
"user_user_groups",
|
"user_user_groups",
|
||||||
#"author",
|
# "author",
|
||||||
]
|
]
|
||||||
|
|
||||||
def save(self, commit=True):
|
def save(self, commit=True):
|
||||||
@@ -75,6 +84,7 @@ class ExamFormMixin:
|
|||||||
|
|
||||||
return instance
|
return instance
|
||||||
|
|
||||||
|
|
||||||
class ExamAuthorFormMixin(ModelForm):
|
class ExamAuthorFormMixin(ModelForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
fields = ["author"]
|
fields = ["author"]
|
||||||
@@ -133,7 +143,6 @@ class QuestionNoteForm(ModelForm):
|
|||||||
|
|
||||||
|
|
||||||
class CidUserForm(ModelForm):
|
class CidUserForm(ModelForm):
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
if kwargs.get("instance"):
|
if kwargs.get("instance"):
|
||||||
# We get the 'initial' keyword argument or initialize it
|
# We get the 'initial' keyword argument or initialize it
|
||||||
@@ -141,12 +150,22 @@ class CidUserForm(ModelForm):
|
|||||||
initial = kwargs.setdefault("initial", {})
|
initial = kwargs.setdefault("initial", {})
|
||||||
# The widget for a ModelMultipleChoiceField expects
|
# The widget for a ModelMultipleChoiceField expects
|
||||||
# a list of primary key for the selected data.
|
# a list of primary key for the selected data.
|
||||||
initial["physics_exams"] = [t.pk for t in kwargs["instance"].physics_exams.all()]
|
initial["physics_exams"] = [
|
||||||
initial["anatomy_exams"] = [t.pk for t in kwargs["instance"].anatomy_exams.all()]
|
t.pk for t in kwargs["instance"].physics_exams.all()
|
||||||
|
]
|
||||||
|
initial["anatomy_exams"] = [
|
||||||
|
t.pk for t in kwargs["instance"].anatomy_exams.all()
|
||||||
|
]
|
||||||
initial["sba_exams"] = [t.pk for t in kwargs["instance"].sba_exams.all()]
|
initial["sba_exams"] = [t.pk for t in kwargs["instance"].sba_exams.all()]
|
||||||
initial["rapid_exams"] = [t.pk for t in kwargs["instance"].rapid_exams.all()]
|
initial["rapid_exams"] = [
|
||||||
initial["longs_exams"] = [t.pk for t in kwargs["instance"].longs_exams.all()]
|
t.pk for t in kwargs["instance"].rapid_exams.all()
|
||||||
initial["casecollection_exams"] = [t.pk for t in kwargs["instance"].casecollection_exams.all()]
|
]
|
||||||
|
initial["longs_exams"] = [
|
||||||
|
t.pk for t in kwargs["instance"].longs_exams.all()
|
||||||
|
]
|
||||||
|
initial["casecollection_exams"] = [
|
||||||
|
t.pk for t in kwargs["instance"].casecollection_exams.all()
|
||||||
|
]
|
||||||
|
|
||||||
ModelForm.__init__(self, *args, **kwargs)
|
ModelForm.__init__(self, *args, **kwargs)
|
||||||
|
|
||||||
@@ -155,12 +174,16 @@ class CidUserForm(ModelForm):
|
|||||||
self.fields["physics_exams"] = ModelMultipleChoiceField(
|
self.fields["physics_exams"] = ModelMultipleChoiceField(
|
||||||
required=False,
|
required=False,
|
||||||
queryset=PhysicsExam.objects.filter(archive=False),
|
queryset=PhysicsExam.objects.filter(archive=False),
|
||||||
widget=FilteredSelectMultiple(verbose_name="Physics Exams", is_stacked=False),
|
widget=FilteredSelectMultiple(
|
||||||
|
verbose_name="Physics Exams", is_stacked=False
|
||||||
|
),
|
||||||
)
|
)
|
||||||
self.fields["anatomy_exams"] = ModelMultipleChoiceField(
|
self.fields["anatomy_exams"] = ModelMultipleChoiceField(
|
||||||
required=False,
|
required=False,
|
||||||
queryset=AnatomyExam.objects.filter(archive=False),
|
queryset=AnatomyExam.objects.filter(archive=False),
|
||||||
widget=FilteredSelectMultiple(verbose_name="Anatomy Exams", is_stacked=False),
|
widget=FilteredSelectMultiple(
|
||||||
|
verbose_name="Anatomy Exams", is_stacked=False
|
||||||
|
),
|
||||||
)
|
)
|
||||||
self.fields["sba_exams"] = ModelMultipleChoiceField(
|
self.fields["sba_exams"] = ModelMultipleChoiceField(
|
||||||
required=False,
|
required=False,
|
||||||
@@ -180,7 +203,9 @@ class CidUserForm(ModelForm):
|
|||||||
self.fields["casecollection_exams"] = ModelMultipleChoiceField(
|
self.fields["casecollection_exams"] = ModelMultipleChoiceField(
|
||||||
required=False,
|
required=False,
|
||||||
queryset=CaseCollection.objects.filter(archive=False),
|
queryset=CaseCollection.objects.filter(archive=False),
|
||||||
widget=FilteredSelectMultiple(verbose_name="Case Collection", is_stacked=False),
|
widget=FilteredSelectMultiple(
|
||||||
|
verbose_name="Case Collection", is_stacked=False
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
def save(self, commit=True):
|
def save(self, commit=True):
|
||||||
@@ -234,31 +259,42 @@ class CidUserForm(ModelForm):
|
|||||||
"group",
|
"group",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class CidUserGroupModelChoiceField(ModelMultipleChoiceField):
|
||||||
|
def label_from_instance(self, obj):
|
||||||
|
return f"{obj.cid} [{obj.email}]"
|
||||||
|
|
||||||
|
|
||||||
class CidUserGroupForm(ModelForm):
|
class CidUserGroupForm(ModelForm):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = CidUserGroup
|
model = CidUserGroup
|
||||||
fields = ["name", "archive"]
|
fields = ["name", "archive"]
|
||||||
|
|
||||||
|
|
||||||
class UserUserGroupModelChoiceField(ModelMultipleChoiceField):
|
class UserUserGroupModelChoiceField(ModelMultipleChoiceField):
|
||||||
def label_from_instance(self, obj):
|
def label_from_instance(self, obj):
|
||||||
return f"{obj.username} ({obj.userprofile.grade}) [{obj.email}]"
|
return f"{obj.username} ({obj.userprofile.grade}) [{obj.email}]"
|
||||||
|
|
||||||
|
|
||||||
class UserUserGroupForm(ModelForm):
|
class UserUserGroupForm(ModelForm):
|
||||||
users = UserUserGroupModelChoiceField(
|
users = UserUserGroupModelChoiceField(
|
||||||
required=False,
|
required=False,
|
||||||
queryset=User.objects.all(),
|
queryset=User.objects.all(),
|
||||||
widget=FilteredSelectMultiple(verbose_name="Users", is_stacked=False),
|
widget=FilteredSelectMultiple(verbose_name="Users", is_stacked=False),
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = UserUserGroup
|
model = UserUserGroup
|
||||||
fields = ["name", "archive", "users"]
|
fields = ["name", "archive", "users"]
|
||||||
|
|
||||||
#class UserForm(ModelForm):
|
|
||||||
|
# class UserForm(ModelForm):
|
||||||
# class Meta:
|
# class Meta:
|
||||||
# model = User
|
# model = User
|
||||||
# fields = ["first_name", "last_name", "email"]
|
# fields = ["first_name", "last_name", "email"]
|
||||||
#
|
#
|
||||||
#class UserProfileForm(ModelForm):
|
# class UserProfileForm(ModelForm):
|
||||||
# class Meta:
|
# class Meta:
|
||||||
# model = UserProfile
|
# model = UserProfile
|
||||||
# fields = ["supervisor_name", "supervisor_email", "registration_number", "peninsula_trainee"]
|
# fields = ["supervisor_name", "supervisor_email", "registration_number", "peninsula_trainee"]
|
||||||
@@ -271,17 +307,24 @@ GRADE_CHOICES = (
|
|||||||
("ST5", "ST5"),
|
("ST5", "ST5"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class UserUserForm(Form):
|
class UserUserForm(Form):
|
||||||
username = EmailField(required=True, help_text="Username / email should be the same. Ideally this should be an nhs email.")
|
username = EmailField(
|
||||||
|
required=True,
|
||||||
|
help_text="Username / email should be the same. Ideally this should be an nhs email.",
|
||||||
|
)
|
||||||
first_name = CharField(max_length=255, required=True)
|
first_name = CharField(max_length=255, required=True)
|
||||||
last_name = CharField(max_length=255, required=True)
|
last_name = CharField(max_length=255, required=True)
|
||||||
grade = ModelChoiceField(UserGrades.objects.all(), required=False)
|
grade = ModelChoiceField(UserGrades.objects.all(), required=False)
|
||||||
supervisor = ModelChoiceField(Supervisor.objects.all(), required=False) # Needs to be a user/object ref
|
supervisor = ModelChoiceField(
|
||||||
|
Supervisor.objects.all(), required=False
|
||||||
|
) # Needs to be a user/object ref
|
||||||
#
|
#
|
||||||
# class Meta:
|
# class Meta:
|
||||||
#
|
#
|
||||||
# fields = ("username", "first_name", "last_name")
|
# fields = ("username", "first_name", "last_name")
|
||||||
|
|
||||||
|
|
||||||
class SupervisorForm(ModelForm):
|
class SupervisorForm(ModelForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Supervisor
|
model = Supervisor
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
# Generated by Django 3.2.13 on 2022-11-21 16:37
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('generic', '0046_auto_20221121_0955'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='supervisor',
|
||||||
|
name='email',
|
||||||
|
field=models.EmailField(help_text='The (nhs.net) email address of the supervisor', max_length=254, unique=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='supervisor',
|
||||||
|
name='name',
|
||||||
|
field=models.CharField(help_text='Name of the supervisor', max_length=255),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='supervisor',
|
||||||
|
name='site',
|
||||||
|
field=models.ForeignKey(blank=True, help_text='Hospital site at which the supervisor is based', null=True, on_delete=django.db.models.deletion.SET_NULL, to='generic.site'),
|
||||||
|
),
|
||||||
|
]
|
||||||
+6
-6
@@ -638,13 +638,13 @@ class CidUserGroup(models.Model):
|
|||||||
|
|
||||||
|
|
||||||
class UserUserGroup(models.Model):
|
class UserUserGroup(models.Model):
|
||||||
name = models.CharField(blank=True, max_length=50)
|
name = models.CharField(blank=True, max_length=50, help_text="Name of the User Group")
|
||||||
archive = models.BooleanField(default=False)
|
archive = models.BooleanField(default=False, help_text="Archived groups remain on the test system but are not displayed by default")
|
||||||
|
|
||||||
users = models.ManyToManyField(
|
users = models.ManyToManyField(
|
||||||
settings.AUTH_USER_MODEL,
|
settings.AUTH_USER_MODEL,
|
||||||
blank=True,
|
blank=True,
|
||||||
related_name="user_groups"
|
related_name="user_groups",
|
||||||
)
|
)
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
@@ -686,10 +686,10 @@ class Supervisor(models.Model):
|
|||||||
|
|
||||||
This can be linked with a user account.
|
This can be linked with a user account.
|
||||||
"""
|
"""
|
||||||
email = models.EmailField(blank=True, unique=True, help_text="The (nhs.net) email address of the supervisor")
|
email = models.EmailField(unique=True, help_text="The (nhs.net) email address of the supervisor")
|
||||||
name = models.CharField(max_length=255, blank=True, help_text="Name of the supervisor")
|
name = models.CharField(max_length=255, help_text="Name of the supervisor")
|
||||||
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True, blank=True, help_text="If the supervisor has an account on the test system that can be associated here")
|
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True, blank=True, help_text="If the supervisor has an account on the test system that can be associated here")
|
||||||
site = models.ForeignKey("Site", on_delete=models.SET_NULL, null=True, blank=True)
|
site = models.ForeignKey("Site", on_delete=models.SET_NULL, null=True, blank=True, help_text="Hospital site at which the supervisor is based")
|
||||||
active = models.BooleanField(default=True)
|
active = models.BooleanField(default=True)
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
|
|||||||
+8
-3
@@ -33,6 +33,7 @@ class CidUserTable(tables.Table):
|
|||||||
#sba_exams = tables.ManyToManyColumn(verbose_name="SBA Exams")
|
#sba_exams = tables.ManyToManyColumn(verbose_name="SBA Exams")
|
||||||
#longs_exams = tables.ManyToManyColumn(verbose_name="Long Exams")
|
#longs_exams = tables.ManyToManyColumn(verbose_name="Long Exams")
|
||||||
#anatomy_exams = tables.ManyToManyColumn(verbose_name="Anatomy Exams")
|
#anatomy_exams = tables.ManyToManyColumn(verbose_name="Anatomy Exams")
|
||||||
|
group = tables.Column(linkify=True)
|
||||||
|
|
||||||
selection = tables.CheckBoxColumn(accessor="pk", orderable=False)
|
selection = tables.CheckBoxColumn(accessor="pk", orderable=False)
|
||||||
|
|
||||||
@@ -143,6 +144,8 @@ class UserUserTable(tables.Table):
|
|||||||
empty_values=(), linkify={"viewname": "account_update", "args":[A("username")]}, orderable=True, verbose_name="Edit",
|
empty_values=(), linkify={"viewname": "account_update", "args":[A("username")]}, orderable=True, verbose_name="Edit",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
user_groups = tables.ManyToManyColumn(verbose_name="Groups", linkify_item=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = User
|
model = User
|
||||||
template_name = "django_tables2/bootstrap4.html"
|
template_name = "django_tables2/bootstrap4.html"
|
||||||
@@ -150,17 +153,19 @@ class UserUserTable(tables.Table):
|
|||||||
# "cid",
|
# "cid",
|
||||||
#"userprofile",
|
#"userprofile",
|
||||||
"userprofile.grade",
|
"userprofile.grade",
|
||||||
|
#"user_groups",
|
||||||
#"userprofile.supervisor",
|
#"userprofile.supervisor",
|
||||||
# "email",
|
# "email",
|
||||||
)
|
)
|
||||||
sequence = ("user", "userprofile.grade", "supervisor", "edit")
|
sequence = ("user", "userprofile.grade", "supervisor", "user_groups", "edit")
|
||||||
|
|
||||||
def __init__(self, data=None, *args, **kwargs):
|
def __init__(self, data=None, *args, **kwargs):
|
||||||
super().__init__(
|
super().__init__(
|
||||||
data.prefetch_related(
|
data.prefetch_related(
|
||||||
"supervisor",
|
|
||||||
"userprofile",
|
"userprofile",
|
||||||
#"userprofile.grade",
|
"user_groups",
|
||||||
|
"userprofile__grade",
|
||||||
|
"supervisor",
|
||||||
),
|
),
|
||||||
*args,
|
*args,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<a href="{% url 'generic:cid_group_create' %}">Create new group</a>
|
<a href="{% url 'generic:cid_group_create' %}">Create new group</a>
|
||||||
</p>
|
</p>
|
||||||
{% for group in groups %}
|
{% for group in groups %}
|
||||||
<p><a href="{% url 'generic:cid_group_detail' group.pk %}">{{group.name}}</a>
|
<p><a href="{% url 'generic:cid_group_detail' group.pk %}"><h4>{{group.name}}</h4></a>
|
||||||
<button class="small-url-button" data-url="{% url 'generic:group_email' pk=group.pk %}
|
<button class="small-url-button" data-url="{% url 'generic:group_email' pk=group.pk %}
|
||||||
">Email candidate details</button>
|
">Email candidate details</button>
|
||||||
<button class="small-url-button" data-url="{% url 'generic:group_email_resend' pk=group.pk %}
|
<button class="small-url-button" data-url="{% url 'generic:group_email_resend' pk=group.pk %}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
{% extends 'generic/base.html' %}
|
{% extends 'generic/base.html' %}
|
||||||
|
|
||||||
|
{% load crispy_forms_tags %}
|
||||||
{% load render_table from django_tables2 %}
|
{% load render_table from django_tables2 %}
|
||||||
{% block css %}
|
{% block css %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -12,7 +13,7 @@
|
|||||||
<h3>Filter CID Users </h3>
|
<h3>Filter CID Users </h3>
|
||||||
</summary>
|
</summary>
|
||||||
<form action="" method="get">
|
<form action="" method="get">
|
||||||
{{ filter.form }}
|
{{ filter.form |crispy}}
|
||||||
<input class="btn btn-primary btn-sm mt-1 mb-1" type="submit" />
|
<input class="btn btn-primary btn-sm mt-1 mb-1" type="submit" />
|
||||||
</form>
|
</form>
|
||||||
</details>
|
</details>
|
||||||
|
|||||||
@@ -28,13 +28,19 @@
|
|||||||
</table>
|
</table>
|
||||||
<input type="submit" class="submit-button" value="Submit" name="submit">
|
<input type="submit" class="submit-button" value="Submit" name="submit">
|
||||||
|
|
||||||
|
<p>Users can be added to the group <a href="{% url 'generic:manage_cids' %}">here</a></p>
|
||||||
|
|
||||||
<h3>Users</h3>
|
<h3>Users</h3>
|
||||||
|
|
||||||
{% if cidusergroup.GetGroupUsers %}
|
<ul>
|
||||||
{{cidusergroup.GetGroupUsers}}
|
{% for user in cidusergroup.ciduser_set.all %}
|
||||||
{% else %}
|
<li><a href="{% url 'generic:update_cid' user.pk %}">{{user.cid}}</a>: {{user.name}} [{{user.email}} {{user.last_name}}] {{user.userprofile.grade}}</li>
|
||||||
No users currently added to group.
|
|
||||||
{% endif %}
|
{% empty %}
|
||||||
|
<li>Group currently has no users.</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
Count: {{cidusergroup.ciduser_set.count}}
|
||||||
|
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ol>
|
</ol>
|
||||||
{% else %}
|
{% else %}
|
||||||
This exam is not associated with any user groups. Edit and add a group to enable user management.
|
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 %}
|
{% endif %}
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
{% extends "generic/supervisor_base.html" %}
|
{% extends "generic/supervisor_base.html" %}
|
||||||
<!-- {% load static from static %} -->
|
<!-- {% load static from static %} -->
|
||||||
|
{% load crispy_forms_tags %}
|
||||||
|
|
||||||
{% block css %}
|
{% block css %}
|
||||||
<style>
|
<style>
|
||||||
@@ -25,7 +26,7 @@ Use this form to create / edit a supervisor
|
|||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
{{ form.as_table }}
|
{{ form|crispy }}
|
||||||
</table>
|
</table>
|
||||||
<input type="submit" class="submit-button" value="Submit" name="submit">
|
<input type="submit" class="submit-button" value="Submit" name="submit">
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -5,8 +5,8 @@
|
|||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
{% for supervisor in object_list %}
|
{% for supervisor in object_list %}
|
||||||
<li><a href="{% url 'generic:supervisor_detail' pk=supervisor.pk %}">Supervisor: {{supervisor.name}}</a>
|
<li><a href="{% url 'generic:supervisor_detail' pk=supervisor.pk %}">{{supervisor.name}}</a>
|
||||||
<br/>{{supervisor.email}}
|
<br/>{{supervisor.email}} [{{supervisor.site}}]
|
||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
{% extends "generic/base.html" %}
|
{% extends "generic/base.html" %}
|
||||||
<!-- {% load static from static %} -->
|
<!-- {% load static from static %} -->
|
||||||
|
{% load crispy_forms_tags %}
|
||||||
|
|
||||||
{% block css %}
|
{% block css %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -18,29 +19,32 @@
|
|||||||
{% else %}
|
{% else %}
|
||||||
<h2>Add New Group</h2>
|
<h2>Add New Group</h2>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
Use this form to create / edit a CID user group.
|
Use this form to create / edit a User group.<br/>
|
||||||
<form action="" method="post" enctype="multipart/form-data" id="condition-form">
|
<form action="" method="post" enctype="multipart/form-data" id="condition-form" class="inline-form">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
|
|
||||||
<table>
|
{{ form|crispy }}
|
||||||
{{ form.as_table }}
|
|
||||||
</table>
|
|
||||||
<input type="submit" class="submit-button" value="Submit" name="submit">
|
<input type="submit" class="submit-button" value="Submit" name="submit">
|
||||||
|
|
||||||
|
|
||||||
|
</form>
|
||||||
|
<div>
|
||||||
<h3>Users</h3>
|
<h3>Users</h3>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
{% for user in userusergroup.users.all %}
|
{% for user in userusergroup.users.all %}
|
||||||
<li>{{user}}</li>{% empty %}
|
<li><a href="{% url 'account_profile' user.username %}">{{user.username}}</a> [{{user.first_name}} {{user.last_name}}] {{user.userprofile.grade}}</li>
|
||||||
|
|
||||||
|
{% empty %}
|
||||||
<li>Group currently has no users.</li>
|
<li>Group currently has no users.</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
Count: {{userusergroup.users.count}}
|
||||||
|
</div>
|
||||||
|
|
||||||
{% comment %} {% if userusergroup.users.all %}
|
{% comment %} {% if userusergroup.users.all %}
|
||||||
{{userusergroup.GetGroupUsers}}
|
{{userusergroup.GetGroupUsers}}
|
||||||
{% else %}
|
{% else %}
|
||||||
No users currently added to group.
|
No users currently added to group.
|
||||||
{% endif %} {% endcomment %}
|
{% endif %} {% endcomment %}
|
||||||
|
|
||||||
</form>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -1,83 +1,78 @@
|
|||||||
{% extends 'longs/base.html' %}
|
{% extends 'longs/base.html' %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="question-display-block">
|
<div class="question-display-block">
|
||||||
<div class="hide-show">HIDE/SHOW</div>
|
<div class="hide-show">HIDE/SHOW</div>
|
||||||
<div class="inner-display-block">
|
<div class="inner-display-block">
|
||||||
Question <span class="question-number">1</span><br />
|
Question <span class="question-number">1</span><br />
|
||||||
History: <span id="history"></span><br />
|
History: <span id="history"></span><br />
|
||||||
Images: <span id="series"></span>
|
Images: <span id="series"></span>
|
||||||
<div id="single-dicom-viewer" class="dicom-viewer" data-images="" data-annotations=''>
|
<div id="single-dicom-viewer" class="dicom-viewer" data-images="" data-annotations=''>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="longs">
|
||||||
<div class="longs">
|
{% include 'user_score_header.html' %}
|
||||||
<h2>Exam: {{ exam.name }}</h2>
|
<ul>
|
||||||
<h3>Candidate: {{ cid }}</h3>
|
{% for score in answers_marks %}
|
||||||
Scores:
|
<li class="user-answer-li">Question {{forloop.counter}}</li>
|
||||||
<ul>{% for score in answers_marks %}
|
<span class="user-answer-score user-answer-score-{{score}}">
|
||||||
<li class="user-answer-li">Question {{forloop.counter}}</li>
|
<pre>{{ans}}</pre> ({{score}})
|
||||||
<span class="user-answer-score user-answer-score-{{score}}">
|
</span>
|
||||||
<pre>{{ans}}</pre> ({{score}})
|
|
||||||
</span>
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
<br /> Total mark: {{ total_score }} / {{max_score}}
|
<div>
|
||||||
<br /> Normalised score: {{normalised_score}}
|
<h4>Answers</h4>
|
||||||
<div>
|
<ul class="long-answer">{% for a,b,c,d,e in answer_text %}
|
||||||
<h4>Answers</h4>
|
<li class="user-answer-li"><b>Question {{forloop.counter}}</b> <span class="view-question-link-longs"
|
||||||
<ul class="long-answer">{% for a,b,c,d,e in answer_text %}
|
|
||||||
<li class="user-answer-li"><b>Question {{forloop.counter}}</b> <span class="view-question-link-longs"
|
|
||||||
data-qn={{forloop.counter0}}>View</span></li>
|
data-qn={{forloop.counter0}}>View</span></li>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<li class="user-answer-li">Observation</br>
|
<li class="user-answer-li">Observation</br>
|
||||||
<pre>{{a}}</pre>
|
<pre>{{a}}</pre>
|
||||||
</li>
|
</li>
|
||||||
<li class="user-answer-li">Interpretation</br>
|
<li class="user-answer-li">Interpretation</br>
|
||||||
<pre>{{b}}</pre>
|
<pre>{{b}}</pre>
|
||||||
</li>
|
</li>
|
||||||
<li class="user-answer-li">Principle Diagnosis</br>
|
<li class="user-answer-li">Principle Diagnosis</br>
|
||||||
<pre>{{c}}</pre>
|
<pre>{{c}}</pre>
|
||||||
</li>
|
</li>
|
||||||
<li class="user-answer-li">Differential Diagnosis</br>
|
<li class="user-answer-li">Differential Diagnosis</br>
|
||||||
<pre>{{d}}</pre>
|
<pre>{{d}}</pre>
|
||||||
</li>
|
</li>
|
||||||
<li class="user-answer-li">Management</br>
|
<li class="user-answer-li">Management</br>
|
||||||
<pre>{{e}}</pre>
|
<pre>{{e}}</pre>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{% include 'user_scores_footer.html' %}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
|
||||||
<a href="{% url 'cid_scores' cid passcode %}">Other exams</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block js %}
|
{% block js %}
|
||||||
<script>
|
<script>
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
$(".hide-show").click((evt, el) => {
|
$(".hide-show").click((evt, el) => {
|
||||||
$(".inner-display-block").toggle();
|
$(".inner-display-block").toggle();
|
||||||
})
|
|
||||||
|
|
||||||
$(".view-question-link-longs").on("click", function (e) {
|
|
||||||
console.log("click", e)
|
|
||||||
question_number = e.currentTarget.dataset.qn;
|
|
||||||
$("#single-dicom-viewer").empty();
|
|
||||||
$.ajax({
|
|
||||||
url: `{% url 'longs:question_review' pk=exam.pk %}`,
|
|
||||||
data: {
|
|
||||||
csrfmiddlewaretoken: "{{ csrf_token }}",
|
|
||||||
question_number: question_number
|
|
||||||
},
|
|
||||||
type: "POST",
|
|
||||||
dataType: "json",
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
$(".view-question-link-longs").on("click", function (e) {
|
||||||
|
console.log("click", e)
|
||||||
|
question_number = e.currentTarget.dataset.qn;
|
||||||
|
$("#single-dicom-viewer").empty();
|
||||||
|
$.ajax({
|
||||||
|
url: `{% url 'longs:question_review' pk=exam.pk %}`,
|
||||||
|
data: {
|
||||||
|
csrfmiddlewaretoken: "{{ csrf_token }}",
|
||||||
|
question_number: question_number
|
||||||
|
},
|
||||||
|
type: "POST",
|
||||||
|
dataType: "json",
|
||||||
|
})
|
||||||
// $.ajax().done(), $.ajax().fail(), $ajax().always() are upto you. Add/change accordingly
|
// $.ajax().done(), $.ajax().fail(), $ajax().always() are upto you. Add/change accordingly
|
||||||
.done(function (data) {
|
.done(function (data) {
|
||||||
console.log(data);
|
console.log(data);
|
||||||
|
|
||||||
let event = new CustomEvent('loadDicomViewerUrls', {
|
let event = new CustomEvent('loadDicomViewerUrls', {
|
||||||
@@ -111,13 +106,13 @@
|
|||||||
})
|
})
|
||||||
$(".inner-display-block").show();
|
$(".inner-display-block").show();
|
||||||
})
|
})
|
||||||
.always(function () {
|
.always(function () {
|
||||||
console.log('[Done]');
|
console.log('[Done]');
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
$(".view-question-link").first().click();
|
$(".view-question-link").first().click();
|
||||||
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -1,26 +1,19 @@
|
|||||||
{% extends 'physics/base.html' %}
|
{% extends 'physics/base.html' %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="physics">
|
<div class="physics">
|
||||||
{% include 'generic/user_scores_header.html' %}
|
{% include 'user_score_header.html' %}
|
||||||
|
<ul>
|
||||||
Answers:
|
{% for question, ans in answers_and_marks %}
|
||||||
<ul>
|
<li class="user-answer-li"><span class="question-stem-text">Question {{forloop.counter}} - {{ question.stem|safe }}</span></li>
|
||||||
{% for question, ans in answers_and_marks %}
|
<ol type="a">
|
||||||
<li class="user-answer-li">Question {{forloop.counter}} - {{ question.stem|safe }}</li>
|
{% for q, a, score, correct_answer in ans %}
|
||||||
<ol type="a">
|
<li><span class="question-text">{{q|safe}}:</span> Correct answer: {{correct_answer}} <br /><span class="submitted-user-answer">{{a}} <span class="answer-{{score}}">(Score:
|
||||||
{% for q, a, score, correct_answer in ans %}
|
{{score}})</span></span></li>
|
||||||
<li>{{q|safe}}: Correct answer: {{correct_answer}} <br />{{a}} <span class="answer-{{score}}">(Score:
|
{% endfor %}
|
||||||
{{score}})</span></li>
|
</ol>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ol>
|
</ul>
|
||||||
{% endfor %}
|
{% include 'user_scores_footer.html' %}
|
||||||
</ul>
|
|
||||||
<br /> Total mark: {{ total_score }} / {{max_score}}
|
|
||||||
<div>
|
|
||||||
{% if cid %}
|
|
||||||
<a href="{% url 'cid_scores' cid passcode %}">Other exams</a>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -73,6 +73,7 @@ INSTALLED_APPS = [
|
|||||||
"tinymce",
|
"tinymce",
|
||||||
"django_unused_media",
|
"django_unused_media",
|
||||||
"django_htmx",
|
"django_htmx",
|
||||||
|
"crispy_forms",
|
||||||
]
|
]
|
||||||
|
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
@@ -298,6 +299,8 @@ EMAIL_USE_SSL = True
|
|||||||
|
|
||||||
ADMINS = [("Ross","ross@xkjq.uk")]
|
ADMINS = [("Ross","ross@xkjq.uk")]
|
||||||
|
|
||||||
|
CRISPY_TEMPLATE_PACK = 'bootstrap'
|
||||||
|
|
||||||
DEBUG_CONTAINER = False
|
DEBUG_CONTAINER = False
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -16,9 +16,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="rapids">
|
<div class="rapids">
|
||||||
<h2>Exam: {{ exam.name }}</h2>
|
{% include 'user_score_header.html' %}
|
||||||
<h3>Candidate: {{ cid|default_if_none:request.user.username }}</h3>
|
|
||||||
Answers:
|
|
||||||
<ul class="score-answer-list">
|
<ul class="score-answer-list">
|
||||||
{% for ans, score, correct_answer in answers_and_marks %}
|
{% for ans, score, correct_answer in answers_and_marks %}
|
||||||
<li class="user-answer-li">Question {{forloop.counter}} - Correct answer: <span class="correct-answer">{{ correct_answer }}</span></li>
|
<li class="user-answer-li">Question {{forloop.counter}} - Correct answer: <span class="correct-answer">{{ correct_answer }}</span></li>
|
||||||
@@ -28,13 +26,7 @@
|
|||||||
<span class="view-question-link" data-qn={{forloop.counter0}}>View</span>
|
<span class="view-question-link" data-qn={{forloop.counter0}}>View</span>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
<br /> Total mark: {{ total_score }} / {{max_score}}
|
{% include 'user_scores_footer.html' %}
|
||||||
<br /> Normalised score: {{ normalised_score }}
|
|
||||||
<div>
|
|
||||||
{% if cid %}
|
|
||||||
<a href="{% url 'cid_scores' cid passcode %}">Other exams</a>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block js %}
|
{% block js %}
|
||||||
|
|||||||
@@ -32,3 +32,4 @@ bs4
|
|||||||
django-htmx
|
django-htmx
|
||||||
debugpy
|
debugpy
|
||||||
django-cookie-consent
|
django-cookie-consent
|
||||||
|
django-crispy-forms
|
||||||
@@ -2,12 +2,7 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="sbas">
|
<div class="sbas">
|
||||||
<h2>Exam: {{ exam.name }}</h2>
|
{% include 'user_score_header.html' %}
|
||||||
<h3>Candidate: {{ cid }}</h3>
|
|
||||||
{% if not exam.publish_results %}
|
|
||||||
<div class="alert alert-info" role="alert"><h4>Exam results not published</h4>Submitted answers are visible below.</div>
|
|
||||||
{% endif %}
|
|
||||||
Answers:
|
|
||||||
<ul>
|
<ul>
|
||||||
{% for question, a, score, correct_answer, chosen_answer in answers_and_marks %}
|
{% for question, a, score, correct_answer, chosen_answer in answers_and_marks %}
|
||||||
<li class="user-answer-li"><a href="{% url 'sbas:exam_take' exam.pk forloop.counter0 cid passcode %}">Question
|
<li class="user-answer-li"><a href="{% url 'sbas:exam_take' exam.pk forloop.counter0 cid passcode %}">Question
|
||||||
@@ -20,9 +15,6 @@
|
|||||||
</span>
|
</span>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
<br /> Total mark: {{ total_score }} / {{max_score}}
|
{% include 'user_scores_footer.html' %}
|
||||||
<div>
|
|
||||||
<a href="{% url 'cid_scores' cid passcode %}">Other exams</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
<!DOCTYPE HTML>
|
<!DOCTYPE HTML>
|
||||||
{% load static %}
|
{% load static %}
|
||||||
{% load django_htmx %}
|
{% load django_htmx %}
|
||||||
|
{% load crispy_forms_tags %}
|
||||||
{% load auth_extras %}
|
{% load auth_extras %}
|
||||||
<html>
|
<html>
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
|
|
||||||
|
|
||||||
<p><a href="http://www.penracourses.org.uk/rts">RTS is available here</a></p>
|
<p><a href="http://www.penracourses.org.uk/rts">RTS is available here</a></p>
|
||||||
|
<p><a href="{% url 'cid_selector' %}">CID users can log in here</a></p>
|
||||||
<div>
|
<div>
|
||||||
{% if request.user.is_staff %}
|
{% if request.user.is_staff %}
|
||||||
Manage users <a href="{% url 'generic:manage_cids'%}">here</a>
|
Manage users <a href="{% url 'generic:manage_cids'%}">here</a>
|
||||||
|
|||||||
+21
-9
@@ -1,30 +1,42 @@
|
|||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="anatomy">
|
<div class="anatomy">
|
||||||
<h1>Profile</h1>
|
<h1>Profile</h1>
|
||||||
<div>
|
<div>
|
||||||
Username: {{ user.username }}
|
Username: {{ user.username }}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
Email: {{ user.email }}
|
Email: {{ user.email }}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
Name: {{ user.first_name }}
|
Name: {{ user.first_name }}
|
||||||
{{ user.last_name }}
|
{{ user.last_name }}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
Grade: {{ user.userprofile.grade }}
|
Grade: {{ user.userprofile.grade }}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
Supervisor: {{ user.userprofile.supervisor }}<br/>
|
Supervisor: {{ user.userprofile.supervisor }}<br/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
Registration number: {{ user.userprofile.registration_number }}
|
Registration number: {{ user.userprofile.registration_number }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<h3>Groups</h3>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
{% for group in user.user_groups.all %}
|
||||||
|
<li>{{group}}</li>
|
||||||
|
{% empty %}
|
||||||
|
<li>No groups.</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
<a href="{% url 'password_change'%}">Change password</a>
|
<a href="{% url 'password_change'%}">Change password</a>
|
||||||
<a href="{% url 'account_update' user.username %}">Update user details</a>
|
<a href="{% url 'account_update' user.username %}">Update user details</a>
|
||||||
<a href="{% url 'account_profile_update' user.username %}">Update user profile</a>
|
<a href="{% url 'account_profile_update' user.username %}">Update user profile</a>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
+8
-2
@@ -1,7 +1,13 @@
|
|||||||
<h2>Exam: {{ exam.name }}</h2>
|
|
||||||
<h3>Candidate: {{ cid|default_if_none:request.user.username }}</h3>
|
|
||||||
{% if view_all_results %}
|
{% if view_all_results %}
|
||||||
<div class="alert alert-info" role="alert">
|
<div class="alert alert-info" role="alert">
|
||||||
Exam state: Active [{{exam.active}}] / Published [{{exam.publish_results}}]
|
Exam state: Active [{{exam.active}}] / Published [{{exam.publish_results}}]
|
||||||
</div>
|
</div>
|
||||||
|
{% else %}
|
||||||
|
{% if not exam.publish_results %}
|
||||||
|
<div class="alert alert-info" role="alert">Results are not currently published. You can see your own answers below.</a></div>
|
||||||
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
<h2>Exam: {{ exam.name }}</h2>
|
||||||
|
<h3>Candidate: {{ cid|default_if_none:request.user.username }}</h3>
|
||||||
|
Answers:
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
{% if view_all_results or exam.publish_results %}
|
||||||
|
<br /> Total mark: {{ total_score }} / {{max_score}}
|
||||||
|
{% if normalised_score %}
|
||||||
|
<br /> Normalised score: {{ normalised_score }}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
<div>
|
||||||
|
{% if cid %}
|
||||||
|
<a href="{% url 'cid_scores' cid passcode %}">Other exams</a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
{% extends 'generic/base.html' %}
|
{% extends 'generic/base.html' %}
|
||||||
|
{% load crispy_forms_tags %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h2>Editing user: {{object.username}}</h2>
|
<h2>Editing user: {{object.username}}</h2>
|
||||||
This form allows you to edit the users name and email address. More details (such as grade / supervisor / etc...) can be changed <a href="{% url 'account_profile_update' object.username %}">here</a>
|
This form allows you to edit the users name and email address. More details (such as grade / supervisor / etc...) can be changed <a href="{% url 'account_profile_update' object.username %}">here</a>
|
||||||
<form method="post">{% csrf_token %}
|
<form method="post">{% csrf_token %}
|
||||||
{{ form.as_p }}
|
{{ form|crispy }}
|
||||||
<input type="submit" value="Update">
|
<input type="submit" value="Update">
|
||||||
</form>
|
</form>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
{% extends 'generic/base.html' %}
|
{% extends 'generic/base.html' %}
|
||||||
|
{% load crispy_forms_tags %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h2>Editing user: {{object.username}}</h2>
|
<h2>Editing user: {{object.username}}</h2>
|
||||||
This form allows you to edit additional user details. Name and emails can be edited <a href="{% url 'account_update' object.username %}">here</a>
|
This form allows you to edit additional user details. Name and emails can be edited <a href="{% url 'account_update' object.username %}">here</a>
|
||||||
<form method="post">{% csrf_token %}
|
<form method="post">{% csrf_token %}
|
||||||
{{ form.as_p }}
|
{{ form|crispy }}
|
||||||
<input type="submit" value="Update">
|
<input type="submit" value="Update">
|
||||||
</form>
|
</form>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
Reference in New Issue
Block a user