Closed mrik974 closed 4 years ago
Hi, What version of Moodle are you using?
Hi Sébastien, thank you for your quick answer ! I'm using Moodle 3.8.2
After further investigation, I found out that it's not about the video plugin, who does it job, but about the logs plugin. The LRS I'm actually testing, Learning Locker, receives this object :
{
"actor": {
"objectType": "Agent",
"name": "REDACTED",
"mbox": "mailto:REDACTED"
},
"verb": {
"id": "https://w3id.org/xapi/video/verbs/paused"
},
"object": {
"id": "https://REDACTED/xapi/activities/traxvideo/e0185619-e6ac-4589-959d-f7a59005ca95/video",
"definition": {
"name": {
"en-US": "Vid\u00e9o : Hygi\u00e8ne des mains : comment, selon quelles techniques ?"
},
"type": "https://w3id.org/xapi/video/activity-type/video"
},
"objectType": "Activity"
},
"result": {
"extensions": {
"https://w3id.org/xapi/video/extensions/time": 8.4570000000000007,
"https://w3id.org/xapi/video/extensions/progress": 0.029999999999999999,
"https://w3id.org/xapi/video/extensions/played-segments": "0.385[.]2.91[,]2.91[.]3.737[,]3.737[.]5.884[,]5.884[.]6.99[,]6.99[.]8.457"
}
},
"context": {
"contextActivities": {
"category": [{
"id": "https://w3id.org/xapi/video",
"objectType": "Activity",
"definition": {
"type": "http://adlnet.gov/expapi/activities/profile"
}
}, {
"id": "http://vocab.xapi.fr/categories/vle-profile",
"definition": {
"type": "http://adlnet.gov/expapi/activities/profile"
}
}, {
"id": "http://vocab.xapi.fr/categories/moodle/traxvideo",
"definition": {
"type": "http://adlnet.gov/expapi/activities/profile"
}
}, {
"id": "http://vocab.xapi.fr/categories/inside-learning-unit",
"definition": {
"type": "http://vocab.xapi.fr/activities/granularity-level"
}
}],
"grouping": [{
"id": "https://REDACTED",
"definition": {
"type": "http://vocab.xapi.fr/activities/system"
}
}, {
"id": "https://REDACTED/xapi/activities/course/80bbc1dd-f4f3-44f3-9f6d-907ccb0367ec",
"definition": {
"type": "http://vocab.xapi.fr/activities/course"
}
}],
"parent": [{
"id": "https://REDACTED/xapi/activities/traxvideo/e0185619-e6ac-4589-959d-f7a59005ca95",
"definition": []
}]
},
"extensions": {
"https://w3id.org/xapi/video/extensions/length": 239.88535100000001,
"https://w3id.org/xapi/video/extensions/session-id": "c79ec2f1-b118-49d0-abce-1490aeb1e9f8"
},
"platform": "Moodle"
},
"timestamp": "2020-06-24T16:31:05.863Z",
"id": "656f4c4e-7558-431c-8870-424a79806779"
}
And it sends this error back to the logs plugin :
{
"errorId": "022e4006-3332-47f8-8a14-7126196d7c28",
"warnings": [
"Expected 'statements.0.context.contextActivities.parent.0.definition' to be 'Object'. Received '[]'"
]
}
When I send an object instead of an array with Postman, the statement is stored successfully.
Thanks for your feedback. Yes, the parent definition should not be an empty list, but an object with the parent type. I will investigate this issue as soon as possible.
I have tested and my Moodle 3.8 installation I don't have this issue.
I have investigated and it looks like Trax Logs can't find a class provided by Trax Video: mod_traxvideo\xapi\vocab\activity_types
.
It may be a class autoload issue. Classes located in the classes
folder of each plugin should be autoloaded by Moodle after a plugin install. Could you try to reinstall Trax Video to see it solves the problem?
My Moodle installation is dockerized, and is regularly restarted. Reinstalling the plugin would mean rebuild the image it is based upon and restart the server, which I've done a few times in the past hours. I also tried purging the cache (based on redis) and got the same results.
Also, I added a simple class test in the file statements_post.php
of the trax video plugin, and it appears the class exists and is loaded. Here was my test :
if (class_exists('mod_traxvideo\xapi\vocab\activity_types')) { echo "class exists" ; }
Let me know if I can do anything else to try and resolve this issue
Thanks for your feedback.
I have a workaround which consist of removing the activity definition if it is an empty array. This will solve the LRS rejection because the activity definition is not required. But this will not explain your issue and the activity type will be missing in your statements. So if we can try something else, it's better.
First, a simple test. In Moodle, when you enter in a Trax Video activity, it should send a navigated-in
statement, and the object of this statement should be the Trax Video activity. Could you check this statement and tell me if there is an object.definition.type
property? When everything is right, you should have it. But with your problem, you shouldn't. Just to see if it is consistent.
Now if we try to understand. Trax Logs can't find the activity type for Trax Video activities, and only for this kind of activity (others are correct). And it should be provided by the mod_traxvideo\xapi\vocab\activity_types
class. That's why I thought this class was not loaded.
Something is going wrong with the logstore_trax\src\activities\activity
line 96:
if ($type = $this->types->type($vocabtype, $plugin)) {
$activity['definition']['type'] = $type;
}
The type(...)
method is implemented by the logstore_trax\src\vocab\vocab
class, line 100:
public function __call($name, $args) {
$key = $args[0];
$plugin = count($args) > 1 ? $args[1] : null;
$item = $this->get($key, $plugin);
if (!$item || !isset($item->$name)) return false;
return $item->$name;
}
which should call the get('traxvideo', 'mod_traxvideo')
method of the same class:
public function get(string $key, string $plugin = null) {
// Internal vocab first.
if (isset($this->items->$key)) return $this->items->$key;
if (!isset($plugin)) return false;
// Plugin vocab.
$class = '\\' . $plugin . '\\xapi\\vocab\\' . $this->class;
if (!class_exists($class)) return false;
$vocab = new $class();
return $vocab->get($key);
}
which should load the mod_traxvideo\xapi\vocab\activity_types
class and then get the traxvideo
item, which contains the desired type.
Something is going wrong with this sequence but I can't go further because I can't reproduce the issue. Let me know if you see something...
Thank you for your useful explanation. I’m not used to develop in PhP, less for Moodle. But now I have enough to understand what’s going on. I already implemented your workaround and it works fine. I’ll spend a moment tomorrow to give you more information about what’s going on.
Hi Sébastien,
I've tried and it seems like the $plugin
variable is null when activity->base_activity() is called.
OK I've pushed as far as I could, given my poor knowledge of PHP, and the fact that I don't have an IDE.
statements_post.php
is called, and calls for $controller->proxy($objecttable) to get the final statement to send.
The controller instanciates a proxy profile of class mod_traxvideo\src\proxy\profile
This proxy looks for the parent object of the statement with the following :
$statement->context->contextActivities->parent = [
$this->activities->get('traxvideo', $this->activity->id, false, 'module')
];
Activities is an object of class logstore_trax\src\services\activities
Its method is called with these parameters :
public function get(string $type = "traxvideo", int $mid = 2, bool $full = false,
string $model = 'module', string $vocabtype = null, string $plugin = null, $entry = null)
The code goes to :
// Finally, search in Trax Logs, based on $model.
if (!class_exists($class)) {
$class = '\\logstore_trax\\src\\activities\\'.$model;
}
Where model is module
It instanciates a class of type \logstore_trax\src\activities\module
and calls for it's get
method with the following parameters :
public function get(string $type = "traxvideo", int $mid = 2, string $uuid = "entry uuid", bool $full = false, string $vocabtype = "traxvideo", string $plugin = null)
The plugin
variable is still null here.
This method calls for the base_activity
method with the following params :
protected function base_activity(string $type = 'traxvideo', string $uuid = 'entry uuid', bool $full = false, string $vocabtype = 'traxvideo', string $plugin = null)
This method contains the following :
if ($type = $this->types->type($vocabtype, $plugin)) {
$activity['definition']['type'] = $type;
}
It calls for logstore_trax\src\vocab\activity_types
which extends logstore_trax\src\vocab\vocab
and contains the following :
public function get(string $key, string $plugin = null) {
// Internal vocab first.
if (isset($this->items->$key)) return $this->items->$key;
if (!isset($plugin)) return false;
// Plugin vocab.
$class = '\\' . $plugin . '\\xapi\\vocab\\' . $this->class;
if (!class_exists($class)) return false;
$vocab = new $class();
return $vocab->get($key);
}
It seems that if the variable plugin
is null
the mod_traxvideo\xapi\vocab\activity_types
you mentioned earlier will not be used, and this method will return false.
this plugin
variable does not seem to be set in any earlier call. Could this be the cause of my bug ?
Hi,
Ok, I got it! Your Trax Video plugin is not up-to-date!
In the class mod_traxvideo\src\proxy\profile
, you should have:
$statement->context->contextActivities->parent = [
$this->activities->get('traxvideo', $this->activity->id, false, 'module', 'traxvideo', 'mod_traxvideo')
];
Please, try to update your plugins from the master branch, even if the Moodle plugin version has not changed.
Just found out what to do, too ! I was downloading the packaged versions of your plugin to make my Docker image, as recommended in your installation instructions. I'll switch to a git pull then. Thanks for your help, I'll close the issue now
Sorry for that. I will update the doc.
I have just published v0.4 release which includes the commit from december. Sorry again, it was a mistake.
That's nothing to worry about. Thank you for fixing it.
I'm using Trax Logs and Trax Video plugin (latest versions available for each one). Trax Logs works out of the box and sends all statements (I'm not using H5P for this test) from Moodle to the LRS. But the Trax Video plugin is receiving a 400 response when it tries to send a statement through the Trax Logs proxy.
Here's the statement sent by the browser :
I'm still investigating the error, I'll post more comments about it.