.
This commit is contained in:
@@ -72,6 +72,7 @@ urlpatterns = [
|
|||||||
),
|
),
|
||||||
path("exam/<int:pk>/", views.GenericExamViews.exam_overview, name="exam_overview"),
|
path("exam/<int:pk>/", views.GenericExamViews.exam_overview, name="exam_overview"),
|
||||||
path("exam/<int:exam_id>/report/email", views.GenericExamViews.exam_report_email, name="exam_report_email"),
|
path("exam/<int:exam_id>/report/email", views.GenericExamViews.exam_report_email, name="exam_report_email"),
|
||||||
|
path("exam/<int:exam_id>/report/email_unsent", views.GenericExamViews.exam_report_email_unsent, name="exam_report_email_unsent"),
|
||||||
path("exam/<int:exam_id>/report/email/status", views.GenericExamViews.exam_report_email_status, name="exam_report_email_status"),
|
path("exam/<int:exam_id>/report/email/status", views.GenericExamViews.exam_report_email_status, name="exam_report_email_status"),
|
||||||
path("exam/<int:exam_id>/report/<int:user_id>", views.GenericExamViews.exam_user_report, name="exam_user_report"),
|
path("exam/<int:exam_id>/report/<int:user_id>", views.GenericExamViews.exam_user_report, name="exam_user_report"),
|
||||||
path("exam/<int:exam_id>/report/<int:user_id>/email", views.GenericExamViews.exam_user_report_email, name="exam_user_report_email"),
|
path("exam/<int:exam_id>/report/<int:user_id>/email", views.GenericExamViews.exam_user_report_email, name="exam_user_report_email"),
|
||||||
|
|||||||
+6
-5
@@ -324,7 +324,7 @@ class ExamBase(models.Model):
|
|||||||
|
|
||||||
return msg
|
return msg
|
||||||
|
|
||||||
def email_user_results(self, user, resend=False, additional_emails=list):
|
def email_user_results(self, user, resend=False, additional_emails=None):
|
||||||
#if self.results_email_sent and not resend:
|
#if self.results_email_sent and not resend:
|
||||||
# return False, "Already sent."
|
# return False, "Already sent."
|
||||||
|
|
||||||
@@ -332,7 +332,7 @@ class ExamBase(models.Model):
|
|||||||
msg = self.generate_user_report(user)
|
msg = self.generate_user_report(user)
|
||||||
|
|
||||||
if not user.email:
|
if not user.email:
|
||||||
return False, "User has no email"
|
return [False, "User has no email"]
|
||||||
|
|
||||||
emails = [user.email]
|
emails = [user.email]
|
||||||
|
|
||||||
@@ -342,7 +342,7 @@ class ExamBase(models.Model):
|
|||||||
emails.append(supervisor_email)
|
emails.append(supervisor_email)
|
||||||
|
|
||||||
|
|
||||||
if additional_emails:
|
if additional_emails is not None:
|
||||||
emails.extend(additional_emails)
|
emails.extend(additional_emails)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -355,11 +355,11 @@ class ExamBase(models.Model):
|
|||||||
# html_message=html_msg,
|
# html_message=html_msg,
|
||||||
)
|
)
|
||||||
except SMTPException as e:
|
except SMTPException as e:
|
||||||
return False, e
|
return [False, e]
|
||||||
|
|
||||||
#self.results_email_sent = True
|
#self.results_email_sent = True
|
||||||
#self.save()
|
#self.save()
|
||||||
return True, ""
|
return [True, ""]
|
||||||
|
|
||||||
|
|
||||||
class NoteType(models.Model):
|
class NoteType(models.Model):
|
||||||
@@ -608,6 +608,7 @@ class CidUserExam(models.Model):
|
|||||||
|
|
||||||
manual_submission = models.BooleanField(default=False)
|
manual_submission = models.BooleanField(default=False)
|
||||||
|
|
||||||
|
# TODO switch to json field?
|
||||||
results_emailed_status = models.CharField(max_length=255, blank=True)
|
results_emailed_status = models.CharField(max_length=255, blank=True)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -91,6 +91,7 @@
|
|||||||
<summary>Email results</summary>
|
<summary>Email results</summary>
|
||||||
User results emailed: {{exam.exam_results_emailed|default:"Never"}}<br/>
|
User results emailed: {{exam.exam_results_emailed|default:"Never"}}<br/>
|
||||||
<button id="email-results-button" title="Email results to users and their supervisors">Email user results</button>
|
<button id="email-results-button" title="Email results to users and their supervisors">Email user results</button>
|
||||||
|
<button id="email-unsent-results-button" title="Email results to users and their supervisors">Email unsent user results</button>
|
||||||
<button id="email-results-check-button" title="Check the status of emailed results">Check email status</button>
|
<button id="email-results-check-button" title="Check the status of emailed results">Check email status</button>
|
||||||
<p>Note: currently only works with registered users</p>
|
<p>Note: currently only works with registered users</p>
|
||||||
</details>
|
</details>
|
||||||
@@ -116,6 +117,23 @@
|
|||||||
}
|
}
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
|
|
||||||
|
})
|
||||||
|
$("#email-unsent-results-button").click((evt) => {
|
||||||
|
if (confirm("This will email results, please make sure scores have been refreshed before continuing")) {
|
||||||
|
|
||||||
|
let additional_email = prompt("Please enter an additional email to send to (user and supervisor will automatically be used if available) if required");
|
||||||
|
|
||||||
|
let url = "{% url exam.app_name|add:':exam_report_email_unsent' exam_id=exam.pk %}";
|
||||||
|
|
||||||
|
if ( additional_email != null ) {
|
||||||
|
url = url + "?additional_email="+encodeURI(additional_email)
|
||||||
|
}
|
||||||
|
|
||||||
|
window.location = url;
|
||||||
|
|
||||||
|
}
|
||||||
|
evt.preventDefault();
|
||||||
|
|
||||||
})
|
})
|
||||||
$("#email-results-check-button").click((evt) => {
|
$("#email-results-check-button").click((evt) => {
|
||||||
window.location = "{% url exam.app_name|add:':exam_report_email_status' exam_id=exam.pk %}";
|
window.location = "{% url exam.app_name|add:':exam_report_email_status' exam_id=exam.pk %}";
|
||||||
|
|||||||
+29
-3
@@ -560,6 +560,20 @@ class ExamViews(View, LoginRequiredMixin):
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@method_decorator(login_required)
|
||||||
|
def exam_user(self, request, exam_id, user_id):
|
||||||
|
exam = get_object_or_404(self.Exam.objects.prefetch_related("author"), pk=exam_id)
|
||||||
|
|
||||||
|
if request.user not in exam.author.all():
|
||||||
|
if not self.check_user_access(request.user, exam_id):
|
||||||
|
raise PermissionDenied
|
||||||
|
|
||||||
|
user = User.objects.get(pk=user_id)
|
||||||
|
user_exam = exam.get_or_create_cid_user_exam(user_user=user)
|
||||||
|
|
||||||
|
return JsonResponse(model_to_dict(user_exam))
|
||||||
|
|
||||||
|
|
||||||
@method_decorator(login_required)
|
@method_decorator(login_required)
|
||||||
def exam_report_email_status(self, request, exam_id):
|
def exam_report_email_status(self, request, exam_id):
|
||||||
exam = get_object_or_404(self.Exam.objects.prefetch_related("author"), pk=exam_id)
|
exam = get_object_or_404(self.Exam.objects.prefetch_related("author"), pk=exam_id)
|
||||||
@@ -578,9 +592,12 @@ class ExamViews(View, LoginRequiredMixin):
|
|||||||
|
|
||||||
return JsonResponse(status)
|
return JsonResponse(status)
|
||||||
|
|
||||||
|
@method_decorator(login_required)
|
||||||
|
def exam_report_email_unsent(self, request, exam_id):
|
||||||
|
return self.exam_report_email(request, exam_id, unsent_only=True)
|
||||||
|
|
||||||
@method_decorator(login_required)
|
@method_decorator(login_required)
|
||||||
def exam_report_email(self, request, exam_id):
|
def exam_report_email(self, request, exam_id, unsent_only=False):
|
||||||
exam = get_object_or_404(self.Exam.objects.prefetch_related("author"), pk=exam_id)
|
exam = get_object_or_404(self.Exam.objects.prefetch_related("author"), pk=exam_id)
|
||||||
|
|
||||||
if request.user not in exam.author.all():
|
if request.user not in exam.author.all():
|
||||||
@@ -606,13 +623,22 @@ class ExamViews(View, LoginRequiredMixin):
|
|||||||
email_results = {}
|
email_results = {}
|
||||||
for u in users:
|
for u in users:
|
||||||
user = User.objects.get(pk=u)
|
user = User.objects.get(pk=u)
|
||||||
|
user_exam = exam.get_or_create_cid_user_exam(user_user=user)
|
||||||
|
|
||||||
|
if unsent_only and user_exam.results_emailed_status:
|
||||||
|
continue
|
||||||
|
#print(user, user_exam.results_emailed_status)
|
||||||
|
#if json.loads(user_exam.results_emailed_status)[0] == True:
|
||||||
|
# continue
|
||||||
|
|
||||||
|
|
||||||
if additional_email:
|
if additional_email:
|
||||||
email_results[user.username] = exam.email_user_results(user, additional_emails=[additional_email])
|
email_results[user.username] = exam.email_user_results(user, additional_emails=[additional_email])
|
||||||
else:
|
else:
|
||||||
email_results[user.username] = exam.email_user_results(user)
|
email_results[user.username] = exam.email_user_results(user)
|
||||||
|
email_results[user.username].append(f" {time}")
|
||||||
|
user_exam.results_emailed_status = json.dumps(email_results[user.username])
|
||||||
|
|
||||||
user_exam = exam.get_or_create_cid_user_exam(user_user=user)
|
|
||||||
user_exam.results_emailed_status = json.dumps(email_results[user.username]) + f" {time}"
|
|
||||||
user_exam.save()
|
user_exam.save()
|
||||||
|
|
||||||
exam.exam_results_emailed = time
|
exam.exam_results_emailed = time
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ urlpatterns = [
|
|||||||
),
|
),
|
||||||
path("exam/<int:pk>/", views.GenericExamViews.exam_overview, name="exam_overview"),
|
path("exam/<int:pk>/", views.GenericExamViews.exam_overview, name="exam_overview"),
|
||||||
path("exam/<int:exam_id>/report/email", views.GenericExamViews.exam_report_email, name="exam_report_email"),
|
path("exam/<int:exam_id>/report/email", views.GenericExamViews.exam_report_email, name="exam_report_email"),
|
||||||
|
path("exam/<int:exam_id>/report/email_unsent", views.GenericExamViews.exam_report_email_unsent, name="exam_report_email_unsent"),
|
||||||
path("exam/<int:exam_id>/report/email/status", views.GenericExamViews.exam_report_email_status, name="exam_report_email_status"),
|
path("exam/<int:exam_id>/report/email/status", views.GenericExamViews.exam_report_email_status, name="exam_report_email_status"),
|
||||||
path("exam/<int:exam_id>/report/<int:user_id>", views.GenericExamViews.exam_user_report, name="exam_user_report"),
|
path("exam/<int:exam_id>/report/<int:user_id>", views.GenericExamViews.exam_user_report, name="exam_user_report"),
|
||||||
path("exam/<int:exam_id>/report/<int:user_id>/email", views.GenericExamViews.exam_user_report_email, name="exam_user_report_email"),
|
path("exam/<int:exam_id>/report/<int:user_id>/email", views.GenericExamViews.exam_user_report_email, name="exam_user_report_email"),
|
||||||
|
|||||||
@@ -72,7 +72,9 @@ urlpatterns = [
|
|||||||
name="exam_question_detail",
|
name="exam_question_detail",
|
||||||
),
|
),
|
||||||
path("exam/<int:pk>/", views.GenericExamViews.exam_overview, name="exam_overview"),
|
path("exam/<int:pk>/", views.GenericExamViews.exam_overview, name="exam_overview"),
|
||||||
|
path("exam/<int:exam_id>/user/<int:user_id>", views.GenericExamViews.exam_user, name="exam_user"),
|
||||||
path("exam/<int:exam_id>/report/email", views.GenericExamViews.exam_report_email, name="exam_report_email"),
|
path("exam/<int:exam_id>/report/email", views.GenericExamViews.exam_report_email, name="exam_report_email"),
|
||||||
|
path("exam/<int:exam_id>/report/email_unsent", views.GenericExamViews.exam_report_email_unsent, name="exam_report_email_unsent"),
|
||||||
path("exam/<int:exam_id>/report/email/status", views.GenericExamViews.exam_report_email_status, name="exam_report_email_status"),
|
path("exam/<int:exam_id>/report/email/status", views.GenericExamViews.exam_report_email_status, name="exam_report_email_status"),
|
||||||
path("exam/<int:exam_id>/report/<int:user_id>", views.GenericExamViews.exam_user_report, name="exam_user_report"),
|
path("exam/<int:exam_id>/report/<int:user_id>", views.GenericExamViews.exam_user_report, name="exam_user_report"),
|
||||||
path("exam/<int:exam_id>/report/<int:user_id>/email", views.GenericExamViews.exam_user_report_email, name="exam_user_report_email"),
|
path("exam/<int:exam_id>/report/<int:user_id>/email", views.GenericExamViews.exam_user_report_email, name="exam_user_report_email"),
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ urlpatterns = [
|
|||||||
),
|
),
|
||||||
path("exam/<int:pk>/", views.GenericExamViews.exam_overview, name="exam_overview"),
|
path("exam/<int:pk>/", views.GenericExamViews.exam_overview, name="exam_overview"),
|
||||||
path("exam/<int:exam_id>/report/email", views.GenericExamViews.exam_report_email, name="exam_report_email"),
|
path("exam/<int:exam_id>/report/email", views.GenericExamViews.exam_report_email, name="exam_report_email"),
|
||||||
|
path("exam/<int:exam_id>/report/email_unsent", views.GenericExamViews.exam_report_email_unsent, name="exam_report_email_unsent"),
|
||||||
path("exam/<int:exam_id>/report/email/status", views.GenericExamViews.exam_report_email_status, name="exam_report_email_status"),
|
path("exam/<int:exam_id>/report/email/status", views.GenericExamViews.exam_report_email_status, name="exam_report_email_status"),
|
||||||
path("exam/<int:exam_id>/report/<int:user_id>", views.GenericExamViews.exam_user_report, name="exam_user_report"),
|
path("exam/<int:exam_id>/report/<int:user_id>", views.GenericExamViews.exam_user_report, name="exam_user_report"),
|
||||||
path("exam/<int:exam_id>/report/<int:user_id>/email", views.GenericExamViews.exam_user_report_email, name="exam_user_report_email"),
|
path("exam/<int:exam_id>/report/<int:user_id>/email", views.GenericExamViews.exam_user_report_email, name="exam_user_report_email"),
|
||||||
|
|||||||
Reference in New Issue
Block a user