Skip to content
Snippets Groups Projects
Commit 2662912f authored by catch's avatar catch
Browse files

Merge branch '3492930-add-activityanswer-plugin' into '1.0.x'

Issue #3492930: add xapi ActivityAnswer plugin.

See merge request !1
parents 1d3ce50d 7a6b26a2
No related branches found
No related tags found
No related merge requests found
Pipeline #394594 failed
Showing
with 305 additions and 10 deletions
langcode: en
status: true
dependencies:
config:
- field.field.lms_activity._bundle_placeholder_.field_xapi_package
- lms.lms_activity_type._bundle_placeholder_
module:
- lms_xapi
id: lms_activity._bundle_placeholder_.default
targetEntityType: lms_activity
bundle: _bundle_placeholder_
mode: default
content:
created:
type: datetime_timestamp
weight: 10
region: content
settings: { }
third_party_settings: { }
field_xapi_package:
type: lms_xapi
weight: 26
region: content
settings:
progress_indicator: throbber
third_party_settings: { }
name:
type: string_textfield
weight: -4
region: content
settings:
size: 60
placeholder: ''
third_party_settings: { }
uid:
type: entity_reference_autocomplete
weight: 5
region: content
settings:
match_operator: CONTAINS
match_limit: 10
size: 60
placeholder: ''
third_party_settings: { }
hidden: { }
langcode: en
status: true
dependencies:
config:
- field.field.lms_activity._bundle_placeholder_.field_xapi_package
- lms.lms_activity_type._bundle_placeholder_
module:
- lms_xapi
- user
id: lms_activity._bundle_placeholder_.default
targetEntityType: lms_activity
bundle: _bundle_placeholder_
mode: default
content:
field_xapi_package:
type: lms_xapi
label: above
settings: { }
third_party_settings: { }
weight: 1
region: content
name:
type: string
label: above
settings:
link_to_entity: false
third_party_settings: { }
weight: -4
region: content
uid:
type: author
label: hidden
settings: { }
third_party_settings: { }
weight: 0
region: content
hidden: { }
langcode: en
status: true
dependencies:
config:
- field.storage.lms_activity.field_xapi_package
- lms.lms_activity_type._bundle_placeholder_
module:
- lms_xapi
id: lms_activity._bundle_placeholder_.field_xapi_package
field_name: field_xapi_package
entity_type: lms_activity
bundle: _bundle_placeholder_
label: 'XAPI package'
description: ''
required: true
translatable: false
default_value: { }
default_value_callback: ''
settings:
file_directory: lms_xapi_packages
file_extensions: zip
max_filesize: ''
description_field: 0
handler: 'default:file'
handler_settings: { }
field_type: lms_xapi
langcode: en
status: true
dependencies:
module:
- file
- lms
- lms_xapi
id: lms_activity.field_xapi_package
field_name: field_xapi_package
entity_type: lms_activity
type: lms_xapi
settings:
display_field: 0
display_default: 0
uri_scheme: public
target_type: file
module: lms_xapi
locked: false
cardinality: 1
translatable: true
indexes: { }
persist_with_no_fields: false
custom_storage: false
name: LMS XAPI Activity
type: module
description: Adds XAPI activity plugin.
core_version_requirement: ^10.3 || ^11
package: LMS
dependencies:
- drupal:lms_xapi
- lms:lms
services:
_defaults:
autowire: true
autoconfigure: true
Drupal\lms_xapi_activity\ActivityXapiIdGenerator:
tags: ['xapi_id_generator']
<?php
declare(strict_types=1);
namespace Drupal\lms_xapi_activity;
use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\lms\Entity\Bundle\Course;
use Drupal\lms\TrainingManager;
use Drupal\lms_xapi\XapiIdGeneratorInterface;
use Drupal\lms\Entity\Activity;
use Drupal\lms\Entity\ActivityTypeInterface;
/**
* Xapi LRS event subscriber.
*/
class ActivityXapiIdGenerator implements XapiIdGeneratorInterface {
/**
* Constructor.
*/
public function __construct(
private readonly RouteMatchInterface $routeMatch,
private readonly TrainingManager $trainingManager,
) {}
/**
* {@inheritdoc}
*/
public function applies(
EntityInterface $entity,
AccountInterface $student,
CacheableMetadata $cacheable_metadata,
): bool {
if (!$entity instanceof Activity) {
return FALSE;
}
$course = $this->routeMatch->getParameter('group');
$cacheable_metadata->setCacheContexts($cacheable_metadata->getCacheContexts() + ['route']);
if ($course instanceof Course) {
$course_status = $this->trainingManager->loadCourseStatus($course, $student, [
'current' => TRUE,
]);
$cacheable_metadata->addCacheableDependency($course_status);
if ($course_status === NULL) {
return FALSE;
}
}
$bundle = $entity->get('type')->entity;
assert($bundle instanceof ActivityTypeInterface);
$plugin = $bundle->getPluginId();
if ($plugin !== 'xapi') {
return FALSE;
}
return TRUE;
}
/**
* {@inheritdoc}
*/
public function generate(
EntityInterface $entity,
AccountInterface $student,
CacheableMetadata $cacheable_metadata,
): array {
$course = $this->routeMatch->getParameter('group');
$course_status = $this->trainingManager->loadCourseStatus($course, $student, [
'current' => TRUE,
]);
return [
$entity->getEntityTypeId(),
$entity->id(),
$course_status->id(),
];
}
}
<?php
declare(strict_types=1);
namespace Drupal\lms_xapi_activity\Plugin\ActivityAnswer;
use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\lms\Attribute\ActivityAnswer;
use Drupal\lms\Entity\Answer;
use Drupal\lms\Plugin\ActivityAnswer\ActivityAnswerBase;
use Drupal\lms\Config\PluginConfigInstaller;
use Drupal\lms_xapi\TincanService;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Xapi/TinCan activity plugin.
*/
#[ActivityAnswer(
id: 'xapi',
name: new TranslatableMarkup('Xapi / TinCan'),
)]
class Xapi extends ActivityAnswerBase {
/**
* The constructor.
*/
public function __construct(
array $configuration,
$plugin_id,
$plugin_definition,
PluginConfigInstaller $plugin_installer,
protected TinCanService $lrsService,
) {
parent::__construct($configuration, $plugin_id, $plugin_definition, $plugin_installer);
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('plugin.config_installer.activity_answer'),
$container->get('lms_xapi.tincan')
);
}
/**
* {@inheritdoc}
*/
public function getScore(Answer $answer): float {
$account = $answer->getOwner();
$activity = $answer->getActivity();
$cacheable_metadata = new CacheableMetadata;
$lms_id = $this->lrsService->getLmsId($activity, $account, $cacheable_metadata);
$score = $this->lrsService->getScoreFromLrs($lms_id);
return $score ?? 0;
}
/**
* {@inheritdoc}
*/
public function evaluatedOnSave(Answer $answer): bool {
return TRUE;
}
}
name: LMS XAPI
type: module
description: Adds XAPI lesson and activity types.
description: Adds XAPI lesson.
core_version_requirement: ^10.3 || ^11
package: LMS
dependencies:
......
......@@ -54,13 +54,4 @@ final class LmsXapiSettingsForm extends ConfigFormBase {
return parent::buildForm($form, $form_state);
}
/**
* {@inheritdoc}
*/
public function validateForm(array &$form, FormStateInterface $form_state) {
// @todo try connecting to some LRS status endpoint to check
// if credentials are correct here.
parent::validateForm($form, $form_state);
}
}
......@@ -29,6 +29,9 @@ final class LmsXapiTest extends WebDriverTestBase {
'lrs_xapi',
];
/**
* Tests that the site can be installed with the modules installed.
*/
public function testXapiLesson() {
$page = $this->getSession()->getPage();
$assert_session = $this->assertSession();
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment