Skip to content
Snippets Groups Projects
Commit 0197b620 authored by Moritz Strohm's avatar Moritz Strohm
Browse files

StEP 3348, closes #3348

Closes #3348

Merge request !2275
parent 39745c9a
No related branches found
No related tags found
No related merge requests found
Showing
with 1725 additions and 575 deletions
...@@ -23,6 +23,7 @@ data/oer_logos/* ...@@ -23,6 +23,7 @@ data/oer_logos/*
data/upload_doc/* data/upload_doc/*
public/.htaccess public/.htaccess
public/.rnd
public/assets/javascripts/*.js public/assets/javascripts/*.js
public/assets/javascripts/*.js.map public/assets/javascripts/*.js.map
public/assets/stylesheets/*.css public/assets/stylesheets/*.css
......
...@@ -23,16 +23,21 @@ class Admin_LtiController extends AuthenticatedController ...@@ -23,16 +23,21 @@ class Admin_LtiController extends AuthenticatedController
$GLOBALS['perm']->check('root'); $GLOBALS['perm']->check('root');
Navigation::activateItem('/admin/config/lti'); Navigation::activateItem('/admin/config/lti');
PageLayout::setTitle(_('Konfiguration der LTI-Tools')); PageLayout::setTitle(_('LTI-Tools'));
$widget = Sidebar::get()->addWidget(new ActionsWidget()); $widget = Sidebar::get()->addWidget(new ActionsWidget());
$widget->addLink( $widget->addLink(
_('Neues LTI-Tool registrieren'), _('Neues LTI-Tool registrieren'),
$this->url_for('admin/lti/edit'), $this->url_for('lti/tool/add/global'),
Icon::create('add') Icon::create('add')
)->asDialog(); )->asDialog();
$widget->addLink(
_('Daten zur LTI-Plattform anzeigen'),
$this->url_for('lti/auth/platform_data'),
Icon::create('info')
)->asDialog();
Helpbar::get()->addPlainText('', _('Hier können Sie Verknüpfungen mit externen Tools konfigurieren, sofern diese den LTI-Standard (Version 1.x) unterstützen.')); Helpbar::get()->addPlainText('', _('Hier können Sie LTI-Tools konfigurieren. Diese müssen den LTI-Standard in Version 1.0/1.1 oder 1.3A unterstützen.'));
} }
/** /**
...@@ -42,66 +47,4 @@ class Admin_LtiController extends AuthenticatedController ...@@ -42,66 +47,4 @@ class Admin_LtiController extends AuthenticatedController
{ {
$this->tools = LtiTool::findAll(); $this->tools = LtiTool::findAll();
} }
/**
* Display dialog for editing an LTI tool.
*
* @param int $id tool id
*/
public function edit_action($id = null)
{
$this->tool = new LtiTool($id);
}
/**
* Save changes for an LTI tool.
*
* @param int $id tool id
*/
public function save_action($id)
{
CSRFProtection::verifyUnsafeRequest();
$tool = new LtiTool($id ?: null);
$tool->name = trim(Request::get('name'));
$tool->launch_url = trim(Request::get('launch_url'));
$tool->consumer_key = trim(Request::get('consumer_key'));
$tool->consumer_secret = trim(Request::get('consumer_secret'));
$tool->custom_parameters = trim(Request::get('custom_parameters'));
$tool->allow_custom_url = Request::int('allow_custom_url', 0);
$tool->deep_linking = Request::int('deep_linking', 0);
$tool->send_lis_person = Request::int('send_lis_person', 0);
$tool->oauth_signature_method = Request::get('oauth_signature_method', 'sha1');
if ($tool->store()) {
PageLayout::postSuccess(sprintf(
_('Einstellungen für "%s" wurden gespeichert.'),
htmlReady($tool->name)
));
}
$this->redirect('admin/lti');
}
/**
* Delete an LTI tool.
*
* @param int $id tool id
*/
public function delete_action($id)
{
CSRFProtection::verifyUnsafeRequest();
$tool = LtiTool::find($id);
$tool_name = $tool->name;
if ($tool && $tool->delete()) {
PageLayout::postSuccess(sprintf(
_('Das LTI-Tool "%s" wurde gelöscht.'),
htmlReady($tool_name)
));
}
$this->redirect('admin/lti');
}
} }
This diff is collapsed.
<?php
use Studip\LTI13a\LineItemRepository;
use Studip\LTI13a\RegistrationManager;
use OAT\Library\Lti1p3Core\Security\OAuth2\Validator\RequestAccessTokenValidator;
use OAT\Library\Lti1p3Ags\Service\LineItem\Server\Handler\UpdateLineItemServiceServerRequestHandler;
use OAT\Library\Lti1p3Ags\Service\LineItem\Server\Handler\DeleteLineItemServiceServerRequestHandler;
use OAT\Library\Lti1p3Ags\Service\LineItem\Server\Handler\GetLineItemServiceServerRequestHandler;
use OAT\Library\Lti1p3Ags\Service\Result\Server\Handler\ResultServiceServerRequestHandler;
use OAT\Library\Lti1p3Ags\Service\Score\Server\Handler\ScoreServiceServerRequestHandler;
use OAT\Library\Lti1p3Ags\Service\LineItem\Server\Handler\CreateLineItemServiceServerRequestHandler;
use OAT\Library\Lti1p3Ags\Service\LineItem\Server\Handler\ListLineItemsServiceServerRequestHandler;
use OAT\Library\Lti1p3Core\Service\Server\LtiServiceServer;
/**
* ags.php - LTI assignment and grade services controller
*
* 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
* @date 2024
* @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2
* @category Stud.IP
*/
class Lti_AgsController extends StudipController
{
use \Studip\OAuth2\NegotiatesWithPsr7;
public function __construct(\Trails\Dispatcher $dispatcher)
{
$this->with_session = true;
parent::__construct($dispatcher);
}
public function before_filter(&$action, &$args)
{
parent::before_filter($action, $args);
//All the work is done by the OAT-SA library and
//the implementation of its interfaces in Stud.IP.
//Only the handler changes for the endpoints.
$reg_manager = new RegistrationManager();
$line_item_repo = new LineItemRepository();
$validator = new RequestAccessTokenValidator($reg_manager);
$handler = null;
if ($action === 'line_item') {
if (empty($args)) {
if (Request::isPut()) {
//Update a line item:
$handler = new UpdateLineItemServiceServerRequestHandler($line_item_repo);
} elseif (Request::isDelete()) {
//Delete a line item:
$handler = new DeleteLineItemServiceServerRequestHandler($line_item_repo);
} else {
//Get a line item:
$handler = new GetLineItemServiceServerRequestHandler($line_item_repo);
}
} elseif ($args[0] === 'results') {
$handler = new ResultServiceServerRequestHandler($line_item_repo, new Studip\LTI13a\ResultRepository());
} elseif ($args[0] === 'scores') {
$handler = new ScoreServiceServerRequestHandler($line_item_repo,new \Studip\LTI13a\ScoreRepository());
}
} elseif ($action === 'line_items') {
if (Request::isPost()) {
//Create a line item:
$handler = new CreateLineItemServiceServerRequestHandler($line_item_repo);
} else {
//List line items:
$handler = new ListLineItemsServiceServerRequestHandler($line_item_repo);
}
} else {
//Invalid endpoint.
throw new AccessDeniedException(studip_interpolate('Invalid endpoint: %{endpoint}', ['endpoint' => $action]));
}
if (!$handler) {
throw new \Studip\LTIException('No handler available for this request.');
}
$server = new LtiServiceServer($validator, $handler);
$this->renderPsrResponse($server->handle($this->getPsrRequest()));
}
/**
* This is the endpoint for the LTI AGS lineitem service.
*
* @return void
*/
public function line_item_action(): void
{
//Nothing here. All is done in the before_filter.
}
/**
* This is the endpoint for the LTI AGS lineitems service.
*
* @return void
*/
public function line_items_action(): void
{
//Nothing here. All is done in the before_filter.
}
}
<?php <?php
use OAT\Library\Lti1p3Core\Message\Payload\Builder\MessagePayloadBuilder;
use OAT\Library\Lti1p3Core\Security\Jwks\Exporter\JwksExporter;
use OAT\Library\Lti1p3Core\Security\Jwks\Server\JwksRequestHandler;
use OAT\Library\Lti1p3Core\Security\Key\KeyChainRepository;
use OAT\Library\Lti1p3Core\Security\OAuth2\Factory\AuthorizationServerFactory;
use OAT\Library\Lti1p3Core\Security\OAuth2\Generator\AccessTokenResponseGenerator;
use OAT\Library\Lti1p3Core\Security\OAuth2\Repository\AccessTokenRepository;
use OAT\Library\Lti1p3Core\Security\OAuth2\Repository\ClientRepository;
use OAT\Library\Lti1p3Core\Security\OAuth2\Repository\ScopeRepository;
use OAT\Library\Lti1p3Core\Security\Oidc\OidcAuthenticator;
use OAT\Library\Lti1p3Core\Security\Oidc\Server\OidcAuthenticationRequestHandler;
use Studip\Cache\Factory;
use Studip\LTI13a\KeyManager;
use Studip\LTI13a\NonceGenerator;
use Studip\LTI13a\PlatformManager;
use Studip\LTI13a\RegistrationManager;
use Studip\LTI13a\UserAuthenticator;
use Studip\OAuth2\Bridge\ScopeEntity;
/** /**
* lti.php - LTI 1.1 single sign on controller * auth.php - LTI authentication controller
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * modify it under the terms of the GNU General Public License as
...@@ -8,25 +28,40 @@ ...@@ -8,25 +28,40 @@
* the License, or (at your option) any later version. * the License, or (at your option) any later version.
* *
* @author Elmar Ludwig * @author Elmar Ludwig
* @author Moritz Strohm
* @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2 * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2
* @category Stud.IP * @category Stud.IP
*/ */
class LtiController extends AuthenticatedController class Lti_AuthController extends StudipController
{ {
use Studip\OAuth2\NegotiatesWithPsr7;
public function __construct(\Trails\Dispatcher $dispatcher)
{
$this->allow_nobody = false;
$action = basename(get_route());
if (in_array($action, ['jwks', 'oauth2_token'])) {
$this->allow_nobody = true;
$this->with_session = $action !== 'jwks';
}
parent::__construct($dispatcher);
}
/** /**
* Callback function being called before an action is executed. * Callback function being called before an action is executed.
*/ */
public function before_filter(&$action, &$args) public function before_filter(&$action, &$args)
{ {
// enforce LTI SSO login if (in_array($action, ['index', 'content_item', 'link_content_item'])) {
Request::set('sso', 'lti'); // enforce LTI SSO login
Request::set('sso', 'lti');
}
parent::before_filter($action, $args); parent::before_filter($action, $args);
} }
/** /**
* Redirect to enrollment action for the given course, if needed. * Redirect to enrolment action for the given course, if needed.
*/ */
public function index_action($course_id = null) public function index_action($course_id = null)
{ {
...@@ -124,4 +159,92 @@ class LtiController extends AuthenticatedController ...@@ -124,4 +159,92 @@ class LtiController extends AuthenticatedController
$this->signature = $lti_link->getLaunchSignature($this->launch_data); $this->signature = $lti_link->getLaunchSignature($this->launch_data);
$this->render_template('course/lti/iframe'); $this->render_template('course/lti/iframe');
} }
/**
* This action handles OIDC (OpenID connect) requests.
*
* @return void
*/
public function oidc_init_action(): void
{
$reg_manager = new RegistrationManager();
$user_authenticator = new UserAuthenticator();
$request = $this->getPsrRequest();
$oidc_handler = new OidcAuthenticationRequestHandler(
new OidcAuthenticator(
$reg_manager,
$user_authenticator,
//The following is necessary due to a library bug.
//See: https://github.com/oat-sa/lib-lti1p3-core/issues/154
new MessagePayloadBuilder(new NonceGenerator(true))
)
);
$response = $oidc_handler->handle($request);
$this->renderPsrResponse($response);
}
/**
* This action handles JSON web key set (JWKS) requests for the platform key.
*
* @return void
*/
public function jwks_action(): void
{
$repo = new KeyChainRepository();
$keyring = Keyring::findOneBySQL("`range_type` = 'global' AND `range_id` = 'lti13a_platform'");
if ($keyring) {
$repo->addKeyChain($keyring->toKeyChain());
}
$handler = new JwksRequestHandler(new JwksExporter($repo));
$response = $handler->handle('lti13a_platform');
$this->renderPsrResponse($response);
}
/**
* Generates OAuth2 tokens for LTI tools.
*/
public function oauth2_token_action(): void
{
$keyring = Keyring::findOneByRange_id('lti13a_platform');
if (!$keyring) {
throw new \Studip\Exception(
'Stud.IP LTI 1.3a platform keyring cannot be found!'
);
}
$key_chain = $keyring->toKeyChain();
$response_generator = new AccessTokenResponseGenerator(
new KeyManager(),
new AuthorizationServerFactory(
new ClientRepository(new RegistrationManager()),
new AccessTokenRepository(Factory::getCache()),
new ScopeRepository(
[
new ScopeEntity('https://purl.imsglobal.org/spec/lti-ags/scope/lineitem'),
new ScopeEntity('https://purl.imsglobal.org/spec/lti-ags/scope/result.readonly'),
new ScopeEntity('https://purl.imsglobal.org/spec/lti-ags/scope/score')
]
),
$key_chain->getPrivateKey()->getContent()
)
);
$response = $response_generator->generate(
$this->getPsrRequest(),
$this->getPsrResponse(),
'lti13a_platform'
);
$this->renderPsrResponse($response);
}
/**
* Displays LTI platform data of the Stud.IP installation. The data are needed for configuring the
* platform on the tool side.
*/
public function platform_data_action()
{
$this->platform = PlatformManager::getPlatformConfiguration();
$this->render_template('lti/_platform_data');
}
} }
<?php
class Lti_ToolController extends AuthenticatedController
{
public function before_filter(&$action, &$args)
{
parent::before_filter($action, $args);
$this->tool = null;
$this->deployment = null;
$this->tool_id = '';
$this->range_id = '';
if (in_array($action, ['index', 'add', 'edit', 'delete'])) {
$this->range_id = $args[0];
$this->tool_id = $args[1] ?? '';
if ($action === 'add' && !$this->tool_id) {
$this->tool = new LtiTool();
$this->tool->range_id = $this->range_id;
} else {
if (!$this->tool_id) {
PageLayout::postError(_('Es wurde kein LTI-Tool angegeben.'));
return;
}
$this->tool = LtiTool::find($this->tool_id);
if (!$this->tool) {
throw new \Studip\Exception(_('Das angegebene LTI-Tool wurde nicht gefunden.'));
}
}
}
}
public function index_action($range_id, $tool_id): void
{
//$this->tool is created in the before-filter.
if ($this->range_id !== 'global') {
$this->deployment = LtiDeployment::findOneBySQL(
'`tool_id` = :tool_id AND `course_id` = :range_id',
['tool_id' => $this->tool->id, 'range_id' => $this->range_id]
);
}
}
public function add_action($range_id, $tool_id = ''): void
{
//NOTE: The parameters are checked and processed in the before_filter.
$this->addEditHandler();
}
public function edit_action($range_id, $tool_id): void
{
//NOTE: The parameters are checked and processed in the before_filter.
$this->addEditHandler();
}
protected function addEditHandler(): void
{
if (!$this->tool) {
return;
}
$this->deployment = null;
if ($this->tool->isNew()) {
if (!Config::get()->LTI_ALLOW_TOOL_CONFIG_IN_COURSE && $this->range_id !== 'global') {
throw new AccessDeniedException(
_('Die Einrichtung von LTI-Tools in Veranstaltungen ist ausgeschaltet.')
);
}
if ($this->tool->range_id === 'global' && !$this->tool->isEditableByUser()) {
throw new AccessDeniedException();
}
PageLayout::postWarning(_('Bitte beachten Sie das geltende europäische Datenschutzrecht (DSGVO)!'));
if ($this->tool->range_id !== 'global') {
$this->deployment = new LtiDeployment();
$this->deployment->course_id = $this->tool->range_id;
}
} elseif ($this->range_id !== 'global') {
$this->deployment = LtiDeployment::findOneBySQL(
'`tool_id` = :tool_id AND `course_id` = :range_id',
['tool_id' => $this->tool->id, 'range_id' => $this->range_id]
);
if (!$this->deployment) {
//Create a new deployment:
$this->deployment = new LtiDeployment();
$this->deployment->tool_id = $this->tool->id;
$this->deployment->course_id = $this->range_id;
}
}
if (Request::isPost()) {
$this->saveTool();
}
}
/**
* Handles the saving of a tool.
*/
protected function saveTool(): void
{
CSRFProtection::verifyUnsafeRequest();
if ($this->range_id === 'global') {
//The admin page for editing global tools.
$this->tool->name = trim(Request::get('name'));
$this->tool->launch_url = trim(Request::get('launch_url'));
} else {
//The page for editing tools configured in courses.
$this->deployment->title = trim(Request::get('name'));
$this->deployment->description = trim(Request::get('description'));
$this->deployment->launch_url = trim(Request::get('launch_url'));
$document_target = trim(Request::get('document_target'));
if ($document_target === 'iframe') {
if (!is_array($this->deployment->options)) {
$this->deployment->options = [];
}
$this->deployment->options['document_target'] = $document_target;
} elseif (isset($this->deployment->options['document_target'])) {
unset($this->deployment->options['document_target']);
}
}
//If a deployment is present, the tool is not used in the global context.
//If a tool is not used in the global context and the range_id is not set to "global",
//it is a tool that is only used for one course.
if (
!$this->deployment
|| $this->tool->range_id !== 'global'
|| $GLOBALS['perm']->have_perm('root')
) {
$this->tool->name = trim(Request::get('name'));
$this->tool->launch_url = trim(Request::get('launch_url'));
$this->tool->terms_of_use_url = trim(Request::get('terms_of_use_url'));
$this->tool->privacy_policy_url = trim(Request::get('privacy_policy_url'));
$this->tool->data_protection_notes = trim(Request::get('data_protection_notes'));
$this->tool->lti_version = Request::get('lti_version', '1.3a');
if ($this->tool->lti_version === '1.3a') {
$this->tool->oauth_signature_method = 'sha256';
$this->tool->oidc_init_url = trim(Request::get('oidc_init_url'));
$this->tool->jwks_url = trim(Request::get('jwks_url'));
$this->tool->jwks_key_id = trim(Request::get('jwks_key_id'));
$this->tool->deep_linking_url = trim(Request::get('deep_linking_url'));
$this->tool->deep_linking = (bool) $this->tool->deep_linking_url;
} else {
//LTI 1.0/1.1:
$this->tool->oauth_signature_method = 'sha1';
$this->tool->consumer_key = trim(Request::get('consumer_key'));
$this->tool->consumer_secret = trim(Request::get('consumer_secret'));
}
$this->tool->send_lis_person = Request::int('send_lis_person', 0);
$this->tool->custom_parameters = trim(Request::get('custom_parameters'));
$tool_public_key = trim(Request::get('tool_public_key'));
$errors = $this->tool->validate();
if ($errors) {
PageLayout::postError(
_('Die folgenden Daten zum LTI-Tool sind fehlerhaft:'),
array_map('htmlReady', $errors)
);
return;
}
if ($this->tool->lti_version === '1.3a' && !$tool_public_key && !$this->tool->jwks_url) {
PageLayout::postError(
_('Es wurde weder ein öffentlicher Schlüssel noch eine JWKS-URL zum Tool angegeben.')
);
return;
}
if ($this->tool->store() !== false) {
if ($this->deployment) {
$this->deployment->tool_id = $this->tool->id;
}
} else {
PageLayout::postError(_('Das LTI-Tool konnte nicht gespeichert werden.'));
return;
}
}
if ($this->deployment) {
$this->deployment->store();
}
if ($this->tool->lti_version === '1.3a' && $tool_public_key) {
if (!$this->tool->updatePublicKey($tool_public_key)) {
PageLayout::postError(
_('Der öffentliche Schlüssel des LTI-Tools konnte nicht gespeichert werden.')
);
}
}
PageLayout::postSuccess(_('Das LTI-Tool wurde gespeichert.'));
if (Request::isDialog()) {
$this->response->add_header('X-Dialog-Close', '1');
$this->render_nothing();
} elseif ($this->range_id === 'global') {
$this->redirect('admin/lti');
} else {
$this->redirect('course/lti');
}
}
public function delete_action($range_id, $tool_id): void
{
//NOTE: The parameters are checked and processed in the before_filter.
CSRFProtection::verifyUnsafeRequest();
$deleted = false;
$tool_name = $this->tool->name;
if ($this->tool->range_id === 'global') {
if ($range_id === 'global') {
$deleted = $this->tool->delete();
} else {
//A tool shall be deleted from a course: Delete the deployment instead.
$deployment = LtiDeployment::findOneBySQL(
"`tool_id` = :tool_id AND `course_id` = :course_id",
['tool_id' => $this->tool->id, 'course_id' => $range_id]
);
if ($deployment) {
$tool_name = $deployment->title;
$deleted = $deployment->delete();
} else {
PageLayout::postError(sprintf(_('Das LTI-Tool „%s“ ist in dieser Veranstaltung nicht vorhanden.'), htmlReady($this->tool->name)));
return;
}
}
} else {
//Delete the tool directly:
$deleted = $this->tool->delete();
}
if ($deleted !== false) {
PageLayout::postSuccess(sprintf(_('Das LTI-Tool „%s“ wurde gelöscht.'), htmlReady($tool_name)));
} else {
PageLayout::postError(_('Das LTI-Tool „%s“ konnte nicht gelöscht werden.'), htmlReady($tool_name));
}
if ($range_id === 'global') {
//Redirect to the admin overview page.
$this->redirect('admin/lti');
} elseif (Course::exists($range_id)) {
//Redirect to the LTI module of the course:
$this->redirect('course/lti', ['cid' => $range_id]);
}
}
}
...@@ -2,73 +2,30 @@ ...@@ -2,73 +2,30 @@
/** /**
* @var Admin_LtiController $controller * @var Admin_LtiController $controller
* @var LtiTool $tool * @var LtiTool $tool
* @var \OAT\Library\Lti1p3Core\Platform\Platform $platform
*/ */
?> ?>
<form class="default" action="<?= $controller->link_for('admin/lti/save/' . $tool->id) ?>" method="post"> <form class="default" action="<?= $controller->link_for('admin/lti/edit/' . $tool->id) ?>"
method="post" data-dialog="reload-on-close">
<?= CSRFProtection::tokenTag() ?> <?= CSRFProtection::tokenTag() ?>
<fieldset> <fieldset>
<legend> <legend>
<?= _('Konfiguration des LTI-Tools') ?> <?= _('Konfiguration des LTI-Tools') ?>
</legend> </legend>
<label class="studiprequired">
<label> <span class="textlabel"><?= _('Name') ?></span>
<span class="required"> <span class="asterisk">*</span>
<?= _('Name der Anwendung') ?> <input type="text" name="name" value="<?= htmlReady($tool->name) ?>">
</span>
<input type="text" name="name" value="<?= htmlReady($tool->name) ?>" required>
</label>
<label>
<span class="required">
<?= _('URL der Anwendung') ?>
</span>
<input type="text" name="launch_url" value="<?= htmlReady($tool->launch_url) ?>" required>
</label>
<label>
<span class="required">
<?= _('Consumer-Key') ?>
</span>
<input type="text" name="consumer_key" value="<?= htmlReady($tool->consumer_key) ?>" required>
</label>
<label>
<span class="required">
<?= _('Consumer-Secret') ?>
</span>
<input type="text" name="consumer_secret" value="<?= htmlReady($tool->consumer_secret) ?>" required>
</label>
<label>
<?= _('OAuth Signatur Methode') ?>
<select name="oauth_signature_method">
<option value="sha1">HMAC-SHA1</option>
<option value="sha256" <?=$tool->oauth_signature_method === 'sha256' ? 'selected' : '' ?>>HMAC-SHA256</option>
</select>
</label>
<label>
<input type="checkbox" name="allow_custom_url" value="1" <?= $tool->allow_custom_url ? ' checked' : '' ?>>
<?= _('Eingabe einer abweichenden URL im Kurs erlauben') ?>
</label>
<label>
<input type="checkbox" name="deep_linking" value="1" <?= $tool->deep_linking ? ' checked' : '' ?>>
<?= _('Auswahl von Inhalten über LTI Deep Linking (Content Item)') ?>
</label>
<label>
<input type="checkbox" name="send_lis_person" value="1" <?= $tool->send_lis_person ? ' checked' : '' ?>>
<?= _('Nutzerdaten an LTI-Tool senden') ?>
<?= tooltipIcon(_('Nutzerdaten dürfen nur an das externe Tool gesendet werden, wenn es keine Datenschutzbedenken gibt. Mit Setzen des Hakens bestätigen Sie, dass die Übermittlung der Daten zulässig ist.')) ?>
</label> </label>
<?= $this->render_partial('lti/_tool_form_fields', ['tool' => $tool]) ?>
</fieldset>
<label> <? if ($platform) : ?>
<?= _('Zusätzliche LTI-Parameter') ?> <fieldset>
<?= tooltipIcon(_('Ein Wert pro Zeile, Beispiel: Review:Chapter=1.2.56')) ?> <legend><?= _('Daten zur LTI-Plattform') ?></legend>
<textarea name="custom_parameters"><?= htmlReady($tool->custom_parameters) ?></textarea> <?= $this->render_partial('lti/_platform_data', ['platform' => $platform]) ?>
</label>
</fieldset> </fieldset>
<? endif ?>
<footer data-dialog-button> <footer data-dialog-button>
<?= Studip\Button::createAccept(_('Speichern'), 'save') ?> <?= Studip\Button::createAccept(_('Speichern'), 'save') ?>
......
...@@ -4,64 +4,64 @@ ...@@ -4,64 +4,64 @@
* @var LtiTool[] $tools * @var LtiTool[] $tools
*/ */
?> ?>
<form action="" method="post"> <? if ($tools) : ?>
<?= CSRFProtection::tokenTag() ?> <form action="" method="post">
<table class="default"> <?= CSRFProtection::tokenTag() ?>
<caption> <table class="default">
<?= _('Aktuell konfigurierte LTI-Tools') ?> <caption><?= _('Aktuell konfigurierte LTI-Tools') ?></caption>
</caption>
<colgroup> <colgroup>
<col style="width: 30%;"> <col style="width: 30%;">
<col style="width: 40%;"> <col style="width: 40%;">
<col style="width: 20%;"> <col style="width: 20%;">
<col style="width: 5%;"> <col style="width: 5%;">
<col style="width: 5%;"> <col style="width: 5%;">
</colgroup> </colgroup>
<thead> <thead>
<tr>
<th><?= _('Name der Anwendung') ?></th>
<th><?= _('URL der Anwendung') ?></th>
<th><?= _('Consumer-Key') ?></th>
<th><?= _('Links') ?></th>
<th class="actions">
<?= _('Aktionen') ?>
</th>
</tr>
</thead>
<tbody>
<? foreach ($tools as $tool): ?>
<tr> <tr>
<td> <th><?= _('Name der Anwendung') ?></th>
<a href="<?= $controller->link_for('admin/lti/edit/' . $tool->id) ?>" title="<?= _('LTI-Tool konfigurieren') ?>" data-dialog> <th><?= _('URL der Anwendung') ?></th>
<?= htmlReady($tool->name) ?> <th><?= _('Consumer-Key') ?></th>
</a> <th><?= _('LTI-Version') ?></th>
</td> <th><?= _('Links') ?></th>
<td> <th class="actions"><?= _('Aktionen') ?></th>
<a href="<?= htmlReady($tool->launch_url) ?>" target="_blank" class="link-extern">
<?= htmlReady($tool->launch_url) ?>
</a>
</td>
<td>
<?= htmlReady($tool->consumer_key) ?>
</td>
<td>
<?= count($tool->links) ?>
</td>
<td class="actions">
<a href="<?= $controller->link_for('admin/lti/edit/' . $tool->id) ?>" title="<?= _('LTI-Tool konfigurieren') ?>" data-dialog>
<?= Icon::create('edit') ?>
</a>
<?= Icon::create('trash')->asInput([
'formaction' => $controller->url_for('admin/lti/delete/' . $tool->id),
'title' => _('LTI-Tool löschen'),
'data-confirm' => sprintf(_('Wollen Sie wirklich das LTI-Tool "%s" löschen?'), $tool->name)
]) ?>
</td>
</tr> </tr>
<? endforeach ?> </thead>
</tbody>
</table> <tbody>
</form> <? foreach ($tools as $tool): ?>
<tr>
<td>
<a href="<?= $controller->link_for('lti/tool/edit/global/' . $tool->id) ?>" data-dialog>
<?= htmlReady($tool->name) ?>
</a>
</td>
<td>
<a href="<?= htmlReady($tool->launch_url) ?>" target="_blank" class="link-extern">
<?= htmlReady($tool->launch_url) ?>
</a>
</td>
<td><?= htmlReady($tool->consumer_key) ?></td>
<td><?= htmlReady($tool->getLtiVersionString()) ?></td>
<td><?= count($tool->links) ?></td>
<td class="actions">
<a href="<?= $controller->link_for('lti/tool/edit/global/' . $tool->id) ?>" title="<?= _('LTI-Tool konfigurieren') ?>"
aria-label="<?= _('LTI-Tool konfigurieren') ?>" data-dialog>
<?= Icon::create('edit') ?>
</a>
<?= Icon::create('trash')->asInput([
'formaction' => $controller->url_for('lti/tool/delete/global/' . $tool->id),
'title' => _('LTI-Tool löschen'),
'data-confirm' => sprintf(_('Wollen Sie das LTI-Tool „%s“ wirklich löschen?'), htmlReady($tool->name)),
'aria-label' => _('LTI-Tool löschen'),
]) ?>
</td>
</tr>
<? endforeach ?>
</tbody>
</table>
</form>
<? else : ?>
<?= MessageBox::info(_('Es sind keine globalen LTI-Tools konfiguriert.')) ?>
<? endif ?>
<form class="default" action="<?= $controller->link_for('course/lti/save_config') ?>" method="post"> <form class="default" action="<?= $controller->link_for('course/lti/save_config') ?>" method="post">
<?= CSRFProtection::tokenTag() ?> <?= CSRFProtection::tokenTag() ?>
<fieldset> <fieldset>
<legend> <legend><?= _('Datenschutzhinweis beim Wechsel in ein LTI-Tool') ?></legend>
<?= _('Einstellungen') ?> <label>
</legend> <?= _('Text des Datenschutzhinweises') ?>
<textarea name="personal_data_warning"><?= htmlReady($personal_data_warning) ?></textarea>
</label>
<label> <label>
<span class="required"> <input type="checkbox" value="1" name="reset_warning"
<?= _('Titel des Reiters') ?> data-deactivates="textarea[name='personal_data_warning']">
</span> <?= _('Den systemweit konfigurierten Standardtext verwenden.') ?>
<input type="text" name="title" value="<?= htmlReady($title) ?>" required>
</label> </label>
</fieldset> </fieldset>
<fieldset>
<legend><?= _('LTI Plattform-Konfiguration') ?></legend>
<?= $this->render_partial('lti/_platform_data', [
'platform' => \Studip\LTI13a\PlatformManager::getPlatformConfiguration(),
]) ?>
</fieldset>
<footer data-dialog-button> <footer data-dialog-button>
<?= Studip\Button::createAccept(_('Speichern'), 'save') ?> <?= Studip\Button::createAccept(_('Speichern'), 'save') ?>
<?= Studip\LinkButton::createCancel(_('Abbrechen'), $controller->url_for('course/lti')) ?> <?= Studip\LinkButton::createCancel(_('Abbrechen'), $controller->url_for('course/lti')) ?>
......
<?php
/**
* @var AuthenticatedController $controller
* @var LtiDeployment $deployment
* @var LtiDeploymentPrivacySettings $privacy_settings
*/
?>
<? if ($deployment) : ?>
<form class="default" method="post" <?= $privacy_settings->isNew() ? 'data-dialog="reload-on-close"' : 'data-dialog' ?>
action="<?= $controller->link_for('course/lti/consent/' . $deployment->id) ?>">
<?= CSRFProtection::tokenTag() ?>
<?
$data_protection_warning = CourseConfig::get(Context::getId())->LTI_DATA_PROTECTION_COURSE_WARNING;
if (empty($data_protection_warning)) {
$data_protection_warning = Config::get()->LTI_DATA_PROTECTION_DEFAULT_WARNING;
}
?>
<fieldset>
<legend><?= _('Datenschutzhinweise') ?></legend>
<section>
<p><?= htmlReady($data_protection_warning) ?></p>
<? if ($deployment->tool->data_protection_notes) : ?>
<p><?= formatReady($deployment->tool->data_protection_notes) ?></p>
<? endif ?>
</section>
</fieldset>
<fieldset>
<?
$optional_field_list = explode(',', $privacy_settings->allowed_optional_fields ?? '');
?>
<legend><?= _('Folgenden Daten werden übertragen') ?></legend>
<?= _('Beim Wechsel in das LTI-Tool werden die folgenden personenbezogenen Daten übertragen:') ?>
<label>
<input type="checkbox" checked disabled>
<?= _('Die ID ihres Stud.IP-Kontos') ?>
</label>
<label>
<input type="checkbox" checked disabled>
<?= _('Ihr Vor- und Nachname, sowie gegebenenfalls vorhandene Titel') ?>
</label>
<label>
<input type="checkbox" checked disabled>
<?= _('Ihre E-Mail Adresse') ?>
</label>
<label>
<input type="checkbox" name="submit_optional_field[lang]" value="1"
<?= in_array('lang', $optional_field_list) ? 'checked' : '' ?>>
<?= _('Ihre in Stud.IP eingestellte Sprache') ?>
</label>
<label>
<input type="checkbox" name="submit_optional_field[avatar_url]" value="1"
<?= in_array('avatar_url', $optional_field_list) ? 'checked' : '' ?>>
<?= _('Ihr Profilbild') ?>
</label>
</fieldset>
<?= $this->render_partial('lti/_deployment_user_info', ['deployment' => $deployment]) ?>
<fieldset>
<legend><?= _('Bestätigung') ?></legend>
<label>
<input type="checkbox" name="confirmed" value="1" required>
<?= _(
'Ich habe die Datenschutzhinweise zur Benutzung des LTI-Tools zur Kenntnis genommen und stimme der Weitergabe meiner personenbezogenen Daten zu. '
. 'Mir ist bewusst, dass ich ohne die Zustimmung das LTI-Tool nicht nutzen kann.'
) ?>
</label>
<div data-dialog-button>
<?= \Studip\Button::createAccept(_('Speichern'), 'save') ?>
<?= \Studip\Button::createCancel(_('Abbrechen')) ?>
</div>
</fieldset>
</form>
<? endif ?>
<?php
/**
* @var Course_LtiController $controller
* @var LtiData $lti_data
* @var LtiTool[] $tools
*/
?>
<form class="default" action="<?= $controller->link_for('course/lti/save', $lti_data->isNew() ? '' : $lti_data->position) ?>" method="post">
<?= CSRFProtection::tokenTag() ?>
<fieldset>
<legend>
<?= _('Einstellungen') ?>
</legend>
<label>
<span class="required">
<?= _('Titel') ?>
</span>
<input type="text" name="title" value="<?= htmlReady($lti_data->title) ?>" required>
</label>
<label>
<?= _('Beschreibung') ?>
<textarea name="description" class="wysiwyg"><?= wysiwygReady($lti_data->description) ?></textarea>
</label>
<label>
<?= _('Auswahl des externen Tools') ?>
<select class="config_tool" name="tool_id">
<? foreach ($tools as $tool): ?>
<option value="<?= $tool->id ?>"
<? if ($tool->allow_custom_url): ?>
data-url="<?= htmlReady($tool->launch_url) ?>"
<? endif ?>
<?= $lti_data->tool_id == $tool->id ? 'selected' : '' ?>><?= htmlReady($tool->name) ?></option>
<? endforeach ?>
<option value="0" <?= !$lti_data->tool_id ? 'selected' : '' ?>><?= _('Zugangsdaten selbst eingeben...') ?></option>
</select>
</label>
<div class="config_custom_url">
<label>
<?= _('URL der Anwendung (optional)') ?>
<?= tooltipIcon(_('Sie können direkt auf eine URL in der Anwendung verlinken.')) ?>
<input type="text" name="custom_url" value="<?= htmlReady($lti_data->launch_url) ?>">
</label>
</div>
<div class="config_launch_url">
<label>
<?= _('URL der Anwendung') ?>
<?= tooltipIcon(_('Die Betreiber dieses Tools müssen Ihnen eine URL und Zugangsdaten (Consumer-Key und Consumer-Secret) mitteilen.')) ?>
<input type="text" name="launch_url" value="<?= htmlReady($lti_data->launch_url) ?>">
</label>
<label>
<?= _('Consumer-Key des LTI-Tools') ?>
<input type="text" name="consumer_key" value="<?= htmlReady($lti_data->options['consumer_key'] ?? '') ?>">
</label>
<label>
<?= _('Consumer-Secret des LTI-Tools') ?>
<input type="text" name="consumer_secret" value="<?= htmlReady($lti_data->options['consumer_secret'] ?? '') ?>">
</label>
<label>
<?= _('OAuth Signatur Methode des LTI-Tools') ?>
<select name="oauth_signature_method">
<option value="sha1">HMAC-SHA1</option>
<option value="sha256" <?= isset($lti_data->options['oauth_signature_method']) && $lti_data->options['oauth_signature_method'] === 'sha256' ? 'selected' : '' ?>>HMAC-SHA256</option>
</select>
</label>
<label>
<input type="checkbox" name="send_lis_person" value="1" <?= !empty($lti_data->options['send_lis_person']) ? ' checked' : '' ?>>
<?= _('Nutzerdaten an LTI-Tool senden') ?>
<?= tooltipIcon(_('Nutzerdaten dürfen nur an das externe Tool gesendet werden, wenn es keine Datenschutzbedenken gibt. Mit Setzen des Hakens bestätigen Sie, dass die Übermittlung der Daten zulässig ist.')) ?>
</label>
</div>
<label>
<input type="checkbox" name="document_target" value="iframe" <?= isset($lti_data->options['document_target']) && $lti_data->options['document_target'] === 'iframe' ? ' checked' : '' ?>>
<?= _('Anzeige im IFRAME auf der Seite') ?>
<?= tooltipIcon(_('Normalerweise wird das externe Tool in einem neuen Fenster angezeigt. Aktivieren Sie diese Option, wenn die Anzeige stattdessen in einem IFRAME erfolgen soll.')) ?>
</label>
<label>
<?= _('Zusätzliche LTI-Parameter') ?>
<?= tooltipIcon(_('Ein Wert pro Zeile, Beispiel: Review:Chapter=1.2.56')) ?>
<textarea name="custom_parameters"><?= htmlReady($lti_data->options['custom_parameters'] ?? '') ?></textarea>
</label>
</fieldset>
<footer data-dialog-button>
<?= Studip\Button::createAccept(_('Speichern'), 'save') ?>
<?= Studip\LinkButton::createCancel(_('Abbrechen'), $controller->url_for('course/lti')) ?>
</footer>
</form>
<script>
$('.config_tool').change(function() {
let url = $(this).find(':selected').data('url');
if ($(this).val() == 0) {
$('.config_launch_url').show();
} else {
$('.config_launch_url').hide();
}
if (url) {
$('.config_custom_url').find('input').attr('placeholder', url);
$('.config_custom_url').show();
} else {
$('.config_custom_url').hide();
}
}).trigger('change');
</script>
<table class="default"> <? if (empty($lti_data_array)): ?>
<caption> <?= MessageBox::info(_('Es sind keine LTI-Tools konfiguriert.')) ?>
<?= _('Ergebnisse') ?> <? else : ?>
</caption> <table class="default">
<caption><?= _('Ergebnisse') ?></caption>
<thead> <thead>
<tr class="sortable"> <tr class="sortable">
<th class="<?= $desc ? 'sortdesc' : 'sortasc' ?>"> <th class="<?= $desc ? 'sortdesc' : 'sortasc' ?>">
<a href="<?= $controller->link_for('course/lti/grades', ['desc' => !$desc]) ?>"> <a href="<?= $controller->link_for('course/lti/grades', ['desc' => !$desc]) ?>">
<?= _('Teilnehmende') ?> <?= _('Teilnehmende') ?>
</a> </a>
</th>
<? foreach ($lti_data_array as $lti_data): ?>
<th style="text-align: right;">
<?= htmlReady($lti_data->title) ?>
</th> </th>
<? endforeach ?>
</tr>
</thead>
<tbody>
<? foreach ($members as $member): ?>
<tr>
<td>
<?= htmlReady($member->nachname) ?>, <?= htmlReady($member->vorname) ?>
</td>
<? foreach ($lti_data_array as $lti_data): ?> <? foreach ($lti_data_array as $lti_data): ?>
<td style="text-align: right;"> <th style="text-align: right;">
<? if ($grade = $lti_data->grades->findOneBy('user_id', $member->user_id)): ?> <?= htmlReady($lti_data->title) ?>
<?= sprintf('%.0f%%', $grade->score * 100) ?> </th>
<? else: ?>
&ndash;
<? endif ?>
</td>
<? endforeach ?> <? endforeach ?>
</tr> </tr>
<? endforeach ?> </thead>
</tbody>
</table> <tbody>
<? foreach ($members as $member): ?>
<tr>
<td>
<?= htmlReady($member->nachname) ?>, <?= htmlReady($member->vorname) ?>
</td>
<? foreach ($lti_data_array as $lti_data): ?>
<td style="text-align: right;">
<? if ($grade = $lti_data->grades->findOneBy('user_id', $member->user_id)): ?>
<?= sprintf('%.0f%%', $grade->score * 100) ?>
<? else: ?>
&ndash;
<? endif ?>
</td>
<? endforeach ?>
</tr>
<? endforeach ?>
</tbody>
</table>
<? endif ?>
<table class="default"> <? if (empty($lti_data_array)): ?>
<caption> <?= MessageBox::info(_('Es sind keine LTI-Tools konfiguriert.')) ?>
<?= _('Ergebnisse') ?> <? else : ?>
</caption> <table class="default">
<caption><?= _('Ergebnisse') ?></caption>
<thead> <thead>
<tr> <tr>
<th> <th><?= _('Abschnitt') ?></th>
<?= _('Abschnitt') ?> <th style="text-align: right;"><?= _('Bewertung') ?></th>
</th>
<th style="text-align: right;">
<?= _('Bewertung') ?>
</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<? foreach ($lti_data_array as $lti_data): ?> <? foreach ($lti_data_array as $lti_data): ?>
<tr> <tr>
<td> <td><?= htmlReady($lti_data->title) ?></td>
<?= htmlReady($lti_data->title) ?> <td style="text-align: right;">
</td> <? if ($grade = LtiGrade::find([$lti_data->id, $GLOBALS['user']->id])): ?>
<td style="text-align: right;"> <?= sprintf('%.0f%%', $grade->score * 100) ?>
<? if ($grade = LtiGrade::find([$lti_data->id, $GLOBALS['user']->id])): ?> <? else: ?>
<?= sprintf('%.0f%%', $grade->score * 100) ?> &ndash;
<? else: ?> <? endif ?>
&ndash; </td>
<? endif ?> </tr>
</td> <? endforeach ?>
</tr> </tbody>
<? endforeach ?> </table>
</tbody> <? endif ?>
</table>
<?php <?php
/** /**
* @var string $launch_url * @var StudipController $controller
* @var LtiDeployment $deployment
* @var array $launch_data * @var array $launch_data
* @var string $signature * @var string $signature
* @var bool $lti13a_mode
* @var \OAT\Library\Lti1p3Core\Message\LtiMessage $message
*/ */
?> ?>
<!DOCTYPE html> <? if ($deployment) : ?>
<html> <!DOCTYPE html>
<head> <html>
<head>
<meta charset="UTF-8"> <meta charset="UTF-8">
</head> <? if (!$lti13a_mode) : ?>
<body onload="document.ltiLaunchForm.submit();"> <script type="text/javascript">
<form name="ltiLaunchForm" method="post" action="<?= htmlReady($launch_url) ?>"> window.onload=document.ltiLaunchForm.submit();
<? foreach ($launch_data as $key => $value): ?> </script>
<input type="hidden" name="<?= htmlReady($key) ?>" value="<?= htmlReady($value, false) ?>"> <? endif ?>
<? endforeach ?> </head>
<input type="hidden" name="oauth_signature" value="<?= $signature ?>"> <body>
<noscript> <? if ($lti13a_mode) : ?>
<button><?= _('Anwendung starten') ?></button> <? if ($message) : ?>
</noscript> <?= $message->toHtmlRedirectForm(Request::submitted('do_not_send') ? false : true) ?>
</form> <? else: ?>
</body> <?= _('Das LTI-Tool kann nicht aufgerufen werden.') ?>
</html> <? endif ?>
<? else : ?>
<form name="ltiLaunchForm" method="post" action="<?= htmlReady($deployment->getLaunchUrl()) ?>">
<? foreach ($launch_data as $key => $value): ?>
<input type="hidden" name="<?= htmlReady($key) ?>" value="<?= htmlReady($value, false) ?>">
<? endforeach ?>
<input type="hidden" name="oauth_signature" value="<?= $signature ?>">
<noscript>
<button><?= _('Anwendung starten') ?></button>
</noscript>
</form>
<? endif ?>
</body>
</html>
<? endif ?>
<?php <?php
/** /**
* @var Course_LtiController $controller * @var Course_LtiController $controller
* @var LtiData[] $lti_data_array * @var LtiDeployment[] $lti_data_array
* @var bool $edit_perm * @var bool $edit_perm
*/ */
?> ?>
<? if (empty($lti_data_array)): ?> <? if (empty($lti_data_array)): ?>
<?= MessageBox::info(_('Es wurden noch keine Inhalte angelegt.')) ?> <?= MessageBox::info(_('Es sind keine LTI-Tools konfiguriert.')) ?>
<? endif ?> <? endif ?>
<? foreach ($lti_data_array as $lti_data): ?> <? foreach ($lti_data_array as $lti_data): ?>
<? $launch_url = $lti_data->getLaunchURL() ?> <?
$launch_url = $lti_data->getLaunchURL();
$unfinished_deep_linking = !empty($lti_data->options['unfinished_deep_linking']);
$no_consent = !LtiToolPrivacySettings::countBySql(
'`tool_id` = :tool_id AND `user_id` = :user_id',
['tool_id' => $lti_data->tool_id, 'user_id' => $GLOBALS['user']->id]
);
?>
<article class="studip"> <article class="studip">
<header> <header>
<h1><?= htmlReady($lti_data->title) ?></h1> <h1>
<?= htmlReady($lti_data->title) ?>
<?= $unfinished_deep_linking ? '(' . _('LTI Deep Linking noch nicht fertig eingerichtet') . ')' : '' ?>
</h1>
<? if ($edit_perm): ?> <? if ($edit_perm): ?>
<nav> <nav>
...@@ -22,47 +32,91 @@ ...@@ -22,47 +32,91 @@
<?= CSRFProtection::tokenTag() ?> <?= CSRFProtection::tokenTag() ?>
<? if ($lti_data->position > 0): ?> <? if ($lti_data->position > 0): ?>
<?= Icon::create('arr_2up', Icon::ROLE_SORT)->asInput([ <?= Icon::create('arr_2up', Icon::ROLE_SORT)->asInput([
'formaction' => $controller->url_for('course/lti/move/' . $lti_data->position . '/up') 'formaction' => $controller->url_for('course/lti/move/' . $lti_data->id . '/up'),
'title' => _('Nach oben verschieben'),
'aria-label' => _('Nach oben verschieben')
]) ?> ]) ?>
<? endif ?> <? endif ?>
<? if ($lti_data->position < count($lti_data_array) - 1): ?> <? if ($lti_data->position < count($lti_data_array) - 1): ?>
<?= Icon::create('arr_2down', Icon::ROLE_SORT)->asInput([ <?= Icon::create('arr_2down', Icon::ROLE_SORT)->asInput([
'formaction' => $controller->url_for('course/lti/move/' . $lti_data->position . '/down') 'formaction' => $controller->url_for('course/lti/move/' . $lti_data->id . '/down'),
'title' => _('Nach unten verschieben'),
'aria-label' => _('Nach unten verschieben')
]) ?> ]) ?>
<? endif ?> <? endif ?>
<?= Icon::create('edit')->asInput([ <?
'formaction' => $controller->url_for('course/lti/edit/' . $lti_data->position), $menu = ActionMenu::get();
'title' => _('Abschnitt bearbeiten'), $show_admin_actions = $GLOBALS['perm']->have_studip_perm('tutor', $lti_data->course_id);
'data-dialog' => '' if ($show_admin_actions) {
]) ?> $menu->addLink(
<?= Icon::create('trash')->asInput([ $controller->url_for('lti/tool/index/' . $lti_data->course_id . '/' . $lti_data->tool->id),
'formaction' => $controller->url_for('course/lti/delete/' . $lti_data->position), _('Konfiguration des LTI-Tools anzeigen'),
'title' => _('Abschnitt löschen'), Icon::create('info-circle'),
'data-confirm' => sprintf(_('Wollen Sie wirklich den Abschnitt "%s" löschen?'), $lti_data->title) ['data-dialog' => 'size=default']
]) ?> );
}
$menu->addLink(
$controller->url_for('course/lti/consent/' . $lti_data->id),
_('Datenschutzeinstellungen'),
Icon::create('privacy'),
['data-dialog' => 'size=default']
);
if ($show_admin_actions) {
$menu->addLink(
$controller->url_for('lti/tool/edit/' . $lti_data->course_id . '/' . $lti_data->tool->id),
_('LTI-Tool konfigurieren'),
Icon::create('edit'),
['data-dialog' => 'size=default']
);
$menu->addLink(
sprintf(
'javascript:void(STUDIP.Dialog.confirmAsPost(\'%s\', \'%s\'))',
sprintf(_('Wollen Sie das LTI-Tool "%s" wirklich entfernen?'), $lti_data->title),
$controller->url_for('lti/tool/delete/' . $lti_data->course_id . '/' . $lti_data->tool->id)
),
_('LTI-Tool entfernen'),
Icon::create('trash')
);
}
?>
<?= $menu->render() ?>
</form> </form>
</nav> </nav>
<? endif ?> <? endif ?>
</header> </header>
<section> <section>
<?= formatReady($lti_data->description) ?> <? if ($unfinished_deep_linking) : ?>
<? if ($launch_url && $lti_data->options['document_target'] === 'iframe'): ?>
<iframe style="border: none; height: 640px; width: 100%;"
src="<?= $controller->link_for('course/lti/iframe', $lti_data->position) ?>"></iframe>
<? endif ?>
</section>
<? if ($launch_url && $lti_data->options['document_target'] !== 'iframe'): ?>
<footer>
<?= Studip\LinkButton::create( <?= Studip\LinkButton::create(
_('Anwendung starten'), _('Einrichtung abschließen'),
$controller->link_for('course/lti/iframe', $lti_data->position), $controller->url_for('course/lti/select_link/' . $lti_data->id, ['tool_id' => $lti_data->tool_id]),
['target' => '_blank'] ['target' => '_blank']
) ?> ) ?>
</footer> <? elseif ($no_consent) : ?>
<? endif ?> <?= formatReady($lti_data->description) ?>
<p><?= _('Sie haben der Datenweitergabe an das LTI-Tool noch nicht zugestimmt und können es deswegen noch nicht nutzen.') ?></p>
<?= Studip\LinkButton::create(
_('Datenschutzeinstellungen öffnen'),
$controller->url_for('course/lti/consent/' . $lti_data->id),
['data-dialog' => 'reload-on-close']
) ?>
<? elseif ($launch_url) : ?>
<?
$document_target = $lti_data->options['document_target'] ?? '';
?>
<?= formatReady($lti_data->description) ?>
<? if ($document_target === 'iframe') : ?>
<iframe style="border: none; height: 640px; width: 100%;"
src="<?= $controller->link_for('course/lti/iframe/' . $lti_data->id) ?>"></iframe>
<? else : ?>
<?= Studip\LinkButton::create(
_('Anwendung starten'),
$controller->url_for('course/lti/iframe/' . $lti_data->id),
['target' => '_blank']
) ?>
<? endif ?>
<? endif ?>
</section>
</article> </article>
<? endforeach ?> <? endforeach ?>
<?php
/**
* @var AuthenticatedController $controller
* @var LtiTool $tool
* @var LtiDeployment $deployment
*/
?>
<form class="default" method="post"
action="<?= $controller->link_for('course/lti/process_select_link/' . htmlReady($deployment->id), ['tool_id' => $tool->id]) ?>">
<?= CSRFProtection::tokenTag() ?>
<?= $this->render_partial('lti/_tool_info', ['tool' => $tool, 'deployment' => $deployment]) ?>
<div data-dialog-button>
<?= \Studip\Button::create(_('Weiter'), 'continue') ?>
</div>
</form>
<?php
/**
* @var StudipController $controller
* @var LtiTool[] $global_tools
*/
?>
<form class="default" method="post" action="<?= $controller->link_for('course/lti/select_tool_redirect') ?>"
data-dialog>
<?= CSRFProtection::tokenTag() ?>
<fieldset>
<legend><?= _('Auswahl des LTI-Tools') ?></legend>
<label>
<?= _('Bitte wählen Sie ein LTI-Tool aus.') ?>
<select name="selected_tool_id">
<? foreach ($global_tools as $tool) : ?>
<option value="<?= htmlReady($tool->id) ?>">
<?= htmlReady($tool->name) ?>
</option>
<? endforeach ?>
<? if (Config::get()->LTI_ALLOW_TOOL_CONFIG_IN_COURSE) : ?>
<option value="new">
<?= _('Neues LTI-Tool für die Veranstaltung einrichten.') ?>
</option>
<? endif ?>
</select>
</label>
</fieldset>
<div data-dialog-button>
<?= \Studip\Button::create(_('Weiter')) ?>
</div>
</form>
<?
/**
* @var LtiDeployment $deployment
*/
?>
<? if (!empty($deployment)) : ?>
<article class="studip">
<header><h1><?= htmlReady($deployment->title) ?></h1></header>
<section>
<? if ($deployment->tool->range_id === 'global') : ?>
<p>
<?= sprintf(
'Dies ist eine Einbindung des LTI-Tools „%s“.',
htmlReady($deployment->tool->name)
) ?>
</p>
<? endif ?>
<p><?= formatReady($deployment->description ?? '') ?></p>
<?
$url_parts = parse_url($deployment->getLaunchURL());
?>
<? if (!empty($url_parts['host'])) : ?>
<p><?= _('Domain') ?>: <?= htmlReady($url_parts['host']) ?></p>
<? endif ?>
<? if ($deployment->tool->terms_of_use_url || $deployment->tool->privacy_policy_url) : ?>
<p>
<? if ($deployment->tool->terms_of_use_url) : ?>
<a href="<?= htmlReady($deployment->tool->terms_of_use_url) ?>">
<?= Icon::create('link-extern')->asImg(['class' => 'text-bottom']) ?>
<?= _('Nutzungsbedingungen') ?>
</a>
<? endif ?>
<? if ($deployment->tool->privacy_policy_url) : ?>
<a href="<?= htmlReady($deployment->tool->privacy_policy_url) ?>">
<?= Icon::create('link-extern')->asImg(['class' => 'text-bottom']) ?>
<?= _('Datenschutzerklärung') ?>
</a>
<? endif ?>
</p>
<? endif ?>
</section>
</article>
<? endif ?>
<?php
/**
* @var \OAT\Library\Lti1p3Core\Platform\Platform $platform
*/
?>
<dl>
<dt><?= _('Plattform-ID') ?></dt>
<dd>
<a href="<?= htmlReady($platform->getAudience()) ?>">
<?= htmlReady($platform->getAudience()) ?>
</a>
</dd>
<dt><?= _('OAuth2 access token URL') ?></dt>
<dd>
<a href="<?= htmlReady($platform->getOAuth2AccessTokenUrl()) ?>">
<?= htmlReady($platform->getOAuth2AccessTokenUrl()) ?>
</a>
</dd>
<dt><?= _('OIDC authentication URL') ?></dt>
<dd>
<a href="<?= htmlReady($platform->getOidcAuthenticationUrl()) ?>">
<?= htmlReady($platform->getOidcAuthenticationUrl()) ?>
</a>
</dd>
<dt><?= _('JWKS URL') ?></dt>
<dd>
<a href="<?= URLHelper::getLink('dispatch.php/lti/auth/jwks', [], true) ?>">
<?= URLHelper::getLink('dispatch.php/lti/auth/jwks', [], true) ?>
</a>
</dd>
<?
$keyring = \Studip\LTI13a\PlatformManager::getPlatformKeyring();
if (!$keyring) {
$keyring = \Studip\LTI13a\PlatformManager::generatePlatformKeyring();
}
?>
<? if ($keyring) : ?>
<dt><?= _('Öffentlicher Schlüssel') ?></dt>
<dd><pre><?= htmlReady($keyring->public_key) ?></pre></dd>
<? endif ?>
</dl>
<?php
/**
* @var LtiTool $tool
* @var LtiDeployment $deployment
*/
?>
<fieldset>
<legend><?= _('Grunddaten') ?></legend>
<label class="studiprequired">
<span class="textlabel"><?= _('Titel') ?></span>
<span class="asterisk">*</span>
<input type="text" name="name" required
value="<?= htmlReady(!empty($deployment) ? $deployment->title : $tool->name ?? '') ?>">
</label>
<? if (!empty($deployment)) : ?>
<label>
<?= _('Beschreibung') ?>
<textarea name="description" class="wysiwyg"><?= wysiwygReady($deployment->description ?? '') ?></textarea>
</label>
<label>
<?= _('Datenschutzhinweise') ?>
<textarea name="data_protection_notes" class="wysiwyg"
placeholder="<?= _('Bitte machen Sie Angaben zu dem angebundenen Werkzeug, soweit sie ihnen bekannt sind. Wie ist der Name, wer bietet es an, wozu wird es eingesetzt und welche Daten werden übertragen? (Beispiel: „Tool XY wird zur Durchführung von Sprachtests genutzt und Testergebnisse und ggf. Noten gespeichert. Zur Anmeldung werden Name und Nutzerkennung übertragen.“)') ?>"><?= wysiwygReady($tool->data_protection_notes) ?></textarea>
</label>
<? endif ?>
<? if ($tool->isEditableByUser()) : ?>
<label>
<?= _('URL zu den Nutzungsbedingungen des LTI-Tools (falls verfügbar)') ?>
<input type="url" name="terms_of_use_url" value="<?= htmlReady($tool->terms_of_use_url) ?>">
</label>
<label>
<?= _('URL zur Datenschutzerklärung des LTI-Tools (falls verfügbar)') ?>
<input type="url" name="privacy_policy_url" value="<?= htmlReady($tool->privacy_policy_url) ?>">
</label>
<? endif ?>
</fieldset>
<fieldset>
<legend><?= _('Konfiguration des LTI-Tools') ?></legend>
<? if ($tool->isEditableByUser()) : ?>
<label class="studiprequired">
<span class="textlabel"><?= _('LTI-Version') ?></span>
<span class="asterisk">*</span>
<select name="lti_version"
data-shows=".lti11-field" data-hides=".lti13a-field"
data-triggering-value="1.1">
<option value="1.1" <?= !empty($tool->lti_version) && $tool->lti_version === '1.1' ? 'selected' : '' ?>>
1.0/1.1
</option>
<option value="1.3a" <?= empty($tool->lti_version) || $tool->lti_version === '1.3a' ? 'selected' : '' ?>>
1.3a
</option>
</select>
</label>
<? endif ?>
<label class="studiprequired">
<span class="textlabel"><?= _('LTI Launch-URL') ?></span>
<span class="asterisk">*</span>
<input type="text" name="launch_url" required
value="<?= htmlReady(
!empty($deployment->launch_url)
? $deployment->launch_url
: $tool->launch_url ?? ''
) ?>">
</label>
<? if ($tool->isEditableByUser()) : ?>
<div class="lti13a-field">
<label>
<?= _('OIDC Login-URL') ?>
<?= tooltipIcon(_('Die URL, mit der der Login via OpenID Connect stattfindet.')) ?>
<input type="text" name="oidc_init_url" value="<?= htmlReady($tool->oidc_init_url ?? '') ?>">
</label>
<label>
<?= _('Deep-linking URL') ?>
<input type="url" name="deep_linking_url" value="<?= htmlReady($tool->deep_linking_url ?? '') ?>">
</label>
<label>
<?= _('JWKS-URL') ?>
<?= tooltipIcon(_('Die URL, mit der der der Austausch von JSON web keys stattfinden kann.')) ?>
<input type="text" name="jwks_url"
value="<?= htmlReady($tool->jwks_url ?? '') ?>">
</label>
<label>
<?= _('Schlüssel-ID') ?>
<?= tooltipIcon(_('Die ID des Schlüssels, der über die JWKS-URL geladen werden soll.')) ?>
<input type="text" name="jwks_key_id" value="<?= htmlReady($tool->jwks_key_id ?? '') ?>">
</label>
<label>
<?= _('Öffentlicher Schlüssel des LTI-Tools') ?>
<?
$keyring = null;
if ($tool && !$tool->isNew()) {
$keyring = $tool->getKeyring();
}
$public_key_string = '';
if ($keyring) {
$keychain = $keyring->toKeyChain();
$public_key_string = $keychain->getPublicKey()->getContent();
}
?>
<textarea name="tool_public_key"><?= htmlReady($public_key_string) ?></textarea>
</label>
</div>
<div class="lti11-field">
<label class="studiprequired">
<span class="textlabel"><?= _('Consumer-Key des LTI-Tools') ?></span>
<span class="asterisk">*</span>
<input type="text" name="consumer_key" required
value="<?= htmlReady($tool->consumer_key ?? '') ?>">
</label>
<label class="studiprequired">
<span class="textlabel"><?= _('Consumer-Secret des LTI-Tools') ?></span>
<span class="asterisk">*</span>
<input type="text" name="consumer_secret" required
value="<?= htmlReady($tool->consumer_secret ?? '') ?>">
</label>
</div>
<label>
<input type="checkbox" name="send_lis_person" value="1" <?= !empty($tool->send_lis_person) ? ' checked' : '' ?>>
<?= _('Personendaten an das LTI-Tool senden') ?>
<?= tooltipIcon(_('Personendaten dürfen nur an das externe Tool gesendet werden, wenn es keine Datenschutzbedenken gibt. Mit Setzen des Hakens bestätigen Sie, dass die Übermittlung der Daten zulässig ist.')) ?>
</label>
<? endif ?>
<label>
<?= _('Zusätzliche LTI-Parameter') ?>
<?= tooltipIcon(_('Ein Wert pro Zeile, Beispiel: Review:Chapter=1.2.56')) ?>
<textarea name="custom_parameters"><?= htmlReady(
!empty($deployment->options['custom_parameters'])
? $deployment->options['custom_parameters']
: $tool->custom_parameters ?? ''
) ?></textarea>
</label>
</fieldset>
<? if (!empty($deployment)) : ?>
<fieldset>
<legend><?= _('Anzeigeeinstellungen') ?></legend>
<label>
<input type="checkbox" name="document_target" value="iframe" <?= isset($deployment->options['document_target']) && $deployment->options['document_target'] === 'iframe' ? ' checked' : '' ?>>
<?= _('Anzeige im IFRAME auf der Seite') ?>
<?= tooltipIcon(_('Normalerweise wird das externe Tool in einem neuen Fenster angezeigt. Aktivieren Sie diese Option, wenn die Anzeige stattdessen in einem IFRAME erfolgen soll.')) ?>
</label>
</fieldset>
<? endif ?>
<footer data-dialog-button>
<?= Studip\Button::createAccept(_('Speichern'), 'save') ?>
</footer>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment