start testing
This commit is contained in:
+1
-1
@@ -51,7 +51,7 @@ class AnatomyUserAnswerFilter(django_filters.FilterSet):
|
||||
model= CidUserAnswer
|
||||
fields = (
|
||||
"cid",
|
||||
#"user",
|
||||
"user",
|
||||
"question",
|
||||
"answer",
|
||||
#"answer_compare",
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
# Generated by Django 3.2.13 on 2022-05-20 19:51
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('anatomy', '0062_exam_valid_user_users'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='ciduseranswer',
|
||||
name='user',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='user_anatomy_user_answers', to=settings.AUTH_USER_MODEL),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,24 @@
|
||||
# Generated by Django 3.2.13 on 2022-05-21 09:20
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('generic', '0032_userprofile_registration_number'),
|
||||
('anatomy', '0063_ciduseranswer_user'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='exam',
|
||||
name='cid_user_groups',
|
||||
field=models.ManyToManyField(blank=True, help_text='These groups define which candidates are able to be added to the exams/collection.', related_name='anatomy_cid_user_groups', to='generic.CidUserGroup'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='exam',
|
||||
name='user_user_groups',
|
||||
field=models.ManyToManyField(blank=True, help_text='These groups define which candidates are able to be added to the exams/collection.', related_name='anatomy_user_user_groups', to='generic.UserUserGroup'),
|
||||
),
|
||||
]
|
||||
+18
-4
@@ -15,7 +15,7 @@ from sortedm2m.fields import SortedManyToManyField
|
||||
|
||||
import string
|
||||
|
||||
from generic.models import CidUser, Examination, ExamBase, QuestionNote
|
||||
from generic.models import CidUser, CidUserGroup, Examination, ExamBase, QuestionNote, UserUserGroup
|
||||
|
||||
from collections import defaultdict
|
||||
from helpers.images import image_as_base64
|
||||
@@ -391,6 +391,20 @@ class Exam(ExamBase):
|
||||
settings.AUTH_USER_MODEL, blank=True, related_name="user_anatomy_exams"
|
||||
)
|
||||
|
||||
cid_user_groups = models.ManyToManyField(
|
||||
CidUserGroup,
|
||||
blank=True,
|
||||
help_text="These groups define which candidates are able to be added to the exams/collection.",
|
||||
related_name="anatomy_cid_user_groups"
|
||||
)
|
||||
|
||||
user_user_groups = models.ManyToManyField(
|
||||
UserUserGroup,
|
||||
blank=True,
|
||||
help_text="These groups define which candidates are able to be added to the exams/collection.",
|
||||
related_name="anatomy_user_user_groups"
|
||||
)
|
||||
|
||||
def get_exam_json(self, based=True):
|
||||
questions = self.exam_questions.all()
|
||||
|
||||
@@ -452,9 +466,9 @@ class CidUserAnswer(models.Model):
|
||||
help_text="Candidate ID (limitied by BigIntegerField size)",
|
||||
)
|
||||
|
||||
#user = models.ForeignKey(
|
||||
# settings.AUTH_USER_MODEL, on_delete=models.CASCADE, blank=True, null=True#, related_name="user_anatomy_user_answers"
|
||||
#)
|
||||
user = models.ForeignKey(
|
||||
settings.AUTH_USER_MODEL, on_delete=models.CASCADE, blank=True, null=True, related_name="user_anatomy_user_answers"
|
||||
)
|
||||
|
||||
# Each user answer is associated with a particular exam
|
||||
exam = models.ForeignKey(
|
||||
|
||||
+1
-1
@@ -69,7 +69,7 @@ class AnatomyUserAnswerTable(tables.Table):
|
||||
template_name = "django_tables2/bootstrap4.html"
|
||||
fields = (
|
||||
"cid",
|
||||
#"user",
|
||||
"user",
|
||||
"question",
|
||||
"answer",
|
||||
#"answer_compare",
|
||||
|
||||
@@ -250,11 +250,6 @@ def loadJsonAnswer(answer):
|
||||
{"success": False, "error": "invalid cid / passcode"}
|
||||
)
|
||||
|
||||
# if not exam.active:
|
||||
# return False, JsonResponse(
|
||||
# {"success": False, "error": "No active exam: {}".format(eid)}
|
||||
# )
|
||||
|
||||
exiting_answers = CidUserAnswer.objects.filter(
|
||||
question__id=answer["qid"], exam__id=eid, cid=cid
|
||||
)
|
||||
|
||||
+32
-1
@@ -1039,7 +1039,38 @@ class ExamViews(View, LoginRequiredMixin):
|
||||
n = 0
|
||||
|
||||
for answer in json.loads(request.POST.get("answers")):
|
||||
ret_status, ret = self.loadJsonAnswer(answer, user=request.user)
|
||||
|
||||
eid = int(answer["eid"].split("/")[1])
|
||||
uid = False
|
||||
|
||||
try:
|
||||
cid = int(answer["cid"])
|
||||
except ValueError:
|
||||
if answer["cid"].startswith("u-"):
|
||||
cid = False
|
||||
uid = int(answer["cid"][2:])
|
||||
|
||||
if not uid == request.user.id:
|
||||
return JsonResponse(
|
||||
{"success": False, "error": "user / uid mismatch"}
|
||||
)
|
||||
|
||||
else:
|
||||
return JsonResponse(
|
||||
{"success": False, "error": "cid or eid or answers not defined"}
|
||||
)
|
||||
|
||||
if not uid:
|
||||
# As access is not restricted make sure the data appears valid
|
||||
if (not isinstance(cid, int)) or (
|
||||
not isinstance(eid, int) or (not isinstance(answer["ans"], str))
|
||||
):
|
||||
return JsonResponse(
|
||||
{"success": False, "error": "cid or eid or answers not defined"}
|
||||
)
|
||||
|
||||
|
||||
ret_status, ret = self.loadJsonAnswer(answer, cid=cid, eid=eid, uid=uid)
|
||||
# try:
|
||||
# ret_status, ret = self.loadJsonAnswer(answer)
|
||||
# except:
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
[pytest]
|
||||
DJANGO_SETTINGS_MODULE=rad.settings
|
||||
python_files = tests.py test_*.py *_tests.py
|
||||
@@ -0,0 +1,21 @@
|
||||
# Generated by Django 3.2.13 on 2022-05-20 19:51
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('rapids', '0056_exam_user_user_groups'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='ciduseranswer',
|
||||
name='user',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='user_rapid_user_answers', to=settings.AUTH_USER_MODEL),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,24 @@
|
||||
# Generated by Django 3.2.13 on 2022-05-21 09:20
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('generic', '0032_userprofile_registration_number'),
|
||||
('rapids', '0057_alter_ciduseranswer_user'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='exam',
|
||||
name='cid_user_groups',
|
||||
field=models.ManyToManyField(blank=True, help_text='These groups define which candidates are able to be added to the exams/collection.', related_name='rapid_cid_user_groups', to='generic.CidUserGroup'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='exam',
|
||||
name='user_user_groups',
|
||||
field=models.ManyToManyField(blank=True, help_text='These groups define which candidates are able to be added to the exams/collection.', related_name='rapid_user_user_groups', to='generic.UserUserGroup'),
|
||||
),
|
||||
]
|
||||
+7
-2
@@ -1,4 +1,5 @@
|
||||
import os
|
||||
import re
|
||||
import dicognito
|
||||
from rad.settings import REMOTE_URL
|
||||
from django.db import models
|
||||
@@ -597,7 +598,7 @@ class Exam(ExamBase):
|
||||
|
||||
time_limit = models.IntegerField(
|
||||
help_text="Exam time limit (in seconds). Default is 2100 secondse (35 minutes)",
|
||||
default=2100,
|
||||
default=35 * 60,
|
||||
)
|
||||
|
||||
author = models.ManyToManyField(
|
||||
@@ -619,12 +620,15 @@ class Exam(ExamBase):
|
||||
CidUserGroup,
|
||||
blank=True,
|
||||
help_text="These groups define which candidates are able to be added to the exams/collection.",
|
||||
related_name="rapid_cid_user_groups"
|
||||
|
||||
)
|
||||
|
||||
user_user_groups = models.ManyToManyField(
|
||||
UserUserGroup,
|
||||
blank=True,
|
||||
help_text="These groups define which candidates are able to be added to the exams/collection.",
|
||||
related_name="rapid_user_user_groups"
|
||||
)
|
||||
|
||||
def get_normal_abnormal_breakdown(self):
|
||||
@@ -740,7 +744,8 @@ class CidUserAnswer(models.Model):
|
||||
settings.AUTH_USER_MODEL,
|
||||
on_delete=models.CASCADE,
|
||||
blank=True,
|
||||
null=True, # , related_name="user_rapid_user_answers"
|
||||
null=True,
|
||||
related_name="user_rapid_user_answers",
|
||||
)
|
||||
|
||||
# Each user answer is associated with a particular exam
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
@@ -0,0 +1,20 @@
|
||||
|
||||
import pytest
|
||||
from rapids.models import Abnormality, Exam
|
||||
|
||||
#@pytest.mark.django_db
|
||||
def test_create_abnormality(db):
|
||||
abnormality = Abnormality.objects.create(name="Abnorm")
|
||||
assert abnormality.name == "Abnorm"
|
||||
|
||||
@pytest.fixture
|
||||
def create_exam(db):
|
||||
return Exam.objects.create(name="test exam")
|
||||
|
||||
def test_exam_creation(create_exam):
|
||||
exams = Exam.objects.filter(name="test exam")
|
||||
assert exams.exists()
|
||||
|
||||
exam = exams.first()
|
||||
|
||||
assert exam.time_limit == 35 * 60
|
||||
@@ -0,0 +1,12 @@
|
||||
import pytest
|
||||
#from django.contrib.auth.models import User
|
||||
from django.urls import reverse
|
||||
|
||||
@pytest.fixture
|
||||
def create_superuser(db, django_user_model):
|
||||
return django_user_model.objects.create_superuser("admin", "ross@xkjq.uk", "adminpassword")
|
||||
|
||||
def test_index(client, create_superuser):
|
||||
client.login(username="admin", password="adminpassword")
|
||||
response = client.get(reverse('rapids:index'))
|
||||
assert response.status_code == 200
|
||||
Executable
+16
@@ -0,0 +1,16 @@
|
||||
from django.test import TestCase, Client
|
||||
|
||||
from django.urls import reverse
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
# Create your tests here.
|
||||
|
||||
|
||||
#class TestUrls(TestCase):
|
||||
# def setUp(self):
|
||||
# User.objects.create_superuser("admin", "ross@xkjq.uk", "adminpassword")
|
||||
#
|
||||
# def test_index(self):
|
||||
# self.client.login(username="admin", password="adminpassword")
|
||||
# response = self.client.get(reverse('rapids:index'))
|
||||
# self.assertEqual(response.status_code, 200)
|
||||
+1
-43
@@ -509,44 +509,7 @@ class RapidView(LoginRequiredMixin, SingleTableMixin, FilterView):
|
||||
filterset_class = RapidFilter
|
||||
|
||||
|
||||
def loadJsonAnswer(answer, user=None):
|
||||
eid = int(answer["eid"].split("/")[1])
|
||||
uid = False
|
||||
|
||||
try:
|
||||
cid = int(answer["cid"])
|
||||
except ValueError:
|
||||
if answer["cid"].startswith("u-"):
|
||||
cid = False
|
||||
uid = int(answer["cid"][2:])
|
||||
|
||||
print(f"{uid=}")
|
||||
print(f"{uid=}")
|
||||
if not uid == user.id:
|
||||
return False, JsonResponse(
|
||||
{"success": False, "error": "user / uid mismatch"}
|
||||
)
|
||||
|
||||
else:
|
||||
return False, JsonResponse(
|
||||
{"success": False, "error": "cid or eid or answers not defined"}
|
||||
)
|
||||
|
||||
#uid = int(answer["uid"])
|
||||
|
||||
if not uid:
|
||||
# As access is not restricted make sure the data appears valid
|
||||
if (not isinstance(cid, int)) or (
|
||||
not isinstance(eid, int) or (not isinstance(answer["ans"], str))
|
||||
):
|
||||
return False, JsonResponse(
|
||||
{"success": False, "error": "cid or eid or answers not defined"}
|
||||
)
|
||||
|
||||
## The model should catch invalid data but this should be less intensive
|
||||
#max_int = 999999999999999999999
|
||||
#if cid > max_int or eid > max_int:
|
||||
# return False, JsonResponse({"success": False, "error": "invalid cid"})
|
||||
def loadJsonAnswer(answer, cid, eid, uid):
|
||||
|
||||
exam = get_object_or_404(Exam, pk=eid)
|
||||
|
||||
@@ -555,11 +518,6 @@ def loadJsonAnswer(answer, user=None):
|
||||
{"success": False, "error": "invalid cid / passcode"}
|
||||
)
|
||||
|
||||
# if not exam.active:
|
||||
# return False, JsonResponse(
|
||||
# {"success": False, "error": "No active exam: {}".format(eid)}
|
||||
# )
|
||||
|
||||
if uid:
|
||||
exiting_answers = CidUserAnswer.objects.filter(
|
||||
question__id=answer["qid"], exam__id=eid, user__id=uid
|
||||
|
||||
@@ -25,4 +25,5 @@ django-autocomplete-light
|
||||
django-querysetsequence
|
||||
dicognito
|
||||
django_unused_media
|
||||
pytest-django
|
||||
gunicorn
|
||||
@@ -15,7 +15,7 @@
|
||||
</div>
|
||||
<div>
|
||||
Supervisor: {{ user.userprofile.supervisor_name }}<br/>
|
||||
Email: {{ user.userprofile.supervisor_email }}<br/>
|
||||
Supervisor Email: {{ user.userprofile.supervisor_email }}<br/>
|
||||
</div>
|
||||
<div>
|
||||
Registration number: {{ user.userprofile.registration_number }}
|
||||
|
||||
Reference in New Issue
Block a user