Files
penracourses/rad/views.py
T

727 lines
23 KiB
Python

import secrets
from django_tables2 import SingleTableMixin
from atlas.models import CaseCollection, CidReportAnswer
from generic.decorators import user_is_cid_user_manager
from generic.filters import UserUserFilter
from generic.tables import UserUserTable
from generic.views import CidManagerRequiredMixin, get_question_and_content_type
from django.core.exceptions import PermissionDenied, ObjectDoesNotExist
from django.shortcuts import render, get_object_or_404, redirect
from django.views.decorators.csrf import csrf_exempt
from django import forms
from django.utils.html import format_html
# from django.contrib.auth.models import User
from django.contrib.auth.decorators import login_required, user_passes_test
from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from django.views.generic import ListView, TemplateView
from django.db.models.functions import Lower
from django.core.cache import cache
from django.urls import reverse_lazy, reverse
from django.http import Http404, JsonResponse
from django.http import HttpResponseRedirect, HttpResponse
from physics.models import CidUserAnswer as PhysicsCidUserAnswer, Question
from physics.models import Exam as PhysicsExam
from physics.models import Question as SbasQuestion
from anatomy.models import CidUserAnswer as AnatomyCidUserAnswer
from anatomy.models import Exam as AnatomyExam
from anatomy.models import AnatomyQuestion
from anatomy.models import Answer as AnatomyAnswer
from rad.filters import UserListFilter
from rapids.models import CidUserAnswer as RapidsCidUserAnswer
from rapids.models import Exam as RapidsExam
from rapids.models import Rapid
from rapids.models import Answer as RapidAnswer
from longs.models import CidUserAnswer as LongsCidUserAnswer
from longs.models import Exam as LongsExam
from longs.models import Long
from sbas.models import CidUserAnswer as SbasCidUserAnswer
from sbas.models import Exam as SbasExam
from sbas.models import Question as SbasQuestion
from anatomy.views import GenericExamViews as AnatomyExamViews
from rapids.views import GenericExamViews as RapidsExamsViews
from longs.views import GenericExamViews as LongsExamViews
from generic.forms import QuestionNoteForm
from generic.models import CidUser, QuestionNote, Supervisor, UserGrades, UserProfile
from django_filters.views import FilterView
import json
from django.template import RequestContext
def feedback_checker(user):
return user.groups.filter(name="feedback_checker").exists()
@login_required
def profile(request):
user = request.user
return render(request, "profile.html", {"user": user})
@user_is_cid_user_manager
def account_profile(request, slug):
user = get_object_or_404(User, username=slug)
return render(request, "profile.html", {"user": user})
def cid_selector(request):
return render(
request,
"cid_selector.html",
)
@login_required
@user_passes_test(lambda u: u.is_superuser)
def cid_scores_admin(request, cid):
cid_user = CidUser.objects.filter(cid=cid).first()
return cid_scores(request, cid_user.cid, cid_user.passcode)
@login_required
# @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()
if not cid_user:
raise Http404("CID not found")
report = cid_user.generate_exam_report()
return render(
request,
"cid_results.html",
{
"report": report,
},
)
@login_required
def user_scores(request):
# exam = get_object_or_404(Exam, pk=pk)
#cid = pk
#cid_user = CidUser.objects.filter(cid=cid).first()
#print(cid_user)
#if not cid_user or cid_user.passcode != passcode:
# raise Http404("CID / Passcode combination not found")
#print(cid_user.passcode)
# questions = exam.exam_questions.all()
EXAM_ANSWER_MAP = {
"physics": (PhysicsCidUserAnswer, PhysicsExam),
"anatomy": (AnatomyCidUserAnswer, AnatomyExam),
"rapids": (RapidsCidUserAnswer, RapidsExam),
"longs": (LongsCidUserAnswer, LongsExam),
"sbas": (SbasCidUserAnswer, SbasExam),
}
kwargs = {"exam_mode": True, "archive": False}
exams = []
for exam_type in EXAM_ANSWER_MAP:
CidUserAnswer, Exam = EXAM_ANSWER_MAP[exam_type]
exam_answers = CidUserAnswer.objects.filter(user=request.user)
exam_ids = exam_answers.values_list("exam").distinct()
exams_to_add = Exam.objects.filter(id__in=exam_ids, **kwargs)
if exams_to_add:
exams.append((exam_type, exams_to_add))
#case_collections = request.user.casecollection_exams.all()
USER_EXAM_TYPES = (
("Physics", "user_physics_exams"),
("Rapids", "user_rapid_exams"),
("SBAs", "user_sba_exams"),
("Anatomy", "user_anatomy_exams"),
("Longs", "user_longs_exams"),
#("CaseCollection", "user_casecollection_exams"),
)
available_exams = []
for n, t in USER_EXAM_TYPES:
exam_rel = getattr(request.user, t)
if exam_rel.exists():
temp_exams = exam_rel.filter(exam_mode=True, archive=False).order_by("name")
available_exams.append((n, temp_exams))
#available_exams = request.user.get_cid_exams()
return render(
request,
"user_scores.html",
{
# "physics_exams": physics_exams,
# "anatomy_exams": anatomy_exams,
# "rapid_exams": rapid_exams,
# "longs_exams": longs_exams,
# "sba_exams": sba_exams,
"all_exams": exams,
#"passcode": passcode,
"cid_user": request.user,
"available_exams": available_exams,
"case_collections": [],#case_collections,
},
)
def cid_scores(request, cid, passcode):
# exam = get_object_or_404(Exam, pk=pk)
cid_user = CidUser.objects.filter(cid=cid).first()
print(cid_user)
if not cid_user or cid_user.passcode != passcode:
raise Http404("CID / Passcode combination not found")
print(cid_user.passcode)
# questions = exam.exam_questions.all()
EXAM_ANSWER_MAP = {
"physics": (PhysicsCidUserAnswer, PhysicsExam),
"anatomy": (AnatomyCidUserAnswer, AnatomyExam),
"rapids": (RapidsCidUserAnswer, RapidsExam),
"longs": (LongsCidUserAnswer, LongsExam),
"sbas": (SbasCidUserAnswer, SbasExam),
}
kwargs = {"exam_mode": True, "archive": False}
exams = []
for exam_type in EXAM_ANSWER_MAP:
CidUserAnswer, Exam = EXAM_ANSWER_MAP[exam_type]
exam_answers = CidUserAnswer.objects.filter(cid=cid)
exam_ids = exam_answers.values_list("exam").distinct()
exams_to_add = Exam.objects.filter(id__in=exam_ids, **kwargs)
if exams_to_add:
exams.append((exam_type, exams_to_add))
case_collections = cid_user.casecollection_exams.all()
available_exams = cid_user.get_cid_exams()
return render(
request,
"cid_scores.html",
{
# "physics_exams": physics_exams,
# "anatomy_exams": anatomy_exams,
# "rapid_exams": rapid_exams,
# "longs_exams": longs_exams,
# "sba_exams": sba_exams,
"all_exams": exams,
"cid": cid,
"passcode": passcode,
"cid_user": cid_user,
"available_exams": available_exams,
"case_collections": case_collections,
},
)
def active_exams(request, cid=None, passcode=None, based=True):
active_exams = {}
if cid is not None:
active_exams["cid"] = cid
cid_user = CidUser.objects.filter(cid=cid).first()
if not cid_user or cid_user.passcode != passcode:
return JsonResponse({"status": "invalid"}, status=401)
anatomy_exams = AnatomyExamViews.active_exams(
request, False, cid=cid, passcode=passcode
)
rapid_exams = RapidsExamsViews.active_exams(
request, False, cid=cid, passcode=passcode
)
long_exams = LongsExamViews.active_exams(request, False, cid=cid, passcode=passcode)
exams = []
exams.extend(anatomy_exams)
exams.extend(rapid_exams)
exams.extend(long_exams)
active_exams["exams"] = exams
if request.user:
active_exams["user"] = request.user.username
active_exams["user_id"] = request.user.pk
else:
active_exams["user"] = False
return JsonResponse(active_exams)
def active_exams_unbased(request, cid=None, passcode=None):
return active_exams(request, cid, passcode, based=False)
@csrf_exempt
def exam_submit(request):
print(request)
if request.is_ajax and request.method == "POST":
print(request.POST)
exam_type, exam_id = request.POST.get("eid").split("/")
try:
if exam_type == "anatomy":
return AnatomyExamViews.postExamAnswers(request)
elif exam_type == "rapid":
return RapidsExamsViews.postExamAnswers(request)
elif exam_type == "long":
return LongsExamViews.postExamAnswers(request)
return JsonResponse({"success": False, "error": "Invalid exam type"})
except ObjectDoesNotExist:
return JsonResponse({"success": False, "error": "Invalid data"})
# postExamAnswers
return JsonResponse({"success": False, "error": "Invalid data"})
def feedback_create(request, question_type, pk):
if question_type == "anatomy":
question = AnatomyQuestion
elif question_type == "rapid":
question = Rapid
elif question_type == "long":
question = Long
return JsonResponse({"success": False, "error": "Invalid exam type"})
class AddQuestionNote(CreateView):
model = QuestionNote
form_class = QuestionNoteForm
# fields = ("author", "note_type", "note")
def get_form_kwargs(self):
kwargs = super(AddQuestionNote, self).get_form_kwargs()
# update the kwargs for the form init method with yours
kwargs.update(self.kwargs) # self.kwargs contains all url conf params
kwargs.update({"user": self.request.user})
return kwargs
def get_initial(self):
pk = self.kwargs["pk"]
self.question_type = self.kwargs["question_type"]
question, content_type = get_question_and_content_type(self.question_type)
self.question = get_object_or_404(question, pk=pk)
return {"content_type": content_type, "object_id": pk}
def get_context_data(self, **kwargs):
# This can also be accessed via view.**** in the template
context = super(AddQuestionNote, self).get_context_data(**kwargs)
context["question"] = self.question
context["question_type"] = self.question_type
return context
def form_valid(self, form):
model = form.save(commit=False)
if self.request.user.is_authenticated:
model.user_author = self.request.user
model.save()
response = super().form_valid(form)
return response
@user_passes_test(lambda u: u.is_superuser)
def feedback_note_delete(request, pk):
q = get_object_or_404(QuestionNote, pk=pk)
q.delete()
return redirect(q.get_object_url())
@login_required
def feedback_mark_complete(request, pk):
q = get_object_or_404(QuestionNote, pk=pk)
if (
request.user not in q.question.author.all()
and not request.user.groups.filter(name="feedback_checker").exists()
):
raise PermissionDenied()
q.complete = True
q.save()
return redirect(q.get_object_url())
@csrf_exempt
def answer_suggestion_submit(request):
if request.is_ajax and request.method == "POST":
post_data = json.loads(request.body)
question_type, qid = post_data["qid"].split("/")
answer_string = post_data["answer"]
status = post_data["status"]
if str(status) not in " 012":
return JsonResponse({"success": False, "error": "Invalid status"})
if question_type == "anatomy":
AnswerModel = AnatomyAnswer
question = AnatomyQuestion
elif question_type == "rapid":
AnswerModel = RapidAnswer
question = Rapid
else:
return JsonResponse({"success": False, "error": "Invalid question type"})
q = get_object_or_404(question, pk=qid)
if AnswerModel.objects.filter(answer=answer_string, question=q):
return JsonResponse({"success": False, "error": "Answer already exists"})
a = AnswerModel(question=q, answer=answer_string, status=status, proposed=True)
a.save()
return JsonResponse({"success": True, "error": "Answer submited"})
# postExamAnswers
return JsonResponse({"success": False, "error": "Invalid data"})
@login_required
def answer_submit(request):
if request.is_ajax and request.method == "POST":
qid = request.POST.get("qid")
question_type = request.POST.get("question_type")
answer_string = request.POST.get("answer")
status = request.POST.get("status")
if str(status) not in "012":
return JsonResponse({"success": False, "error": "Invalid status"})
if question_type == "anatomy":
AnswerModel = AnatomyAnswer
question = AnatomyQuestion
elif question_type == "rapid":
AnswerModel = RapidAnswer
question = Rapid
else:
return JsonResponse({"success": False, "error": "Invalid question type"})
q = get_object_or_404(question, pk=qid)
if AnswerModel.objects.filter(answer=answer_string, question=q):
return JsonResponse({"success": False, "error": "Answer already exists"})
a = AnswerModel(question=q, answer=answer_string, status=status)
a.save()
return JsonResponse({"success": True, "error": "Answer added"})
return JsonResponse({"success": False, "error": "Invalid data"})
@login_required
def answer_suggestion_confirm(request):
if request.is_ajax and request.method == "POST":
question_type = request.POST.get("question_type")
aid = request.POST.get("aid")
status = request.POST.get("status")
if question_type == "anatomy":
AnswerModel = AnatomyAnswer
question = AnatomyQuestion
elif question_type == "rapid":
AnswerModel = RapidAnswer
question = Rapid
else:
return JsonResponse({"success": False, "error": "Invalid question type"})
answer = get_object_or_404(AnswerModel, pk=aid)
answer.proposed = False
answer.status = status
answer.save()
return JsonResponse({"success": True, "error": "Answer changed"})
@login_required
@user_passes_test(feedback_checker)
def view_feedback(request):
# exam = get_object_or_404(Exam, pk=pk)
feedback_notes = QuestionNote.objects.filter(complete=False)
return render(
request,
"view_feedback.html",
{
"notes": feedback_notes,
},
)
def privacy_view(request):
return render(request, "privacy.html")
# HTTP Error 400
def page_not_found(request, exception):
response = render(request, "404.html")
response.status_code = 404
return response
def page_forbidden(request, exception):
response = render(request, "403.html")
response.status_code = 403
return response
def server_error(request):
response = render(request, "500.html")
response.status_code = 500
return response
class UserListView(CidManagerRequiredMixin, FilterView):
model = User
template_name = "user_list_view.html"
filterset_class = UserListFilter
class UserListTableView(CidManagerRequiredMixin, SingleTableMixin, FilterView):
model = User
table_class = UserUserTable
template_name = "generic/user_view.html"
filterset_class = UserUserFilter
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
# user = self.request.user
#filters = {"archive": False, "exam_mode": True}
#physics_exams = [(i.name, i.pk) for i in PhysicsExam.objects.filter(**filters)]
#rapid_exams = [(i.name, i.pk) for i in RapidExam.objects.filter(**filters)]
#sba_exams = [(i.name, i.pk) for i in SbasExam.objects.filter(**filters)]
#longs_exams = [(i.name, i.pk) for i in LongExam.objects.filter(**filters)]
#anatomy_exams = [(i.name, i.pk) for i in AnatomyExam.objects.filter(**filters)]
#casecollection_exams = [
# (i.name, i.pk)
# for i in CaseCollection.objects.filter(archive=False, collection_type__gt=0)
#]
#context["physics_exams"] = physics_exams
#context["rapid_exams"] = rapid_exams
#context["sba_exams"] = sba_exams
#context["longs_exams"] = longs_exams
#context["anatomy_exams"] = anatomy_exams
#context["casecollection_exams"] = casecollection_exams
#cid_user_groups = [
# (i.name, i.pk) for i in CidUserGroup.objects.filter(archive=False)
#]
#context["cid_user_groups"] = cid_user_groups
return context
class UpdateUserView(CidManagerRequiredMixin, UpdateView):
model = User
fields = ["first_name", "last_name", "email"] # Keep listing whatever fields
# the combined UserProfile and User exposes.
template_name = "user_update.html"
slug_field = "username"
slug_url_kwarg = "slug"
def get_success_url(self):
view_name = 'account_profile'
# No need for reverse_lazy here, because it's called inside the method
return reverse(view_name, kwargs={'slug': self.object.username})
class UpdateUserProfileView(CidManagerRequiredMixin, UpdateView):
model = UserProfile
fields = [
"supervisor",
"grade",
"registration_number",
"peninsula_trainee",
] # Keep listing whatever fields
template_name = "user_update_profile.html"
slug_field = "user__username"
slug_url_kwarg = "slug"
def get_success_url(self):
view_name = 'account_profile'
# No need for reverse_lazy here, because it's called inside the method
return reverse(view_name, kwargs={'slug': self.object.username})
# class UpdateUser(TemplateView):
#
# user_form_class = UserForm
# comment_form_class = UserProfileForm
# template_name = 'user_update.html'
# slug_field = 'username'
# slug_url_kwarg = 'slug'
#
# def post(self, request):
# post_data = request.POST or None
# user_form = self.user_form_class(post_data, prefix='user')
# profile_form = self.profile_form_class(post_data, prefix='userprofile')
#
# context = self.get_context_data(post_form=user_form,
# profile_form=profile_form)
#
# if user_form.is_valid():
# self.form_save(user_form)
# if profile_form.is_valid():
# self.form_save(profile_form)
#
# return self.render_to_response(context)
#
# def form_save(self, form):
# obj = form.save()
# #messages.success(self.request, "{} saved successfully".format(obj))
# return obj
#
# def get(self, request, *args, **kwargs):
# return self.post(request, *args, **kwargs)
@user_is_cid_user_manager
def accounts_check_users(request):
if request.method == "POST":
users = json.loads(request.POST.get("user_list"))
existing_users = []
for email in users:
if User.objects.filter(username=email).exists():
existing_users.append(email)
return JsonResponse({"users": existing_users})
return
@user_is_cid_user_manager
def accounts_bulk_create(request):
if request.method == "POST":
context = {}
users = json.loads(request.POST.get("usersjson"))
print(users)
created_users = []
existing_users = []
error_text = ""
try:
users = json.loads(request.POST.get("usersjson"))
print(users)
for user in users:
if not User.objects.filter(username=user["email"]).exists():
try:
print(user)
user_dict = {
"username": user["email"],
"first_name": user["first_name"],
"last_name": user["last_name"],
"email": user["email"],
"password": secrets.token_hex(nbytes=16)
}
new_user = User.objects.create_user(**user_dict)
except Exception as error:
error_text = (
error_text
+ f"<p>Error creating user: { user['email'] }<br/>{error}</p>"
)
try:
user_profile = UserProfile.objects.get(user=new_user)
user_profile.peninsula_trainee = True
if "supervisor_email" in user and "supervisor_name" in user:
s, created = Supervisor.objects.get_or_create(email=user["supervisor_email"], name=user["supervisor_name"])
if created:
s.save()
user_profile.supervisor = s
if "grade" in user:
if not user["grade"].startswith("ST"):
user["grade"] = f"ST{user['grade']}"
grade = UserGrades.objects.get(name=user["grade"])
user_profile.grade = grade
user_profile.save()
created_users.append(user["email"])
except Exception as error:
error_text = (
error_text
+ f"<p>Error creating user profile: { user['email'] }<br/>{error}</p>"
)
else:
existing_users.append(user["email"])
except Exception as error:
error_text = error_text + f"<p>Error creating users.<br/>{error}</p>"
context["error"] = format_html(error_text)
context["created_users"] = created_users
if existing_users:
context["message"] = "The following users already exist: " + ", ".join(
existing_users
)
# if not self.check_user_edit_access(request.user):
# data = {"status": "error, insufficient permission"}
# return JsonResponse(data, status=400)
# exam = get_object_or_404(self.Exam, pk=pk)
# exam.publish_results = (
# True if request.POST.get("publish_results") == "true" else False
# )
# exam.save()
# data = {
# "status": "success",
# "publish_results": exam.publish_results,
# "name": exam.name,
# "id": exam.id,
# }
return render(request, "accounts_bulk_create.html", context)
else:
return render(request, "accounts_bulk_create.html", {})