vbv/server/vbv_lernwelt/assignment/tests/test_graphql.py

564 lines
20 KiB
Python

import json
from datetime import date
from django.core.files.uploadedfile import SimpleUploadedFile
from django.utils import timezone
from graphene_django.utils import GraphQLTestCase
from vbv_lernwelt.assignment.models import (
Assignment,
AssignmentCompletion,
AssignmentCompletionAuditLog,
)
from vbv_lernwelt.core.create_default_users import create_default_users
from vbv_lernwelt.core.models import User
from vbv_lernwelt.core.utils import find_first
from vbv_lernwelt.course.creators.test_course import create_test_course
from vbv_lernwelt.course.models import CourseSession
from vbv_lernwelt.files.models import UploadFile
from vbv_lernwelt.notify.models import Notification
class AttendanceCourseUserMutationTestCase(GraphQLTestCase):
GRAPHQL_URL = "/server/graphql/"
def setUp(self):
create_default_users()
create_test_course(include_vv=False, with_sessions=True)
self.course_session = CourseSession.objects.get(title="Test Bern 2022 a")
self.trainer = User.objects.get(username="test-trainer1@example.com")
self.student = User.objects.get(username="test-student1@example.com")
self.assignment = Assignment.objects.get(
slug="test-lehrgang-assignment-überprüfen-einer-motorfahrzeugs-versicherungspolice"
)
self.assignment_subtasks = self.assignment.filter_user_subtasks()
self.assignment_task_ids = [t.id for t in self.assignment.tasks]
# self.client.force_login(self.trainer)
def test_student_can_upsertAssignmentCompletion(self):
self.client.force_login(self.student)
user_text_input = find_first(
self.assignment_subtasks, pred=lambda x: x["type"] == "user_text_input"
)
task_id = self.assignment_task_ids[0]
# Create file
uploaded_file = SimpleUploadedFile("file.txt", b"file_content")
file = UploadFile(
original_file_name="file.txt",
file_name="file.txt",
file_type="text/plain",
uploaded_by=self.student,
file=uploaded_file,
)
file.full_clean()
file.save()
file_id = str(file.id)
file_url = file.url
completion_data_string = json.dumps(
{
user_text_input["id"]: {"user_data": {"text": "Hallo via API"}},
task_id: {"user_data": {"fileId": file_id}},
}
).replace('"', '\\"')
query = f"""
mutation {{
upsert_assignment_completion(
assignment_id: {self.assignment.id}
course_session_id: {self.course_session.id}
completion_status: IN_PROGRESS
completion_data_string: "{completion_data_string}"
) {{
assignment_completion {{
id
completion_status
completion_data
task_completion_data
assignment_user {{ id }}
assignment {{ id }}
}}
}}
}}
"""
response = self.query(query)
self.assertResponseNoErrors(response)
data = json.loads(response.content)["data"]["upsert_assignment_completion"][
"assignment_completion"
]
self.assertEqual(data["assignment_user"]["id"], str(self.student.id))
self.assertEqual(data["assignment"]["id"], str(self.assignment.id))
self.assertEqual(data["completion_status"], "IN_PROGRESS")
self.assertDictEqual(
data["completion_data"],
{
user_text_input["id"]: {"user_data": {"text": "Hallo via API"}},
task_id: {"user_data": {"fileId": file_id}},
},
)
task_data = data["task_completion_data"][task_id]
self.maxDiff = None
self.assertEqual(task_data["user_data"]["fileId"], file_id)
self.assertEqual(task_data["user_data"]["fileInfo"]["id"], file_id)
self.assertEqual(task_data["user_data"]["fileInfo"]["name"], "file.txt")
self.assertTrue(
task_data["user_data"]["fileInfo"]["url"].startswith(
"https://s3.eu-central-1.amazonaws.com/myvbv-dev.iterativ.ch"
)
)
# check DB data
db_entry = AssignmentCompletion.objects.get(
assignment_user=self.student,
course_session_id=self.course_session.id,
assignment_id=self.assignment.id,
)
self.assertEqual(db_entry.completion_status, "IN_PROGRESS")
self.assertDictEqual(
db_entry.completion_data,
{
user_text_input["id"]: {"user_data": {"text": "Hallo via API"}},
task_id: {"user_data": {"fileId": file_id}},
},
)
# submit the response
completion_data_string = json.dumps(
{
user_text_input["id"]: {"user_data": {"text": "Hallo via API 2"}},
}
).replace('"', '\\"')
query = f"""
mutation {{
upsert_assignment_completion(
assignment_id: {self.assignment.id}
course_session_id: {self.course_session.id}
completion_status: SUBMITTED
completion_data_string: "{completion_data_string}"
) {{
assignment_completion {{
id
completion_status
completion_data
assignment_user {{ id }}
assignment {{ id }}
}}
}}
}}
"""
response = self.query(query)
self.assertResponseNoErrors(response)
data = json.loads(response.content)["data"]["upsert_assignment_completion"][
"assignment_completion"
]
self.assertEqual(data["assignment_user"]["id"], str(self.student.id))
self.assertEqual(data["assignment"]["id"], str(self.assignment.id))
self.assertEqual(data["completion_status"], "SUBMITTED")
self.assertDictEqual(
data["completion_data"],
{
user_text_input["id"]: {"user_data": {"text": "Hallo via API 2"}},
task_id: {"user_data": {"fileId": file_id}},
},
)
# check DB data
db_entry = AssignmentCompletion.objects.get(
assignment_user=self.student,
course_session_id=self.course_session.id,
assignment_id=self.assignment.id,
)
self.assertEqual(db_entry.completion_status, "SUBMITTED")
self.assertEqual(db_entry.submitted_at.date(), date.today())
self.assertDictEqual(
db_entry.completion_data,
{
user_text_input["id"]: {"user_data": {"text": "Hallo via API 2"}},
task_id: {"user_data": {"fileId": file_id}},
},
)
# check notification
self.assertEqual(Notification.objects.count(), 1)
notification = Notification.objects.first()
self.assertEqual(
"Test Student1 hat die geleitete Fallarbeit «Überprüfen einer Motorfahrzeugs-Versicherungspolice» abgegeben.",
notification.verb,
)
self.assertEqual(
"test-trainer1@example.com",
notification.recipient.email,
)
self.assertEqual(
"test-student1@example.com",
notification.actor.email,
)
self.assertEqual(
"USER_INTERACTION",
notification.notification_category,
)
self.assertEqual(
"CASEWORK_SUBMITTED",
notification.notification_trigger,
)
self.assertEqual(
notification.action_object,
db_entry,
)
self.assertEqual(
notification.course_session,
self.course_session,
)
self.assertTrue(
f"/course/test-lehrgang/cockpit/assignment" in notification.target_url
)
# second submit will fail
completion_data_string = json.dumps(
{
user_text_input["id"]: {"user_data": {"text": "Hallo via API 3"}},
}
).replace('"', '\\"')
query = f"""
mutation {{
upsert_assignment_completion(
assignment_id: {self.assignment.id}
course_session_id: {self.course_session.id}
completion_status: SUBMITTED
completion_data_string: "{completion_data_string}"
) {{
assignment_completion {{
id
completion_status
completion_data
assignment_user {{ id }}
assignment {{ id }}
}}
}}
}}
"""
response = self.query(query)
self.assertResponseHasErrors(response)
self.assertTrue("Cannot update completion status" in str(response.json()))
def test_expert_can_gradeAssignmentCompletion(self):
# setup AssignmentCompletion
subtasks = self.assignment.filter_user_subtasks(
subtask_types=["user_text_input"]
)
user_text_input = find_first(
subtasks,
pred=lambda x: (value := x.get("value"))
and value.get("text", "").startswith(
"Gibt es zusätzliche Deckungen, die du der Person empfehlen würdest?"
),
)
ac = AssignmentCompletion.objects.create(
assignment_user=self.student,
assignment=self.assignment,
learning_content_page=self.assignment.find_attached_learning_content(),
course_session=self.course_session,
completion_status="SUBMITTED",
submitted_at=timezone.now(),
completion_data={
user_text_input["id"]: {
"user_data": {"text": "Ich würde nichts weiteres empfehlen."}
},
},
)
self.client.force_login(self.trainer)
completion_data_string = json.dumps(
{
user_text_input["id"]: {
"expert_data": {"points": 1, "comment": "Gut gemacht!"}
},
}
).replace('"', '\\"')
query = f"""
mutation {{
upsert_assignment_completion(
assignment_id: {self.assignment.id}
assignment_user_id: "{self.student.id}"
course_session_id: {self.course_session.id}
completion_status: EVALUATION_IN_PROGRESS
completion_data_string: "{completion_data_string}"
) {{
assignment_completion {{
id
completion_status
completion_data
assignment_user {{ id }}
assignment {{ id }}
}}
}}
}}
"""
print(query)
response = self.query(query)
self.assertResponseNoErrors(response)
data = json.loads(response.content)["data"]["upsert_assignment_completion"][
"assignment_completion"
]
self.assertEqual(data["assignment_user"]["id"], str(self.student.id))
self.assertEqual(data["assignment"]["id"], str(self.assignment.id))
self.assertEqual(data["completion_status"], "EVALUATION_IN_PROGRESS")
self.assertDictEqual(
data["completion_data"],
{
user_text_input["id"]: {
"user_data": {"text": "Ich würde nichts weiteres empfehlen."},
"expert_data": {"points": 1, "comment": "Gut gemacht!"},
},
},
)
db_entry = AssignmentCompletion.objects.get(
assignment_user=self.student,
course_session_id=self.course_session.id,
assignment_id=self.assignment.id,
)
self.assertEqual(db_entry.completion_status, "EVALUATION_IN_PROGRESS")
self.assertDictEqual(
db_entry.completion_data,
{
user_text_input["id"]: {
"user_data": {"text": "Ich würde nichts weiteres empfehlen."},
"expert_data": {"points": 1, "comment": "Gut gemacht!"},
},
},
)
# finish grading
completion_data_string = json.dumps(
{
user_text_input["id"]: {
"expert_data": {"points": 1, "comment": "Gut gemacht!"}
},
}
).replace('"', '\\"')
query = f"""
mutation {{
upsert_assignment_completion(
assignment_id: {self.assignment.id}
assignment_user_id: "{self.student.id}"
course_session_id: {self.course_session.id}
completion_status: EVALUATION_SUBMITTED
completion_data_string: "{completion_data_string}"
evaluation_points: 16,
) {{
assignment_completion {{
id
completion_status
completion_data
assignment_user {{ id }}
assignment {{ id }}
}}
}}
}}
"""
response = self.query(query)
self.assertResponseNoErrors(response)
data = json.loads(response.content)["data"]["upsert_assignment_completion"][
"assignment_completion"
]
self.assertEqual(data["assignment_user"]["id"], str(self.student.id))
self.assertEqual(data["assignment"]["id"], str(self.assignment.id))
self.assertEqual(data["completion_status"], "EVALUATION_SUBMITTED")
self.assertDictEqual(
data["completion_data"],
{
user_text_input["id"]: {
"user_data": {"text": "Ich würde nichts weiteres empfehlen."},
"expert_data": {"points": 1, "comment": "Gut gemacht!"},
},
},
)
db_entry = AssignmentCompletion.objects.get(
assignment_user=self.student,
course_session_id=self.course_session.id,
assignment_id=self.assignment.id,
)
self.assertEqual(db_entry.completion_status, "EVALUATION_SUBMITTED")
self.assertEqual(db_entry.evaluation_points, 16)
self.assertEqual(db_entry.evaluation_max_points, 24)
self.assertTrue(db_entry.evaluation_passed)
self.assertDictEqual(
db_entry.completion_data,
{
user_text_input["id"]: {
"user_data": {"text": "Ich würde nichts weiteres empfehlen."},
"expert_data": {"points": 1, "comment": "Gut gemacht!"},
},
},
)
# check notification
self.assertEqual(Notification.objects.count(), 1)
notification = Notification.objects.first()
self.assertEqual(
"Test Trainer1 hat die geleitete Fallarbeit «Überprüfen einer Motorfahrzeugs-Versicherungspolice» bewertet.",
notification.verb,
)
self.assertEqual(
"test-student1@example.com",
notification.recipient.email,
)
self.assertEqual(
"test-trainer1@example.com",
notification.actor.email,
)
self.assertEqual(
"USER_INTERACTION",
notification.notification_category,
)
self.assertEqual(
"CASEWORK_EVALUATED",
notification.notification_trigger,
)
self.assertEqual(
notification.action_object,
db_entry,
)
self.assertEqual(
notification.course_session,
self.course_session,
)
self.assertEqual(
notification.target_url,
"/course/test-lehrgang/learn/fahrzeug/überprüfen-einer-motorfahrzeug-versicherungspolice",
)
# `EVALUATION_SUBMITTED` will create a new AssignmentCompletionAuditLog
acl = AssignmentCompletionAuditLog.objects.get(
assignment_user=self.student,
course_session_id=self.course_session.id,
assignment_id=self.assignment.id,
completion_status="EVALUATION_SUBMITTED",
)
self.maxDiff = None
self.assertDictEqual(
acl.completion_data,
{
user_text_input["id"]: {
"id": user_text_input["id"],
"type": "user_text_input",
"value": {
"text": "Gibt es zusätzliche Deckungen, die du der Person empfehlen würdest? Begründe deine Empfehlung",
},
"user_data": {"text": "Ich würde nichts weiteres empfehlen."},
"expert_data": {"points": 1, "comment": "Gut gemacht!"},
},
},
)
self.assertEqual(acl.evaluation_points, 16)
self.assertEqual(acl.evaluation_max_points, 24)
self.assertTrue(acl.evaluation_passed)
def test_student_can_upsert_reflection(self):
"""
when upserting a reflection, it will store also the page_id of the learning content
"""
reflection = Assignment.objects.get(slug="test-lehrgang-assignment-reflexion")
reflection_subtasks = reflection.filter_user_subtasks()
reflection_learning_content = reflection.find_attached_learning_content()
self.client.force_login(self.student)
user_text_input = find_first(
reflection_subtasks, pred=lambda x: x["type"] == "user_text_input"
)
completion_data_string = json.dumps(
{
user_text_input["id"]: {
"user_data": {"text": "Hallo via Reflection API"}
},
}
).replace('"', '\\"')
query = f"""
mutation {{
upsert_assignment_completion(
assignment_id: {reflection.id}
course_session_id: {self.course_session.id}
learning_content_page_id: {reflection_learning_content.id}
completion_status: IN_PROGRESS
completion_data_string: "{completion_data_string}"
) {{
assignment_completion {{
id
completion_status
completion_data
assignment_user {{ id }}
assignment {{ id }}
learning_content_page_id
}}
}}
}}
"""
response = self.query(query)
self.assertResponseNoErrors(response)
data = json.loads(response.content)["data"]["upsert_assignment_completion"][
"assignment_completion"
]
print(data)
self.assertEqual(data["assignment_user"]["id"], str(self.student.id))
self.assertEqual(data["assignment"]["id"], str(reflection.id))
self.assertEqual(data["completion_status"], "IN_PROGRESS")
self.assertEqual(
data["learning_content_page_id"], str(reflection_learning_content.id)
)
self.assertDictEqual(
data["completion_data"],
{
user_text_input["id"]: {
"user_data": {"text": "Hallo via Reflection API"}
},
},
)
# check DB data
db_entry = AssignmentCompletion.objects.get(
assignment_user=self.student,
course_session_id=self.course_session.id,
assignment_id=reflection.id,
learning_content_page_id=reflection_learning_content.id,
)
self.assertEqual(db_entry.completion_status, "IN_PROGRESS")
self.assertDictEqual(
db_entry.completion_data,
{
user_text_input["id"]: {
"user_data": {"text": "Hallo via Reflection API"}
},
},
)