ILIAS  trunk Revision v11.0_alpha-1851-ga8564da6fed
All Data Structures Namespaces Files Functions Variables Enumerations Enumerator Modules Pages
class.ilLTIConsumerGradeServiceScores.php
Go to the documentation of this file.
1 <?php
2 
19 declare(strict_types=1);
20 
30 {
32  {
33  parent::__construct($service);
34  $this->id = 'Score.collection';
35  $this->template = '/{context_id}/lineitems/{item_id}/lineitem/scores';
36  $this->variables[] = 'Scores.url';
37  $this->formats[] = 'application/vnd.ims.lis.v1.scorecontainer+json';
38  $this->formats[] = 'application/vnd.ims.lis.v1.score+json';
39  $this->methods[] = 'POST';
40  }
41 
46  {
47  $params = $this->parseTemplate();
48  $contextId = $params['context_id'];
49  $itemId = $params['item_id'];
50 
51  ilObjLTIConsumer::getLogger()->debug("contextId: " . $contextId);
52  ilObjLTIConsumer::getLogger()->debug("objId: " . $itemId);
53  ilObjLTIConsumer::getLogger()->debug("request data: " . $response->getRequestData());
54 
55  // GET is disabled by the moment, but we have the code ready
56  // for a future implementation.
57 
58  //$container = empty($contentType) || ($contentType === $this->formats[0]);
59 
60  $typeid = 0;
61 
63  try {
64  $token = $this->checkTool(array($scope));
65  if (is_null($token)) {
66  throw new Exception('invalid request', 401);
67  }
68 
69  // Bug in Moodle as tool provider, should accept only "204 No Content" but schedules grade sync task will notices a failed status if not exactly 200
70  // see: http://www.imsglobal.org/spec/lti-ags/v2p0#score-service-scope-and-allowed-http-methods
71  //$response->setCode(204); // correct
72  $returnCode = 200;
73  $returnCode = $this->checkScore($response->getRequestData(), (int) $itemId);
74  $response->setCode($returnCode); // not really correct
75  } catch (Exception $e) {
76  $response->setCode($e->getCode());
77  $response->setReason($e->getMessage());
78  }
79  }
80 
81  protected function checkScore(string $requestData, int $objId): int
82  {
83  global $DIC; /* @var \ILIAS\DI\Container $DIC */
84  $score = json_decode($requestData);
85  //prüfe Userid
86  $userId = ilCmiXapiUser::getUsrIdForObjectAndUsrIdent($objId, $score->userId);
87  if ($userId == null) {
88  ilObjLTIConsumer::getLogger()->debug('User not available');
89  throw new Exception('User not available', 404);
90  return 404;
91  }
92 
93  if (empty($score) ||
94  !isset($score->userId) ||
95  !isset($score->gradingProgress) ||
96  !isset($score->activityProgress) ||
97  !isset($score->timestamp) ||
98  isset($score->timestamp) && !self::validate_iso8601_date($score->timestamp) ||
99  (isset($score->scoreGiven) && !is_numeric($score->scoreGiven)) ||
100  (isset($score->scoreGiven) && !isset($score->scoreMaximum)) ||
101  (isset($score->scoreMaximum) && !is_numeric($score->scoreMaximum))
102  ) {
103  ilObjLTIConsumer::getLogger()->debug('Incorrect score received');
104  ilObjLTIConsumer::getLogger()->dump($score);
105  throw new Exception('Incorrect score received', 400);
106  return 400;
107  }
108  //Achtung Ggfs. Timestamp prüfen falls schon was ankam
109  if (!isset($score->scoreMaximum)) {
110  $score->scoreMaximum = 1;
111  }
112  if (isset($score->scoreGiven)) {
113  if ($score->gradingProgress != 'FullyGraded') {
114  $score->scoreGiven = null;
115  }
116  }
117  $result = (float)$score->scoreGiven / (float)$score->scoreMaximum;
118  ilObjLTIConsumer::getLogger()->debug("result: " . $result);
119 
120  $ltiObjRes = new ilLTIConsumerResultService();
121 
122  $ltiObjRes->readProperties($objId);
123  // check the object status
124  if (!$ltiObjRes->isAvailable()) {
125  throw new Exception('Tool for Object not available', 404);
126  return 404;
127  }
128 
129  if ($result >= $ltiObjRes->getMasteryScore()) {
131  } else {
133  }
134  $lp_percentage = (int) round(100 * $result);
135 
136  $consRes = ilLTIConsumerResult::getByKeys($objId, $userId, false);
137  if (empty($consRes)) {
138  ilObjLTIConsumer::getLogger()->debug("lti_consumer_results_id not found!");
139  // throw new Exception('lti_consumer_results_id not found!', 404);
140  // return 404;
141  }
142  if (!isset($consRes->id)) {
143  $consRes->id = $DIC->database()->nextId('lti_consumer_results');
144  }
145  $DIC->database()->replace(
146  'lti_consumer_results',
147  array(
148  'id' => array('integer', $consRes->id)
149  ),
150  array(
151  'obj_id' => array('integer', $objId),
152  'usr_id' => array('integer', $userId),
153  'result' => array('float', $result)
154  )
155  );
156 
157  ilLPStatus::writeStatus($objId, $userId, $lp_status, $lp_percentage, true);
158 
159  $ltiTimestamp = DateTimeImmutable::createFromFormat(DateTimeInterface::RFC3339_EXTENDED, $score->timestamp);
160  if (!$ltiTimestamp) { //moodle 4
161  $ltiTimestamp = DateTimeImmutable::createFromFormat(DateTimeInterface::ISO8601, $score->timestamp);
162  }
163  if (!$ltiTimestamp) { //for example nothing
164  $ltiTimestamp = new DateTime('now');
165  }
166  $gradeValues = [
167  'id' => array('integer', $DIC->database()->nextId('lti_consumer_grades')),
168  'obj_id' => array('integer', $objId),
169  'usr_id' => array('integer', $userId),
170  'score_given' => array('float', $score->scoreGiven),
171  'score_maximum' => array('float', $score->scoreMaximum),
172  'activity_progress' => array('text', $score->activityProgress),
173  'grading_progress' => array('text', $score->gradingProgress),
174  'lti_timestamp' => array('timestamp',$ltiTimestamp->format("Y-m-d H:i:s")),
175  'stored' => array('timestamp', date("Y-m-d H:i:s"))
176  ];
177  $DIC->database()->insert('lti_consumer_grades', $gradeValues);
178 
179 
180 
181  return 200;
182  }
183 
184  public static function validate_iso8601_date(string $date): bool
185  {
186  if (preg_match('/^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])' .
187  '(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))' .
188  '([T\s]((([01]\d|2[0-3])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)' .
189  '?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/', $date) > 0) {
190  return true;
191  }
192  return false;
193  }
194 }
const LP_STATUS_COMPLETED_NUM
array $params
Template variables parsed from the resource template.
execute(ilLTIConsumerServiceResponse $response)
Execute the request for this resource.
$scope
Definition: ltiregstart.php:47
parseTemplate()
Parse the template for variables.
ilLTIConsumerServiceBase $service
Service associated with this resource.
const LP_STATUS_IN_PROGRESS_NUM
$response
Definition: xapitoken.php:93
$objId
Definition: xapitoken.php:57
static getUsrIdForObjectAndUsrIdent(int $objId, string $userIdent)
__construct(ilLTIConsumerServiceBase $service)
const SCOPE_GRADESERVICE_SCORE
Scope for access to Score service.
while($session_entry=$r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) return null
checkTool(array $scopes=array())
Check to make sure the request is valid.
$token
Definition: xapitoken.php:70
global $DIC
Definition: shib_login.php:22
setCode(int $code)
Set the response code.
static getByKeys(int $a_obj_id, int $a_usr_id, ?bool $a_create=false)
Get a result by object and user key.
setReason(string $reason)
Set the response reason.
__construct(Container $dic, ilPlugin $plugin)
static writeStatus(int $a_obj_id, int $a_user_id, int $a_status, int $a_percentage=0, bool $a_force_per=false, ?int &$a_old_status=self::LP_STATUS_NOT_ATTEMPTED_NUM)
Write status for user and object.