Differences Between: [Versions 310 and 403] [Versions 311 and 403] [Versions 39 and 403] [Versions 400 and 403] [Versions 401 and 403] [Versions 402 and 403]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 /** 18 * Badge assertion library. 19 * 20 * @package core 21 * @subpackage badges 22 * @copyright 2012 onwards Totara Learning Solutions Ltd {@link http://www.totaralms.com/} 23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 * @author Yuliya Bozhko <yuliya.bozhko@totaralms.com> 25 */ 26 27 defined('MOODLE_INTERNAL') || die(); 28 29 /** 30 * Open Badges Assertions specification 1.0 {@link https://github.com/mozilla/openbadges-backpack/wiki/Assertions} 31 * 32 * Badge asserion is defined by three parts: 33 * - Badge Assertion (information regarding a specific badge that was awarded to a badge earner) 34 * - Badge Class (general information about a badge and what it is intended to represent) 35 * - Issuer Class (general information of an issuing organisation) 36 */ 37 require_once($CFG->libdir . '/badgeslib.php'); 38 require_once($CFG->dirroot . '/badges/renderer.php'); 39 40 /** 41 * Class that represents badge assertion. 42 * 43 */ 44 class core_badges_assertion { 45 /** @var object Issued badge information from database */ 46 private $_data; 47 48 /** @var moodle_url Issued badge url */ 49 private $_url; 50 51 /** @var int $obversion to control version JSON-LD. */ 52 private $_obversion = OPEN_BADGES_V2; 53 54 /** 55 * Constructs with issued badge unique hash. 56 * 57 * @param string $hash Badge unique hash from badge_issued table. 58 * @param int $obversion to control version JSON-LD. 59 */ 60 public function __construct($hash, $obversion = OPEN_BADGES_V2) { 61 global $DB; 62 63 $this->_data = $DB->get_record_sql(' 64 SELECT 65 bi.dateissued, 66 bi.dateexpire, 67 bi.uniquehash, 68 u.email, 69 b.*, 70 bb.email as backpackemail 71 FROM 72 {badge} b 73 JOIN {badge_issued} bi 74 ON b.id = bi.badgeid 75 JOIN {user} u 76 ON u.id = bi.userid 77 LEFT JOIN {badge_backpack} bb 78 ON bb.userid = bi.userid 79 WHERE ' . $DB->sql_compare_text('bi.uniquehash', 40) . ' = ' . $DB->sql_compare_text(':hash', 40), 80 array('hash' => $hash), IGNORE_MISSING); 81 82 if ($this->_data) { 83 $this->_url = new moodle_url('/badges/badge.php', array('hash' => $this->_data->uniquehash)); 84 } else { 85 $this->_url = new moodle_url('/badges/badge.php'); 86 } 87 $this->_obversion = $obversion; 88 } 89 90 /** 91 * Get the local id for this badge. 92 * 93 * @return int 94 */ 95 public function get_badge_id() { 96 $badgeid = 0; 97 if ($this->_data) { 98 $badgeid = $this->_data->id; 99 } 100 return $badgeid; 101 } 102 103 /** 104 * Get the local id for this badge assertion. 105 * 106 * @return string 107 */ 108 public function get_assertion_hash() { 109 $hash = ''; 110 if ($this->_data) { 111 $hash = $this->_data->uniquehash; 112 } 113 return $hash; 114 } 115 116 /** 117 * Get badge assertion. 118 * 119 * @param boolean $issued Include the nested badge issued information. 120 * @param boolean $usesalt Hash the identity and include the salt information for the hash. 121 * @return array Badge assertion. 122 */ 123 public function get_badge_assertion($issued = true, $usesalt = true) { 124 global $CFG; 125 $assertion = array(); 126 if ($this->_data) { 127 $hash = $this->_data->uniquehash; 128 $email = empty($this->_data->backpackemail) ? $this->_data->email : $this->_data->backpackemail; 129 $assertionurl = new moodle_url('/badges/assertion.php', array('b' => $hash, 'obversion' => $this->_obversion)); 130 131 if ($this->_obversion >= OPEN_BADGES_V2) { 132 $classurl = new moodle_url('/badges/badge_json.php', array('id' => $this->get_badge_id())); 133 } else { 134 $classurl = new moodle_url('/badges/assertion.php', array('b' => $hash, 'action' => 1)); 135 } 136 137 // Required. 138 $assertion['uid'] = $hash; 139 $assertion['recipient'] = array(); 140 if ($usesalt) { 141 $assertion['recipient']['identity'] = 'sha256$' . hash('sha256', $email . $CFG->badges_badgesalt); 142 } else { 143 $assertion['recipient']['identity'] = $email; 144 } 145 $assertion['recipient']['type'] = 'email'; // Currently the only supported type. 146 $assertion['recipient']['hashed'] = true; // We are always hashing recipient. 147 if ($usesalt) { 148 $assertion['recipient']['salt'] = $CFG->badges_badgesalt; 149 } 150 if ($issued) { 151 $assertion['badge'] = $classurl->out(false); 152 } 153 $assertion['verify'] = array(); 154 $assertion['verify']['type'] = 'hosted'; // 'Signed' is not implemented yet. 155 $assertion['verify']['url'] = $assertionurl->out(false); 156 $assertion['issuedOn'] = $this->_data->dateissued; 157 if ($issued) { 158 $assertion['evidence'] = $this->_url->out(false); // Currently issued badge URL. 159 } 160 // Optional. 161 if (!empty($this->_data->dateexpire)) { 162 $assertion['expires'] = $this->_data->dateexpire; 163 } 164 $tags = $this->get_tags(); 165 if (is_array($tags) && count($tags) > 0) { 166 $assertion['tags'] = $tags; 167 } 168 $this->embed_data_badge_version2($assertion, OPEN_BADGES_V2_TYPE_ASSERTION); 169 } 170 return $assertion; 171 } 172 173 /** 174 * Get badge class information. 175 * 176 * @param boolean $issued Include the nested badge issuer information. 177 * @return array Badge Class information. 178 */ 179 public function get_badge_class($issued = true) { 180 $class = []; 181 if ($this->_data) { 182 if (empty($this->_data->courseid)) { 183 $context = context_system::instance(); 184 } else { 185 $context = context_course::instance($this->_data->courseid); 186 } 187 // Required. 188 $class['name'] = $this->_data->name; 189 $class['description'] = $this->_data->description; 190 $storage = get_file_storage(); 191 $imagefile = $storage->get_file($context->id, 'badges', 'badgeimage', $this->_data->id, '/', 'f3.png'); 192 if ($imagefile) { 193 $imagedata = base64_encode($imagefile->get_content()); 194 } else { 195 if (defined('PHPUNIT_TEST') && PHPUNIT_TEST) { 196 // Unit tests the file might not exist yet. 197 $imagedata = ''; 198 } else { 199 throw new coding_exception('Image file does not exist.'); 200 } 201 } 202 $class['image'] = 'data:image/png;base64,' . $imagedata; 203 204 $params = ['id' => $this->get_badge_id()]; 205 $badgeurl = new moodle_url('/badges/badgeclass.php', $params); 206 $class['criteria'] = $badgeurl->out(false); // Currently badge URL. 207 if ($issued) { 208 $params = ['id' => $this->get_badge_id(), 'obversion' => $this->_obversion]; 209 $issuerurl = new moodle_url('/badges/issuer_json.php', $params); 210 $class['issuer'] = $issuerurl->out(false); 211 } 212 $tags = $this->get_tags(); 213 if (is_array($tags) && count($tags) > 0) { 214 $class['tags'] = $tags; 215 } 216 $this->embed_data_badge_version2($class, OPEN_BADGES_V2_TYPE_BADGE); 217 if (!$issued) { 218 unset($class['issuer']); 219 } 220 } 221 return $class; 222 } 223 224 /** 225 * Get badge issuer information. 226 * 227 * @return array Issuer information. 228 */ 229 public function get_issuer() { 230 global $CFG; 231 $issuer = array(); 232 if ($this->_data) { 233 // Required. 234 if ($this->_obversion == OPEN_BADGES_V1) { 235 $issuer['name'] = $this->_data->issuername; 236 $issuer['url'] = $this->_data->issuerurl; 237 // Optional. 238 if (!empty($this->_data->issuercontact)) { 239 $issuer['email'] = $this->_data->issuercontact; 240 } else { 241 $issuer['email'] = $CFG->badges_defaultissuercontact; 242 } 243 } else { 244 $badge = new badge($this->get_badge_id()); 245 $issuer = $badge->get_badge_issuer(); 246 } 247 } 248 $this->embed_data_badge_version2($issuer, OPEN_BADGES_V2_TYPE_ISSUER); 249 return $issuer; 250 } 251 252 /** 253 * Get related badges of the badge. 254 * 255 * @param badge $badge Badge object. 256 * @return array|bool List related badges. 257 */ 258 public function get_related_badges(badge $badge) { 259 global $DB; 260 $arraybadges = array(); 261 $relatedbadges = $badge->get_related_badges(true); 262 if ($relatedbadges) { 263 foreach ($relatedbadges as $rb) { 264 $url = new moodle_url('/badges/badge_json.php', array('id' => $rb->id)); 265 $arraybadges[] = array( 266 'id' => $url->out(false), 267 'version' => $rb->version, 268 '@language' => $rb->language 269 ); 270 } 271 } 272 return $arraybadges; 273 } 274 275 /** 276 * Get endorsement of the badge. 277 * 278 * @return false|stdClass Endorsement information. 279 */ 280 public function get_endorsement() { 281 global $DB; 282 $endorsement = array(); 283 $record = $DB->get_record_select('badge_endorsement', 'badgeid = ?', array($this->_data->id)); 284 return $record; 285 } 286 287 /** 288 * Get criteria of badge class. 289 * 290 * @return array|string Criteria information. 291 */ 292 public function get_criteria_badge_class() { 293 $badge = new badge($this->_data->id); 294 $narrative = $badge->markdown_badge_criteria(); 295 $params = ['id' => $this->get_badge_id()]; 296 $badgeurl = new moodle_url('/badges/badgeclass.php', $params); 297 if (!empty($narrative)) { 298 $criteria = []; 299 $criteria['id'] = $badgeurl->out(false); 300 $criteria['narrative'] = $narrative; 301 return $criteria; 302 } else { 303 return $badgeurl->out(false); 304 } 305 } 306 307 /** 308 * Get alignment of the badge. 309 * 310 * @return array information. 311 */ 312 public function get_alignments() { 313 global $DB; 314 $badgeid = $this->_data->id; 315 $alignments = array(); 316 $items = $DB->get_records_select('badge_alignment', 'badgeid = ?', array($badgeid)); 317 foreach ($items as $item) { 318 $alignment = array('targetName' => $item->targetname, 'targetUrl' => $item->targeturl); 319 if ($item->targetdescription) { 320 $alignment['targetDescription'] = $item->targetdescription; 321 } 322 if ($item->targetframework) { 323 $alignment['targetFramework'] = $item->targetframework; 324 } 325 if ($item->targetcode) { 326 $alignment['targetCode'] = $item->targetcode; 327 } 328 $alignments[] = $alignment; 329 } 330 return $alignments; 331 } 332 333 /** 334 * Embed data of Open Badges Specification Version 2.0 to json. 335 * 336 * @param array $json for assertion, badges, issuer. 337 * @param string $type Content type. 338 */ 339 protected function embed_data_badge_version2 (&$json, $type = OPEN_BADGES_V2_TYPE_ASSERTION) { 340 // Specification Version 2.0. 341 if ($this->_obversion >= OPEN_BADGES_V2) { 342 $badge = new badge($this->_data->id); 343 if (empty($this->_data->courseid)) { 344 $context = context_system::instance(); 345 } else { 346 $context = context_course::instance($this->_data->courseid); 347 } 348 349 $hash = $this->_data->uniquehash; 350 $assertionsurl = new moodle_url('/badges/assertion.php', array('b' => $hash, 'obversion' => $this->_obversion)); 351 $classurl = new moodle_url( 352 '/badges/badge_json.php', 353 array('id' => $this->get_badge_id()) 354 ); 355 $issuerurl = new moodle_url('/badges/issuer_json.php', ['id' => $this->get_badge_id()]); 356 // For assertion. 357 if ($type == OPEN_BADGES_V2_TYPE_ASSERTION) { 358 $json['@context'] = OPEN_BADGES_V2_CONTEXT; 359 $json['type'] = OPEN_BADGES_V2_TYPE_ASSERTION; 360 $json['id'] = $assertionsurl->out(false); 361 $json['badge'] = $this->get_badge_class(); 362 $json['issuedOn'] = date('c', $this->_data->dateissued); 363 if (!empty($this->_data->dateexpire)) { 364 $json['expires'] = date('c', $this->_data->dateexpire); 365 } 366 unset($json['uid']); 367 } 368 // For Badge. 369 if ($type == OPEN_BADGES_V2_TYPE_BADGE) { 370 $json['@context'] = OPEN_BADGES_V2_CONTEXT; 371 $json['id'] = $classurl->out(false); 372 $json['type'] = OPEN_BADGES_V2_TYPE_BADGE; 373 $json['version'] = $this->_data->version; 374 $json['criteria'] = $this->get_criteria_badge_class(); 375 $json['issuer'] = $this->get_issuer(); 376 $json['@language'] = $this->_data->language; 377 if (!empty($relatedbadges = $this->get_related_badges($badge))) { 378 $json['related'] = $relatedbadges; 379 } 380 if ($endorsement = $this->get_endorsement()) { 381 $endorsementurl = new moodle_url('/badges/endorsement_json.php', array('id' => $this->_data->id)); 382 $json['endorsement'] = $endorsementurl->out(false); 383 } 384 if ($alignments = $this->get_alignments()) { 385 $json['alignments'] = $alignments; 386 } 387 if ($this->_data->imageauthorname || 388 $this->_data->imageauthoremail || 389 $this->_data->imageauthorurl || 390 $this->_data->imagecaption) { 391 $storage = get_file_storage(); 392 $imagefile = $storage->get_file($context->id, 'badges', 'badgeimage', $this->_data->id, '/', 'f3.png'); 393 if ($imagefile) { 394 $imagedata = base64_encode($imagefile->get_content()); 395 } else { 396 // The file might not exist in unit tests. 397 if (defined('PHPUNIT_TEST') && PHPUNIT_TEST) { 398 $imagedata = ''; 399 } else { 400 throw new coding_exception('Image file does not exist.'); 401 } 402 } 403 $json['image'] = 'data:image/png;base64,' . $imagedata; 404 } 405 } 406 407 // For issuer. 408 if ($type == OPEN_BADGES_V2_TYPE_ISSUER) { 409 $json['@context'] = OPEN_BADGES_V2_CONTEXT; 410 $json['id'] = $issuerurl->out(false); 411 $json['type'] = OPEN_BADGES_V2_TYPE_ISSUER; 412 } 413 } 414 } 415 416 /** 417 * Get tags of the badge. 418 * 419 * @return array tags. 420 */ 421 public function get_tags(): array { 422 return array_values(\core_tag_tag::get_item_tags_array('core_badges', 'badge', $this->get_badge_id())); 423 } 424 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body