478 lines
15 KiB
PHP
478 lines
15 KiB
PHP
|
<?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) 2013-2019 (original work) Open Assessment Technologies SA (under the project TAO-PRODUCT);
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
namespace oat\taoLti\models\classes;
|
||
|
|
||
|
use common_http_Request;
|
||
|
use core_kernel_classes_Resource;
|
||
|
use OAT\Library\Lti1p3Core\Message\Payload\LtiMessagePayloadInterface;
|
||
|
use oat\taoLti\models\classes\LtiMessages\LtiErrorMessage;
|
||
|
use oat\taoLti\models\classes\Platform\LtiPlatform;
|
||
|
use tao_helpers_Request;
|
||
|
use oat\oatbox\log\LoggerAwareTrait;
|
||
|
use Psr\Http\Message\ServerRequestInterface;
|
||
|
|
||
|
class LtiLaunchData implements \JsonSerializable
|
||
|
{
|
||
|
use LoggerAwareTrait;
|
||
|
|
||
|
const OAUTH_CONSUMER_KEY = 'oauth_consumer_key';
|
||
|
const RESOURCE_LINK_ID = 'resource_link_id';
|
||
|
const RESOURCE_LINK_TITLE = 'resource_link_title';
|
||
|
const CONTEXT_ID = 'context_id';
|
||
|
const CONTEXT_LABEL = 'context_label';
|
||
|
const CONTEXT_TITLE = 'context_title';
|
||
|
|
||
|
const USER_ID = 'user_id';
|
||
|
const ROLES = 'roles';
|
||
|
const LIS_PERSON_NAME_GIVEN = 'lis_person_name_given';
|
||
|
const LIS_PERSON_NAME_FAMILY = 'lis_person_name_family';
|
||
|
const LIS_PERSON_NAME_FULL = 'lis_person_name_full';
|
||
|
const LIS_PERSON_CONTACT_EMAIL_PRIMARY = 'lis_person_contact_email_primary';
|
||
|
|
||
|
const LAUNCH_PRESENTATION_LOCALE = 'launch_presentation_locale';
|
||
|
const LAUNCH_PRESENTATION_RETURN_URL = 'launch_presentation_return_url';
|
||
|
|
||
|
const TOOL_CONSUMER_INSTANCE_ID = 'tool_consumer_instance_id';
|
||
|
const TOOL_CONSUMER_INSTANCE_NAME = 'tool_consumer_instance_name';
|
||
|
const TOOL_CONSUMER_INSTANCE_DESCRIPTION = 'tool_consumer_instance_description';
|
||
|
|
||
|
const LTI_VERSION = 'lti_version';
|
||
|
const LTI_MESSAGE_TYPE = 'lti_message_type';
|
||
|
|
||
|
const LIS_RESULT_SOURCEDID = 'lis_result_sourcedid';
|
||
|
const LIS_OUTCOME_SERVICE_URL = 'lis_outcome_service_url';
|
||
|
|
||
|
// review mode
|
||
|
const LTI_SHOW_SCORE = 'custom_show_score';
|
||
|
const LTI_SHOW_CORRECT = 'custom_show_correct';
|
||
|
|
||
|
/**
|
||
|
* LTI variables
|
||
|
*
|
||
|
* @var array
|
||
|
*/
|
||
|
private $variables;
|
||
|
|
||
|
/**
|
||
|
* Custom parameters of the LTI call
|
||
|
*
|
||
|
* @var array
|
||
|
*/
|
||
|
private $customParams;
|
||
|
|
||
|
/**
|
||
|
* @var core_kernel_classes_Resource
|
||
|
*/
|
||
|
private $ltiConsumer;
|
||
|
|
||
|
/**
|
||
|
* Spawns an LtiSession
|
||
|
*
|
||
|
* @param array $ltiVariables
|
||
|
* @param array $customParameters
|
||
|
*/
|
||
|
public function __construct(array $ltiVariables, array $customParameters)
|
||
|
{
|
||
|
$this->variables = $ltiVariables;
|
||
|
$this->customParams = $customParameters;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param array $json
|
||
|
* @return LtiLaunchData
|
||
|
*/
|
||
|
public static function fromJsonArray($json)
|
||
|
{
|
||
|
return new static($json['variables'], $json['customParams']);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
* @param common_http_Request $request
|
||
|
* @return LtiLaunchData
|
||
|
* @throws \ResolverException
|
||
|
*/
|
||
|
public static function fromPsrRequest(ServerRequestInterface $request)
|
||
|
{
|
||
|
$extra = self::getParametersFromUrl($request->getUri()->__toString());
|
||
|
$combined = array_merge($request->getQueryParams(), $request->getParsedBody());
|
||
|
return new static($combined, $extra);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
* @param common_http_Request $request
|
||
|
* @return LtiLaunchData
|
||
|
* @throws \ResolverException
|
||
|
*/
|
||
|
public static function fromRequest(common_http_Request $request)
|
||
|
{
|
||
|
$extra = self::getParametersFromUrl($request->getUrl());
|
||
|
return new static($request->getParams(), $extra);
|
||
|
}
|
||
|
|
||
|
public static function fromLti1p3MessagePayload(LtiMessagePayloadInterface $ltiMessagePayload, LtiPlatform $platform = null)
|
||
|
{
|
||
|
$variables[self::OAUTH_CONSUMER_KEY] = '';
|
||
|
$variables[self::RESOURCE_LINK_ID] = $ltiMessagePayload->getResourceLink() ? $ltiMessagePayload->getResourceLink()->getIdentifier() : null;
|
||
|
$variables[self::RESOURCE_LINK_TITLE] = $ltiMessagePayload->getResourceLink() ? $ltiMessagePayload->getResourceLink()->getTitle() : null;
|
||
|
$variables[self::CONTEXT_ID] = $ltiMessagePayload->getContext() ? $ltiMessagePayload->getContext()->getIdentifier() : null;
|
||
|
$variables[self::CONTEXT_LABEL] = $ltiMessagePayload->getContext() ? $ltiMessagePayload->getContext()->getLabel() : null;
|
||
|
$variables[self::CONTEXT_TITLE] = $ltiMessagePayload->getContext() ? $ltiMessagePayload->getContext()->getTitle() : null;
|
||
|
$variables[self::USER_ID] = $ltiMessagePayload->getUserIdentity() ? $ltiMessagePayload->getUserIdentity()->getIdentifier() : null;
|
||
|
$variables[self::ROLES] = implode(',', $ltiMessagePayload->getRoles());
|
||
|
$variables[self::LIS_PERSON_NAME_GIVEN] = $ltiMessagePayload->getUserIdentity() ? $ltiMessagePayload->getUserIdentity()->getGivenName() : null;
|
||
|
$variables[self::LIS_PERSON_NAME_FAMILY] = $ltiMessagePayload->getUserIdentity() ? $ltiMessagePayload->getUserIdentity()->getFamilyName() : null;
|
||
|
$variables[self::LIS_PERSON_NAME_FULL] = $ltiMessagePayload->getUserIdentity() ? $ltiMessagePayload->getUserIdentity()->getName() : null;
|
||
|
$variables[self::LIS_PERSON_CONTACT_EMAIL_PRIMARY] = $ltiMessagePayload->getUserIdentity() ? $ltiMessagePayload->getUserIdentity()->getEmail() : null;
|
||
|
$variables[self::LAUNCH_PRESENTATION_LOCALE] = $ltiMessagePayload->getLaunchPresentation() ? $ltiMessagePayload->getLaunchPresentation()->getLocale(): null;
|
||
|
$variables[self::LAUNCH_PRESENTATION_RETURN_URL] = $ltiMessagePayload->getLaunchPresentation() ? $ltiMessagePayload->getLaunchPresentation()->getReturnUrl() : null;
|
||
|
$variables[self::LTI_VERSION] = $ltiMessagePayload->getVersion();
|
||
|
$variables[self::LTI_MESSAGE_TYPE] = $ltiMessagePayload->getMessageType();
|
||
|
$variables[self::LIS_RESULT_SOURCEDID] = $ltiMessagePayload->getBasicOutcome() ? $ltiMessagePayload->getBasicOutcome()->getLisResultSourcedId() : null;
|
||
|
$variables[self::LIS_OUTCOME_SERVICE_URL] = $ltiMessagePayload->getBasicOutcome() ? $ltiMessagePayload->getBasicOutcome()->getLisOutcomeServiceUrl() : null;
|
||
|
|
||
|
if ($platform) {
|
||
|
// we need to have inner platform ID
|
||
|
$variables[self::TOOL_CONSUMER_INSTANCE_ID] = $platform->getId();
|
||
|
|
||
|
if ($platformFromClaim = $ltiMessagePayload->getPlatformInstance()) {
|
||
|
$variables[self::TOOL_CONSUMER_INSTANCE_NAME] = $platformFromClaim->getName();
|
||
|
$variables[self::TOOL_CONSUMER_INSTANCE_DESCRIPTION] = $platformFromClaim->getDescription();
|
||
|
} else {
|
||
|
$variables[self::TOOL_CONSUMER_INSTANCE_NAME] = $platform->getLabel();
|
||
|
$variables[self::TOOL_CONSUMER_INSTANCE_DESCRIPTION] = $platform->getLabel();
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
$customParams = $ltiMessagePayload->getCustom();
|
||
|
|
||
|
// review mode
|
||
|
if (isset($customParams[self::LTI_SHOW_SCORE])) {
|
||
|
$variables[self::LTI_SHOW_SCORE] = true;
|
||
|
}
|
||
|
|
||
|
if (isset($customParams[self::LTI_SHOW_CORRECT])) {
|
||
|
$variables[self::LTI_SHOW_CORRECT] = true;
|
||
|
}
|
||
|
|
||
|
return new static($variables, $customParams);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param string $url
|
||
|
* @return array
|
||
|
* @throws \ResolverException
|
||
|
*/
|
||
|
private static function getParametersFromUrl($url)
|
||
|
{
|
||
|
$returnValue = [];
|
||
|
|
||
|
// get parameters
|
||
|
parse_str(parse_url($url, PHP_URL_QUERY), $returnValue);
|
||
|
|
||
|
// encoded in url
|
||
|
$parts = explode('/', tao_helpers_Request::getRelativeUrl($url), 4);
|
||
|
if (count($parts) == 4) {
|
||
|
list ($extension, $module, $action, $codedUri) = $parts;
|
||
|
$base64String = base64_decode($codedUri);
|
||
|
if ($base64String !== false) {
|
||
|
// old serialised url
|
||
|
if (substr($base64String, 0, strlen('a:')) == 'a:') {
|
||
|
$additionalParams = unserialize($base64String);
|
||
|
} else {
|
||
|
$additionalParams = json_decode($base64String, true);
|
||
|
}
|
||
|
if ($additionalParams !== false && is_array($additionalParams)) {
|
||
|
foreach ($additionalParams as $key => $value) {
|
||
|
$returnValue[$key] = $value;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return $returnValue;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param string $key
|
||
|
* @return mixed|null
|
||
|
*/
|
||
|
public function getCustomParameter($key)
|
||
|
{
|
||
|
return isset($this->customParams[$key]) ? $this->customParams[$key] : null;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get all custom parameters provided during launch.
|
||
|
*
|
||
|
* @return array
|
||
|
*/
|
||
|
public function getCustomParameters()
|
||
|
{
|
||
|
return $this->customParams;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get all lti variables provided during launch.
|
||
|
*
|
||
|
* @return array
|
||
|
*/
|
||
|
public function getVariables()
|
||
|
{
|
||
|
return $this->variables;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return mixed
|
||
|
* @throws LtiVariableMissingException
|
||
|
*/
|
||
|
public function getResourceLinkID()
|
||
|
{
|
||
|
return $this->getVariable(self::RESOURCE_LINK_ID);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param $key
|
||
|
* @return mixed
|
||
|
* @throws LtiVariableMissingException
|
||
|
*/
|
||
|
public function getVariable($key)
|
||
|
{
|
||
|
if (isset($this->variables[$key])) {
|
||
|
return $this->variables[$key];
|
||
|
} else {
|
||
|
throw new LtiVariableMissingException($key);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param string $key
|
||
|
* @return boolean mixed
|
||
|
*
|
||
|
* @throws LtiException
|
||
|
* @throws LtiVariableMissingException
|
||
|
*/
|
||
|
public function getBooleanVariable($key)
|
||
|
{
|
||
|
$var = mb_strtolower($this->getVariable($key));
|
||
|
|
||
|
if ($var === 'true') {
|
||
|
return true;
|
||
|
} elseif ($var === 'false') {
|
||
|
return false;
|
||
|
} else {
|
||
|
throw new LtiInvalidVariableException(
|
||
|
'Invalid value of `' . $key . '` variable, boolean string expected.',
|
||
|
LtiErrorMessage::ERROR_INVALID_PARAMETER
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return mixed|string
|
||
|
* @throws LtiVariableMissingException
|
||
|
*/
|
||
|
public function getResourceLinkTitle()
|
||
|
{
|
||
|
if ($this->hasVariable(self::RESOURCE_LINK_TITLE)) {
|
||
|
return $this->getVariable(self::RESOURCE_LINK_TITLE);
|
||
|
} else {
|
||
|
return __('link');
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public function hasVariable($key)
|
||
|
{
|
||
|
return isset($this->variables[$key]);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return mixed
|
||
|
* @throws LtiVariableMissingException
|
||
|
*/
|
||
|
public function getUserID()
|
||
|
{
|
||
|
return $this->getVariable(self::USER_ID);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return mixed
|
||
|
*/
|
||
|
public function getUserGivenName()
|
||
|
{
|
||
|
if ($this->hasVariable(static::LIS_PERSON_NAME_GIVEN)) {
|
||
|
return $this->getVariable(static::LIS_PERSON_NAME_GIVEN);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return mixed
|
||
|
*/
|
||
|
public function getUserFamilyName()
|
||
|
{
|
||
|
if ($this->hasVariable(static::LIS_PERSON_NAME_FAMILY)) {
|
||
|
return $this->getVariable(static::LIS_PERSON_NAME_FAMILY);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return mixed
|
||
|
* @throws LtiVariableMissingException
|
||
|
*/
|
||
|
public function getUserFullName()
|
||
|
{
|
||
|
if ($this->hasVariable(self::LIS_PERSON_NAME_FULL)) {
|
||
|
return $this->getVariable(self::LIS_PERSON_NAME_FULL);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return mixed
|
||
|
* @throws LtiVariableMissingException
|
||
|
*/
|
||
|
public function getUserEmail()
|
||
|
{
|
||
|
return $this->getVariable(self::LIS_PERSON_CONTACT_EMAIL_PRIMARY);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return array
|
||
|
* @throws LtiVariableMissingException
|
||
|
*/
|
||
|
public function getUserRoles()
|
||
|
{
|
||
|
return explode(',', $this->getVariable(self::ROLES));
|
||
|
}
|
||
|
|
||
|
public function hasLaunchLanguage()
|
||
|
{
|
||
|
return $this->hasVariable(self::LAUNCH_PRESENTATION_LOCALE);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return mixed
|
||
|
* @throws LtiVariableMissingException
|
||
|
*/
|
||
|
public function getLaunchLanguage()
|
||
|
{
|
||
|
return $this->getVariable(self::LAUNCH_PRESENTATION_LOCALE);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Tries to return the tool consumer name
|
||
|
*
|
||
|
* Returns null if no name found
|
||
|
*
|
||
|
* @return string
|
||
|
* @throws LtiVariableMissingException
|
||
|
*/
|
||
|
public function getToolConsumerName()
|
||
|
{
|
||
|
$consumerName = null;
|
||
|
|
||
|
if ($this->hasVariable(self::TOOL_CONSUMER_INSTANCE_NAME)) {
|
||
|
$consumerName = $this->getVariable(self::TOOL_CONSUMER_INSTANCE_NAME);
|
||
|
}
|
||
|
|
||
|
if (
|
||
|
$consumerName === null
|
||
|
&& $this->hasVariable(self::TOOL_CONSUMER_INSTANCE_DESCRIPTION)
|
||
|
) {
|
||
|
$consumerName = $this->getVariable(self::TOOL_CONSUMER_INSTANCE_DESCRIPTION);
|
||
|
}
|
||
|
|
||
|
return $consumerName;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return core_kernel_classes_Resource
|
||
|
* @throws LtiVariableMissingException
|
||
|
*/
|
||
|
public function getLtiConsumer()
|
||
|
{
|
||
|
if (is_null($this->ltiConsumer)) {
|
||
|
$dataStore = new \tao_models_classes_oauth_DataStore();
|
||
|
$this->ltiConsumer = $dataStore->findOauthConsumerResource($this->getOauthKey())->getUri();
|
||
|
}
|
||
|
|
||
|
return new \core_kernel_classes_Resource($this->ltiConsumer);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return mixed
|
||
|
* @throws LtiVariableMissingException
|
||
|
*/
|
||
|
public function getOauthKey()
|
||
|
{
|
||
|
return $this->getVariable(self::OAUTH_CONSUMER_KEY);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return bool
|
||
|
* @throws LtiException
|
||
|
*/
|
||
|
public function hasReturnUrl()
|
||
|
{
|
||
|
if ($this->hasVariable(self::LAUNCH_PRESENTATION_RETURN_URL)) {
|
||
|
$returnUrl = $this->getReturnUrl();
|
||
|
|
||
|
if (!empty($returnUrl)) {
|
||
|
if (filter_var($returnUrl, FILTER_VALIDATE_URL)) {
|
||
|
return true;
|
||
|
} else {
|
||
|
$this->logWarning("Invalid LTI Return URL '${returnUrl}'.");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Return the returnUrl to the tool consumer
|
||
|
*
|
||
|
* @return string
|
||
|
* @throws LtiException
|
||
|
*/
|
||
|
public function getReturnUrl()
|
||
|
{
|
||
|
return $this->getVariable(self::LAUNCH_PRESENTATION_RETURN_URL);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Specify data which should be serialized to JSON
|
||
|
* @link https://php.net/manual/en/jsonserializable.jsonserialize.php
|
||
|
* @return mixed data which can be serialized by <b>json_encode</b>,
|
||
|
* which is a value of any type other than a resource.
|
||
|
* @since 5.4.0
|
||
|
*/
|
||
|
public function jsonSerialize()
|
||
|
{
|
||
|
return [
|
||
|
'variables' => $this->variables,
|
||
|
'customParams' => $this->customParams,
|
||
|
];
|
||
|
}
|
||
|
}
|