diff --git a/plugin/ims_lti/Entity/ImsLtiTool.php b/plugin/ims_lti/Entity/ImsLtiTool.php new file mode 100644 index 0000000000..6c4ba10ea0 --- /dev/null +++ b/plugin/ims_lti/Entity/ImsLtiTool.php @@ -0,0 +1,221 @@ +id; + } + + /** + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * @param string $name + * @return ImsLtiTool + */ + public function setName($name) + { + $this->name = $name; + + return $this; + } + + /** + * @return null|string + */ + public function getDescription() + { + return $this->description; + } + + /** + * @param null|string $description + * @return ImsLtiTool + */ + public function setDescription($description) + { + $this->description = $description; + + return $this; + } + + /** + * @return string + */ + public function getLaunchUrl() + { + return $this->launchUrl; + } + + /** + * @param string $launchUrl + * @return ImsLtiTool + */ + public function setLaunchUrl($launchUrl) + { + $this->launchUrl = $launchUrl; + + return $this; + } + + /** + * @return string + */ + public function getConsumerKey() + { + return $this->consumerKey; + } + + /** + * @param string $consumerKey + * @return ImsLtiTool + */ + public function setConsumerKey($consumerKey) + { + $this->consumerKey = $consumerKey; + + return $this; + } + + /** + * @return string + */ + public function getSharedSecret() + { + return $this->sharedSecret; + } + + /** + * @param string $sharedSecret + * @return ImsLtiTool + */ + public function setSharedSecret($sharedSecret) + { + $this->sharedSecret = $sharedSecret; + + return $this; + } + + /** + * @return null|string + */ + public function getCustomParams() + { + return $this->customParams; + } + + /** + * @param null|string $customParams + * @return ImsLtiTool + */ + public function setCustomParams($customParams) + { + $this->customParams = $customParams; + + return $this; + } + + /** + * @return bool + */ + public function isGlobal() + { + return $this->isGlobal; + } + + /** + * @param bool $isGlobal + * @return ImsLtiTool + */ + public function setIsGlobal($isGlobal) + { + $this->isGlobal = $isGlobal; + + return $this; + } + + /** + * @return array + */ + public function parseCustomParams() + { + $strings = explode($this->customParams, "\n"); + $pairs = explode('=', $strings); + + return [ + 'key' => 'custom_'.$pairs[0], + 'value' => $pairs[1] + ]; + } +} diff --git a/plugin/ims_lti/ImsLtiPlugin.php b/plugin/ims_lti/ImsLtiPlugin.php index 9c0dfcc396..07e45725d2 100644 --- a/plugin/ims_lti/ImsLtiPlugin.php +++ b/plugin/ims_lti/ImsLtiPlugin.php @@ -6,6 +6,8 @@ use Chamilo\CoreBundle\Entity\Course; use Doctrine\DBAL\Schema\Schema; use Doctrine\DBAL\Types\Type; use Doctrine\DBAL\DBALException; +use Symfony\Component\Filesystem\Filesystem; +use Chamilo\PluginBundle\Entity\ImsLti\ImsLtiTool; /** * Description of MsiLti @@ -14,7 +16,7 @@ use Doctrine\DBAL\DBALException; */ class ImsLtiPlugin extends Plugin { - const TABLE_TOOL = 'plugin_msi_lti_tool'; + const TABLE_TOOL = 'plugin_ims_lti_tool'; public $isAdminPlugin = true; @@ -23,7 +25,7 @@ class ImsLtiPlugin extends Plugin */ protected function __construct() { - $version = '1.0'; + $version = '1.0 (beta)'; $author = 'Angel Fernando Quiroz Campos'; parent::__construct($version, $author, ['enabled' => 'boolean']); @@ -56,11 +58,23 @@ class ImsLtiPlugin extends Plugin */ public function install() { - try { - $this->setupDatabase(); - } catch (DBALException $e) { - error_log('Error while installing IMS/LTI plugin: '.$e->getMessage()); + $pluginEntityPath = $this->getEntityPath(); + + if (!is_dir($pluginEntityPath)) { + if (!is_writable(dirname($pluginEntityPath))) { + $message = get_lang('ErrorCreatingDir').': '.$pluginEntityPath; + Display::addFlash(Display::return_message($message, 'error')); + + return false; + } + + mkdir($pluginEntityPath, api_get_permissions_for_new_directories()); } + + $fs = new Filesystem(); + $fs->mirror(__DIR__.'/Entity/', $pluginEntityPath, null, ['override']); + + $this->createPluginTables(); } /** @@ -68,8 +82,15 @@ class ImsLtiPlugin extends Plugin */ public function uninstall() { + $pluginEntityPath = $this->getEntityPath(); + $fs = new Filesystem(); + + if ($fs->exists($pluginEntityPath)) { + $fs->remove($pluginEntityPath); + } + try { - $this->clearDatabase(); + $this->dropPluginTables(); $this->removeTools(); } catch (DBALException $e) { error_log('Error while uninstalling IMS/LTI plugin: '.$e->getMessage()); @@ -81,7 +102,7 @@ class ImsLtiPlugin extends Plugin * @return boolean * @throws \Doctrine\DBAL\DBALException */ - private function setupDatabase() + private function createPluginTables() { $entityManager = Database::getManager(); $connection = $entityManager->getConnection(); @@ -99,7 +120,7 @@ class ImsLtiPlugin extends Plugin $toolTable->addColumn('launch_url', Type::TEXT); $toolTable->addColumn('consumer_key', Type::STRING); $toolTable->addColumn('shared_secret', Type::STRING); - $toolTable->addColumn('custom_params', Type::TEXT); + $toolTable->addColumn('custom_params', Type::TEXT)->setNotnull(false); $toolTable->addColumn('is_global', Type::BOOLEAN); $toolTable->setPrimaryKey(['id']); @@ -117,7 +138,7 @@ class ImsLtiPlugin extends Plugin * @return boolean * @throws \Doctrine\DBAL\DBALException */ - private function clearDatabase() + private function dropPluginTables() { $entityManager = Database::getManager(); $connection = $entityManager->getConnection(); @@ -166,14 +187,13 @@ class ImsLtiPlugin extends Plugin * Add the course tool * @param Course $course * @param ImsLtiTool $tool + * @throws \Doctrine\ORM\OptimisticLockException */ public function addCourseTool(Course $course, ImsLtiTool $tool) { $em = Database::getManager(); - $cToolId = AddCourse::generateToolId($course->getId()); $cTool = new CTool(); $cTool - ->setId($cToolId) ->setCId($course->getId()) ->setName($tool->getName()) ->setLink($this->get_name().'/start.php?'.http_build_query(['id' => $tool->getId()])) @@ -188,6 +208,11 @@ class ImsLtiPlugin extends Plugin $em->persist($cTool); $em->flush(); + + $cTool->setId($cTool->getIid()); + + $em->persist($cTool); + $em->flush(); } /** @@ -203,4 +228,12 @@ class ImsLtiPlugin extends Plugin return $text; } + + /** + * @return string + */ + public function getEntityPath() + { + return api_get_path(SYS_PATH).'src/Chamilo/PluginBundle/Entity/'.$this->getCamelCaseName(); + } } diff --git a/plugin/ims_lti/ImsLtiTool.php b/plugin/ims_lti/ImsLtiTool.php deleted file mode 100644 index 31865c83b4..0000000000 --- a/plugin/ims_lti/ImsLtiTool.php +++ /dev/null @@ -1,185 +0,0 @@ - - */ -class ImsLtiTool -{ - private $id = 0; - private $name = ''; - private $description = null; - private $launchUrl = ''; - private $consumerKey = ''; - private $sharedSecret = ''; - private $customParams = null; - private $isGlobal = false; - - public function getId() - { - return $this->id; - } - - public function getName() - { - return $this->name; - } - - public function getDescription() - { - return $this->description; - } - - public function getLaunchUrl() - { - return $this->launchUrl; - } - - public function getConsumerKey() - { - return $this->consumerKey; - } - - public function getSharedSecret() - { - return $this->sharedSecret; - } - - public function getCustomParams() - { - return $this->customParams; - } - - public function setId($id) - { - $this->id = $id; - - return $this; - } - - public function setName($name) - { - $this->name = $name; - - return $this; - } - - public function setDescription($description) - { - $this->description = $description; - - return $this; - } - - public function setLaunchUrl($launchUrl) - { - $this->launchUrl = $launchUrl; - - return $this; - } - - public function setConsumerKey($consumerKey) - { - $this->consumerKey = $consumerKey; - - return $this; - } - - public function setSharedSecret($sharedSecret) - { - $this->sharedSecret = $sharedSecret; - - return $this; - } - - public function setCustomParams($customParams) - { - $this->customParams = $customParams; - - return $this; - } - - public function save() - { - $parameters = [ - 'name' => $this->name, - 'description' => $this->description, - 'launch_url' => $this->launchUrl, - 'consumer_key' => $this->consumerKey, - 'shared_secret' => $this->sharedSecret, - 'custom_params' => $this->customParams, - 'is_global' => $this->isGlobal - ]; - - if (!empty($this->id)) { - Database::update( - ImsLtiPlugin::TABLE_TOOL, - $parameters, - ['id' => $this->id] - ); - - return; - } - - $this->id = Database::insert(ImsLtiPlugin::TABLE_TOOL, $parameters); - } - - public static function fetch($id) - { - $result = Database::select( - '*', - ImsLtiPlugin::TABLE_TOOL, - ['where' => [ - 'id = ?' => intval($id) - ]], - 'first' - ); - - if (empty($result)) { - return null; - } - - $tool = new self(); - $tool->id = $result['id']; - $tool->name = $result['name']; - $tool->description = $result['description']; - $tool->launchUrl = $result['launch_url']; - $tool->consumerKey = $result['consumer_key']; - $tool->sharedSecret = $result['shared_secret']; - $tool->customParams = $result['custom_params']; - $tool->isGlobal = (boolean) $result['is_global']; - - return $tool; - } - - public static function fetchAll() - { - return Database::select( - '*', - ImsLtiPlugin::TABLE_TOOL - ); - } - - public function parseCustomParams() - { - $strings = $this->customParams; - - $foo = explode('=', $strings); - - return [ - 'key' => 'custom_'.$foo[0], - 'value' => $foo[1] - ]; - } - - public function setIsGlobal($isGlobal = true) - { - $this->isGlobal = $isGlobal; - } - - public function isGlobal() - { - return $this->isGlobal; - } -} diff --git a/plugin/ims_lti/README.md b/plugin/ims_lti/README.md index d8f9c96f37..b8515c3dc8 100644 --- a/plugin/ims_lti/README.md +++ b/plugin/ims_lti/README.md @@ -1,6 +1,14 @@ IMS/LTI plugin === +Version 1.0 (beta) + +Installation +------------ +1. Install the plugin from Plugin page +2. Enable the plugin from Plugin Settings page +3. Assign to the Administrator region. + This plugin is meant to be later integrated into Chamilo (in a major version release). IMS/LTI defines the possibility to integrate tools or content into Chamilo. diff --git a/plugin/ims_lti/add.php b/plugin/ims_lti/add.php index 597a7780da..4be534257d 100644 --- a/plugin/ims_lti/add.php +++ b/plugin/ims_lti/add.php @@ -1,6 +1,9 @@ getRepository('ChamiloPluginBundle:ImsLti\ImsLtiTool'); -$type = isset($_GET['type']) ? intval($_GET['type']) : 0; +/** @var ImsLtiTool $baseTool */ +$baseTool = isset($_REQUEST['type']) ? $toolsRepo->find(intval($_REQUEST['type'])) : null; +/** @var Course $course */ $course = $em->find('ChamiloCoreBundle:Course', api_get_course_int_id()); -$tools = array_filter( - ImsLtiTool::fetchAll(), - function ($tool) { - return (boolean) $tool['is_global']; - } -); +$globalTools = $toolsRepo->findBy(['isGlobal' => true]); -$isGlobalTool = $type ? array_key_exists($type, $tools) : true; - -if (!$isGlobalTool) { +if ($baseTool && !$baseTool->isGlobal()) { Display::addFlash( Display::return_message($plugin->get_lang('ToolNotAvailable'), 'warning') ); @@ -31,16 +30,22 @@ if (!$isGlobalTool) { } $form = new FormValidator('ims_lti_add_tool'); -$form->addText('name', $plugin->get_lang('ToolName')); -if (!$type) { - $form->addHtml('
'); +if ($baseTool) { + $form->addHtml('

'.Security::remove_XSS($baseTool->getDescription()).'

'); +} + +$form->addText('name', get_lang('Title')); +$form->addTextarea('description', get_lang('Description'), ['rows' => 10]); + +if (!$baseTool) { $form->addElement('url', 'url', $plugin->get_lang('LaunchUrl')); $form->addText('consumer_key', $plugin->get_lang('ConsumerKey'), true); $form->addText('shared_secret', $plugin->get_lang('SharedSecret'), true); $form->addTextarea('custom_params', $plugin->get_lang('CustomParams')); - $form->addHtml('
'); $form->addRule('url', get_lang('Required'), 'required'); +} else { + $form->addHidden('type', $baseTool->getId()); } $form->addButtonCreate($plugin->get_lang('AddExternalTool')); @@ -49,45 +54,41 @@ if ($form->validate()) { $formValues = $form->getSubmitValues(); $tool = null; - if ($type) { - $baseTool = ImsLtiTool::fetch($type); - - if ($baseTool) { - $baseTool->setName($formValues['name']); - } - - $tool = $baseTool; + if ($baseTool) { + $tool = clone $baseTool; } else { $tool = new ImsLtiTool(); $tool - ->setName($formValues['name']) ->setLaunchUrl($formValues['url']) ->setConsumerKey($formValues['consumer_key']) ->setSharedSecret($formValues['shared_secret']) - ->setCustomParams($formValues['custom_params']) - ->isGlobal(false); - $tool->save(); + ->setCustomParams( + empty($formValues['custom_params']) ? null : $formValues['custom_params'] + ); } - if ($tool) { - $plugin->addCourseTool($course, $tool); + $tool + ->setName($formValues['name']) + ->setDescription( + empty($formValues['description']) ? null : $formValues['description'] + ) + ->isGlobal(false); + $em->persist($tool); + $em->flush(); - Display::addFlash( - Display::return_message($plugin->get_lang('ToolAdded'), 'success') - ); - } else { - Display::addFlash( - Display::return_message($plugin->get_lang('NoTool'), 'error') - ); - } + $plugin->addCourseTool($course, $tool); + + Display::addFlash( + Display::return_message($plugin->get_lang('ToolAdded'), 'success') + ); header('Location: '.api_get_course_url()); exit; } $template = new Template($plugin->get_lang('AddExternalTool')); -$template->assign('type', $type); -$template->assign('tools', $tools); +$template->assign('type', $baseTool->getId()); +$template->assign('tools', $globalTools); $template->assign('form', $form->returnForm()); $content = $template->fetch('ims_lti/view/add.tpl'); diff --git a/plugin/ims_lti/admin.php b/plugin/ims_lti/admin.php index c3dad2b7bd..865cb3657c 100644 --- a/plugin/ims_lti/admin.php +++ b/plugin/ims_lti/admin.php @@ -4,10 +4,12 @@ $cidReset = true; require_once __DIR__.'/../../main/inc/global.inc.php'; +api_protect_admin_script(); + $plugin = ImsLtiPlugin::create(); -$em = Database::getManager(); -$tools = Database::select('*', ImsLtiPlugin::TABLE_TOOL); +$em = Database::getManager(); +$tools = $em->getRepository('ChamiloPluginBundle:ImsLti\ImsLtiTool')->findAll(); $template = new Template($plugin->get_title()); $template->assign('tools', $tools); diff --git a/plugin/ims_lti/create.php b/plugin/ims_lti/create.php index 2cea8720b5..129aa50cd3 100644 --- a/plugin/ims_lti/create.php +++ b/plugin/ims_lti/create.php @@ -1,5 +1,7 @@ addText('name', get_lang('Name')); -$form->addText('base_url', get_lang('BaseUrl')); +$form->addText('base_url', $plugin->get_lang('LaunchUrl')); $form->addText('consumer_key', $plugin->get_lang('ConsumerKey')); $form->addText('shared_secret', $plugin->get_lang('SharedSecret')); +$form->addTextarea('description', get_lang('Description'), ['rows' => 10]); $form->addTextarea('custom_params', $plugin->get_lang('CustomParams')); $form->addButtonCreate($plugin->get_lang('AddExternalTool')); @@ -27,7 +32,10 @@ if ($form->validate()) { ->setConsumerKey($formValues['consumer_key']) ->setSharedSecret($formValues['shared_secret']) ->setCustomParams($formValues['custom_params']) - ->save(); + ->setIsGlobal(true); + + $em->persist($externalTool); + $em->flush(); Display::addFlash( Display::return_message($plugin->get_lang('ToolAdded'), 'success') diff --git a/plugin/ims_lti/delete.php b/plugin/ims_lti/delete.php index ce023e8439..881ae2ca7c 100644 --- a/plugin/ims_lti/delete.php +++ b/plugin/ims_lti/delete.php @@ -1,6 +1,29 @@ find('ChamiloPluginBundle:ImsLti\ImsLtiTool', intval($_GET['id'])) : 0; + +if (!$tool) { + api_not_allowed(true); +} + +$em->remove($tool); +$em->flush(); + +Display::addFlash( + Display::return_message($plugin->get_lang('ToolDeleted'), 'success') +); + +header('Location: '.api_get_path(WEB_PLUGIN_PATH).'ims_lti/admin.php'); +exit; diff --git a/plugin/ims_lti/edit.php b/plugin/ims_lti/edit.php index 43756cfd7f..34a11a53e0 100644 --- a/plugin/ims_lti/edit.php +++ b/plugin/ims_lti/edit.php @@ -1,21 +1,26 @@ find('ChamiloPluginBundle:ImsLti\ImsLtiTool', $toolId); + +if (!$tool) { Display::addFlash( Display::return_message($plugin->get_lang('NoTool'), 'error') ); @@ -26,12 +31,12 @@ if (empty($tool)) { $form = new FormValidator('ims_lti_edit_tool'); $form->addText('name', get_lang('Name')); -$form->addTextarea('description', get_lang('Description')); -$form->addText('url', get_lang('Url')); +$form->addTextarea('description', get_lang('Description'), ['rows' => 10]); +$form->addText('url', $plugin->get_lang('LaunchUrl')); $form->addText('consumer_key', $plugin->get_lang('ConsumerKey')); $form->addText('shared_secret', $plugin->get_lang('SharedSecret')); $form->addTextarea('custom_params', $plugin->get_lang('CustomParams')); -$form->addButtonCreate($plugin->get_lang('AddExternalTool')); +$form->addButtonSave(get_lang('Save')); $form->addHidden('id', $tool->getId()); $form->setDefaults([ 'name' => $tool->getName(), @@ -51,8 +56,10 @@ if ($form->validate()) { ->setLaunchUrl($formValues['url']) ->setConsumerKey($formValues['consumer_key']) ->setSharedSecret($formValues['shared_secret']) - ->setCustomParams($formValues['custom_params']) - ->save(); + ->setCustomParams($formValues['custom_params']); + + $em->persist($tool); + $em->flush(); Display::addFlash( Display::return_message($plugin->get_lang('ToolEdited'), 'success') diff --git a/plugin/ims_lti/form.php b/plugin/ims_lti/form.php index 9059b26fa8..1474a6327b 100644 --- a/plugin/ims_lti/form.php +++ b/plugin/ims_lti/form.php @@ -3,20 +3,25 @@ use Chamilo\UserBundle\Entity\User; use Chamilo\CoreBundle\Entity\Course; +use Chamilo\PluginBundle\Entity\ImsLti\ImsLtiTool; require_once __DIR__.'/../../main/inc/global.inc.php'; require './OAuthSimple.php'; api_protect_course_script(); -$toolId = isset($_GET['id']) ? intval($_GET['id']) : 0; - $em = Database::getManager(); + +/** @var ImsLtiTool $tool */ +$tool = isset($_GET['id']) ? $em->find('ChamiloPluginBundle:ImsLti\ImsLtiTool', intval($_GET['id'])) : 0; + +if (!$tool) { + api_not_allowed(true); +} + /** @var ImsLtiPlugin $imsLtiPlugin */ $imsLtiPlugin = ImsLtiPlugin::create(); -/** @var ImsLtiTool $tool */ -$tool = ImsLtiTool::fetch($toolId); /** @var Course $course */ $course = $em->find('ChamiloCoreBundle:Course', api_get_course_int_id()); /** @var User $user */ diff --git a/plugin/ims_lti/lang/english.php b/plugin/ims_lti/lang/english.php index 3485461bd1..e42e4c7b65 100644 --- a/plugin/ims_lti/lang/english.php +++ b/plugin/ims_lti/lang/english.php @@ -18,3 +18,6 @@ $strings['ToolNotAdded'] = 'Tool not added'; $strings['AvailableTools'] = 'Available tools'; $strings['ToolSettings'] = 'Tool settings'; $strings['ToolNotAvailable'] = 'Tool not available'; +$strings['IsGlobal'] = 'Is global'; +$strings['EditExternalTool'] = 'Editar external tool'; +$strings['ToolDeleted'] = 'Tool deleted'; diff --git a/plugin/ims_lti/start.php b/plugin/ims_lti/start.php index 2db7fa1506..70dd2fcb94 100644 --- a/plugin/ims_lti/start.php +++ b/plugin/ims_lti/start.php @@ -1,23 +1,25 @@ find('ChamiloPluginBundle:ImsLti\ImsLtiTool', intval($_GET['id'])) : null; -if (empty($toolId)) { +if (!$tool) { api_not_allowed(true); } -api_protect_course_script(); - $imsLtiPlugin = ImsLtiPlugin::create(); -$tool = ImsLtiTool::fetch($toolId); - -$htmlHeadXtra[] = ''; - -$template = new Template($imsLtiPlugin->get_title()); +$template = new Template($tool->getName()); +$template->assign('tool', $tool); $template->assign( 'launch_url', api_get_path(WEB_PLUGIN_PATH).'ims_lti/form.php?'.http_build_query(['id' => $tool->getId()]) diff --git a/plugin/ims_lti/view/admin.tpl b/plugin/ims_lti/view/admin.tpl index 87811201f2..569f652559 100644 --- a/plugin/ims_lti/view/admin.tpl +++ b/plugin/ims_lti/view/admin.tpl @@ -10,15 +10,25 @@ {{ 'Name'|get_lang }} {{ 'LaunchUrl'|get_plugin_lang('ImsLtiPlugin') }} - {{ 'Actions'|get_lang }} + {{ 'IsGlobal'|get_plugin_lang('ImsLtiPlugin') }} + {{ 'Actions'|get_lang }} {% for tool in tools %} {{ tool.name }} - {{ tool.launch_url }} - + {{ tool.launchUrl }} + + {% if tool.isGlobal %} + + {{ 'Yes'|get_lang }} + {% else %} + + {{ 'No'|get_lang }} + {% endif %} + + {{ 'Edit'|get_lang }} diff --git a/plugin/ims_lti/view/start.tpl b/plugin/ims_lti/view/start.tpl index 3ca976a0b0..46a8cb0ca1 100644 --- a/plugin/ims_lti/view/start.tpl +++ b/plugin/ims_lti/view/start.tpl @@ -1,3 +1,6 @@ +{% if tool.description %} +

{{ tool.description }}

+{% endif %}