.
This commit is contained in:
@@ -0,0 +1,17 @@
|
|||||||
|
# Generated by Django 3.2.13 on 2022-06-30 20:45
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('anatomy', '0065_exam_exam_results_emailed'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='exam',
|
||||||
|
name='stats_graph',
|
||||||
|
),
|
||||||
|
]
|
||||||
+1
-1
@@ -1538,7 +1538,7 @@ def collection_scores_cid(request, pk):
|
|||||||
collection.stats_min = min(user_scores_list)
|
collection.stats_min = min(user_scores_list)
|
||||||
collection.stats_max = max(user_scores_list)
|
collection.stats_max = max(user_scores_list)
|
||||||
|
|
||||||
collection.stats_graph = fig_html
|
#collection.stats_graph = fig_html
|
||||||
|
|
||||||
collection.user_scores = user_scores
|
collection.user_scores = user_scores
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -138,7 +138,7 @@ class ExamBase(models.Model):
|
|||||||
|
|
||||||
stats_max_possible = models.FloatField(default=0)
|
stats_max_possible = models.FloatField(default=0)
|
||||||
|
|
||||||
stats_graph = models.TextField(default=0)
|
#stats_graph = models.TextField(default=0)
|
||||||
|
|
||||||
user_scores = models.JSONField(default=dict)
|
user_scores = models.JSONField(default=dict)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
<ul>
|
||||||
|
{% for user, status in status.items %}
|
||||||
|
<li class='{% if status.0 %}text-success{% else %}text-warning{% endif %}'>
|
||||||
|
{{user.username}} {% if status.0 %}success{% else %}failed [{{status.1}}]{% endif %} ({{status.2}})
|
||||||
|
<button hx-get="{% url exam.app_name|add:':exam_user_report_email' exam_id=exam.pk user_id=user.pk %}"
|
||||||
|
hx-prompt="Enter any additional emails"
|
||||||
|
hx-confirm="Are you sure you wish to delete your account?"
|
||||||
|
hx-trigger="click, click from:#test"
|
||||||
|
>Resend</button>
|
||||||
|
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
<button id="test">Test</button>
|
||||||
@@ -92,8 +92,11 @@
|
|||||||
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-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"
|
||||||
|
hx-get="{% url exam.app_name|add:':exam_report_email_status' exam_id=exam.pk %}"
|
||||||
|
hx-target="#user-details">Check email status</button>
|
||||||
<p>Note: currently only works with registered users</p>
|
<p>Note: currently only works with registered users</p>
|
||||||
|
<div id="user-details"></div>
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -135,9 +138,9 @@
|
|||||||
evt.preventDefault();
|
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 %}";
|
||||||
})
|
//})
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
+26
-15
@@ -588,8 +588,17 @@ class ExamViews(View, LoginRequiredMixin):
|
|||||||
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)
|
user_exam = exam.get_or_create_cid_user_exam(user_user=user)
|
||||||
status[user.username] = user_exam.results_emailed_status
|
status[user] = json.loads(user_exam.results_emailed_status)
|
||||||
|
|
||||||
|
return render(
|
||||||
|
request,
|
||||||
|
"generic/exam_report_email_status.html",
|
||||||
|
{
|
||||||
|
"exam": exam,
|
||||||
|
"status": status,
|
||||||
|
"app_name": self.app_name,
|
||||||
|
},
|
||||||
|
)
|
||||||
return JsonResponse(status)
|
return JsonResponse(status)
|
||||||
|
|
||||||
@method_decorator(login_required)
|
@method_decorator(login_required)
|
||||||
@@ -597,7 +606,7 @@ class ExamViews(View, LoginRequiredMixin):
|
|||||||
return self.exam_report_email(request, exam_id, unsent_only=True)
|
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, unsent_only=False):
|
def exam_report_email(self, request, exam_id, unsent_only=False, users=None):
|
||||||
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():
|
||||||
@@ -616,7 +625,8 @@ class ExamViews(View, LoginRequiredMixin):
|
|||||||
|
|
||||||
# We only need to send emails to those who have scores
|
# We only need to send emails to those who have scores
|
||||||
# (who should be in exam.user_scores)
|
# (who should be in exam.user_scores)
|
||||||
users = [i[2:] for i in exam.user_scores if i.startswith("u/")]
|
if users is None:
|
||||||
|
users = [i[2:] for i in exam.user_scores if i.startswith("u/")]
|
||||||
|
|
||||||
time = timezone.now()
|
time = timezone.now()
|
||||||
|
|
||||||
@@ -631,11 +641,11 @@ class ExamViews(View, LoginRequiredMixin):
|
|||||||
|
|
||||||
|
|
||||||
if additional_email:
|
if additional_email:
|
||||||
email_results[user.username] = exam.email_user_results(user, additional_emails=[additional_email])
|
email_results[user.pk] = exam.email_user_results(user, additional_emails=[additional_email])
|
||||||
else:
|
else:
|
||||||
email_results[user.username] = exam.email_user_results(user)
|
email_results[user.pk] = exam.email_user_results(user)
|
||||||
email_results[user.username].append(f" {time}")
|
email_results[user.pk].append(f"{time}")
|
||||||
user_exam.results_emailed_status = json.dumps(email_results[user.username])
|
user_exam.results_emailed_status = json.dumps(email_results[user.pk])
|
||||||
|
|
||||||
user_exam.save()
|
user_exam.save()
|
||||||
|
|
||||||
@@ -646,20 +656,21 @@ class ExamViews(View, LoginRequiredMixin):
|
|||||||
|
|
||||||
@method_decorator(login_required)
|
@method_decorator(login_required)
|
||||||
def exam_user_report_email(self, request, exam_id, user_id):
|
def exam_user_report_email(self, request, exam_id, user_id):
|
||||||
|
return self.exam_report_email(request, exam_id, users=[user_id])
|
||||||
# print(Exam.objects.all())
|
# print(Exam.objects.all())
|
||||||
# exams = Exam.objects.all()
|
# exams = Exam.objects.all()
|
||||||
# print("test", Exam.objects.all().get(id=pk))
|
# print("test", Exam.objects.all().get(id=pk))
|
||||||
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)
|
||||||
|
|
||||||
u = get_object_or_404(User, pk=user_id)
|
#u = get_object_or_404(User, pk=user_id)
|
||||||
|
|
||||||
if request.user not in exam.author.all():
|
#if request.user not in exam.author.all():
|
||||||
if not self.check_user_access(request.user, exam_id):
|
# if not self.check_user_access(request.user, exam_id):
|
||||||
raise PermissionDenied
|
# raise PermissionDenied
|
||||||
|
|
||||||
res = exam.email_user_results(u)
|
#res = exam.email_user_results(u)
|
||||||
|
|
||||||
return HttpResponse(res)
|
#return HttpResponse(res)
|
||||||
|
|
||||||
@method_decorator(login_required)
|
@method_decorator(login_required)
|
||||||
def exam_user_report(self, request, exam_id, user_id):
|
def exam_user_report(self, request, exam_id, user_id):
|
||||||
@@ -1654,7 +1665,7 @@ class ExamViews(View, LoginRequiredMixin):
|
|||||||
exam.stats_min = min(user_scores_list)
|
exam.stats_min = min(user_scores_list)
|
||||||
exam.stats_max = max(user_scores_list)
|
exam.stats_max = max(user_scores_list)
|
||||||
|
|
||||||
exam.stats_graph = fig_html
|
#exam.stats_graph = fig_html
|
||||||
|
|
||||||
user_data = {}
|
user_data = {}
|
||||||
for u in cids:
|
for u in cids:
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
# Generated by Django 3.2.13 on 2022-06-30 20:45
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('longs', '0063_exam_exam_results_emailed'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='exam',
|
||||||
|
name='stats_graph',
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
# Generated by Django 3.2.13 on 2022-06-30 20:45
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('physics', '0025_exam_exam_results_emailed'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='exam',
|
||||||
|
name='stats_graph',
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -71,6 +71,7 @@ INSTALLED_APPS = [
|
|||||||
"rest_framework",
|
"rest_framework",
|
||||||
"tinymce",
|
"tinymce",
|
||||||
"django_unused_media",
|
"django_unused_media",
|
||||||
|
"django_htmx",
|
||||||
]
|
]
|
||||||
|
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
@@ -84,6 +85,8 @@ MIDDLEWARE = [
|
|||||||
"django.contrib.messages.middleware.MessageMiddleware",
|
"django.contrib.messages.middleware.MessageMiddleware",
|
||||||
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
||||||
"reversion.middleware.RevisionMiddleware",
|
"reversion.middleware.RevisionMiddleware",
|
||||||
|
"django_htmx.middleware.HtmxMiddleware",
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
ROOT_URLCONF = "rad.urls"
|
ROOT_URLCONF = "rad.urls"
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
# Generated by Django 3.2.13 on 2022-06-30 20:45
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('rapids', '0060_exam_exam_results_emailed'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='exam',
|
||||||
|
name='stats_graph',
|
||||||
|
),
|
||||||
|
]
|
||||||
+2
-1
@@ -28,4 +28,5 @@ django_unused_media
|
|||||||
pytest-django
|
pytest-django
|
||||||
gunicorn
|
gunicorn
|
||||||
rich
|
rich
|
||||||
bs4
|
bs4
|
||||||
|
django-htmx
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
# Generated by Django 3.2.13 on 2022-06-30 20:45
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('sbas', '0015_exam_exam_results_emailed'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='exam',
|
||||||
|
name='stats_graph',
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
<!DOCTYPE HTML>
|
<!DOCTYPE HTML>
|
||||||
{% load static %}
|
{% load static %}
|
||||||
|
{% load django_htmx %}
|
||||||
<html>
|
<html>
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
@@ -24,6 +25,9 @@
|
|||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/core.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/core.js"></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/md5.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/md5.js"></script>
|
||||||
|
|
||||||
|
<script src="https://unpkg.com/alpinejs" defer></script>
|
||||||
|
<script src="https://unpkg.com/htmx.org@1.7.0/dist/htmx.min.js" defer></script>
|
||||||
|
{% django_htmx_script %}
|
||||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
|
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
|
||||||
<script src="{% static 'admin/js/core.js' %}"></script>
|
<script src="{% static 'admin/js/core.js' %}"></script>
|
||||||
<script src="{% static 'admin/js/SelectBox.js' %}"></script>
|
<script src="{% static 'admin/js/SelectBox.js' %}"></script>
|
||||||
|
|||||||
Reference in New Issue
Block a user