ILIAS  release_6 Revision v6.24-5-g0c8bfefb3b8
All Data Structures Namespaces Files Functions Variables Modules Pages
ilCmiXapiLaunchGUI Class Reference
+ Collaboration diagram for ilCmiXapiLaunchGUI:

Public Member Functions

 __construct (ilObjCmiXapi $object)
 
 executeCommand ()
 

Data Fields

const XAPI_PROXY_ENDPOINT = 'Modules/CmiXapi/xapiproxy.php'
 

Protected Member Functions

 launchCmd ()
 
 buildLaunchLink ($token)
 
 getLaunchParameters ($token)
 
 getAuthTokenFetchLink ()
 
 buildAuthTokenFetchParam ()
 
 getValidToken ()
 
 initCmixUser ()
 
 getCmi5LearnerPreferences ()
 
 CMI5preLaunch ($token)
 Prelaunch post cmi5LearnerPreference (agent profile) post LMS.LaunchData. More...
 

Protected Attributes

 $object
 
 $cmixUser
 
 $plugin = false
 

Private Member Functions

 log ()
 

Detailed Description

Definition at line 15 of file class.ilCmiXapiLaunchGUI.php.

Constructor & Destructor Documentation

◆ __construct()

ilCmiXapiLaunchGUI::__construct ( ilObjCmiXapi  $object)
Parameters
ilObjCmiXapi$object

Definition at line 37 of file class.ilCmiXapiLaunchGUI.php.

References $object.

38  {
39  $this->object = $object;
40  }

Member Function Documentation

◆ buildAuthTokenFetchParam()

ilCmiXapiLaunchGUI::buildAuthTokenFetchParam ( )
protected
Returns
string
Exceptions
ilCmiXapiException

Definition at line 145 of file class.ilCmiXapiLaunchGUI.php.

References $param, ilCmiXapiAuthToken\getWacSalt(), ilCmiXapiAuthToken\OPENSSL_ENCRYPTION_METHOD, and ilCmiXapiAuthToken\OPENSSL_IV.

Referenced by getAuthTokenFetchLink().

146  {
147  $params = [
148  session_name() => session_id(),
149  'obj_id' => $this->object->getId(),
150  'ref_id' => $this->object->getRefId(),
151  'ilClientId' => CLIENT_ID
152  ];
153 
154  $encryptionKey = ilCmiXapiAuthToken::getWacSalt();
155 
156  $param = urlencode(base64_encode(openssl_encrypt(
157  json_encode($params),
159  $encryptionKey,
160  0,
162  )));
163  return $param;
164  }
$param
Definition: xapitoken.php:31
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ buildLaunchLink()

ilCmiXapiLaunchGUI::buildLaunchLink (   $token)
protected

Definition at line 61 of file class.ilCmiXapiLaunchGUI.php.

References $token, ilUtil\appendUrlParameterString(), getLaunchParameters(), ilUtil\getWebspaceDir(), ILIAS_HTTP_PATH, ilCmiXapiContentUploadImporter\RELATIVE_CONTENT_DIRECTORY_NAMEBASE, ilObjCmiXapi\SRC_TYPE_LOCAL, and ilObjCmiXapi\SRC_TYPE_REMOTE.

Referenced by launchCmd().

62  {
63  if ($this->object->getSourceType() == ilObjCmiXapi::SRC_TYPE_REMOTE) {
64  $launchLink = $this->object->getLaunchUrl();
65  } elseif ($this->object->getSourceType() == ilObjCmiXapi::SRC_TYPE_LOCAL) {
66  if (preg_match("/^(https?:\/\/)/",$this->object->getLaunchUrl()) == 1) {
67  $launchLink = $this->object->getLaunchUrl();
68  } else {
69  $launchLink = implode('/', [
72  ]);
73 
74  $launchLink .= DIRECTORY_SEPARATOR . $this->object->getLaunchUrl();
75  }
76  }
77 
78  foreach ($this->getLaunchParameters($token) as $paramName => $paramValue) {
79  $launchLink = ilUtil::appendUrlParameterString($launchLink, "{$paramName}={$paramValue}");
80  }
81 
82  return $launchLink;
83  }
static appendUrlParameterString($a_url, $a_par, $xml_style=false)
append URL parameter string ("par1=value1&par2=value2...") to given URL string
$token
Definition: xapitoken.php:57
static getWebspaceDir($mode="filesystem")
get webspace directory
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ CMI5preLaunch()

ilCmiXapiLaunchGUI::CMI5preLaunch (   $token)
protected

Prelaunch post cmi5LearnerPreference (agent profile) post LMS.LaunchData.

Definition at line 224 of file class.ilCmiXapiLaunchGUI.php.

References $client, $DIC, Vendor\Package\$e, $lang, $response, $token, ilCmiXapiAbstractRequest\buildQuery(), ilCmiXapiAbstractRequest\checkResponse(), ilCmiXapiDateTime\dateIntervalToISO860Duration(), ilCmiXapiUser\generateRegistration(), getCmi5LearnerPreferences(), ilCmiXapiVerbList\getInstance(), ilCmiXapiAuthToken\getInstanceByToken(), getValidToken(), ilObjCmiXapi\guidv4(), IL_CAL_UNIX, log(), and ilLPObjSettings\LP_MODE_DEACTIVATED.

Referenced by launchCmd().

225  {
226  global $DIC;
227 
228  $lrsType = $this->object->getLrsType();
229  $defaultLrs = $lrsType->getLrsEndpoint();
230  //$fallbackLrs = $lrsType->getLrsFallbackEndpoint();
231  $defaultBasicAuth = $lrsType->getBasicAuth();
232  //$fallbackBasicAuth = $lrsType->getFallbackBasicAuth();
233  $defaultHeaders = [
234  'X-Experience-API-Version' => '1.0.3',
235  'Authorization' => $defaultBasicAuth,
236  'Content-Type' => 'application/json;charset=utf-8',
237  'Cache-Control' => 'no-cache, no-store, must-revalidate'
238  ];
239 
240  $registration = $this->cmixUser->getRegistration();
241  // for old CMI5 Content after switch commit but before cmi5 bugfix
242  if ($registration == '')
243  {
244  $registration = ilCmiXapiUser::generateRegistration($this->object, $DIC->user());
245  }
246 
247  $activityId = $this->object->getActivityId();
248 
249  // profile
250  $profileParams = [];
251  $defaultAgentProfileUrl = $defaultLrs . "/agents/profile";
252  $profileParams['agent'] = json_encode($this->object->getStatementActor($this->cmixUser));
253  $profileParams['profileId'] = 'cmi5LearnerPreferences';
254  $defaultProfileUrl = $defaultAgentProfileUrl . '?' . ilCmiXapiAbstractRequest::buildQuery($profileParams);
255 
256  // launchData
257  $launchDataParams = [];
258  $defaultStateUrl = $defaultLrs . "/activities/state";
259  //$launchDataParams['agent'] = $this->buildCmi5ActorParameter();
260  $launchDataParams['agent'] = json_encode($this->object->getStatementActor($this->cmixUser));
261  $launchDataParams['activityId'] = $activityId;
262  $launchDataParams['activity_id'] = $activityId;
263  $launchDataParams['registration'] = $registration;
264  $launchDataParams['stateId'] = 'LMS.LaunchData';
265  $defaultLaunchDataUrl = $defaultStateUrl . '?' . ilCmiXapiAbstractRequest::buildQuery($launchDataParams);
266  $cmi5LearnerPreferencesObj = $this->getCmi5LearnerPreferences();
267  $cmi5LearnerPreferences = json_encode($cmi5LearnerPreferencesObj);
268  $lang = $cmi5LearnerPreferencesObj['languagePreference'];
269  $cmi5_session = ilObjCmiXapi::guidv4();
271  $oldSession = $tokenObject->getCmi5Session();
272  $oldSessionLaunchedTimestamp = '';
273  $abandoned = false;
274  // cmi5_session already exists?
275  if (!empty($oldSession)) {
276  $oldSessionData = json_decode($tokenObject->getCmi5SessionData());
277  $oldSessionLaunchedTimestamp = $oldSessionData->launchedTimestamp;
278  $tokenObject->delete();
279  $token = $this->getValidToken();
281  $lastStatement = $this->object->getLastStatement($oldSession);
282  // should never be 'terminated', because terminated statement is sniffed from proxy -> token delete
283  if ($lastStatement[0]['statement']['verb']['id'] != ilCmiXapiVerbList::getInstance()->getVerbUri('terminated'))
284  {
285  $abandoned = true;
286  $start = new DateTime($oldSessionLaunchedTimestamp);
287  $end = new DateTime($lastStatement[0]['statement']['timestamp']);
288  $diff = $end->diff($start);
290  }
291  }
292  // satisfied on launch?
293  // see: https://github.com/AICC/CMI-5_Spec_Current/blob/quartz/cmi5_spec.md#moveon
294  // https://aicc.github.io/CMI-5_Spec_Current/samples/
295  // Session that includes the absolute minimum data, and is associated with a NotApplicable Move On criteria
296  // which results in immediate satisfaction of the course upon registration creation. Includes Satisfied Statement.
297  $satisfied = false;
298  $lpMode = $this->object->getLPMode();
299  // only do this, if we decide to map the moveOn NotApplicable to ilLPObjSettings::LP_MODE_DEACTIVATED on import and settings editing
300  // and what about user result status?
301  if ($lpMode === ilLPObjSettings::LP_MODE_DEACTIVATED) {
302  $satisfied = true;
303  }
304 
305  $tokenObject->setCmi5Session($cmi5_session);
306  $sessionData = array();
307  $sessionData['cmi5LearnerPreferences'] = $cmi5LearnerPreferencesObj;
308  //https://www.php.net/manual/de/class.dateinterval.php
309  $now = new ilCmiXapiDateTime(time(), IL_CAL_UNIX);
310  $sessionData['launchedTimestamp'] = $now->toXapiTimestamp(); // required for abandoned statement duration, don't want another roundtrip to lrs ...puhhh
311  $tokenObject->setCmi5SessionData(json_encode($sessionData));
312  $tokenObject->update();
313  $defaultStatementsUrl = $defaultLrs . "/statements";
314 
315  // launchedStatement
316  $launchData = json_encode($this->object->getLaunchData($this->cmixUser,$lang));
317  $launchedStatement = $this->object->getLaunchedStatement($this->cmixUser);
318  $launchedStatementParams = [];
319  $launchedStatementParams['statementId'] = $launchedStatement['id'];
320  $defaultLaunchedStatementUrl = $defaultStatementsUrl . '?' . ilCmiXapiAbstractRequest::buildQuery($launchedStatementParams);
321 
322  // abandonedStatement
323  if ($abandoned) {
324  $abandonedStatement = $this->object->getAbandonedStatement($oldSession, $duration, $this->cmixUser);
325  $abandonedStatementParams = [];
326  $abandonedStatementParams['statementId'] = $abandonedStatement['id'];
327  $defaultAbandonedStatementUrl = $defaultStatementsUrl . '?' . ilCmiXapiAbstractRequest::buildQuery($abandonedStatementParams);
328  }
329  // abandonedStatement
330  if ($satisfied) {
331  $satisfiedStatement = $this->object->getSatisfiedStatement($this->cmixUser);
332  $satisfiedStatementParams = [];
333  $satisfiedStatementParams['statementId'] = $satisfiedStatement['id'];
334  $defaultSatisfiedStatementUrl = $defaultStatementsUrl . '?' . ilCmiXapiAbstractRequest::buildQuery($satisfiedStatementParams);
335  }
336  $client = new GuzzleHttp\Client();
337  $req_opts = array(
338  GuzzleHttp\RequestOptions::VERIFY => true,
339  GuzzleHttp\RequestOptions::CONNECT_TIMEOUT => 10,
340  GuzzleHttp\RequestOptions::HTTP_ERRORS => false
341  );
342  $defaultProfileRequest = new GuzzleHttp\Psr7\Request(
343  'POST',
344  $defaultProfileUrl,
345  $defaultHeaders,
346  $cmi5LearnerPreferences
347  );
348  $defaultLaunchDataRequest = new GuzzleHttp\Psr7\Request(
349  'PUT',
350  $defaultLaunchDataUrl,
351  $defaultHeaders,
352  $launchData
353  );
354  $defaultLaunchedStatementRequest = new GuzzleHttp\Psr7\Request(
355  'PUT',
356  $defaultLaunchedStatementUrl,
357  $defaultHeaders,
358  json_encode($launchedStatement)
359  );
360  if ($abandoned) {
361  $defaultAbandonedStatementRequest = new GuzzleHttp\Psr7\Request(
362  'PUT',
363  $defaultAbandonedStatementUrl,
364  $defaultHeaders,
365  json_encode($abandonedStatement)
366  );
367  }
368  if ($satisfied) {
369  $defaultSatisfiedStatementRequest = new GuzzleHttp\Psr7\Request(
370  'PUT',
371  $defaultSatisfiedStatementUrl,
372  $defaultHeaders,
373  json_encode($satisfiedStatement)
374  );
375  }
376  $promises = array();
377  $promises['defaultProfile'] = $client->sendAsync($defaultProfileRequest, $req_opts);
378  $promises['defaultLaunchData'] = $client->sendAsync($defaultLaunchDataRequest, $req_opts);
379  $promises['defaultLaunchedStatement'] = $client->sendAsync($defaultLaunchedStatementRequest, $req_opts);
380  if ($abandoned) {
381  $promises['defaultAbandonedStatement'] = $client->sendAsync($defaultAbandonedStatementRequest, $req_opts);
382  }
383  if ($satisfied) {
384  $promises['defaultSatisfiedStatement'] = $client->sendAsync($defaultSatisfiedStatementRequest, $req_opts);
385  }
386  try
387  {
388  $responses = GuzzleHttp\Promise\Utils::settle($promises)->wait();
389  $body = '';
390  foreach ($responses as $response) {
391  ilCmiXapiAbstractRequest::checkResponse($response,$body,[204]);
392  }
393  }
394  catch(Exception $e)
395  {
396  $this->log()->error('error:' . $e->getMessage());
397  }
398  return array('cmi5_session' => $cmi5_session, 'token' => $token);
399  }
static generateRegistration(ilObjCmiXapi $obj, ilObjUser $user)
if($_SERVER['argc']< 4) $client
Definition: cron.php:12
const IL_CAL_UNIX
$token
Definition: xapitoken.php:57
static guidv4($data=null)
$lang
Definition: xapiexit.php:8
static checkResponse($response, &$body, $allowedStatus=[200, 204])
$DIC
Definition: xapitoken.php:46
static buildQuery(array $params, $encoding=PHP_QUERY_RFC3986)
$response
static dateIntervalToISO860Duration(\DateInterval $d)
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ executeCommand()

ilCmiXapiLaunchGUI::executeCommand ( )

Definition at line 42 of file class.ilCmiXapiLaunchGUI.php.

References launchCmd().

43  {
44  $this->launchCmd();
45  }
+ Here is the call graph for this function:

◆ getAuthTokenFetchLink()

ilCmiXapiLaunchGUI::getAuthTokenFetchLink ( )
protected

Definition at line 129 of file class.ilCmiXapiLaunchGUI.php.

References $param, buildAuthTokenFetchParam(), and ILIAS_HTTP_PATH.

Referenced by getLaunchParameters().

130  {
131  $link = implode('/', [
132  ILIAS_HTTP_PATH, 'Modules', 'CmiXapi', 'xapitoken.php'
133  ]);
134 
135  $param = $this->buildAuthTokenFetchParam();
136  $link = iLUtil::appendUrlParameterString($link, "param={$param}");
137 
138  return $link;
139  }
$param
Definition: xapitoken.php:31
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ getCmi5LearnerPreferences()

ilCmiXapiLaunchGUI::getCmi5LearnerPreferences ( )
protected

Definition at line 207 of file class.ilCmiXapiLaunchGUI.php.

References $DIC.

Referenced by CMI5preLaunch().

208  {
209  global $DIC;
210  $language = $DIC->user()->getLanguage();
211  $audio = "on";
212  $prefs = [
213  "languagePreference" => "{$language}",
214  "audioPreference" => "{$audio}"
215  ];
216  return $prefs;
217  }
$DIC
Definition: xapitoken.php:46
+ Here is the caller graph for this function:

◆ getLaunchParameters()

ilCmiXapiLaunchGUI::getLaunchParameters (   $token)
protected

Definition at line 85 of file class.ilCmiXapiLaunchGUI.php.

References $DIC, $token, ilObjCmiXapi\CONT_TYPE_CMI5, ilCmiXapiUser\generateRegistration(), getAuthTokenFetchLink(), and ILIAS_HTTP_PATH.

Referenced by buildLaunchLink().

86  {
87  global $DIC; /* @var \ILIAS\DI\Container $DIC */
88 
89  $params = [];
90 
91  if ($this->object->isBypassProxyEnabled()) {
92  $params['endpoint'] = urlencode(rtrim($this->object->getLrsType()->getLrsEndpoint(), '/') . '/');
93  } else {
94  $params['endpoint'] = urlencode(rtrim(ILIAS_HTTP_PATH . '/' . self::XAPI_PROXY_ENDPOINT, '/') . '/');
95  }
96 
97  if ($this->object->isAuthFetchUrlEnabled()) {
98  $params['fetch'] = urlencode($this->getAuthTokenFetchLink());
99  } else {
100  if ($this->object->isBypassProxyEnabled()) {
101  $params['auth'] = urlencode($this->object->getLrsType()->getBasicAuth());
102  } else {
103  $params['auth'] = urlencode('Basic ' . base64_encode(
104  CLIENT_ID . ':' . $token
105  ));
106  }
107  }
108 
109  $params['activity_id'] = urlencode($this->object->getActivityId());
110  $params['activityId'] = urlencode($this->object->getActivityId());
111  $params['actor'] = urlencode(json_encode($this->object->getStatementActor($this->cmixUser)));
112  if ($this->object->getContentType() == ilObjCmiXapi::CONT_TYPE_CMI5)
113  {
114  $registration = $this->cmixUser->getRegistration();
115  // for old CMI5 Content after switch commit but before cmi5 bugfix
116  if ($registration == '')
117  {
118  $registration = ilCmiXapiUser::generateRegistration($this->object, $DIC->user());
119  }
120  $params['registration'] = $registration;
121  }
122  else
123  {
124  $params['registration'] = urlencode(ilCmiXapiUser::generateRegistration($this->object, $DIC->user()));
125  }
126  return $params;
127  }
static generateRegistration(ilObjCmiXapi $obj, ilObjUser $user)
$token
Definition: xapitoken.php:57
$DIC
Definition: xapitoken.php:46
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ getValidToken()

ilCmiXapiLaunchGUI::getValidToken ( )
protected

Definition at line 166 of file class.ilCmiXapiLaunchGUI.php.

References $DIC, $token, and ilCmiXapiAuthToken\fillToken().

Referenced by CMI5preLaunch(), and launchCmd().

167  {
168  global $DIC; /* @var \ILIAS\DI\Container $DIC */
169 
171  $DIC->user()->getId(),
172  $this->object->getRefId(),
173  $this->object->getId(),
174  $this->object->getLrsType()->getTypeId()
175  );
176  return $token;
177  }
$token
Definition: xapitoken.php:57
static fillToken($usrId, $refId, $objId, $lrsTypeId=0)
$DIC
Definition: xapitoken.php:46
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ initCmixUser()

ilCmiXapiLaunchGUI::initCmixUser ( )
protected

Definition at line 179 of file class.ilCmiXapiLaunchGUI.php.

References $DIC, ilLPStatusWrapper\_updateStatus(), ilObjCmiXapi\CONT_TYPE_CMI5, ilCmiXapiUser\generateCMI5Registration(), ilCmiXapiUser\getIdent(), and ilCmiXapiUser\getUsrIdent().

Referenced by launchCmd().

180  {
181  global $DIC; /* @var \ILIAS\DI\Container $DIC */
182 
183  $doLpUpdate = false;
184 
185  // if (!ilCmiXapiUser::exists($this->object->getId(), $DIC->user()->getId())) {
186  // $doLpUpdate = true;
187  // }
188 
189  $this->cmixUser = new ilCmiXapiUser($this->object->getId(), $DIC->user()->getId(), $this->object->getPrivacyIdent());
190  $user_ident = $this->cmixUser->getUsrIdent();
191  if ($user_ident == '' || $user_ident == null) {
192  $user_ident = ilCmiXapiUser::getIdent($this->object->getPrivacyIdent(), $DIC->user());
193  $this->cmixUser->setUsrIdent($user_ident);
194 
195  if ($this->object->getContentType() == ilObjCmiXapi::CONT_TYPE_CMI5)
196  {
197  $this->cmixUser->setRegistration(ilCmiXapiUser::generateCMI5Registration($this->object->getId(), $DIC->user()->getId()));
198  }
199  $this->cmixUser->save();
200  ilLPStatusWrapper::_updateStatus($this->object->getId(), $DIC->user()->getId());
201  }
202  // if ($doLpUpdate) {
203  // ilLPStatusWrapper::_updateStatus($this->object->getId(), $DIC->user()->getId());
204  // }
205  }
static _updateStatus($a_obj_id, $a_usr_id, $a_obj=null, $a_percentage=false, $a_force_raise=false)
Update status.
static generateCMI5Registration($objId, $usrId)
$DIC
Definition: xapitoken.php:46
static getIdent($userIdentMode, ilObjUser $user)
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ launchCmd()

ilCmiXapiLaunchGUI::launchCmd ( )
protected

Definition at line 47 of file class.ilCmiXapiLaunchGUI.php.

References $DIC, $ret, $token, buildLaunchLink(), CMI5preLaunch(), ilObjCmiXapi\CONT_TYPE_CMI5, getValidToken(), and initCmixUser().

Referenced by executeCommand().

48  {
49  global $DIC; /* @var \ILIAS\DI\Container $DIC */
50 
51  $this->initCmixUser();
52  $token = $this->getValidToken();
53  if ($this->object->getContentType() == ilObjCmiXapi::CONT_TYPE_CMI5) {
54  $ret = $this->CMI5preLaunch($token);
55  $token = $ret['token'];
56  }
57  $launchLink = $this->buildLaunchLink($token);
58  $DIC->ctrl()->redirectToURL($launchLink);
59  }
$token
Definition: xapitoken.php:57
CMI5preLaunch($token)
Prelaunch post cmi5LearnerPreference (agent profile) post LMS.LaunchData.
$ret
Definition: parser.php:6
$DIC
Definition: xapitoken.php:46
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ log()

ilCmiXapiLaunchGUI::log ( )
private

Definition at line 401 of file class.ilCmiXapiLaunchGUI.php.

References $log.

Referenced by CMI5preLaunch().

401  {
402  global $log;
403  if ($this->plugin) {
404  return $log;
405  }
406  else {
407  return \ilLoggerFactory::getLogger('cmix');
408  }
409  }
$log
Definition: result.php:15
+ Here is the caller graph for this function:

Field Documentation

◆ $cmixUser

ilCmiXapiLaunchGUI::$cmixUser
protected

Definition at line 27 of file class.ilCmiXapiLaunchGUI.php.

◆ $object

ilCmiXapiLaunchGUI::$object
protected

Definition at line 22 of file class.ilCmiXapiLaunchGUI.php.

Referenced by __construct().

◆ $plugin

ilCmiXapiLaunchGUI::$plugin = false
protected

Definition at line 32 of file class.ilCmiXapiLaunchGUI.php.

◆ XAPI_PROXY_ENDPOINT

const ilCmiXapiLaunchGUI::XAPI_PROXY_ENDPOINT = 'Modules/CmiXapi/xapiproxy.php'

Definition at line 17 of file class.ilCmiXapiLaunchGUI.php.


The documentation for this class was generated from the following file: