diff options
| author | Moritz Strohm <strohm@data-quest.de> | 2025-04-24 10:48:24 +0000 |
|---|---|---|
| committer | Moritz Strohm <strohm@data-quest.de> | 2025-04-24 10:48:24 +0000 |
| commit | cd8222ba049eca136bb443410022d99dfbc5d0f2 (patch) | |
| tree | 99b46288e335427b3f3bde5555b56497a80c1b88 /lib | |
| parent | 3c783c028c229a3e6561500521800e1fac4383ba (diff) | |
distinguish between LTI deployment IDs and LTI resource links in the database, fixes #5330
Closes #5330
Merge request studip/studip!4045
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/classes/LTI13a/LineItemRepository.php | 32 | ||||
| -rw-r--r-- | lib/models/Grading/Definition.php | 27 | ||||
| -rw-r--r-- | lib/models/LtiDeployment.php | 52 | ||||
| -rw-r--r-- | lib/models/LtiResourceLink.php | 187 | ||||
| -rw-r--r-- | lib/models/LtiTool.php | 2 | ||||
| -rw-r--r-- | lib/modules/LtiToolModule.php | 6 |
6 files changed, 223 insertions, 83 deletions
diff --git a/lib/classes/LTI13a/LineItemRepository.php b/lib/classes/LTI13a/LineItemRepository.php index add863e..c6c6ef1 100644 --- a/lib/classes/LTI13a/LineItemRepository.php +++ b/lib/classes/LTI13a/LineItemRepository.php @@ -110,22 +110,19 @@ class LineItemRepository implements LineItemRepositoryInterface return $result; } - //$resourceLinkIdentifier contains the Stud.IP tool-ID, the deployment-ID and the course-ID, - //separated by underscores. - $id_parts = explode('_', $resourceLinkIdentifier); - if (count($id_parts) !== 3) { + //Find the LTI resource link by its ID: + $resource_link = \LtiResourceLink::find($resourceLinkIdentifier); + if (!$resource_link) { throw new LTIException('Invalid resource link identifier.'); } - $tool_id = $id_parts[0]; - $deployment_id = $id_parts[1]; - $course_id = $id_parts[2]; + $tool_id = $resource_link->deployment->tool_id ?? null; $sql = ''; $sql_params = []; - if ($tool_id && $course_id) { + if ($tool_id && $resource_link->course_id) { $sql .= "`tool` = :tool AND `course_id` = :course_id"; - $sql_params['tool'] = self::getGradingToolName($tool_id, $deployment_id); - $sql_params['course_id'] = $course_id; + $sql_params['tool'] = self::getGradingToolName($tool_id, $resource_link->deployment_id); + $sql_params['course_id'] = $resource_link->course_id; } else { //No tool-ID means no line item collection can be found. return $result; @@ -155,18 +152,17 @@ class LineItemRepository implements LineItemRepositoryInterface */ public function save(LineItemInterface $lineItem): LineItemInterface { - //The resource link identifier contains the Stud.IP tool-ID, deployment-ID and course-ID - //separated by underscores. - $studip_ids = explode('_', $lineItem->getResourceLinkIdentifier() ?? ''); - $tool_id = $studip_ids[0]; - $deployment_id = $studip_ids[1]; - $course_id = $studip_ids[2]; + $resource_link_id = $lineItem->getResourceLinkIdentifier() ?? ''; + $resource_link = \LtiResourceLink::find($resource_link_id); + if (!$resource_link) { + throw new LTIException('Invalid resource link identifier.'); + } $definition = new Definition(); $definition->id = $lineItem->getIdentifier(); $definition->name = $lineItem->getLabel(); - $definition->course_id = $course_id; - $definition->tool = sprintf('lti-%s-%s', $tool_id, $deployment_id); + $definition->course_id = $resource_link->course_id; + $definition->tool = $resource_link->id; $definition->weight = '1.0'; if ($definition->store()) { return $definition->toLineItem(); diff --git a/lib/models/Grading/Definition.php b/lib/models/Grading/Definition.php index 7fc2066..56417b2 100644 --- a/lib/models/Grading/Definition.php +++ b/lib/models/Grading/Definition.php @@ -72,21 +72,20 @@ class Definition extends \SimpleORMap public function toLineItem() : LineItemInterface { - //Build the resource link identifier first: - $studip_ids = explode('-', $this->tool ?? ''); - $tool_id = $studip_ids[1] ?? ''; - $deployment_id = $studip_ids[2] ?? ''; - $resource_link_identifier = sprintf('%s_%s_%s', $tool_id, $deployment_id, $this->course_id); + $resource_link_identifier = $this->tool ?? ''; + $deployment_id = ''; + if ($resource_link_identifier) { + $lti_resource_link = \LtiResourceLink::find($resource_link_identifier); + if ($lti_resource_link) { + $deployment_id = $lti_resource_link->deployment_id; + } + } - $identifier = \URLHelper::getURL( - 'dispatch.php/lti/ags/line_item', - [ - 'cid' => $this->course_id, - 'definition_id' => $this->id, - 'deployment_id' => $deployment_id, - 'tool_id' => $tool_id - ] - ); + $identifier = \URLHelper::getURL(sprintf( + 'dispatch.php/lti/ags/line_item/%1$s/%2$s', + $resource_link_identifier, + $this->id + )); return new LineItem( PHP_FLOAT_MAX, diff --git a/lib/models/LtiDeployment.php b/lib/models/LtiDeployment.php index 0b66427..e59e738 100644 --- a/lib/models/LtiDeployment.php +++ b/lib/models/LtiDeployment.php @@ -12,8 +12,6 @@ * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2 * * @property int $id database column - * @property int $position database column - * @property string $course_id database column * @property string $title database column * @property string $description database column * @property int $tool_id database column @@ -37,64 +35,24 @@ class LtiDeployment extends SimpleORMap $config['serialized_fields']['options'] = JSONArrayObject::class; - $config['belongs_to']['course'] = [ - 'class_name' => Course::class, - 'foreign_key' => 'course_id' - ]; $config['belongs_to']['tool'] = [ 'class_name' => LtiTool::class, 'foreign_key' => 'tool_id' ]; - + $config['has_many']['resource_links'] = [ + 'class_name' => LtiResourceLink::class, + 'assoc_foreign_key' => 'deployment_id', + 'on_delete' => 'delete' + ]; $config['has_many']['grades'] = [ 'class_name' => LtiGrade::class, 'assoc_foreign_key' => 'link_id', 'on_delete' => 'delete' ]; - $config['registered_callbacks']['before_create'] = ['cbCalculatePosition']; - parent::configure($config); } - /** - * Calculates the position of the new deployment in the course. - */ - public function cbCalculatePosition() : void - { - $this->position = self::countBySql( - 'JOIN `lti_tools` ON `tool_id` = `lti_tools`.`id` - WHERE `lti_tools`.`range_id` = :range_id', - ['range_id' => $this->tool->range_id] - ) + 1; - } - - /** - * Find a single entry by course_id and position. - * - * @return static|null - */ - public static function findByCourseAndPosition($course_id, $position) - { - return self::findOneBySQL('course_id = ? AND position = ?', [$course_id, $position]); - } - - /** - * Delete this entity. - */ - public function delete() - { - $db = DBManager::get(); - $course_id = $this->course_id; - $position = $this->position; - - if ($result = parent::delete()) { - $db->execute('UPDATE `lti_deployments` SET `position` = position - 1 WHERE `course_id` = ? AND `position` > ?', [$course_id, $position]); - } - - return $result; - } - public function getToolLtiVersion() : string { return $this->tool->lti_version ?? ''; diff --git a/lib/models/LtiResourceLink.php b/lib/models/LtiResourceLink.php new file mode 100644 index 0000000..785c350 --- /dev/null +++ b/lib/models/LtiResourceLink.php @@ -0,0 +1,187 @@ +<?php +/* + * LtiResourceLink.php + * This file is part of Stud.IP. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * @author Moritz Strohm + * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2 + */ + + +use OAT\Library\Lti1p3Core\Resource\LtiResourceLink\LtiResourceLinkInterface; +use OAT\Library\Lti1p3Core\Util\Collection\Collection; +use OAT\Library\Lti1p3Core\Util\Collection\CollectionInterface; + +/** + * The LtiResourceLink class is a model for the lti_resource_links table. + * + * @property int $id database column + * @property int $deployment_id database column + * @property string $course_id database column + * @property int $position database column + * @property int $mkdate database column + * @property int $chdate database column + * @property ?LtiDeployment $deployment related object + * @property ?Course $course related object + */ +class LtiResourceLink extends \SimpleORMap implements LtiResourceLinkInterface +{ + protected static function configure($config = []) + { + $config['db_table'] = 'lti_resource_links'; + + $config['belongs_to']['course'] = [ + 'class_name' => Course::class, + 'foreign_key' => 'course_id' + ]; + $config['belongs_to']['deployment'] = [ + 'class_name' => LtiDeployment::class, + 'foreign_key' => 'deployment_id' + ]; + + $config['registered_callbacks']['before_create'] = ['cbCalculatePosition']; + + parent::configure($config); + } + + /** + * Calculates the position for a new LTI resource link in the course. + */ + public function cbCalculatePosition() : void + { + $this->position = self::countByCourse_id($this->course_id); + } + + /** + * Delete this entity. + */ + public function delete() + { + $course_id = $this->course_id; + $position = $this->position; + if ($result = parent::delete()) { + DBManager::get()->execute( + "UPDATE `lti_resource_links` + SET `position` = position - 1 + WHERE `course_id` = :course_id AND `position` > :position", + [ + 'course_id' => $course_id, + 'position' => $position + ] + ); + } + + return $result; + } + + /** + * Find a single entry by course_id and position. + * + * @return static|null + */ + public static function findByCourseAndPosition($course_id, $position) + { + return self::findOneBySQL('course_id = ? AND position = ?', [$course_id, $position]); + } + + //OAT library LtiResourceLinkInterface and ResourceInterface implementation: + + public function getUrl(): ?string + { + if ($this->deployment) { + return $this->deployment->getLaunchURL(); + } + return null; + } + + public function getIcon(): ?array + { + return null; + } + + public function getThumbnail(): ?array + { + if ($this->course) { + return [$this->course->getItemAvatarURL()]; + } + return null; + } + + public function getIframe(): ?array + { + //Not supported. + return null; + } + + public function getCustom(): ?array + { + //Not supported. + return null; + } + + public function getLineItem(): ?array + { + // TODO: Implement getLineItem() method. + return null; + } + + public function getAvailability(): ?array + { + // TODO: Implement getAvailability() method. + return null; + } + + public function getSubmission(): ?array + { + // TODO: Implement getSubmission() method. + return null; + } + + public function getIdentifier(): string + { + return strval($this->id); + } + + public function getType(): string + { + return 'ltiResourceLink'; + } + + public function getTitle(): ?string + { + if ($this->deployment) { + return $this->deployment->title; + } + return null; + } + + public function getText(): ?string + { + return null; + } + + public function getProperties(): CollectionInterface + { + $collection = new Collection(); + $collection->add([ + 'url' => $this->getUrl(), + 'title' => $this->getTitle() + ]); + return $collection; + } + + public function normalize(): array + { + return array_filter( + array_merge( + $this->getProperties()->all(), + ['type' => $this->getType()] + ) + ); + } +} diff --git a/lib/models/LtiTool.php b/lib/models/LtiTool.php index 9839ac0..bde6203 100644 --- a/lib/models/LtiTool.php +++ b/lib/models/LtiTool.php @@ -48,7 +48,7 @@ class LtiTool extends SimpleORMap { $config['db_table'] = 'lti_tools'; - $config['has_many']['links'] = [ + $config['has_many']['deployments'] = [ //formerly: links 'class_name' => LtiDeployment::class, 'assoc_foreign_key' => 'tool_id', 'on_delete' => 'delete' diff --git a/lib/modules/LtiToolModule.php b/lib/modules/LtiToolModule.php index 2a64e83..9d977be 100644 --- a/lib/modules/LtiToolModule.php +++ b/lib/modules/LtiToolModule.php @@ -27,7 +27,7 @@ class LtiToolModule extends CorePlugin implements StudipModule, SystemPlugin, Pr LtiGrade::deleteBySQL('user_id = ?', [$user->id]); }); NotificationCenter::on('CourseDidDelete', function ($event, $course) { - LtiDeployment::deleteBySQL('course_id = ?', [$course->id]); + \LtiResourceLink::deleteBySQL('course_id = ?', [$course->id]); }); } @@ -40,7 +40,7 @@ class LtiToolModule extends CorePlugin implements StudipModule, SystemPlugin, Pr return null; } - $changed = LtiDeployment::countBySQL('course_id = ? AND chdate > ?', [$course_id, $last_visit]); + $changed = \LtiResourceLink::countBySQL('course_id = ? AND chdate > ?', [$course_id, $last_visit]); $icon = Icon::create('plugin', $changed ? Icon::ROLE_NEW : Icon::ROLE_CLICKABLE); @@ -60,7 +60,7 @@ class LtiToolModule extends CorePlugin implements StudipModule, SystemPlugin, Pr return []; } - $grades = LtiDeployment::countBySQL('course_id = ?', [$course_id]); + $grades = \LtiResourceLink::countBySQL('course_id = ?', [$course_id]); $navigation = new Navigation(_('LTI-Tools')); $navigation->setImage(Icon::create('link-extern', Icon::ROLE_INFO_ALT)); |
