Skip to content

Commit

Permalink
feat: add xapi transformer for exam attempts events
Browse files Browse the repository at this point in the history
fix: add attempt type for exam attempt events

fix: add context data to event attempt events

test: add fixtures for special exams

refactor: use exam object for event attempts

fix: add missing xapi concepts for exam events

fix: use scorm pattern for exam events

test: add fixtures for special exams

fix: remove proctored and timed extensions

fix: add duration extension

fix: do not override get context extensions

feat: include practice and proctored exam events

fix: use attempt-id for attempt events

test: add fixtures for proctored and practice exam events
  • Loading branch information
Ian2012 committed Sep 13, 2023
1 parent 41c960b commit 7fe6c17
Show file tree
Hide file tree
Showing 20 changed files with 746 additions and 1 deletion.
1 change: 1 addition & 0 deletions actual_transformed_event.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"id": "32e08e30-f8ae-4ce2-94a8-c2bfe38a70cb", "version": "1.0.3", "actor": {"objectType": "Agent", "account": {"name": "32e08e30-f8ae-4ce2-94a8-c2bfe38a70cb", "homePage": "http://localhost:18000"}}, "verb": {"id": "http://adlnet.gov/expapi/verbs/terminated", "display": {"en": "terminated"}}, "object": {"id": "block-v1:edX+DemoX+Demo_Course+type@sequential+block@5b4bf8d7d41c4070b299abefed74155e", "objectType": "Activity", "definition": {"name": {"en": "Subsection"}, "type": "https://w3id.org/xapi/openedx/activity/practice-assessment", "extensions": {"https://w3id.org/xapi/acrossx/extensions/time-limit": 60}}}, "timestamp": "2023-09-08T15:58:04.833393+00:00", "context": {"contextActivities": {"parent": [{"id": "http://localhost:18000/course/course-v1:edX+DemoX+Demo_Course", "objectType": "Activity", "definition": {"name": {"en-US": "Demonstration Course"}, "type": "http://adlnet.gov/expapi/activities/course"}}], "grouping": [{"id": "438AD672-DE2C-4F0B-8876-35444E7DD746", "objectType": "Activity", "definition": {"name": {"en": "Subsection"}, "type": "http://adlnet.gov/expapi/activities/attempt", "extensions": {"http://id.tincanapi.com/extension/attempt-id": 1}}}]}, "extensions": {"https://w3id.org/xapi/openedx/extension/transformer-version": "[email protected]", "https://w3id.org/xapi/openedx/extensions/session-id": "1c7862f091c5d7232ad3d7cf558f6e80"}}}
8 changes: 8 additions & 0 deletions docs/event-mapping/Supported_events.rst
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,12 @@ Forum events
* `edx.forum.comment.reported`_ | edX `sample <../../event_routing_backends/processors/tests/fixtures/current/edx.forum.comment.reported.json>`__ | xAPI `map <./xAPI_mapping.rst#edx.forum.comment.reported>`__ , `sample <../../event_routing_backends/processors/xapi/tests/fixtures/expected/edx.forum.comment.reported.json>`__
* `edx.forum.comment.unreported`_ | edX `sample <../../event_routing_backends/processors/tests/fixtures/current/edx.forum.comment.unreported.json>`__ | xAPI `map <./xAPI_mapping.rst#edx.forum.comment.unreported>`__ , `sample <../../event_routing_backends/processors/xapi/tests/fixtures/expected/edx.forum.comment.unreported.json>`__

Exam events
------------------

* `edx.special_exam.timed.attempt.started`_ | edX `sample <../../event_routing_backends/processors/tests/fixtures/current/edx.special_exam.timed.attempt.started.json>`__ | xAPI `map <./xAPI_mapping.rst#edx-special-exam-timed-attempt-started>`__ , `sample <../../event_routing_backends/processors/xapi/tests/fixtures/expected/edx.special_exam.timed.attempt.started.json>`__
* `edx.special_exam.timed.attempt.submitted`_ | edX `sample <../../event_routing_backends/processors/tests/fixtures/current/edx.special_exam.timed.attempt.submitted.json>`__ | xAPI `map <./xAPI_mapping.rst#edx-special-exam-timed-attempt-submitted>`__ , `sample <../../event_routing_backends/processors/xapi/tests/fixtures/expected/edx.special_exam.timed.attempt.submitted.json>`__


.. _edx.course.enrollment.activated: http://edx.readthedocs.io/projects/devdata/en/latest/internal_data_formats/tracking_logs/student_event_types.html#edx-course-enrollment-activated-and-edx-course-enrollment-deactivated
.. _edx.course.enrollment.deactivated: http://edx.readthedocs.io/projects/devdata/en/latest/internal_data_formats/tracking_logs/student_event_types.html#edx-course-enrollment-activated-and-edx-course-enrollment-deactivated
Expand Down Expand Up @@ -115,3 +121,5 @@ Forum events
.. _edx.forum.comment.deleted: https://docs.openedx.org/en/latest/developers/references/internal_data_formats/tracking_logs/student_event_types.html#edx-forum-comment-deleted
.. _edx.forum.comment.reported: https://docs.openedx.org/en/latest/developers/references/internal_data_formats/tracking_logs/student_event_types.html#edx-forum-comment-reported
.. _edx.forum.comment.unreported: https://docs.openedx.org/en/latest/developers/references/internal_data_formats/tracking_logs/student_event_types.html#edx-forum-comment-unreported
.. _edx.special_exam.timed.attempt.started: https://docs.openedx.org/en/latest/developers/references/internal_data_formats/tracking_logs/student_event_types.html#edx-special-exam-proctored-attempt-started-edx-special-exam-practice-attempt-started-and-edx-special-exam-timed-attempt-started
.. _edx.special_exam.timed.attempt.submitted: https://docs.openedx.org/en/latest/developers/references/internal_data_formats/tracking_logs/student_event_types.html#edx-special-exam-proctored-attempt-submitted-edx-special-exam-practice-attempt-submitted-and-edx-special-exam-timed-attempt-submitted
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"name": "edx.special_exam.practice.attempt.created",
"context": {
"user_id": 3,
"path": "/api/edx_proctoring/v1/proctored_exam/attempt",
"course_id": "course-v1:edX+DemoX+Demo_Course",
"org_id": "edX",
"enterprise_uuid": ""
},
"username": "student",
"session": "1c7862f091c5d7232ad3d7cf558f6e80",
"ip": "172.18.0.1",
"agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36",
"host": "localhost:18000",
"referer": "http://localhost:18000",
"accept_language": "en-US,en;q=0.9",
"event": {
"exam_id": 1,
"exam_content_id": "block-v1:edX+DemoX+Demo_Course+type@sequential+block@5b4bf8d7d41c4070b299abefed74155e",
"exam_name": "Subsection",
"exam_default_time_limit_mins": 60,
"exam_is_proctored": false,
"exam_is_practice_exam": true,
"exam_is_active": true,
"attempt_id": 1,
"attempt_user_id": 3,
"attempt_started_at": null,
"attempt_completed_at": null,
"attempt_code": "438AD672-DE2C-4F0B-8876-35444E7DD746",
"attempt_allowed_time_limit_mins": null,
"attempt_status": "created",
"attempt_event_elapsed_time_secs": null
},
"time": "2023-09-08T15:58:04.833393+00:00",
"event_type": "edx.special_exam.timed.attempt.created",
"event_source": "server",
"page": null
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"name": "edx.special_exam.practice.attempt.submitted",
"context": {
"user_id": 3,
"path": "/api/edx_proctoring/v1/proctored_exam/attempt/1",
"course_id": "course-v1:edX+DemoX+Demo_Course",
"org_id": "edX",
"enterprise_uuid": ""
},
"username": "student",
"session": "1c7862f091c5d7232ad3d7cf558f6e80",
"ip": "172.18.0.1",
"agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36",
"host": "localhost:18000",
"referer": "http://localhost:18000",
"accept_language": "en-US,en;q=0.9",
"event": {
"exam_id": 1,
"exam_content_id": "block-v1:edX+DemoX+Demo_Course+type@sequential+block@5b4bf8d7d41c4070b299abefed74155e",
"exam_name": "Subsection",
"exam_default_time_limit_mins": 60,
"exam_is_proctored": false,
"exam_is_practice_exam": true,
"exam_is_active": true,
"attempt_id": 1,
"attempt_user_id": 3,
"attempt_started_at": "2023-09-08T15:58:04.838598+00:00",
"attempt_completed_at": "2023-09-08T16:20:53.577698+00:00",
"attempt_code": "438AD672-DE2C-4F0B-8876-35444E7DD746",
"attempt_allowed_time_limit_mins": 60,
"attempt_status": "submitted",
"attempt_event_elapsed_time_secs": 1368.7657
},
"time": "2023-09-08T16:20:53.604375+00:00",
"event_type": "edx.special_exam.timed.attempt.submitted",
"event_source": "server",
"page": null
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"name": "edx.special_exam.proctored.attempt.created",
"context": {
"user_id": 3,
"path": "/api/edx_proctoring/v1/proctored_exam/attempt",
"course_id": "course-v1:edX+DemoX+Demo_Course",
"org_id": "edX",
"enterprise_uuid": ""
},
"username": "student",
"session": "1c7862f091c5d7232ad3d7cf558f6e80",
"ip": "172.18.0.1",
"agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36",
"host": "localhost:18000",
"referer": "http://localhost:18000",
"accept_language": "en-US,en;q=0.9",
"event": {
"exam_id": 1,
"exam_content_id": "block-v1:edX+DemoX+Demo_Course+type@sequential+block@5b4bf8d7d41c4070b299abefed74155e",
"exam_name": "Subsection",
"exam_default_time_limit_mins": 60,
"exam_is_proctored": true,
"exam_is_practice_exam": false,
"exam_is_active": true,
"attempt_id": 1,
"attempt_user_id": 3,
"attempt_started_at": null,
"attempt_completed_at": null,
"attempt_code": "438AD672-DE2C-4F0B-8876-35444E7DD746",
"attempt_allowed_time_limit_mins": null,
"attempt_status": "created",
"attempt_event_elapsed_time_secs": null
},
"time": "2023-09-08T15:58:04.833393+00:00",
"event_type": "edx.special_exam.timed.attempt.created",
"event_source": "server",
"page": null
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"name": "edx.special_exam.proctored.attempt.submitted",
"context": {
"user_id": 3,
"path": "/api/edx_proctoring/v1/proctored_exam/attempt/1",
"course_id": "course-v1:edX+DemoX+Demo_Course",
"org_id": "edX",
"enterprise_uuid": ""
},
"username": "student",
"session": "1c7862f091c5d7232ad3d7cf558f6e80",
"ip": "172.18.0.1",
"agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36",
"host": "localhost:18000",
"referer": "http://localhost:18000",
"accept_language": "en-US,en;q=0.9",
"event": {
"exam_id": 1,
"exam_content_id": "block-v1:edX+DemoX+Demo_Course+type@sequential+block@5b4bf8d7d41c4070b299abefed74155e",
"exam_name": "Subsection",
"exam_default_time_limit_mins": 60,
"exam_is_proctored": true,
"exam_is_practice_exam": false,
"exam_is_active": true,
"attempt_id": 1,
"attempt_user_id": 3,
"attempt_started_at": "2023-09-08T15:58:04.838598+00:00",
"attempt_completed_at": "2023-09-08T16:20:53.577698+00:00",
"attempt_code": "438AD672-DE2C-4F0B-8876-35444E7DD746",
"attempt_allowed_time_limit_mins": 60,
"attempt_status": "submitted",
"attempt_event_elapsed_time_secs": 1368.7657
},
"time": "2023-09-08T16:20:53.604375+00:00",
"event_type": "edx.special_exam.timed.attempt.submitted",
"event_source": "server",
"page": null
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"name": "edx.special_exam.timed.attempt.created",
"context": {
"user_id": 3,
"path": "/api/edx_proctoring/v1/proctored_exam/attempt",
"course_id": "course-v1:edX+DemoX+Demo_Course",
"org_id": "edX",
"enterprise_uuid": ""
},
"username": "student",
"session": "1c7862f091c5d7232ad3d7cf558f6e80",
"ip": "172.18.0.1",
"agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36",
"host": "localhost:18000",
"referer": "http://localhost:18000",
"accept_language": "en-US,en;q=0.9",
"event": {
"exam_id": 1,
"exam_content_id": "block-v1:edX+DemoX+Demo_Course+type@sequential+block@5b4bf8d7d41c4070b299abefed74155e",
"exam_name": "Subsection",
"exam_default_time_limit_mins": 60,
"exam_is_proctored": false,
"exam_is_practice_exam": false,
"exam_is_active": true,
"attempt_id": 1,
"attempt_user_id": 3,
"attempt_started_at": null,
"attempt_completed_at": null,
"attempt_code": "438AD672-DE2C-4F0B-8876-35444E7DD746",
"attempt_allowed_time_limit_mins": null,
"attempt_status": "created",
"attempt_event_elapsed_time_secs": null
},
"time": "2023-09-08T15:58:04.833393+00:00",
"event_type": "edx.special_exam.timed.attempt.created",
"event_source": "server",
"page": null
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"name": "edx.special_exam.timed.attempt.submitted",
"context": {
"user_id": 3,
"path": "/api/edx_proctoring/v1/proctored_exam/attempt/1",
"course_id": "course-v1:edX+DemoX+Demo_Course",
"org_id": "edX",
"enterprise_uuid": ""
},
"username": "student",
"session": "1c7862f091c5d7232ad3d7cf558f6e80",
"ip": "172.18.0.1",
"agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36",
"host": "localhost:18000",
"referer": "http://localhost:18000",
"accept_language": "en-US,en;q=0.9",
"event": {
"exam_id": 1,
"exam_content_id": "block-v1:edX+DemoX+Demo_Course+type@sequential+block@5b4bf8d7d41c4070b299abefed74155e",
"exam_name": "Subsection",
"exam_default_time_limit_mins": 60,
"exam_is_proctored": false,
"exam_is_practice_exam": false,
"exam_is_active": true,
"attempt_id": 1,
"attempt_user_id": 3,
"attempt_started_at": "2023-09-08T15:58:04.838598+00:00",
"attempt_completed_at": "2023-09-08T16:20:53.577698+00:00",
"attempt_code": "438AD672-DE2C-4F0B-8876-35444E7DD746",
"attempt_allowed_time_limit_mins": 60,
"attempt_status": "submitted",
"attempt_event_elapsed_time_secs": 1368.7657
},
"time": "2023-09-08T16:20:53.604375+00:00",
"event_type": "edx.special_exam.timed.attempt.submitted",
"event_source": "server",
"page": null
}
Original file line number Diff line number Diff line change
Expand Up @@ -114,4 +114,13 @@ def test_event_transformer(self, event_filename, mocked_uuid):
self.registry.get_transformer(original_event).transform()
else:
actual_transformed_event = self.registry.get_transformer(original_event).transform()
self.compare_events(actual_transformed_event, expected_event)
try:
self.compare_events(actual_transformed_event, expected_event)
except Exception as e: # pragma: no cover
with open("actual_transformed_event.json", "w") as actual_transformed_event_file:
actual_transformed_event_file.write(actual_transformed_event.to_json())

with open("expected_event.json", "w") as expected_event_file:
json.dump(expected_event, expected_event_file, indent=4)

raise e
10 changes: 10 additions & 0 deletions event_routing_backends/processors/xapi/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
XAPI_ACTIVITY_ATTEMPT = 'http://id.tincanapi.com/extension/attempt-id'
XAPI_ACTIVITY_GRADE_CLASSIFICATION = 'http://www.tincanapi.co.uk/activitytypes/grade_classification'
XAPI_ACTIVITY_GRADE = 'http://www.tincanapi.co.uk/extensions/result/classification'
XAPI_ACTIVITY_ASSESSMENT_FORMAT = 'https://w3id.org/xapi/openedx/activity/{}-assessment'
# xAPI context
XAPI_CONTEXT_VIDEO_LENGTH = 'https://w3id.org/xapi/video/extensions/length'
XAPI_CONTEXT_VIDEO_CC_LANGUAGE = 'https://w3id.org/xapi/video/extensions/cc-subtitle-lang'
Expand All @@ -58,6 +59,15 @@
XAPI_CONTEXT_COMPLETION_THRESHOLD = 'https://w3id.org/xapi/video/extensions/completion-threshold'
XAPI_CONTEXT_SESSION_ID = 'https://w3id.org/xapi/openedx/extensions/session-id'

XAPI_ACTIVITY_TIME_LIMIT = 'https://w3id.org/xapi/acrossx/extensions/time-limit'

XAPI_ACTIVITY_EXAM_ATTEMPT = 'http://adlnet.gov/expapi/activities/attempt'

XAPI_CONTEXT_ATTEMPT_STARTED = 'https://w3id.org/xapi/openedx/extension/attempt-started'
XAPI_CONTEXT_ATTEMPT_COMPLETED = 'https://w3id.org/xapi/openedx/extension/attempt-completed'
XAPI_CONTEXT_DURATION = 'http://id.tincanapi.com/extension/duration'
XAPI_CONTEXT_CODE = 'https://w3id.org/xapi/openedx/extension/code'

# xAPI result
XAPI_RESULT_VIDEO_TIME = 'https://w3id.org/xapi/video/extensions/time'
XAPI_RESULT_VIDEO_TIME_FROM = 'https://w3id.org/xapi/video/extensions/time-from'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
EnrollmentActivatedTransformer,
EnrollmentDeactivatedTransformer,
)
from event_routing_backends.processors.xapi.event_transformers.exam_events import (
PracticeExamStartedTransformer,
PracticeExamSubmittedTransformer,
)
from event_routing_backends.processors.xapi.event_transformers.forum_events import (
ThreadCreatedTransformer,
ThreadDeletedTransformer,
Expand Down
Loading

0 comments on commit 7fe6c17

Please sign in to comment.