ILIAS  release_7 Revision v7.30-3-g800a261c036
class.ilBadgeAssignment.php
Go to the documentation of this file.
1<?php
2
3/* Copyright (c) 1998-2019 ILIAS open source, Extended GPL, see docs/LICENSE */
4
11{
15 protected $db;
16
17 protected $badge_id; // [int]
18 protected $user_id; // [int]
19 protected $tstamp; // [timestamp]
20 protected $awarded_by; // [int]
21 protected $pos; // [int]
22 protected $stored; // [bool]
23
24 public function __construct($a_badge_id = null, $a_user_id = null)
25 {
26 global $DIC;
27
28 $this->db = $DIC->database();
29 if ($a_badge_id &&
30 $a_user_id) {
31 $this->setBadgeId($a_badge_id);
32 $this->setUserId($a_user_id);
33
34 $this->read($a_badge_id, $a_user_id);
35 }
36 }
37
44 public static function getNewCounter(int $a_user_id) : int
45 {
46 global $DIC;
47
48 $db = $DIC->database();
49
50 $user = new ilObjUser($a_user_id);
51 $noti_repo = new \ILIAS\Badge\Notification\BadgeNotificationPrefRepository($user);
52
53 $last = $noti_repo->getLastCheckedTimestamp();
54
55
56 // if no last check exists, we use last 24 hours
57 if ($last == 0) {
58 $last = time() - (24 * 60 * 60);
59 }
60
61 if ($last > 0) {
62 $set = $db->queryF(
63 "SELECT count(*) cnt FROM badge_user_badge " .
64 " WHERE user_id = %s AND tstamp >= %s",
65 ["integer", "integer"],
66 [$a_user_id, $last]
67 );
68 $rec = $db->fetchAssoc($set);
69 return (int) $rec["cnt"];
70 }
71 return 0;
72 }
73
80 public static function getLatestTimestamp(int $a_user_id) : int
81 {
82 global $DIC;
83
84 $db = $DIC->database();
85
86 $set = $db->queryF(
87 "SELECT max(tstamp) maxts FROM badge_user_badge " .
88 " WHERE user_id = %s",
89 ["integer"],
90 [$a_user_id]
91 );
92 $rec = $db->fetchAssoc($set);
93 return (int) $rec["maxts"];
94 }
95
96 public static function getInstancesByUserId($a_user_id)
97 {
98 global $DIC;
99
100 $ilDB = $DIC->database();
101
102 $res = array();
103
104 $set = $ilDB->query("SELECT * FROM badge_user_badge" .
105 " WHERE user_id = " . $ilDB->quote($a_user_id, "integer") .
106 " ORDER BY pos");
107 while ($row = $ilDB->fetchAssoc($set)) {
108 $obj = new self();
109 $obj->importDBRow($row);
110 $res[] = $obj;
111 }
112
113 return $res;
114 }
115
116
117 public static function getInstancesByBadgeId($a_badge_id)
118 {
119 global $DIC;
120
121 $ilDB = $DIC->database();
122
123 $res = array();
124
125 $set = $ilDB->query("SELECT * FROM badge_user_badge" .
126 " WHERE badge_id = " . $ilDB->quote($a_badge_id, "integer"));
127 while ($row = $ilDB->fetchAssoc($set)) {
128 $obj = new self();
129 $obj->importDBRow($row);
130 $res[] = $obj;
131 }
132
133 return $res;
134 }
135
136 public static function getInstancesByParentId($a_parent_obj_id)
137 {
138 global $DIC;
139
140 $ilDB = $DIC->database();
141
142 $res = array();
143
144 $badge_ids = array();
145 foreach (ilBadge::getInstancesByParentId($a_parent_obj_id) as $badge) {
146 $badge_ids[] = $badge->getId();
147 }
148 if (sizeof($badge_ids)) {
149 $set = $ilDB->query("SELECT * FROM badge_user_badge" .
150 " WHERE " . $ilDB->in("badge_id", $badge_ids, "", "integer"));
151 while ($row = $ilDB->fetchAssoc($set)) {
152 $obj = new self();
153 $obj->importDBRow($row);
154 $res[] = $obj;
155 }
156 }
157
158 return $res;
159 }
160
161 public static function getAssignedUsers($a_badge_id)
162 {
163 $res = array();
164
165 foreach (self::getInstancesByBadgeId($a_badge_id) as $ass) {
166 $res[] = $ass->getUserId();
167 }
168
169 return $res;
170 }
171
172 public static function exists($a_badge_id, $a_user_id)
173 {
174 $obj = new self($a_badge_id, $a_user_id);
175 return $obj->stored;
176 }
177
178
179 //
180 // setter/getter
181 //
182
183 protected function setBadgeId($a_value)
184 {
185 $this->badge_id = (int) $a_value;
186 }
187
188 public function getBadgeId()
189 {
190 return $this->badge_id;
191 }
192
193 protected function setUserId($a_value)
194 {
195 $this->user_id = (int) $a_value;
196 }
197
198 public function getUserId()
199 {
200 return $this->user_id;
201 }
202
203 protected function setTimestamp($a_value)
204 {
205 $this->tstamp = (int) $a_value;
206 }
207
208 public function getTimestamp()
209 {
210 return $this->tstamp;
211 }
212
213 public function setAwardedBy($a_id)
214 {
215 $this->awarded_by = (int) $a_id;
216 }
217
218 public function getAwardedBy()
219 {
220 return $this->awarded_by;
221 }
222
223 public function setPosition($a_value)
224 {
225 if ($a_value !== null) {
226 $a_value = (int) $a_value;
227 }
228 $this->pos = $a_value;
229 }
230
231 public function getPosition()
232 {
233 return $this->pos;
234 }
235
236
237 //
238 // crud
239 //
240
241 protected function importDBRow(array $a_row)
242 {
243 $this->stored = true;
244 $this->setBadgeId($a_row["badge_id"]);
245 $this->setUserId($a_row["user_id"]);
246 $this->setTimestamp($a_row["tstamp"]);
247 $this->setAwardedBy($a_row["awarded_by"]);
248 $this->setPosition($a_row["pos"]);
249 }
250
251 protected function read($a_badge_id, $a_user_id)
252 {
254
255 $set = $ilDB->query("SELECT * FROM badge_user_badge" .
256 " WHERE badge_id = " . $ilDB->quote($a_badge_id, "integer") .
257 " AND user_id = " . $ilDB->quote($a_user_id, "integer"));
258 $row = $ilDB->fetchAssoc($set);
259 if ($row["user_id"]) {
260 $this->importDBRow($row);
261 }
262 }
263
264 protected function getPropertiesForStorage()
265 {
266 return array(
267 "tstamp" => array("integer", (bool) $this->stored ? $this->getTimestamp() : time()),
268 "awarded_by" => array("integer", $this->getAwardedBy()),
269 "pos" => array("integer", $this->getPosition())
270 );
271 }
272
273 public function store()
274 {
276
277 if (!$this->getBadgeId() ||
278 !$this->getUserId()) {
279 return;
280 }
281
282 $keys = array(
283 "badge_id" => array("integer", $this->getBadgeId()),
284 "user_id" => array("integer", $this->getUserId())
285 );
286 $fields = $this->getPropertiesForStorage();
287
288 if (!(bool) $this->stored) {
289 $ilDB->insert("badge_user_badge", $fields + $keys);
290 } else {
291 $ilDB->update("badge_user_badge", $fields, $keys);
292 }
293 }
294
295 public function delete()
296 {
298
299 if (!$this->getBadgeId() ||
300 !$this->getUserId()) {
301 return;
302 }
303
304 $this->deleteStaticFiles();
305
306 $ilDB->manipulate("DELETE FROM badge_user_badge" .
307 " WHERE badge_id = " . $ilDB->quote($this->getBadgeId(), "integer") .
308 " AND user_id = " . $ilDB->quote($this->getUserId(), "integer"));
309 }
310
311 public static function deleteByUserId($a_user_id)
312 {
313 foreach (self::getInstancesByUserId($a_user_id) as $ass) {
314 $ass->delete();
315 }
316 }
317
318 public static function deleteByBadgeId($a_badge_id)
319 {
320 foreach (self::getInstancesByBadgeId($a_badge_id) as $ass) {
321 $ass->delete();
322 }
323 }
324
325 public static function deleteByParentId($a_parent_obj_id)
326 {
327 foreach (self::getInstancesByParentId($a_parent_obj_id) as $ass) {
328 $ass->delete();
329 }
330 }
331
332 public static function updatePositions($a_user_id, array $a_positions)
333 {
334 $existing = array();
335 foreach (self::getInstancesByUserId($a_user_id) as $ass) {
336 $badge = new ilBadge($ass->getBadgeId());
337 $existing[$badge->getId()] = array($badge->getTitle(), $ass);
338 }
339
340 $new_pos = 0;
341 foreach ($a_positions as $title) {
342 foreach ($existing as $id => $item) {
343 if ($title == $item[0]) {
344 $item[1]->setPosition(++$new_pos);
345 $item[1]->store();
346 unset($existing[$id]);
347 }
348 }
349 }
350 }
351
359 public static function getBadgesForUser($a_user_id, $a_ts_from, $a_ts_to)
360 {
361 global $DIC;
362
363 $db = $DIC->database();
364
365 $set = $db->queryF(
366 "SELECT bdg.parent_id, ub.tstamp, bdg.title FROM badge_user_badge ub JOIN badge_badge bdg" .
367 " ON (ub.badge_id = bdg.id) " .
368 " WHERE ub.user_id = %s AND ub.tstamp >= %s AND ub.tstamp <= %s",
369 array("integer","integer","integer"),
370 array($a_user_id, $a_ts_from, $a_ts_to)
371 );
372 $res = [];
373 while ($rec = $db->fetchAssoc($set)) {
374 $res[] = $rec;
375 }
376 return $res;
377 }
378
379
380 //
381 // PUBLISHING
382 //
383
384 protected function prepareJson($a_url)
385 {
386 $verify = new stdClass();
387 $verify->type = "hosted";
388 $verify->url = $a_url;
389
390 $recipient = new stdClass();
391 $recipient->type = "email";
392 $recipient->hashed = true;
393 $recipient->salt = ilBadgeHandler::getInstance()->getObiSalt();
394
395 // https://github.com/mozilla/openbadges-backpack/wiki/How-to-hash-&-salt-in-various-languages.
396 $user = new ilObjUser($this->getUserId());
397 $mail = $user->getPref(ilBadgeProfileGUI::BACKPACK_EMAIL);
398 if (!$mail) {
399 $mail = $user->getEmail();
400 }
401 $recipient->identity = 'sha256$' . hash('sha256', $mail . $recipient->salt);
402
403 // spec: should be locally unique
404 $unique_id = md5($this->getBadgeId() . "-" . $this->getUserId());
405
406 $json = new stdClass();
407 $json->{"@context"} = "https://w3id.org/openbadges/v1";
408 $json->type = "Assertion";
409 $json->id = $a_url;
410 $json->uid = $unique_id;
411 $json->recipient = $recipient;
412
413 $badge = new ilBadge($this->getBadgeId());
414 $badge_url = $badge->getStaticUrl();
415
416 // created baked image
417 $baked_image = $this->getImagePath($badge);
418 if ($this->bakeImage($baked_image, $badge->getImagePath(), $a_url)) {
419 // path to url
420 $parts = explode("/", $a_url);
421 array_pop($parts);
422 $parts[] = basename($baked_image);
423 $json->image = implode("/", $parts);
424 }
425
426 $json->issuedOn = $this->getTimestamp();
427 $json->badge = $badge_url;
428 $json->verify = $verify;
429
430 return $json;
431 }
432
433 public function getImagePath(ilBadge $a_badge)
434 {
435 $json_path = ilBadgeHandler::getInstance()->getInstancePath($this);
436 $baked_path = dirname($json_path);
437 $baked_file = array_shift(explode(".", basename($json_path)));
438
439 // get correct suffix from badge image
440 $suffix = strtolower(array_pop(explode(".", basename($a_badge->getImagePath()))));
441 return $baked_path . "/" . $baked_file . "." . $suffix;
442 }
443
444 protected function bakeImage($a_baked_image_path, $a_badge_image_path, $a_assertion_url)
445 {
446 $suffix = strtolower(array_pop(explode(".", basename($a_badge_image_path))));
447 if ($suffix == "png") {
448 // using chamilo baker lib
449 include_once "Services/Badge/lib/baker.lib.php";
450 $png = new PNGImageBaker(file_get_contents($a_badge_image_path));
451
452 // add payload
453 if ($png->checkChunks("tEXt", "openbadges")) {
454 $baked = $png->addChunk("tEXt", "openbadges", $a_assertion_url);
455 }
456
457 // create baked file
458 if (!file_exists($a_baked_image_path)) {
459 file_put_contents($a_baked_image_path, $baked);
460 }
461
462 // verify file
463 $verify = $png->extractBadgeInfo(file_get_contents($a_baked_image_path));
464 if (is_array($verify)) {
465 return true;
466 }
467 } elseif ($suffix == "svg") {
468 // :TODO: not really sure if this is correct
469 $svg = simplexml_load_file($a_badge_image_path);
470 $ass = $svg->addChild("openbadges:assertion", "", "http://openbadges.org");
471 $ass->addAttribute("verify", $a_assertion_url);
472 $baked = $svg->asXML();
473
474 // create baked file
475 if (!file_exists($a_baked_image_path)) {
476 file_put_contents($a_baked_image_path, $baked);
477 }
478
479 return true;
480 }
481
482 return false;
483 }
484
485 public function getStaticUrl()
486 {
487 $path = ilBadgeHandler::getInstance()->getInstancePath($this);
488
489 $url = ILIAS_HTTP_PATH . substr($path, 1);
490
491 if (!file_exists($path)) {
492 $json = json_encode($this->prepareJson($url));
493 file_put_contents($path, $json);
494 }
495
496 return $url;
497 }
498
499 public function deleteStaticFiles()
500 {
501 // remove instance files
502 $path = ilBadgeHandler::getInstance()->getInstancePath($this);
503 $path = str_replace(".json", ".*", $path);
504 array_map("unlink", glob($path));
505 }
506
507 public static function clearBadgeCache($a_user_id)
508 {
509 foreach (self::getInstancesByUserId($a_user_id) as $ass) {
510 $ass->deleteStaticFiles();
511 }
512 }
513}
An exception for terminatinating execution or to throw for unit testing.
Php library to Bake the PNG Images.
Definition: baker.lib.php:8
Class ilBadgeAssignment.
static getInstancesByUserId($a_user_id)
static getNewCounter(int $a_user_id)
Get new counter.
bakeImage($a_baked_image_path, $a_badge_image_path, $a_assertion_url)
static getAssignedUsers($a_badge_id)
static clearBadgeCache($a_user_id)
static deleteByBadgeId($a_badge_id)
static getInstancesByBadgeId($a_badge_id)
read($a_badge_id, $a_user_id)
static getBadgesForUser($a_user_id, $a_ts_from, $a_ts_to)
Get badges for user.
static deleteByUserId($a_user_id)
__construct($a_badge_id=null, $a_user_id=null)
getImagePath(ilBadge $a_badge)
static updatePositions($a_user_id, array $a_positions)
static exists($a_badge_id, $a_user_id)
static getInstancesByParentId($a_parent_obj_id)
static getLatestTimestamp(int $a_user_id)
Get latest badge.
static deleteByParentId($a_parent_obj_id)
static getInstance()
Constructor.
Class ilBadge.
static getInstancesByParentId($a_parent_id, array $a_filter=null)
getImagePath($a_full_path=true)
global $DIC
Definition: goto.php:24
$keys
Definition: metadata.php:187
$url
foreach($_POST as $key=> $value) $res
global $ilDB