From 6424a4007e0a44c2d017e5dc85e70f1630be3fff Mon Sep 17 00:00:00 2001 From: ilee2u Date: Thu, 21 Sep 2023 11:39:59 -0400 Subject: [PATCH] feat: improved event defs + avro --- ...arning+exam+attempt+errored+v1_schema.avsc | 79 +++++++++++++++++ ...rning+exam+attempt+rejected+v1_schema.avsc | 79 +++++++++++++++++ ...learning+exam+attempt+reset+v1_schema.avsc | 79 +++++++++++++++++ ...ning+exam+attempt+submitted+v1_schema.avsc | 79 +++++++++++++++++ ...rning+exam+attempt+verified+v1_schema.avsc | 79 +++++++++++++++++ openedx_events/learning/data.py | 70 +++------------ openedx_events/learning/signals.py | 86 ++++++++----------- 7 files changed, 444 insertions(+), 107 deletions(-) create mode 100644 openedx_events/event_bus/avro/tests/schemas/org+openedx+learning+exam+attempt+errored+v1_schema.avsc create mode 100644 openedx_events/event_bus/avro/tests/schemas/org+openedx+learning+exam+attempt+rejected+v1_schema.avsc create mode 100644 openedx_events/event_bus/avro/tests/schemas/org+openedx+learning+exam+attempt+reset+v1_schema.avsc create mode 100644 openedx_events/event_bus/avro/tests/schemas/org+openedx+learning+exam+attempt+submitted+v1_schema.avsc create mode 100644 openedx_events/event_bus/avro/tests/schemas/org+openedx+learning+exam+attempt+verified+v1_schema.avsc diff --git a/openedx_events/event_bus/avro/tests/schemas/org+openedx+learning+exam+attempt+errored+v1_schema.avsc b/openedx_events/event_bus/avro/tests/schemas/org+openedx+learning+exam+attempt+errored+v1_schema.avsc new file mode 100644 index 00000000..bfbdb12d --- /dev/null +++ b/openedx_events/event_bus/avro/tests/schemas/org+openedx+learning+exam+attempt+errored+v1_schema.avsc @@ -0,0 +1,79 @@ +{ + "name": "CloudEvent", + "type": "record", + "doc": "Avro Event Format for CloudEvents created with openedx_events/schema", + "fields": [ + { + "name": "exam_attempt_data", + "type": { + "name": "ExamAttemptData", + "type": "record", + "fields": [ + { + "name": "user_id", + "type": "long" + }, + { + "name": "course_key", + "type": "string" + }, + { + "name": "usage_key", + "type": "string" + }, + { + "name": "requesting_user", + "type": [ + "null", + { + "name": "UserData", + "type": "record", + "fields": [ + { + "name": "id", + "type": "long" + }, + { + "name": "is_active", + "type": "boolean" + }, + { + "name": "pii", + "type": { + "name": "UserPersonalData", + "type": "record", + "fields": [ + { + "name": "username", + "type": "string" + }, + { + "name": "email", + "type": "string" + }, + { + "name": "name", + "type": "string" + } + ] + } + } + ] + } + ], + "default": null + }, + { + "name": "credit_requirement_status", + "type": [ + "null", + "string" + ], + "default": null + } + ] + } + } + ], + "namespace": "org.openedx.learning.exam.attempt.errored.v1" +} \ No newline at end of file diff --git a/openedx_events/event_bus/avro/tests/schemas/org+openedx+learning+exam+attempt+rejected+v1_schema.avsc b/openedx_events/event_bus/avro/tests/schemas/org+openedx+learning+exam+attempt+rejected+v1_schema.avsc new file mode 100644 index 00000000..dee79ecf --- /dev/null +++ b/openedx_events/event_bus/avro/tests/schemas/org+openedx+learning+exam+attempt+rejected+v1_schema.avsc @@ -0,0 +1,79 @@ +{ + "name": "CloudEvent", + "type": "record", + "doc": "Avro Event Format for CloudEvents created with openedx_events/schema", + "fields": [ + { + "name": "exam_attempt_data", + "type": { + "name": "ExamAttemptData", + "type": "record", + "fields": [ + { + "name": "user_id", + "type": "long" + }, + { + "name": "course_key", + "type": "string" + }, + { + "name": "usage_key", + "type": "string" + }, + { + "name": "requesting_user", + "type": [ + "null", + { + "name": "UserData", + "type": "record", + "fields": [ + { + "name": "id", + "type": "long" + }, + { + "name": "is_active", + "type": "boolean" + }, + { + "name": "pii", + "type": { + "name": "UserPersonalData", + "type": "record", + "fields": [ + { + "name": "username", + "type": "string" + }, + { + "name": "email", + "type": "string" + }, + { + "name": "name", + "type": "string" + } + ] + } + } + ] + } + ], + "default": null + }, + { + "name": "credit_requirement_status", + "type": [ + "null", + "string" + ], + "default": null + } + ] + } + } + ], + "namespace": "org.openedx.learning.exam.attempt.rejected.v1" +} \ No newline at end of file diff --git a/openedx_events/event_bus/avro/tests/schemas/org+openedx+learning+exam+attempt+reset+v1_schema.avsc b/openedx_events/event_bus/avro/tests/schemas/org+openedx+learning+exam+attempt+reset+v1_schema.avsc new file mode 100644 index 00000000..a279d550 --- /dev/null +++ b/openedx_events/event_bus/avro/tests/schemas/org+openedx+learning+exam+attempt+reset+v1_schema.avsc @@ -0,0 +1,79 @@ +{ + "name": "CloudEvent", + "type": "record", + "doc": "Avro Event Format for CloudEvents created with openedx_events/schema", + "fields": [ + { + "name": "exam_attempt_data", + "type": { + "name": "ExamAttemptData", + "type": "record", + "fields": [ + { + "name": "user_id", + "type": "long" + }, + { + "name": "course_key", + "type": "string" + }, + { + "name": "usage_key", + "type": "string" + }, + { + "name": "requesting_user", + "type": [ + "null", + { + "name": "UserData", + "type": "record", + "fields": [ + { + "name": "id", + "type": "long" + }, + { + "name": "is_active", + "type": "boolean" + }, + { + "name": "pii", + "type": { + "name": "UserPersonalData", + "type": "record", + "fields": [ + { + "name": "username", + "type": "string" + }, + { + "name": "email", + "type": "string" + }, + { + "name": "name", + "type": "string" + } + ] + } + } + ] + } + ], + "default": null + }, + { + "name": "credit_requirement_status", + "type": [ + "null", + "string" + ], + "default": null + } + ] + } + } + ], + "namespace": "org.openedx.learning.exam.attempt.reset.v1" +} \ No newline at end of file diff --git a/openedx_events/event_bus/avro/tests/schemas/org+openedx+learning+exam+attempt+submitted+v1_schema.avsc b/openedx_events/event_bus/avro/tests/schemas/org+openedx+learning+exam+attempt+submitted+v1_schema.avsc new file mode 100644 index 00000000..dee651ad --- /dev/null +++ b/openedx_events/event_bus/avro/tests/schemas/org+openedx+learning+exam+attempt+submitted+v1_schema.avsc @@ -0,0 +1,79 @@ +{ + "name": "CloudEvent", + "type": "record", + "doc": "Avro Event Format for CloudEvents created with openedx_events/schema", + "fields": [ + { + "name": "exam_attempt_data", + "type": { + "name": "ExamAttemptData", + "type": "record", + "fields": [ + { + "name": "user_id", + "type": "long" + }, + { + "name": "course_key", + "type": "string" + }, + { + "name": "usage_key", + "type": "string" + }, + { + "name": "requesting_user", + "type": [ + "null", + { + "name": "UserData", + "type": "record", + "fields": [ + { + "name": "id", + "type": "long" + }, + { + "name": "is_active", + "type": "boolean" + }, + { + "name": "pii", + "type": { + "name": "UserPersonalData", + "type": "record", + "fields": [ + { + "name": "username", + "type": "string" + }, + { + "name": "email", + "type": "string" + }, + { + "name": "name", + "type": "string" + } + ] + } + } + ] + } + ], + "default": null + }, + { + "name": "credit_requirement_status", + "type": [ + "null", + "string" + ], + "default": null + } + ] + } + } + ], + "namespace": "org.openedx.learning.exam.attempt.submitted.v1" +} \ No newline at end of file diff --git a/openedx_events/event_bus/avro/tests/schemas/org+openedx+learning+exam+attempt+verified+v1_schema.avsc b/openedx_events/event_bus/avro/tests/schemas/org+openedx+learning+exam+attempt+verified+v1_schema.avsc new file mode 100644 index 00000000..eeec0765 --- /dev/null +++ b/openedx_events/event_bus/avro/tests/schemas/org+openedx+learning+exam+attempt+verified+v1_schema.avsc @@ -0,0 +1,79 @@ +{ + "name": "CloudEvent", + "type": "record", + "doc": "Avro Event Format for CloudEvents created with openedx_events/schema", + "fields": [ + { + "name": "exam_attempt_data", + "type": { + "name": "ExamAttemptData", + "type": "record", + "fields": [ + { + "name": "user_id", + "type": "long" + }, + { + "name": "course_key", + "type": "string" + }, + { + "name": "usage_key", + "type": "string" + }, + { + "name": "requesting_user", + "type": [ + "null", + { + "name": "UserData", + "type": "record", + "fields": [ + { + "name": "id", + "type": "long" + }, + { + "name": "is_active", + "type": "boolean" + }, + { + "name": "pii", + "type": { + "name": "UserPersonalData", + "type": "record", + "fields": [ + { + "name": "username", + "type": "string" + }, + { + "name": "email", + "type": "string" + }, + { + "name": "name", + "type": "string" + } + ] + } + } + ] + } + ], + "default": null + }, + { + "name": "credit_requirement_status", + "type": [ + "null", + "string" + ], + "default": null + } + ] + } + } + ], + "namespace": "org.openedx.learning.exam.attempt.verified.v1" +} \ No newline at end of file diff --git a/openedx_events/learning/data.py b/openedx_events/learning/data.py index 91ff052c..6dc9668e 100644 --- a/openedx_events/learning/data.py +++ b/openedx_events/learning/data.py @@ -97,10 +97,9 @@ class CourseEnrollmentData: @attr.s(frozen=True) -class Invalidate: +class CertificateData: """ - Attributes dAttributes for - This is separate from ceritificate data because of how diff the params areefined for Open edX Certificate data object. + Attributes defined for Open edX Certificate data object. Arguments: user (UserData): user associated with the Certificate. @@ -313,64 +312,21 @@ class CourseStaffData: user = attr.ib(type=UserData) -attr.s(frozen=True) -class GradeOverrideData: +@attr.s(frozen=True) +class ExamAttemptData: """ - Attributes defined for the Open edX Grades Override data object. + Attributes defined for the Open edX Exam downstream effects. Arguments: user_id (int): identifier of the user to which the grade override belongs - course_key_or_id (str): identifier of the course to which the grade override belongs - usage_key_or_id (str): identifier of the content that will get a grade override - earned_all (float): the value that the subsection grade will be changed to - earned_graded (float): the value that the subsection grade will be changed to - overrider (str): the user creating the override - comment (str): reason for the override + course_key (CourseKey): identifier of the course to which the grade override belongs + usage_key (UsageKey): identifier of the content that will get a grade override + requesting_user (UserData): user triggering event, sent only when instructor modifies an exam attempt + credit_requirement_status (str): status to change the student's CreditRequirement to """ - used_id = attr.ib(type=int) - course_key_or_id = attr.ib(type=str) - usage_key_or_id = attr.ib(type=str) - earned_all = attr.ib(type=float, default=None) - earned_graded = attr.ib(type=float, default=None) - overrider = attr.ib(type=str, default=None) - comment = attr.ib(type=str, default=None) - -attr.s(frozen=True) -class InstructorCompletionData: - # TODO: These docstrings!!! - """ - Attributes defined for Open edX Instructor service functions - that handle the completion state of xblocks within a course. - - Arguments: - username (str): - content_id (str): - course_id (str): - """ - username = attr.ib(type=str) - content_id = attr.ib(type=str) - course_id = attr.ib(type=str, default=None) + user_id = attr.ib(type=int) + course_key = attr.ib(type=CourseKey) + usage_key = attr.ib(type=UsageKey) requesting_user = attr.ib(type=UserData, default=None) - - -attr.s(frozen=True) -class CreditRequirementStatusData: - """ - - """ - user_id = attr.id(type=int) - course_key_or_id = attr.id(type=str) - req_namespace = attr.id(type=str) - req_name = attr.id(type=str) - status = attr.id(type=str, default=None) - - -attr.s(frozen=True) -class InvalidateCertificateData: - """ - Attributes for - This is separate from ceritificate data because of how diff the params are - """ - user_id = attr.id(type=int) - course_id = attr.ib(type=str) + credit_requirement_status = attr.ib(type=str, default=None) diff --git a/openedx_events/learning/signals.py b/openedx_events/learning/signals.py index b462ac58..9fac0696 100644 --- a/openedx_events/learning/signals.py +++ b/openedx_events/learning/signals.py @@ -14,10 +14,7 @@ CourseDiscussionConfigurationData, CourseEnrollmentData, CourseStaffData, - CreditRequirementStatusData, - GradeOverrideData, - InstructorCompletionData, - InvalidateCertificateData, + ExamAttemptData, PersistentCourseGradeData, ProgramCertificateData, UserData, @@ -224,68 +221,57 @@ } ) -# .. event_type: org.openedx.learning.grade.override.created.v1 -# .. event_name: GRADE_OVERRIDE_CREATED -# .. event_description: Emitted when a user's grade for a subsection is overriden. -# .. event_data: GradeOverrideData -GRADE_OVERRIDE_CREATED = OpenEdxPublicSignal( - event_type="org.openedx.learning.grade.override.created.v1", +# .. event_type: org.openedx.learning.exam.attempt.submitted.v1 +# .. event_name: EXAM_ATTEMPT_SUBMITTED +# .. event_description: Emitted when an exam attempt is submitted by a learner. +# .. event_data: ExamAttemptData +EXAM_ATTEMPT_SUBMITTED = OpenEdxPublicSignal( + event_type="org.openedx.learning.exam.attempt.submitted.v1", data={ - "grade_override_data": GradeOverrideData, + "exam_attempt_data": ExamAttemptData, } ) -# .. event_type: org.openedx.learning.grade.override.deleted.v1 -# .. event_name: GRADE_OVERRIDE_DELETED -# .. event_description: Emitted to undo a grade override for a subsection. -# .. event_data: GradeOverrideData -GRADE_OVERRIDE_DELETED = OpenEdxPublicSignal( - event_type="org.openedx.learning.grade.override.deleted.v1", +# .. event_type: org.openedx.learning.exam.attempt.rejected.v1 +# .. event_name: EXAM_ATTEMPT_REJECTED +# .. event_description: Emitted when an exam attempt is marked rejected by an instructor or staff. +# .. event_data: ExamAttemptData +EXAM_ATTEMPT_REJECTED = OpenEdxPublicSignal( + event_type="org.openedx.learning.exam.attempt.rejected.v1", data={ - "grade_override_data": GradeOverrideData, + "exam_attempt_data": ExamAttemptData, } ) -# .. event_type: org.openedx.learning.all.child.xblocks.completed.v1 -# .. event_name: ALL_CHILD_XBLOCKS_COMPLETED -# .. event_description: Emitted to mark all the child xblocks of section/subsection/unit as completed. -# .. event_data: InstructorCompletionData -ALL_CHILD_XBLOCKS_COMPLETED = OpenEdxPublicSignal( - event_type="org.openedx.learning.all.child.xblocks.completed.v1", +# .. event_type: org.openedx.learning.exam.attempt.verified.v1 +# .. event_name: EXAM_ATTEMPT_VERIFIED +# .. event_description: Emitted when an exam attempt is marked verified by an instructor or staff. +# .. event_data: ExamAttemptData +EXAM_ATTEMPT_VERIFIED = OpenEdxPublicSignal( + event_type="org.openedx.learning.exam.attempt.verified.v1", data={ - "instructor_completed_data": InstructorCompletionData, + "exam_attempt_data": ExamAttemptData, } ) -# .. event_type: org.openedx.learning.all.child.xblocks.reset.v1 -# .. event_name: ALL_CHILD_XBLOCKS_RESET -# .. event_description: Emitted to reset the state of all child xblocks in a section/subsection/unit. -# .. event_data: InstructorCompletionData -ALL_CHILD_XBLOCKS_RESET = OpenEdxPublicSignal( - event_type="org.openedx.learning.all.child.xblocks.reset.v1", +# .. event_type: org.openedx.learning.exam.attempt.errored.v1 +# .. event_name: EXAM_ATTEMPT_ERRORED +# .. event_description: Emitted when a learner's exam attempt errors out. +# .. event_data: ExamAttemptData +EXAM_ATTEMPT_ERRORED = OpenEdxPublicSignal( + event_type="org.openedx.learning.exam.attempt.errored.v1", data={ - "instructor_completed_data": InstructorCompletionData, + "exam_attempt_data": ExamAttemptData, } ) -# .. event_type: org.openedx.learning.credit.requirement.status.set.v1 -# .. event_name: CREDIT_REQUIREMENT_STATUS_SET -# .. event_description: Creates or modifies a user's credit requirement status for a course. -# .. event_data: CreditRequirementStatusData -CREDIT_REQUIREMENT_STATUS_SET = OpenEdxPublicSignal( - event_type="org.openedx.learning.set.credit.requirement.status.set.v1", +# .. event_type: org.openedx.learning.exam.attempt.reset.v1 +# .. event_name: EXAM_ATTEMPT_RESET +# .. event_description: Emitted when an exam attempt is reset by an instructor or staff. +# .. event_data: ExamAttemptData +EXAM_ATTEMPT_RESET = OpenEdxPublicSignal( + event_type="org.openedx.learning.exam.attempt.reset.v1", data={ - "credit_requirement_status_data": CreditRequirementStatusData, - } -) - -# .. event_type: org.openedx.learning.credit.requirement.status.data.v1 -# .. event_name: CREDIT_REQUIREMENT_STATUS_REMOVED -# .. event_description: Deletes a user's credit requirement status for a course. -# .. event_data: CreditRequirementStatusData -CREDIT_REQUIREMENT_STATUS_REMOVED = OpenEdxPublicSignal( - event_type="org.openedx.learning.remove.credit.requirement.status.v1", - data={ - "credit_requirement_status_data": CreditRequirementStatusData, + "exam_attempt_data": ExamAttemptData, } )