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