diff --git a/src/ralph/models/xapi/__init__.py b/src/ralph/models/xapi/__init__.py index e655b1ea0..501e9a3db 100644 --- a/src/ralph/models/xapi/__init__.py +++ b/src/ralph/models/xapi/__init__.py @@ -2,6 +2,12 @@ # flake8: noqa +from .assessment.statements import ( + AssessmentCompleted, + AssessmentInitialized, + AssessmentLaunched, + AssessmentTerminated, +) from .navigation.statements import PageTerminated, PageViewed from .video.statements import ( VideoCompleted, @@ -14,20 +20,3 @@ VideoTerminated, VideoVolumeChangeInteraction, ) -from .virtual_classroom.statements import ( - VirtualClassroomAnsweredPoll, - VirtualClassroomInitialized, - VirtualClassroomJoined, - VirtualClassroomLeft, - VirtualClassroomLoweredHand, - VirtualClassroomMuted, - VirtualClassroomPostedPublicMessage, - VirtualClassroomRaisedHand, - VirtualClassroomSharedScreen, - VirtualClassroomStartedCamera, - VirtualClassroomStartedPoll, - VirtualClassroomStoppedCamera, - VirtualClassroomTerminated, - VirtualClassroomUnmuted, - VirtualClassroomUnsharedScreen -) diff --git a/src/ralph/models/xapi/assessment/contexts.py b/src/ralph/models/xapi/assessment/contexts.py new file mode 100644 index 000000000..0ff2309d8 --- /dev/null +++ b/src/ralph/models/xapi/assessment/contexts.py @@ -0,0 +1,61 @@ +"""`Assessment` xAPI events context fields definitions.""" + +from typing import List, Union + +from ..base.contexts import BaseXapiContext, BaseXapiContextContextActivities +from ..base.unnested_objects import BaseXapiActivityType, BaseXapiActivityTypeDefinition +from ..concepts.constants.assessment import ASSESSMENT_CONTEXT_CATEGORY +from ..constants import CONTEXT_CONTEXTACTIVTIES_CATEGORY_DEFINITION_TYPE + + +class AssessmentContextActivitiesCategoryDefinition(BaseXapiActivityTypeDefinition): + # noqa: D205 + """Pydantic model for assessment `context`.`contextActivities`.`category`. + `definition` property. + + Attributes: + type (str): Consists of the value `http://adlnet.gov/expapi/activities/profile`. + """ + + type: CONTEXT_CONTEXTACTIVTIES_CATEGORY_DEFINITION_TYPE = ( + CONTEXT_CONTEXTACTIVTIES_CATEGORY_DEFINITION_TYPE.__args__[0] + ) + + +class AssessmentContextActivitiesCategory(BaseXapiActivityType): + # noqa: D205, D415 + """Pydantic model for assessment `context`.`contextActivities`.`category` + property. + + Attributes: + id (str): Consists of the value `https://w3id.org/xapi/virtual-classroom`. + definition (dict): see AssessmentContextActivitiesCategoryDefinition. + """ + + id: ASSESSMENT_CONTEXT_CATEGORY = ASSESSMENT_CONTEXT_CATEGORY.__args__[0] + definition: AssessmentContextActivitiesCategoryDefinition = ( + AssessmentContextActivitiesCategoryDefinition() + ) + + +class AssessmentContextActivities(BaseXapiContextContextActivities): + """Pydantic model for assessment `context`.`contextActivities` property. + + Attributes: + category (list): see AssessmentContextActivitiesCategory. + """ + + category: Union[ + AssessmentContextActivitiesCategory, + List[AssessmentContextActivitiesCategory], + ] = [AssessmentContextActivitiesCategory()] + + +class AssessmentContext(BaseXapiContext): + """Pydantic model for assessment base `context` property. + + Attributes: + contextActivities: see AssessmentContextActivities. + """ + + contextActivities: AssessmentContextActivities = AssessmentContextActivities() diff --git a/src/ralph/models/xapi/assessment/fields/contexts.py b/src/ralph/models/xapi/assessment/fields/contexts.py deleted file mode 100644 index 2f1bcdf9a..000000000 --- a/src/ralph/models/xapi/assessment/fields/contexts.py +++ /dev/null @@ -1,43 +0,0 @@ -"""Assessment xAPI events context fields definitions.""" - -from typing import Dict, List, Union - -try: - from typing import Literal -except ImportError: - from typing_extensions import Literal - -from ...config import BaseModelWithConfig -from ...fields.contexts import ContextActivitiesContextField -from ..constants import ASSESSMENT_CONTEXT_CATEGORY -from .objects import AssessmentObjectField - - -class AssessmentContextActivitiesField(ContextActivitiesContextField): - """Pydantic model for assessment `context`.`contextActivities` field. - - Attributes: - category (List): Consists of a list containing the dictionary - {"id": "http://schema.dases.eu/xapi/profile/assessment"}. - parent (List): See AssessmentObjectField. - """ - - category: Union[ - Dict[Literal["id"], ASSESSMENT_CONTEXT_CATEGORY], - List[Dict[Literal["id"], ASSESSMENT_CONTEXT_CATEGORY]], - ] = [{"id": ASSESSMENT_CONTEXT_CATEGORY.__args__[0]}] - parent: Union[AssessmentObjectField, List[AssessmentObjectField]] = [ - AssessmentObjectField() - ] - - -class AssessmentContextField(BaseModelWithConfig): - """Pydantic model for assessment `context` field. - - Attributes: - contextActivities (json): see AssessmentContextActivitiesField. - """ - - contextActivities: AssessmentContextActivitiesField = ( - AssessmentContextActivitiesField() - ) diff --git a/src/ralph/models/xapi/assessment/fields/objects.py b/src/ralph/models/xapi/assessment/fields/objects.py deleted file mode 100644 index a8a24d91a..000000000 --- a/src/ralph/models/xapi/assessment/fields/objects.py +++ /dev/null @@ -1,41 +0,0 @@ -"""Video xAPI events object fields definitions.""" - -from ...fields.unnested_objects import ( - ActivityObjectField, - InteractionObjectDefinitionField, - ObjectDefinitionField, -) -from ..constants import ASSESSMENT_OBJECT_DEFINITION_TYPE - - -class AssessmentObjectDefinitionField(ObjectDefinitionField): - """Pydantic model for assessment `object`.`definition` field. - - Attributes: - type (str): Consists of the value - `http://adlnet.gov/expapi/activities/assessment`. - """ - - type: ASSESSMENT_OBJECT_DEFINITION_TYPE = ( - ASSESSMENT_OBJECT_DEFINITION_TYPE.__args__[0] - ) - - -class AssessmentObjectField(ActivityObjectField): - """Pydantic model for assessment `object` field. - - Attributes: - definition (dict): See AssessmentObjectDefinitionField. - """ - - definition: AssessmentObjectDefinitionField = AssessmentObjectDefinitionField() - - -class QuestionObjectField(ActivityObjectField): - """Pydantic model for question `object` field. - - Attributes: - definition (dict): See InteractionObjectDefinitionField. - """ - - definition: InteractionObjectDefinitionField = InteractionObjectDefinitionField() diff --git a/src/ralph/models/xapi/assessment/fields/verbs.py b/src/ralph/models/xapi/assessment/fields/verbs.py deleted file mode 100644 index 3af865273..000000000 --- a/src/ralph/models/xapi/assessment/fields/verbs.py +++ /dev/null @@ -1,20 +0,0 @@ -"""Assessment xAPI events verb fields definitions.""" - -from typing import Dict - -from ...constants import LANG_EN_US_DISPLAY, VERB_ANSWERED_DISPLAY, VERB_ANSWERED_ID -from ...fields.verbs import VerbField - - -class AnsweredVerbField(VerbField): - """Pydantic model for answered `verb` field. - - Attributes: - id (str): Consists of the value `http://adlnet.gov/expapi/verbs/answered`. - display (Dict): Consists of the dictionary `{"en-US": "answered"}`. - """ - - id: VERB_ANSWERED_ID = VERB_ANSWERED_ID.__args__[0] - display: Dict[LANG_EN_US_DISPLAY, VERB_ANSWERED_DISPLAY] = { - LANG_EN_US_DISPLAY.__args__[0]: VERB_ANSWERED_DISPLAY.__args__[0] - } diff --git a/src/ralph/models/xapi/assessment/statements.py b/src/ralph/models/xapi/assessment/statements.py index ff8c0368a..b760ce96b 100644 --- a/src/ralph/models/xapi/assessment/statements.py +++ b/src/ralph/models/xapi/assessment/statements.py @@ -1,34 +1,110 @@ -"""Video xAPI event definitions.""" +"""`Assessment` xAPI event definitions.""" -from typing import Optional +from datetime import datetime from ...selector import selector -from ..base import BaseXapiModel -from ..fields.results import ResultField -from .fields.contexts import AssessmentContextField -from .fields.objects import QuestionObjectField -from .fields.verbs import AnsweredVerbField +from ..base.statements import BaseXapiStatement +from ..concepts.activity_types.scorm_profile import CMIInteractionActivityType +from ..concepts.verbs.scorm_profile import ( + CompletedVerb, + InitializedVerb, + LaunchedVerb, + TerminatedVerb, +) +from .contexts import AssessmentContext +# Mandatory statements -class AssessmentAnsweredQuestion(BaseXapiModel): - """Pydantic model for video answered question statement. - Example: John has answered a question in an assessment. +class AssessmentInitialized(BaseXapiStatement): + """Pydantic model for assessment initialized statement. + + Example: + + Attributes: + verb (dict): See InitializedVerb. + object (dict): See CMIInteractionActivityType. + context (dict): See AssessmentContext. + timestamp (datetime): Consists of the timestamp of when the event occurred. + """ + + __selector__ = selector( + verb__id="http://adlnet.gov/expapi/verbs/initialized", + object__definition__type=( + "http://adlnet.gov/expapi/activities/cmi.interaction" + ), + ) + + verb: InitializedVerb = InitializedVerb() + object: CMIInteractionActivityType + context: AssessmentContext + timestamp: datetime + + +class AssessmentLaunched(BaseXapiStatement): + """Pydantic model for assessment launched statement. + + Example: Attributes: - object (dict): See QuestionObjectField. - verb (dict): See AnsweredVerbField. - context (dict): See AssessmentContextField. + verb (dict): See LaunchedVerb. + object (dict): See CMIInteractionActivityType. + context (dict): See AssessmentContext. + timestamp (datetime): Consists of the timestamp of when the event occurred. """ __selector__ = selector( - verb__id="http://adlnet.gov/expapi/verbs/answered", - context__contextActivities__definition__type=( - "http://adlnet.gov/expapi/activities/assessment" + verb__id="http://adlnet.gov/expapi/verbs/launched", + object__definition__type=( + "http://adlnet.gov/expapi/activities/cmi.interaction" ), ) - object: QuestionObjectField = QuestionObjectField() - verb: AnsweredVerbField = AnsweredVerbField() - context: AssessmentContextField = AssessmentContextField() - result: Optional[ResultField] + verb: LaunchedVerb = LaunchedVerb() + object: CMIInteractionActivityType + context: AssessmentContext + timestamp: datetime + + +class AssessmentCompleted(BaseXapiStatement): + """Pydantic model for assessment completed statement. + + Example: + + Attributes: + verb (dict): See CompletedVerb. + result (dict): See CMIInteractionActivityType. + context (dict): See VideoCompletedContext. + """ + + __selector__ = selector( + object__definition__type="http://adlnet.gov/expapi/activities/cmi.interaction", + verb__id="http://adlnet.gov/expapi/verbs/completed", + ) + + verb: CompletedVerb = CompletedVerb() + result: CMIInteractionActivityType + context: AssessmentContext + timestamp: datetime + + +class AssessmentTerminated(BaseXapiStatement): + """Pydantic model for assessment terminated statement. + + Example: + + Attributes: + verb (dict): See CompletedVerb. + result (dict): See CMIInteractionActivityType. + context (dict): See VideoCompletedContext. + """ + + __selector__ = selector( + object__definition__type="http://adlnet.gov/expapi/activities/cmi.interaction", + verb__id="http://adlnet.gov/expapi/verbs/terminated", + ) + + verb: TerminatedVerb = TerminatedVerb() + result: CMIInteractionActivityType + context: AssessmentContext + timestamp: datetime diff --git a/src/ralph/models/xapi/concepts/activity_types/virtual_classroom.py b/src/ralph/models/xapi/concepts/activity_types/virtual_classroom.py index 5e7378268..3ab409406 100644 --- a/src/ralph/models/xapi/concepts/activity_types/virtual_classroom.py +++ b/src/ralph/models/xapi/concepts/activity_types/virtual_classroom.py @@ -1,10 +1,13 @@ """`Virtual classroom` activity types definitions.""" -from ...fields.unnested_objects import ActivityObjectField, ObjectDefinitionField +from ...base.unnested_objects import ( + BaseXapiActivityType, + BaseXapiActivityTypeDefinition, +) from ..constants.virtual_classroom import VIRTUAL_CLASSROOM_OBJECT_DEFINITION_TYPE -class VirtualClassroomObjectDefinitionField(ObjectDefinitionField): +class VirtualClassroomObjectDefinitionField(BaseXapiActivityTypeDefinition): """Pydantic model for virtual classroom `object`.`definition` field. Attributes: @@ -17,7 +20,7 @@ class VirtualClassroomObjectDefinitionField(ObjectDefinitionField): ) -class VirtualClassroomObjectField(ActivityObjectField): +class VirtualClassroomObjectField(BaseXapiActivityType): """Pydantic model for virtual classroom `object` field. Attributes: diff --git a/src/ralph/models/xapi/concepts/constants/assessment.py b/src/ralph/models/xapi/concepts/constants/assessment.py new file mode 100644 index 000000000..6333d7856 --- /dev/null +++ b/src/ralph/models/xapi/concepts/constants/assessment.py @@ -0,0 +1,11 @@ +"""Constants for `Assessment` xAPI profile.""" + +try: + from typing import Literal +except ImportError: + from typing_extensions import Literal + + +ASSESSMENT_CONTEXT_CATEGORY = Literal[ # pylint:disable=invalid-name + "https://w3id.org/xapi/assessment" +] diff --git a/src/ralph/models/xapi/concepts/constants/scorm_profile.py b/src/ralph/models/xapi/concepts/constants/scorm_profile.py index 83de0e4c8..2918317f4 100644 --- a/src/ralph/models/xapi/concepts/constants/scorm_profile.py +++ b/src/ralph/models/xapi/concepts/constants/scorm_profile.py @@ -15,6 +15,9 @@ VERB_INTERACTED_ID = Literal[ # pylint:disable=invalid-name "http://adlnet.gov/expapi/verbs/interacted" ] +VERB_LAUNCHED_ID = Literal[ # pylint:disable=invalid-name + "http://adlnet.gov/expapi/verbs/launched" +] VERB_TERMINATED_ID = Literal[ # pylint:disable=invalid-name "http://adlnet.gov/expapi/verbs/terminated" ] @@ -23,6 +26,7 @@ VERB_COMPLETED_DISPLAY = Literal["completed"] # pylint:disable=invalid-name VERB_INITIALIZED_DISPLAY = Literal["initialized"] # pylint:disable=invalid-name VERB_INTERACTED_DISPLAY = Literal["interacted"] # pylint:disable=invalid-name +VERB_LAUNCHED_DISPLAY = Literal["launched"] # pylint:disable=invalid-name VERB_TERMINATED_DISPLAY = Literal["terminated"] # pylint:disable=invalid-name # Activity types IRIs diff --git a/src/ralph/models/xapi/concepts/verbs/scorm_profile.py b/src/ralph/models/xapi/concepts/verbs/scorm_profile.py index 3a06c396e..3b832528d 100644 --- a/src/ralph/models/xapi/concepts/verbs/scorm_profile.py +++ b/src/ralph/models/xapi/concepts/verbs/scorm_profile.py @@ -10,6 +10,8 @@ VERB_INITIALIZED_ID, VERB_INTERACTED_DISPLAY, VERB_INTERACTED_ID, + VERB_LAUNCHED_DISPLAY, + VERB_LAUNCHED_ID, VERB_TERMINATED_DISPLAY, VERB_TERMINATED_ID, ) @@ -52,6 +54,18 @@ class InteractedVerb(BaseXapiVerb): display: Optional[Dict[LANG_EN_US_DISPLAY, VERB_INTERACTED_DISPLAY]] +class LaunchedVerb(BaseXapiVerb): + """Pydantic model for launched `verb`. + + Attributes: + id (str): Consists of the value `http://adlnet.gov/expapi/verbs/launched`. + display (dict): Consists of the dictionary `{"en-US": "launched"}`. + """ + + id: VERB_LAUNCHED_ID = VERB_LAUNCHED_ID.__args__[0] + display: Optional[Dict[LANG_EN_US_DISPLAY, VERB_LAUNCHED_DISPLAY]] + + class TerminatedVerb(BaseXapiVerb): """Pydantic model for terminated `verb`.