See Release Notes
Long Term Support Release
Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401] [Versions 400 and 401] [Versions 401 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 $this->embed_data_badge_version2($assertion, OPEN_BADGES_V2_TYPE_ASSERTION); 165 } 166 return $assertion; 167 } 168 169 /** 170 * Get badge class information. 171 * 172 * @param boolean $issued Include the nested badge issuer information. 173 * @return array Badge Class information. 174 */ 175 public function get_badge_class($issued = true) { 176 $class = []; 177 if ($this->_data) { 178 if (empty($this->_data->courseid)) { 179 $context = context_system::instance(); 180 } else { 181 $context = context_course::instance($this->_data->courseid); 182 } 183 // Required. 184 $class['name'] = $this->_data->name; 185 $class['description'] = $this->_data->description; 186 $storage = get_file_storage(); 187 $imagefile = $storage->get_file($context->id, 'badges', 'badgeimage', $this->_data->id, '/', 'f3.png'); 188 if ($imagefile) { 189 $imagedata = base64_encode($imagefile->get_content()); 190 } else { 191 if (defined('PHPUNIT_TEST') && PHPUNIT_TEST) { 192 // Unit tests the file might not exist yet. 193 $imagedata = ''; 194 } else { 195 throw new coding_exception('Image file does not exist.'); 196 } 197 } 198 $class['image'] = 'data:image/png;base64,' . $imagedata; 199 200 $params = ['id' => $this->get_badge_id()]; 201 $badgeurl = new moodle_url('/badges/badgeclass.php', $params); 202 $class['criteria'] = $badgeurl->out(false); // Currently badge URL. 203 if ($issued) { 204 $params = ['id' => $this->get_badge_id(), 'obversion' => $this->_obversion]; 205 $issuerurl = new moodle_url('/badges/issuer_json.php', $params); 206 $class['issuer'] = $issuerurl->out(false); 207 } 208 $this->embed_data_badge_version2($class, OPEN_BADGES_V2_TYPE_BADGE); 209 if (!$issued) { 210 unset($class['issuer']); 211 } 212 } 213 return $class; 214 } 215 216 /** 217 * Get badge issuer information. 218 * 219 * @return array Issuer information. 220 */ 221 public function get_issuer() { 222 global $CFG; 223 $issuer = array(); 224 if ($this->_data) { 225 // Required. 226 if ($this->_obversion == OPEN_BADGES_V1) { 227 $issuer['name'] = $this->_data->issuername; 228 $issuer['url'] = $this->_data->issuerurl; 229 // Optional. 230 if (!empty($this->_data->issuercontact)) { 231 $issuer['email'] = $this->_data->issuercontact; 232 } else { 233 $issuer['email'] = $CFG->badges_defaultissuercontact; 234 } 235 } else { 236 $badge = new badge($this->get_badge_id()); 237 $issuer = $badge->get_badge_issuer(); 238 } 239 } 240 $this->embed_data_badge_version2($issuer, OPEN_BADGES_V2_TYPE_ISSUER); 241 return $issuer; 242 } 243 244 /** 245 * Get related badges of the badge. 246 * 247 * @param badge $badge Badge object. 248 * @return array|bool List related badges. 249 */ 250 public function get_related_badges(badge $badge) { 251 global $DB; 252 $arraybadges = array(); 253 $relatedbadges = $badge->get_related_badges(true); 254 if ($relatedbadges) { 255 foreach ($relatedbadges as $rb) { 256 $url = new moodle_url('/badges/badge_json.php', array('id' => $rb->id)); 257 $arraybadges[] = array( 258 'id' => $url->out(false), 259 'version' => $rb->version, 260 '@language' => $rb->language 261 ); 262 } 263 } 264 return $arraybadges; 265 } 266 267 /** 268 * Get endorsement of the badge. 269 * 270 * @return false|stdClass Endorsement information. 271 */ 272 public function get_endorsement() { 273 global $DB; 274 $endorsement = array(); 275 $record = $DB->get_record_select('badge_endorsement', 'badgeid = ?', array($this->_data->id)); 276 return $record; 277 } 278 279 /** 280 * Get criteria of badge class. 281 * 282 * @return array|string Criteria information. 283 */ 284 public function get_criteria_badge_class() { 285 $badge = new badge($this->_data->id); 286 $narrative = $badge->markdown_badge_criteria(); 287 $params = ['id' => $this->get_badge_id()]; 288 $badgeurl = new moodle_url('/badges/badgeclass.php', $params); 289 if (!empty($narrative)) { 290 $criteria = []; 291 $criteria['id'] = $badgeurl->out(false); 292 $criteria['narrative'] = $narrative; 293 return $criteria; 294 } else { 295 return $badgeurl->out(false); 296 } 297 } 298 299 /** 300 * Get alignment of the badge. 301 * 302 * @return array information. 303 */ 304 public function get_alignments() { 305 global $DB; 306 $badgeid = $this->_data->id; 307 $alignments = array(); 308 $items = $DB->get_records_select('badge_alignment', 'badgeid = ?', array($badgeid)); 309 foreach ($items as $item) { 310 $alignment = array('targetName' => $item->targetname, 'targetUrl' => $item->targeturl); 311 if ($item->targetdescription) { 312 $alignment['targetDescription'] = $item->targetdescription; 313 } 314 if ($item->targetframework) { 315 $alignment['targetFramework'] = $item->targetframework; 316 } 317 if ($item->targetcode) { 318 $alignment['targetCode'] = $item->targetcode; 319 } 320 $alignments[] = $alignment; 321 } 322 return $alignments; 323 } 324 325 /** 326 * Embed data of Open Badges Specification Version 2.0 to json. 327 * 328 * @param array $json for assertion, badges, issuer. 329 * @param string $type Content type. 330 */ 331 protected function embed_data_badge_version2 (&$json, $type = OPEN_BADGES_V2_TYPE_ASSERTION) { 332 // Specification Version 2.0. 333 if ($this->_obversion >= OPEN_BADGES_V2) { 334 $badge = new badge($this->_data->id); 335 if (empty($this->_data->courseid)) { 336 $context = context_system::instance(); 337 } else { 338 $context = context_course::instance($this->_data->courseid); 339 } 340 341 $hash = $this->_data->uniquehash; 342 $assertionsurl = new moodle_url('/badges/assertion.php', array('b' => $hash, 'obversion' => $this->_obversion)); 343 $classurl = new moodle_url( 344 '/badges/badge_json.php', 345 array('id' => $this->get_badge_id()) 346 ); 347 $issuerurl = new moodle_url('/badges/issuer_json.php', ['id' => $this->get_badge_id()]); 348 // For assertion. 349 if ($type == OPEN_BADGES_V2_TYPE_ASSERTION) { 350 $json['@context'] = OPEN_BADGES_V2_CONTEXT; 351 $json['type'] = OPEN_BADGES_V2_TYPE_ASSERTION; 352 $json['id'] = $assertionsurl->out(false); 353 $json['badge'] = $this->get_badge_class(); 354 $json['issuedOn'] = date('c', $this->_data->dateissued); 355 if (!empty($this->_data->dateexpire)) { 356 $json['expires'] = date('c', $this->_data->dateexpire); 357 } 358 unset($json['uid']); 359 } 360 // For Badge. 361 if ($type == OPEN_BADGES_V2_TYPE_BADGE) { 362 $json['@context'] = OPEN_BADGES_V2_CONTEXT; 363 $json['id'] = $classurl->out(false); 364 $json['type'] = OPEN_BADGES_V2_TYPE_BADGE; 365 $json['version'] = $this->_data->version; 366 $json['criteria'] = $this->get_criteria_badge_class(); 367 $json['issuer'] = $this->get_issuer(); 368 $json['@language'] = $this->_data->language; 369 if (!empty($relatedbadges = $this->get_related_badges($badge))) { 370 $json['related'] = $relatedbadges; 371 } 372 if ($endorsement = $this->get_endorsement()) { 373 $endorsementurl = new moodle_url('/badges/endorsement_json.php', array('id' => $this->_data->id)); 374 $json['endorsement'] = $endorsementurl->out(false); 375 } 376 if ($alignments = $this->get_alignments()) { 377 $json['alignments'] = $alignments; 378 } 379 if ($this->_data->imageauthorname || 380 $this->_data->imageauthoremail || 381 $this->_data->imageauthorurl || 382 $this->_data->imagecaption) { 383 $storage = get_file_storage(); 384 $imagefile = $storage->get_file($context->id, 'badges', 'badgeimage', $this->_data->id, '/', 'f3.png'); 385 if ($imagefile) { 386 $imagedata = base64_encode($imagefile->get_content()); 387 } else { 388 // The file might not exist in unit tests. 389 if (defined('PHPUNIT_TEST') && PHPUNIT_TEST) { 390 $imagedata = ''; 391 } else { 392 throw new coding_exception('Image file does not exist.'); 393 } 394 } 395 $json['image'] = 'data:image/png;base64,' . $imagedata; 396 } 397 } 398 399 // For issuer. 400 if ($type == OPEN_BADGES_V2_TYPE_ISSUER) { 401 $json['@context'] = OPEN_BADGES_V2_CONTEXT; 402 $json['id'] = $issuerurl->out(false); 403 $json['type'] = OPEN_BADGES_V2_TYPE_ISSUER; 404 } 405 } 406 } 407 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body