Skip to content

Commit

Permalink
Merge branch 'release-15.19.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
github-actions committed Apr 4, 2024
2 parents 97aeffc + 1e3004e commit 26fcbb5
Show file tree
Hide file tree
Showing 6 changed files with 264 additions and 31 deletions.
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@
"oat-sa/lib-lti1p3-ags": "^1.2",
"oat-sa/lib-lti1p3-core": "^6.0.0",
"oat-sa/generis" : ">=15.22",
"oat-sa/tao-core" : ">=54.8.0"
"oat-sa/tao-core" : ">=54.10.0"
},
"autoload" : {
"psr-4" : {
Expand Down
21 changes: 0 additions & 21 deletions controller/AuthoringTool.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@
use helpers_Random;
use InterruptedActionException;
use OAT\Library\Lti1p3Core\Message\Payload\LtiMessagePayloadInterface;
use oat\tao\model\featureFlag\FeatureFlagChecker;
use oat\tao\model\featureFlag\FeatureFlagCheckerInterface;
use oat\taoLti\models\classes\LtiException;
use oat\taoLti\models\classes\LtiMessages\LtiErrorMessage;
use oat\taoLti\models\classes\LtiService;
Expand Down Expand Up @@ -106,18 +104,6 @@ public function launch(): void
$this->forward('run', null, null, $_GET);
}

/**
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
private function isFeatureTaoAsToolEnabled(): bool
{
return $this->getServiceManager()
->getContainer()
->get(FeatureFlagChecker::class)
->isEnabled(FeatureFlagCheckerInterface::FEATURE_FLAG_TAO_AS_A_TOOL);
}

/**
* @throws ContainerExceptionInterface
* @throws InterruptedActionException
Expand All @@ -126,13 +112,6 @@ private function isFeatureTaoAsToolEnabled(): bool
*/
private function getLtiMessageOrRedirectToLogin(): LtiMessagePayloadInterface
{
if (!$this->isFeatureTaoAsToolEnabled()) {
$this->getLogger()->info(
'TAO as tool feature is disabled. The user will be redirected to the login page.'
);
$this->redirect(_url('login', 'Main', 'tao'));
}

try {
$message = $this->getValidatedLtiMessagePayload();
} catch (LtiException $exception) {
Expand Down
88 changes: 88 additions & 0 deletions models/classes/DynamicConfig/LtiConfigProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<?php

/**
* 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; under version 2
* of the License (non-upgradable).
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Copyright (c) 2024 (original work) Open Assessment Technologies SA;
*/

declare(strict_types=1);

namespace oat\taoLti\models\classes\DynamicConfig;

use oat\oatbox\session\SessionService;
use oat\tao\model\DynamicConfig\DynamicConfigProviderInterface;
use oat\taoLti\models\classes\LtiLaunchData;
use oat\taoLti\models\classes\TaoLtiSession;
use Psr\Log\LoggerInterface;
use Throwable;

class LtiConfigProvider implements DynamicConfigProviderInterface
{
private DynamicConfigProviderInterface $configFallback;

private SessionService $session;
private LoggerInterface $logger;

public function __construct(
DynamicConfigProviderInterface $configFallback,
SessionService $session,
LoggerInterface $logger
) {
$this->configFallback = $configFallback;
$this->session = $session;
$this->logger = $logger;
}

public function getConfigByName(string $name): ?string
{
return $this->getConfigByLtiClaimName($name) ?? $this->configFallback->getConfigByName($name);
}

public function hasConfig(string $name): bool
{
return $this->getConfigByName($name) !== null;
}

private function getConfigByLtiClaimName(string $name): ?string
{
$currentSession = $this->session->getCurrentSession();

if (!$currentSession instanceof TaoLtiSession) {
return null;
}

$ltiLaunchData = $currentSession->getLaunchData();

if ($name === self::LOGIN_URL_CONFIG_NAME) {
return $ltiLaunchData->getCustomParameter(LtiLaunchData::LTI_TAO_LOGIN_URL);
}
if ($name === self::LOGOUT_URL_CONFIG_NAME) {
return $ltiLaunchData->getCustomParameter(LtiLaunchData::LTI_REDIRECT_AFTER_LOGOUT_URL);
}

try {
if ($name === self::PLATFORM_URL_CONFIG_NAME && $ltiLaunchData->hasReturnUrl()) {
return $ltiLaunchData->getReturnUrl();
}
} catch (Throwable $exception) {
$this->logger->warning(
sprintf('It was not possible to recover return url claim. Exception: %s', $exception)
);
}

return null;
}
}
10 changes: 7 additions & 3 deletions models/classes/LtiLaunchData.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@
use OAT\Library\Lti1p3Core\Message\Payload\Claim\AgsClaim;
use OAT\Library\Lti1p3Core\Message\Payload\LtiMessagePayloadInterface;
use OAT\Library\Lti1p3Core\Platform\PlatformInterface;
use oat\taoLti\models\classes\LtiMessages\LtiErrorMessage;
use tao_helpers_Request;
use oat\oatbox\log\LoggerAwareTrait;
use oat\taoLti\models\classes\LtiMessages\LtiErrorMessage;
use Psr\Http\Message\ServerRequestInterface;
use tao_helpers_Request;

class LtiLaunchData implements \JsonSerializable
{
Expand Down Expand Up @@ -66,6 +66,10 @@ class LtiLaunchData implements \JsonSerializable
public const LTI_SHOW_SCORE = 'custom_show_score';
public const LTI_SHOW_CORRECT = 'custom_show_correct';

public const LTI_REDIRECT_AFTER_LOGOUT_URL = 'authoringSettings.redirectAfterLogoutUrl';

public const LTI_TAO_LOGIN_URL = 'authoringSettings.taoLoginUrl';

// for user claim
private const LTI_FOR_USER_ID = 'lti_for_user_id';
private const LTI_FOR_USER_EMAIL = 'lti_for_user_email';
Expand Down Expand Up @@ -242,7 +246,7 @@ private static function getParametersFromUrl(string $url): array
// encoded in url
$parts = explode('/', tao_helpers_Request::getRelativeUrl($url), 4);
if (count($parts) == 4) {
list($extension, $module, $action, $codedUri) = $parts;
[$extension, $module, $action, $codedUri] = $parts;
$base64String = base64_decode($codedUri);
if ($base64String !== false) {
// old serialised url
Expand Down
48 changes: 42 additions & 6 deletions models/classes/ServiceProvider/LtiServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,12 @@
use oat\oatbox\cache\factory\CacheItemPoolFactory;
use oat\oatbox\cache\ItemPoolSimpleCacheAdapter;
use oat\oatbox\log\LoggerService;
use oat\oatbox\session\SessionService;
use oat\tao\model\DynamicConfig\DynamicConfigProviderInterface;
use oat\tao\model\accessControl\RoleBasedContextRestrictAccess;
use oat\tao\model\menu\SectionVisibilityByRoleFilter;
use oat\taoLti\models\classes\Client\LtiClientFactory;
use oat\taoLti\models\classes\DynamicConfig\LtiConfigProvider;
use oat\taoLti\models\classes\LtiAgs\LtiAgsScoreService;
use oat\taoLti\models\classes\LtiAgs\LtiAgsScoreServiceInterface;
use oat\taoLti\models\classes\LtiRoles;
Expand All @@ -64,13 +69,19 @@
use Psr\Cache\CacheItemPoolInterface;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;

use function Symfony\Component\DependencyInjection\Loader\Configurator\inline_service;
use function Symfony\Component\DependencyInjection\Loader\Configurator\service;
use function Symfony\Component\DependencyInjection\Loader\Configurator\env;
use function Symfony\Component\DependencyInjection\Loader\Configurator\inline_service;
use function Symfony\Component\DependencyInjection\Loader\Configurator\param;
use function Symfony\Component\DependencyInjection\Loader\Configurator\service;

class LtiServiceProvider implements ContainerServiceProviderInterface
{
private const PORTAL_ACCESS_ROLES = [
LtiRoles::CONTEXT_LTI1P3_ADMINISTRATOR_SUB_DEVELOPER,
LtiRoles::CONTEXT_LTI1P3_CONTENT_DEVELOPER_SUB_CONTENT_DEVELOPER,
LTIRoles::CONTEXT_INSTITUTION_LTI1P3_ADMINISTRATOR,
LtiRoles::CONTEXT_LTI1P3_INSTRUCTOR
];
public function __invoke(ContainerConfigurator $configurator): void
{
$services = $configurator->services();
Expand All @@ -83,11 +94,14 @@ public function __invoke(ContainerConfigurator $configurator): void

$parameters->set(
'rolesAllowed',
self::PORTAL_ACCESS_ROLES
);

$parameters->set(
'restrictedRolesForSectionMap',
[
LtiRoles::CONTEXT_LTI1P3_ADMINISTRATOR_SUB_DEVELOPER,
LtiRoles::CONTEXT_LTI1P3_CONTENT_DEVELOPER_SUB_CONTENT_DEVELOPER,
LTIRoles::CONTEXT_INSTITUTION_LTI1P3_ADMINISTRATOR,
LtiRoles::CONTEXT_LTI1P3_INSTRUCTOR
'help' => self::PORTAL_ACCESS_ROLES,
'settings_my_password' => self::PORTAL_ACCESS_ROLES,
]
);

Expand Down Expand Up @@ -259,5 +273,27 @@ public function __invoke(ContainerConfigurator $configurator): void
param('rolesAllowed')
]
);

$services
->get(RoleBasedContextRestrictAccess::class)
->arg('$restrictedRoles', [
'ltiAuthoringLaunchRestrictRoles' => param('rolesAllowed')
]);

$services->set(SectionVisibilityByRoleFilter::class, SectionVisibilityByRoleFilter::class)
->public()
->args([param('restrictedRolesForSectionMap')]);

$services
->set(LtiConfigProvider::class)
->decorate(DynamicConfigProviderInterface::class)
->public()
->args(
[
service(LtiConfigProvider::class . '.inner'),
service(SessionService::SERVICE_ID),
service(LoggerService::SERVICE_ID),
]
);
}
}
126 changes: 126 additions & 0 deletions test/unit/models/classes/DynamicConfig/LtiConfigProviderTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
<?php

/**
* 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; under version 2
* of the License (non-upgradable).
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Copyright (c) 2024 (original work) Open Assessment Technologies SA;
*/

declare(strict_types=1);

namespace oat\taoLti\test\unit\models\classes\DynamicConfig;

use oat\oatbox\session\SessionService;
use oat\tao\model\DynamicConfig\DynamicConfigProviderInterface;
use oat\taoLti\models\classes\DynamicConfig\LtiConfigProvider;
use oat\taoLti\models\classes\LtiLaunchData;
use oat\taoLti\models\classes\TaoLtiSession;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;

class LtiConfigProviderTest extends TestCase
{
public function testGetConfigByName(): void
{
$ltiLaunchData = $this->createMock(LtiLaunchData::class);
$ltiLaunchData->method('getCustomParameter')
->will(
$this->returnCallback(function ($param) {
switch ($param) {
case LtiLaunchData::LTI_TAO_LOGIN_URL:
return 'https://example.com/login';
case LtiLaunchData::LTI_REDIRECT_AFTER_LOGOUT_URL:
return 'https://example.com/logout';
default:
return null;
}
})
);

$taoLtiSession = $this->createMock(TaoLtiSession::class);
$taoLtiSession->method('getLaunchData')
->willReturn($ltiLaunchData);

$session = $this->createMock(SessionService::class);
$session->method('getCurrentSession')
->willReturn($taoLtiSession);

$fallbackConfigProvider = $this->createMock(DynamicConfigProviderInterface::class);
$fallbackConfigProvider->method('getConfigByName')
->willReturnMap([
[LtiConfigProvider::LOGOUT_URL_CONFIG_NAME, 'https://fallback.com/logout'],
[LtiConfigProvider::PLATFORM_URL_CONFIG_NAME, null], // Simulating no value from fallback
[LtiConfigProvider::LOGIN_URL_CONFIG_NAME, 'https://fallback.com/login'],
]);

$logger = $this->createMock(LoggerInterface::class);
$logger->expects($this->never())->method('warning');

$ltiConfigProvider = new LtiConfigProvider($fallbackConfigProvider, $session, $logger);

// Test LTI-specific configurations
$this->assertSame(
'https://example.com/logout',
$ltiConfigProvider->getConfigByName(LtiConfigProvider::LOGOUT_URL_CONFIG_NAME)
);
$this->assertSame(
'https://example.com/login',
$ltiConfigProvider->getConfigByName(LtiConfigProvider::LOGIN_URL_CONFIG_NAME)
);
$this->assertNull(
$ltiConfigProvider->getConfigByName(LtiConfigProvider::PLATFORM_URL_CONFIG_NAME)
);
}

public function testHasConfig(): void
{
// Simulating LTI environment where portal URL is provided
$ltiLaunchData = $this->createMock(LtiLaunchData::class);
$ltiLaunchData->method('hasReturnUrl')->willReturn(true);

$taoLtiSession = $this->createMock(TaoLtiSession::class);
$taoLtiSession->method('getLaunchData')->willReturn($ltiLaunchData);

$session = $this->createMock(SessionService::class);
$session->method('getCurrentSession')->willReturn($taoLtiSession);

$fallbackConfigProvider = $this->createMock(DynamicConfigProviderInterface::class);
$fallbackConfigProvider->method('getConfigByName')->willReturnMap([
[LtiConfigProvider::LOGOUT_URL_CONFIG_NAME, null],
[LtiConfigProvider::PLATFORM_URL_CONFIG_NAME, 'https://example.com/portal'],
[LtiConfigProvider::LOGIN_URL_CONFIG_NAME, null],
]);

$logger = $this->createMock(LoggerInterface::class);

$ltiConfigProvider = new LtiConfigProvider($fallbackConfigProvider, $session, $logger);
$this->assertTrue($ltiConfigProvider->hasConfig(DynamicConfigProviderInterface::PLATFORM_URL_CONFIG_NAME));

// Simulating non-LTI environment
$session = $this->createMock(SessionService::class);
$session->method('getCurrentSession')->willReturn(null);

$fallbackConfigProvider = $this->createMock(DynamicConfigProviderInterface::class);
$fallbackConfigProvider->method('getConfigByName')->willReturnMap([
[LtiConfigProvider::LOGOUT_URL_CONFIG_NAME, null],
[LtiConfigProvider::PLATFORM_URL_CONFIG_NAME, null],
[LtiConfigProvider::LOGIN_URL_CONFIG_NAME, null],
]);


$ltiConfigProvider = new LtiConfigProvider($fallbackConfigProvider, $session, $logger);
$this->assertFalse($ltiConfigProvider->hasConfig(DynamicConfigProviderInterface::PLATFORM_URL_CONFIG_NAME));
}
}

0 comments on commit 26fcbb5

Please sign in to comment.