This commit is contained in:
Ross
2022-01-11 19:20:20 +00:00
parent 84b1e1e9a2
commit eac89252f9
8 changed files with 204 additions and 44 deletions
+14 -2
View File
@@ -805,14 +805,26 @@ input {
.view-finding-button {
flex: 1;
}
.view-finding-details {
flex: 4;
}
.delete-finding-link, .edit-finding-link {
.delete-finding-link,
.edit-finding-link {
flex: 1;
}
summary h2, summary h3, summary h4, summary h5 {
summary h2,
summary h3,
summary h4,
summary h5 {
display: inline;
}
.mark-buttons {
position: sticky;
bottom: 0px;
background-color: black;
opacity: 80%;
}
+14 -11
View File
@@ -36,17 +36,20 @@
<li><pre><span class="answer incorrect" title="{{answer}}">{{ answer }}</span></pre></li>
{% endfor %}
</ul>
<div class="answer-list key">Key: <span class="correct">2 Marks</span>, <span class="half-correct">1
Mark</span>, <span class="incorrect">0 Marks</span></div>
{% if question_details.current > 1 %}
<button type="submit" name="previous" class="save btn btn-default">Previous</button>
{% endif %}
<button type="submit" name="save" class="save btn btn-default">Save</button>
{% if question_details.current >= question_details.total %}
{% else %}
<button type="submit" name="next" class="save btn btn-default">Next</button>
<button type="submit" name="skip" class="save btn btn-default">Skip</button>
{% endif %}
<div class="mark-buttons">
<div class="answer-list key">Key: <span class="correct">2 Marks</span>, <span class="half-correct">1
Mark</span>, <span class="incorrect">0 Marks</span>
</div>
{% if question_details.current > 1 %}
<button type="submit" name="previous" class="save btn btn-default">Previous</button>
{% endif %}
<button type="submit" name="save" class="save btn btn-default">Save</button>
{% if question_details.current >= question_details.total %}
{% else %}
<button type="submit" name="next" class="save btn btn-default">Next</button>
<button type="submit" name="skip" class="save btn btn-default">Skip</button>
{% endif %}
</div>
</div>
<span class=hide>
{{ form.as_p }}
+2
View File
@@ -143,4 +143,6 @@ class CidUserForm(ModelForm):
"name",
"email",
"supervisor_email",
"login_email_sent",
"results_email_sent",
]
+13 -5
View File
@@ -312,7 +312,7 @@ class CidUser(models.Model):
for n, t in self.EXAM_TYPES:
exam_rel = getattr(self, t)
if exam_rel.exists():
exams = exam_rel.filter(exam_mode=True).order_by("name")
exams = exam_rel.filter(exam_mode=True, archive=False).order_by("name")
available_exams.append((n, exams))
return available_exams
@@ -324,28 +324,33 @@ class CidUser(models.Model):
if self.name:
name = f"{self.name} "
exam_text = [f"Candidate {name}{self.cid} [{self.email}]"]
exam_text = [f"Candidate {self.cid} {name}[{self.email}]"]
for exam_type, exams in exam_list:
exam_text.append(f"{'='*len(exam_type)}\n{exam_type}\n{'='*len(exam_type)}")
for exam in exams:
print(exam)
try:
user_score = exam.user_scores[str(self.cid)]
except KeyError:
user_score = "Score not generated"
t = exam.get_exam_stats()
try:
percentage = (
f" ({user_score / int(exam.stats_max_possible) * 100:.2f}%)"
)
except TypeError:
percentage = ""
exam_text.append(
f"""{t}
# Score: {user_score} / {int(exam.stats_max_possible)}
# Score: {user_score} / {int(exam.stats_max_possible)}{percentage}
"""
)
msg = "\n\n".join(exam_text)
print(msg)
return msg
html_msg = f""""""
@@ -430,6 +435,9 @@ class CidUser(models.Model):
self.save()
return True, ""
def get_email_results_url(self):
return reverse("generic:candidate_email_results", kwargs={"cid": self.cid})
class CidUserExam(models.Model):
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
+118 -9
View File
@@ -1,15 +1,124 @@
{% extends 'generic/base.html' %}
{% block content %}
Attempted to send {{users_count}} emails.
{{users_count}} emails to send.
<h2>Emails to send:</h2>
<div class="sending"><div class="lds-ripple"><div></div><div></div></div> Emailing <span id="active-email"></span></div>
<ul id="user-list">
{% for user in users %}
<li data-email={{user.email}} data-posturl='{{user.get_email_results_url}}'>{{user.cid}}/{{user.name}}: {{user.email}} [{{user.supervisor_email}}] </li>
{% endfor %}
</ul>
<button id="send-emails">Send emails</button>
<script>
$('document').ready(() => {
$("#send-emails").click(() => {
//$("#user-list li").each((n, el) => {
// console.log(n, el);
//})
li_list = $("#user-list li").get();
sendEmail(li_list);
});
})
function sendEmail(li_list) {
//console.log(li_list)
$(".sending").show()
li = li_list.shift();
//console.log(li)
url = li.dataset.posturl;
$("#active-email").text(li.dataset.email)
console.log(url)
$.get(url, function(data, status) {
if (status == "success") {
if (data.sent) {
$(li).append("Email Sent");
$(li).addClass("email-sent");
} else {
$(li).append(`Error ${data.comment}`);
$(li).addClass("email-error");
}
} else {
$(li).append(`Error ${status}`);
$(li).addClass("email-error");
}
}).fail(function(jqXHR, textStatus, errorThrown) {
$(li).append(`Error ${textStatus} / ${errorThrown}`);
$(li).addClass("email-error");
}).always(() => {
if (li_list.length > 0) {
sendEmail(li_list)
} else {
$(".sending").hide()
}
})
}
</script>
<style>
.email-sent {
color: purple;
}
.email-error {
color: red;
}
.sending {
display: none;
color: darkblue;
font-size: larger;
}
.lds-ripple {
display: inline-block;
position: relative;
width: 80px;
height: 80px;
}
.lds-ripple div {
position: absolute;
border: 4px solid blue;
opacity: 1;
border-radius: 50%;
animation: lds-ripple 1s cubic-bezier(0, 0.2, 0.8, 1) infinite;
}
.lds-ripple div:nth-child(2) {
animation-delay: -0.5s;
}
@keyframes lds-ripple {
0% {
top: 36px;
left: 36px;
width: 0;
height: 0;
opacity: 1;
}
100% {
top: 0px;
left: 0px;
width: 72px;
height: 72px;
opacity: 0;
}
}
</style>
<h2>Emails sent:</h2>
{% for u in sent %}
<p>{{u.cid}}: {{u.email}}</p>
{% endfor %}
<h2>Emails not sent:</h2>
{% for u, msg in not_sent %}
<p>{{u.cid}}: {{u.email}} [{{msg}}]</p>
{% endfor %}
{% endblock %}
+18 -3
View File
@@ -26,12 +26,27 @@ urlpatterns = [
),
name="examination-autocomplete",
),
path("cids/manage/<int:pk>/update", views.CidUserUpdate.as_view(), name="update_cid"),
path(
"cids/manage/<int:pk>/update", views.CidUserUpdate.as_view(), name="update_cid"
),
path(
"cids/manage/<int:cid>/email_results",
views.candidate_email_results,
name="candidate_email_results",
),
path("cids/manage/", views.CidUserView.as_view(), name="manage_cids"),
path("cids/manage/exams", views.CidUserExamView.as_view(), name="manage_cid_exams"),
path("cids/group/", views.group_view, name="group_view"),
path("cids/group/<int:pk>/email", views.group_email, name="group_email"),
path("cids/group/<int:pk>/email_results", views.group_email_results, name="group_email_results"),
path("cids/group/<int:pk>/email/resend", views.group_email_resend, name="group_email_resend"),
path(
"cids/group/<int:pk>/email_results",
views.group_email_results,
name="group_email_results",
),
path(
"cids/group/<int:pk>/email/resend",
views.group_email_resend,
name="group_email_resend",
),
path("cids/create", views.manage_cid_users, name="manage_cid_users"),
]
+21 -12
View File
@@ -1415,31 +1415,40 @@ def group_email(request, pk, resend=False):
)
@login_required
@user_is_cid_user_manager
def group_email_results(request, pk, resend=False):
group = get_object_or_404(CidUserGroup, pk=pk)
if resend:
users = group.ciduser_set.filter()
users = group.ciduser_set.filter(internal_candidate=True)
else:
users = group.ciduser_set.filter(results_email_sent=False)
users = group.ciduser_set.filter(internal_candidate=True, results_email_sent=False)
sent = []
not_sent = []
for u in users:
success, msg = u.email_results(resend=resend)
if success:
sent.append(u)
else:
not_sent.append((u, msg))
#sent = []
#not_sent = []
#for u in users:
# success, msg = u.email_results(resend=resend)
# if success:
# sent.append(u)
# else:
# not_sent.append((u, msg))
return render(
request,
"generic/group_emailed.html",
{"sent": sent, "not_sent": not_sent, "users_count": users.count()},
#{"sent": sent, "not_sent": not_sent, "users_count": users.count()},
{"users": users, "users_count": users.count()},
)
@user_is_cid_user_manager
def candidate_email_results(request, cid, resend=False):
user = CidUser.objects.get(cid=cid)
email_sent, comment = user.email_results()
return JsonResponse({"sent": email_sent, "comment": comment})
@login_required
@user_is_cid_user_manager
+4 -2
View File
@@ -1,3 +1,4 @@
from generic.decorators import user_is_cid_user_manager
from generic.views import get_question_and_content_type
from django.core.exceptions import PermissionDenied
from django.shortcuts import render, get_object_or_404, redirect
@@ -85,7 +86,8 @@ def cid_scores_admin(request, cid):
@login_required
@user_passes_test(lambda u: u.is_superuser)
#@user_passes_test(lambda u: u.is_superuser)
@user_is_cid_user_manager
def cid_results(request, cid):
cid_user = CidUser.objects.filter(cid=cid).first()
@@ -122,7 +124,7 @@ def cid_scores(request, pk, passcode):
"longs": (LongsCidUserAnswer, LongsExam),
"sbas": (SbasCidUserAnswer, SbasExam),
}
kwargs = {"exam_mode": True}
kwargs = {"exam_mode": True, "archive": False}
exams = []
for exam_type in EXAM_ANSWER_MAP: