We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Create XAPI statements for live video
## Feature Request

**Is your feature request related to a problem or unsupported use case? Please describe.**

When a video is a live all the existing XAPI statement are sent like a regular videos. Some events should not be sent and some data can't be computed

**Describe the solution you'd like**

Change the activity-type to `http://id.tincanapi.com/activitytype/webinar`
Send statement for those events : 
- initialized
- play
- pause
- interacted

Also, do not send video length info, we can't have it. The completion threshold can not be computed too.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `src/backend/marsha/core/xapi.py`
Content:
```
1 """XAPI module."""
2 import re
3 import uuid
4 
5 from django.conf import settings
6 from django.utils import timezone
7 from django.utils.translation import to_locale
8 
9 import requests
10 
11 
12 class XAPIStatement:
13     """Object to work on a XAPI Statement."""
14 
15     statement = None
16 
17     def __init__(self, video, statement, lti_user):
18         """Compute a valid xapi satement.
19 
20         Parameters
21         ----------
22         video : Type[.models/videos]
23             The video object used in the xAPI statement
24 
25         statement : dictionary
26             Statement containing base information to send to the LRS
27             An example of expected statement:
28             {
29                 "verb": {
30                     "id": "http://adlnet.gov/expapi/verbs/initialized",
31                     "display": {
32                         "en-US": "initialized"
33                     }
34                 },
35                 "context": {
36                     "extensions": {
37                         "https://w3id.org/xapi/video/extensions/volume": 1,
38                         "https://w3id.org/xapi/video/extensions/video-playback-size": "640x264",
39                     }
40                 }
41             }
42 
43         lti_user : Type[lti.LTIUser]
44             Object representing data stored in the JWT Token and related to the user authenticated
45             with LTI
46 
47         """
48         try:
49             user_id = lti_user.user.get("id")
50         except AttributeError:
51             user_id = lti_user.session_id
52 
53         homepage = video.playlist.consumer_site.domain
54 
55         if re.match(r"^http(s?):\/\/.*", homepage) is None:
56             homepage = f"http://{homepage}"
57 
58         if "id" not in statement:
59             statement["id"] = str(uuid.uuid4())
60 
61         statement["timestamp"] = timezone.now().isoformat()
62         statement["context"].update(
63             {"contextActivities": {"category": [{"id": "https://w3id.org/xapi/video"}]}}
64         )
65 
66         statement["actor"] = {
67             "objectType": "Agent",
68             "account": {"name": user_id, "homePage": homepage},
69         }
70 
71         statement["object"] = {
72             "definition": {
73                 "type": "https://w3id.org/xapi/video/activity-type/video",
74                 "name": {
75                     to_locale(settings.LANGUAGE_CODE).replace("_", "-"): video.title
76                 },
77             },
78             "id": "uuid://{id}".format(id=str(video.id)),
79             "objectType": "Activity",
80         }
81 
82         object_extensions = {}
83         if lti_user.course.get("school_name") is not None:
84             object_extensions[
85                 "https://w3id.org/xapi/acrossx/extensions/school"
86             ] = lti_user.course["school_name"]
87 
88         if lti_user.course.get("course_name") is not None:
89             object_extensions[
90                 "http://adlnet.gov/expapi/activities/course"
91             ] = lti_user.course["course_name"]
92 
93         if lti_user.course.get("course_run") is not None:
94             object_extensions[
95                 "http://adlnet.gov/expapi/activities/module"
96             ] = lti_user.course["course_run"]
97 
98         if object_extensions:
99             statement["object"]["definition"]["extensions"] = object_extensions
100 
101         self.statement = statement
102 
103     def get_statement(self):
104         """Return the enriched statement."""
105         return self.statement
106 
107 
108 class XAPI:
109     """The XAPI object compute statements and send them to a LRS."""
110 
111     def __init__(self, url, auth_token, xapi_version="1.0.3"):
112         """Initialize the XAPI module.
113 
114         Parameters
115         ----------
116         url: string
117             The LRS endpoint to fetch
118 
119         auth_token: string
120             The basic_auth token used to authenticate on the LRS
121 
122         xapi_version: string
123             The xAPI version used.
124 
125         """
126         self.url = url
127         self.auth_token = auth_token
128         self.xapi_version = xapi_version
129 
130     def send(self, xapi_statement):
131         """Send the statement to a LRS.
132 
133         Parameters
134         ----------
135         statement : Type[.XAPIStatement]
136 
137         """
138         headers = {
139             "Authorization": self.auth_token,
140             "Content-Type": "application/json",
141             "X-Experience-API-Version": self.xapi_version,
142         }
143 
144         response = requests.post(
145             self.url, json=xapi_statement.get_statement(), headers=headers
146         )
147 
148         response.raise_for_status()
149
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/src/backend/marsha/core/xapi.py b/src/backend/marsha/core/xapi.py
--- a/src/backend/marsha/core/xapi.py
+++ b/src/backend/marsha/core/xapi.py
@@ -52,6 +52,12 @@
 
         homepage = video.playlist.consumer_site.domain
 
+        activity_type = "https://w3id.org/xapi/video/activity-type/video"
+
+        # When the video is a live we change the activity to webinar
+        if video.live_state is not None:
+            activity_type = "http://id.tincanapi.com/activitytype/webinar"
+
         if re.match(r"^http(s?):\/\/.*", homepage) is None:
             homepage = f"http://{homepage}"
 
@@ -70,7 +76,7 @@
 
         statement["object"] = {
             "definition": {
-                "type": "https://w3id.org/xapi/video/activity-type/video",
+                "type": activity_type,
                 "name": {
                     to_locale(settings.LANGUAGE_CODE).replace("_", "-"): video.title
                 },

{"golden_diff": "diff --git a/src/backend/marsha/core/xapi.py b/src/backend/marsha/core/xapi.py\n--- a/src/backend/marsha/core/xapi.py\n+++ b/src/backend/marsha/core/xapi.py\n@@ -52,6 +52,12 @@\n \n         homepage = video.playlist.consumer_site.domain\n \n+        activity_type = \"https://w3id.org/xapi/video/activity-type/video\"\n+\n+        # When the video is a live we change the activity to webinar\n+        if video.live_state is not None:\n+            activity_type = \"http://id.tincanapi.com/activitytype/webinar\"\n+\n         if re.match(r\"^http(s?):\\/\\/.*\", homepage) is None:\n             homepage = f\"http://{homepage}\"\n \n@@ -70,7 +76,7 @@\n \n         statement[\"object\"] = {\n             \"definition\": {\n-                \"type\": \"https://w3id.org/xapi/video/activity-type/video\",\n+                \"type\": activity_type,\n                 \"name\": {\n                     to_locale(settings.LANGUAGE_CODE).replace(\"_\", \"-\"): video.title\n                 },\n", "issue": "Create XAPI statements for live video\n## Feature Request\r\n\r\n**Is your feature request related to a problem or unsupported use case? Please describe.**\r\n\r\nWhen a video is a live all the existing XAPI statement are sent like a regular videos. Some events should not be sent and some data can't be computed\r\n\r\n**Describe the solution you'd like**\r\n\r\nChange the activity-type to `http://id.tincanapi.com/activitytype/webinar`\r\nSend statement for those events : \r\n- initialized\r\n- play\r\n- pause\r\n- interacted\r\n\r\nAlso, do not send video length info, we can't have it. The completion threshold can not be computed too.\r\n\n", "before_files": [{"content": "\"\"\"XAPI module.\"\"\"\nimport re\nimport uuid\n\nfrom django.conf import settings\nfrom django.utils import timezone\nfrom django.utils.translation import to_locale\n\nimport requests\n\n\nclass XAPIStatement:\n    \"\"\"Object to work on a XAPI Statement.\"\"\"\n\n    statement = None\n\n    def __init__(self, video, statement, lti_user):\n        \"\"\"Compute a valid xapi satement.\n\n        Parameters\n        ----------\n        video : Type[.models/videos]\n            The video object used in the xAPI statement\n\n        statement : dictionary\n            Statement containing base information to send to the LRS\n            An example of expected statement:\n            {\n                \"verb\": {\n                    \"id\": \"http://adlnet.gov/expapi/verbs/initialized\",\n                    \"display\": {\n                        \"en-US\": \"initialized\"\n                    }\n                },\n                \"context\": {\n                    \"extensions\": {\n                        \"https://w3id.org/xapi/video/extensions/volume\": 1,\n                        \"https://w3id.org/xapi/video/extensions/video-playback-size\": \"640x264\",\n                    }\n                }\n            }\n\n        lti_user : Type[lti.LTIUser]\n            Object representing data stored in the JWT Token and related to the user authenticated\n            with LTI\n\n        \"\"\"\n        try:\n            user_id = lti_user.user.get(\"id\")\n        except AttributeError:\n            user_id = lti_user.session_id\n\n        homepage = video.playlist.consumer_site.domain\n\n        if re.match(r\"^http(s?):\\/\\/.*\", homepage) is None:\n            homepage = f\"http://{homepage}\"\n\n        if \"id\" not in statement:\n            statement[\"id\"] = str(uuid.uuid4())\n\n        statement[\"timestamp\"] = timezone.now().isoformat()\n        statement[\"context\"].update(\n            {\"contextActivities\": {\"category\": [{\"id\": \"https://w3id.org/xapi/video\"}]}}\n        )\n\n        statement[\"actor\"] = {\n            \"objectType\": \"Agent\",\n            \"account\": {\"name\": user_id, \"homePage\": homepage},\n        }\n\n        statement[\"object\"] = {\n            \"definition\": {\n                \"type\": \"https://w3id.org/xapi/video/activity-type/video\",\n                \"name\": {\n                    to_locale(settings.LANGUAGE_CODE).replace(\"_\", \"-\"): video.title\n                },\n            },\n            \"id\": \"uuid://{id}\".format(id=str(video.id)),\n            \"objectType\": \"Activity\",\n        }\n\n        object_extensions = {}\n        if lti_user.course.get(\"school_name\") is not None:\n            object_extensions[\n                \"https://w3id.org/xapi/acrossx/extensions/school\"\n            ] = lti_user.course[\"school_name\"]\n\n        if lti_user.course.get(\"course_name\") is not None:\n            object_extensions[\n                \"http://adlnet.gov/expapi/activities/course\"\n            ] = lti_user.course[\"course_name\"]\n\n        if lti_user.course.get(\"course_run\") is not None:\n            object_extensions[\n                \"http://adlnet.gov/expapi/activities/module\"\n            ] = lti_user.course[\"course_run\"]\n\n        if object_extensions:\n            statement[\"object\"][\"definition\"][\"extensions\"] = object_extensions\n\n        self.statement = statement\n\n    def get_statement(self):\n        \"\"\"Return the enriched statement.\"\"\"\n        return self.statement\n\n\nclass XAPI:\n    \"\"\"The XAPI object compute statements and send them to a LRS.\"\"\"\n\n    def __init__(self, url, auth_token, xapi_version=\"1.0.3\"):\n        \"\"\"Initialize the XAPI module.\n\n        Parameters\n        ----------\n        url: string\n            The LRS endpoint to fetch\n\n        auth_token: string\n            The basic_auth token used to authenticate on the LRS\n\n        xapi_version: string\n            The xAPI version used.\n\n        \"\"\"\n        self.url = url\n        self.auth_token = auth_token\n        self.xapi_version = xapi_version\n\n    def send(self, xapi_statement):\n        \"\"\"Send the statement to a LRS.\n\n        Parameters\n        ----------\n        statement : Type[.XAPIStatement]\n\n        \"\"\"\n        headers = {\n            \"Authorization\": self.auth_token,\n            \"Content-Type\": \"application/json\",\n            \"X-Experience-API-Version\": self.xapi_version,\n        }\n\n        response = requests.post(\n            self.url, json=xapi_statement.get_statement(), headers=headers\n        )\n\n        response.raise_for_status()\n", "path": "src/backend/marsha/core/xapi.py"}], "after_files": [{"content": "\"\"\"XAPI module.\"\"\"\nimport re\nimport uuid\n\nfrom django.conf import settings\nfrom django.utils import timezone\nfrom django.utils.translation import to_locale\n\nimport requests\n\n\nclass XAPIStatement:\n    \"\"\"Object to work on a XAPI Statement.\"\"\"\n\n    statement = None\n\n    def __init__(self, video, statement, lti_user):\n        \"\"\"Compute a valid xapi satement.\n\n        Parameters\n        ----------\n        video : Type[.models/videos]\n            The video object used in the xAPI statement\n\n        statement : dictionary\n            Statement containing base information to send to the LRS\n            An example of expected statement:\n            {\n                \"verb\": {\n                    \"id\": \"http://adlnet.gov/expapi/verbs/initialized\",\n                    \"display\": {\n                        \"en-US\": \"initialized\"\n                    }\n                },\n                \"context\": {\n                    \"extensions\": {\n                        \"https://w3id.org/xapi/video/extensions/volume\": 1,\n                        \"https://w3id.org/xapi/video/extensions/video-playback-size\": \"640x264\",\n                    }\n                }\n            }\n\n        lti_user : Type[lti.LTIUser]\n            Object representing data stored in the JWT Token and related to the user authenticated\n            with LTI\n\n        \"\"\"\n        try:\n            user_id = lti_user.user.get(\"id\")\n        except AttributeError:\n            user_id = lti_user.session_id\n\n        homepage = video.playlist.consumer_site.domain\n\n        activity_type = \"https://w3id.org/xapi/video/activity-type/video\"\n\n        # When the video is a live we change the activity to webinar\n        if video.live_state is not None:\n            activity_type = \"http://id.tincanapi.com/activitytype/webinar\"\n\n        if re.match(r\"^http(s?):\\/\\/.*\", homepage) is None:\n            homepage = f\"http://{homepage}\"\n\n        if \"id\" not in statement:\n            statement[\"id\"] = str(uuid.uuid4())\n\n        statement[\"timestamp\"] = timezone.now().isoformat()\n        statement[\"context\"].update(\n            {\"contextActivities\": {\"category\": [{\"id\": \"https://w3id.org/xapi/video\"}]}}\n        )\n\n        statement[\"actor\"] = {\n            \"objectType\": \"Agent\",\n            \"account\": {\"name\": user_id, \"homePage\": homepage},\n        }\n\n        statement[\"object\"] = {\n            \"definition\": {\n                \"type\": activity_type,\n                \"name\": {\n                    to_locale(settings.LANGUAGE_CODE).replace(\"_\", \"-\"): video.title\n                },\n            },\n            \"id\": \"uuid://{id}\".format(id=str(video.id)),\n            \"objectType\": \"Activity\",\n        }\n\n        object_extensions = {}\n        if lti_user.course.get(\"school_name\") is not None:\n            object_extensions[\n                \"https://w3id.org/xapi/acrossx/extensions/school\"\n            ] = lti_user.course[\"school_name\"]\n\n        if lti_user.course.get(\"course_name\") is not None:\n            object_extensions[\n                \"http://adlnet.gov/expapi/activities/course\"\n            ] = lti_user.course[\"course_name\"]\n\n        if lti_user.course.get(\"course_run\") is not None:\n            object_extensions[\n                \"http://adlnet.gov/expapi/activities/module\"\n            ] = lti_user.course[\"course_run\"]\n\n        if object_extensions:\n            statement[\"object\"][\"definition\"][\"extensions\"] = object_extensions\n\n        self.statement = statement\n\n    def get_statement(self):\n        \"\"\"Return the enriched statement.\"\"\"\n        return self.statement\n\n\nclass XAPI:\n    \"\"\"The XAPI object compute statements and send them to a LRS.\"\"\"\n\n    def __init__(self, url, auth_token, xapi_version=\"1.0.3\"):\n        \"\"\"Initialize the XAPI module.\n\n        Parameters\n        ----------\n        url: string\n            The LRS endpoint to fetch\n\n        auth_token: string\n            The basic_auth token used to authenticate on the LRS\n\n        xapi_version: string\n            The xAPI version used.\n\n        \"\"\"\n        self.url = url\n        self.auth_token = auth_token\n        self.xapi_version = xapi_version\n\n    def send(self, xapi_statement):\n        \"\"\"Send the statement to a LRS.\n\n        Parameters\n        ----------\n        statement : Type[.XAPIStatement]\n\n        \"\"\"\n        headers = {\n            \"Authorization\": self.auth_token,\n            \"Content-Type\": \"application/json\",\n            \"X-Experience-API-Version\": self.xapi_version,\n        }\n\n        response = requests.post(\n            self.url, json=xapi_statement.get_statement(), headers=headers\n        )\n\n        response.raise_for_status()\n", "path": "src/backend/marsha/core/xapi.py"}]}