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 * Unit tests for badges 19 * 20 * @package core 21 * @subpackage badges 22 * @copyright 2013 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 global $CFG; 30 require_once($CFG->libdir . '/badgeslib.php'); 31 require_once($CFG->dirroot . '/badges/lib.php'); 32 33 use core_badges\helper; 34 use core\task\manager; 35 36 class badgeslib_test extends advanced_testcase { 37 protected $badgeid; 38 protected $course; 39 protected $user; 40 protected $module; 41 protected $coursebadge; 42 protected $assertion; 43 44 /** @var $assertion2 to define json format for Open badge version 2 */ 45 protected $assertion2; 46 47 protected function setUp(): void { 48 global $DB, $CFG; 49 $this->resetAfterTest(true); 50 $CFG->enablecompletion = true; 51 $user = $this->getDataGenerator()->create_user(); 52 $fordb = new stdClass(); 53 $fordb->id = null; 54 $fordb->name = "Test badge with 'apostrophe' and other friends (<>&@#)"; 55 $fordb->description = "Testing badges"; 56 $fordb->timecreated = time(); 57 $fordb->timemodified = time(); 58 $fordb->usercreated = $user->id; 59 $fordb->usermodified = $user->id; 60 $fordb->issuername = "Test issuer"; 61 $fordb->issuerurl = "http://issuer-url.domain.co.nz"; 62 $fordb->issuercontact = "issuer@example.com"; 63 $fordb->expiredate = null; 64 $fordb->expireperiod = null; 65 $fordb->type = BADGE_TYPE_SITE; 66 $fordb->version = 1; 67 $fordb->language = 'en'; 68 $fordb->courseid = null; 69 $fordb->messagesubject = "Test message subject"; 70 $fordb->message = "Test message body"; 71 $fordb->attachment = 1; 72 $fordb->notification = 0; 73 $fordb->imageauthorname = "Image Author 1"; 74 $fordb->imageauthoremail = "author@example.com"; 75 $fordb->imageauthorurl = "http://author-url.example.com"; 76 $fordb->imagecaption = "Test caption image"; 77 $fordb->status = BADGE_STATUS_INACTIVE; 78 79 $this->badgeid = $DB->insert_record('badge', $fordb, true); 80 81 // Set the default Issuer (because OBv2 needs them). 82 set_config('badges_defaultissuername', $fordb->issuername); 83 set_config('badges_defaultissuercontact', $fordb->issuercontact); 84 85 // Create a course with activity and auto completion tracking. 86 $this->course = $this->getDataGenerator()->create_course(array('enablecompletion' => true)); 87 $this->user = $this->getDataGenerator()->create_user(); 88 $studentrole = $DB->get_record('role', array('shortname' => 'student')); 89 $this->assertNotEmpty($studentrole); 90 91 // Get manual enrolment plugin and enrol user. 92 require_once($CFG->dirroot.'/enrol/manual/locallib.php'); 93 $manplugin = enrol_get_plugin('manual'); 94 $maninstance = $DB->get_record('enrol', array('courseid' => $this->course->id, 'enrol' => 'manual'), '*', MUST_EXIST); 95 $manplugin->enrol_user($maninstance, $this->user->id, $studentrole->id); 96 $this->assertEquals(1, $DB->count_records('user_enrolments')); 97 $completionauto = array('completion' => COMPLETION_TRACKING_AUTOMATIC); 98 $this->module = $this->getDataGenerator()->create_module('forum', array('course' => $this->course->id), $completionauto); 99 100 // Build badge and criteria. 101 $fordb->type = BADGE_TYPE_COURSE; 102 $fordb->courseid = $this->course->id; 103 $fordb->status = BADGE_STATUS_ACTIVE; 104 $this->coursebadge = $DB->insert_record('badge', $fordb, true); 105 106 // Insert Endorsement. 107 $endorsement = new stdClass(); 108 $endorsement->badgeid = $this->coursebadge; 109 $endorsement->issuername = "Issuer 123"; 110 $endorsement->issueremail = "issuer123@email.com"; 111 $endorsement->issuerurl = "https://example.org/issuer-123"; 112 $endorsement->dateissued = 1524567747; 113 $endorsement->claimid = "https://example.org/robotics-badge.json"; 114 $endorsement->claimcomment = "Test endorser comment"; 115 $DB->insert_record('badge_endorsement', $endorsement, true); 116 117 // Insert related badges. 118 $badge = new badge($this->coursebadge); 119 $clonedid = $badge->make_clone(); 120 $badgeclone = new badge($clonedid); 121 $badgeclone->status = BADGE_STATUS_ACTIVE; 122 $badgeclone->save(); 123 124 $relatebadge = new stdClass(); 125 $relatebadge->badgeid = $this->coursebadge; 126 $relatebadge->relatedbadgeid = $clonedid; 127 $relatebadge->relatedid = $DB->insert_record('badge_related', $relatebadge, true); 128 129 // Insert a aligment. 130 $alignment = new stdClass(); 131 $alignment->badgeid = $this->coursebadge; 132 $alignment->targetname = 'CCSS.ELA-Literacy.RST.11-12.3'; 133 $alignment->targeturl = 'http://www.corestandards.org/ELA-Literacy/RST/11-12/3'; 134 $alignment->targetdescription = 'Test target description'; 135 $alignment->targetframework = 'CCSS.RST.11-12.3'; 136 $alignment->targetcode = 'CCSS.RST.11-12.3'; 137 $DB->insert_record('badge_alignment', $alignment, true); 138 139 $this->assertion = new stdClass(); 140 $this->assertion->badge = '{"uid":"%s","recipient":{"identity":"%s","type":"email","hashed":true,"salt":"%s"},"badge":"%s","verify":{"type":"hosted","url":"%s"},"issuedOn":"%d","evidence":"%s"}'; 141 $this->assertion->class = '{"name":"%s","description":"%s","image":"%s","criteria":"%s","issuer":"%s"}'; 142 $this->assertion->issuer = '{"name":"%s","url":"%s","email":"%s"}'; 143 // Format JSON-LD for Openbadge specification version 2.0. 144 $this->assertion2 = new stdClass(); 145 $this->assertion2->badge = '{"recipient":{"identity":"%s","type":"email","hashed":true,"salt":"%s"},' . 146 '"badge":{"name":"%s","description":"%s","image":"%s",' . 147 '"criteria":{"id":"%s","narrative":"%s"},"issuer":{"name":"%s","url":"%s","email":"%s",' . 148 '"@context":"https:\/\/w3id.org\/openbadges\/v2","id":"%s","type":"Issuer"},' . 149 '"@context":"https:\/\/w3id.org\/openbadges\/v2","id":"%s","type":"BadgeClass","version":"%s",' . 150 '"@language":"en","related":[{"id":"%s","version":"%s","@language":"%s"}],"endorsement":"%s",' . 151 '"alignments":[{"targetName":"%s","targetUrl":"%s","targetDescription":"%s","targetFramework":"%s",' . 152 '"targetCode":"%s"}]},"verify":{"type":"hosted","url":"%s"},"issuedOn":"%s","evidence":"%s",' . 153 '"@context":"https:\/\/w3id.org\/openbadges\/v2","type":"Assertion","id":"%s"}'; 154 155 $this->assertion2->class = '{"name":"%s","description":"%s","image":"%s",' . 156 '"criteria":{"id":"%s","narrative":"%s"},"issuer":{"name":"%s","url":"%s","email":"%s",' . 157 '"@context":"https:\/\/w3id.org\/openbadges\/v2","id":"%s","type":"Issuer"},' . 158 '"@context":"https:\/\/w3id.org\/openbadges\/v2","id":"%s","type":"BadgeClass","version":"%s",' . 159 '"@language":"%s","related":[{"id":"%s","version":"%s","@language":"%s"}],"endorsement":"%s",' . 160 '"alignments":[{"targetName":"%s","targetUrl":"%s","targetDescription":"%s","targetFramework":"%s",' . 161 '"targetCode":"%s"}]}'; 162 $this->assertion2->issuer = '{"name":"%s","url":"%s","email":"%s",' . 163 '"@context":"https:\/\/w3id.org\/openbadges\/v2","id":"%s","type":"Issuer"}'; 164 } 165 166 public function test_create_badge() { 167 $badge = new badge($this->badgeid); 168 169 $this->assertInstanceOf('badge', $badge); 170 $this->assertEquals($this->badgeid, $badge->id); 171 } 172 173 public function test_clone_badge() { 174 $badge = new badge($this->badgeid); 175 $newid = $badge->make_clone(); 176 $clonedbadge = new badge($newid); 177 178 $this->assertEquals($badge->description, $clonedbadge->description); 179 $this->assertEquals($badge->issuercontact, $clonedbadge->issuercontact); 180 $this->assertEquals($badge->issuername, $clonedbadge->issuername); 181 $this->assertEquals($badge->issuercontact, $clonedbadge->issuercontact); 182 $this->assertEquals($badge->issuerurl, $clonedbadge->issuerurl); 183 $this->assertEquals($badge->expiredate, $clonedbadge->expiredate); 184 $this->assertEquals($badge->expireperiod, $clonedbadge->expireperiod); 185 $this->assertEquals($badge->type, $clonedbadge->type); 186 $this->assertEquals($badge->courseid, $clonedbadge->courseid); 187 $this->assertEquals($badge->message, $clonedbadge->message); 188 $this->assertEquals($badge->messagesubject, $clonedbadge->messagesubject); 189 $this->assertEquals($badge->attachment, $clonedbadge->attachment); 190 $this->assertEquals($badge->notification, $clonedbadge->notification); 191 $this->assertEquals($badge->version, $clonedbadge->version); 192 $this->assertEquals($badge->language, $clonedbadge->language); 193 $this->assertEquals($badge->imagecaption, $clonedbadge->imagecaption); 194 $this->assertEquals($badge->imageauthorname, $clonedbadge->imageauthorname); 195 $this->assertEquals($badge->imageauthoremail, $clonedbadge->imageauthoremail); 196 $this->assertEquals($badge->imageauthorurl, $clonedbadge->imageauthorurl); 197 } 198 199 public function test_badge_status() { 200 $badge = new badge($this->badgeid); 201 $old_status = $badge->status; 202 $badge->set_status(BADGE_STATUS_ACTIVE); 203 $this->assertNotEquals($old_status, $badge->status); 204 $this->assertEquals(BADGE_STATUS_ACTIVE, $badge->status); 205 } 206 207 public function test_delete_badge() { 208 $badge = new badge($this->badgeid); 209 $badge->delete(); 210 // We don't actually delete badges. We archive them. 211 $this->assertEquals(BADGE_STATUS_ARCHIVED, $badge->status); 212 } 213 214 /** 215 * Really delete the badge. 216 */ 217 public function test_delete_badge_for_real() { 218 global $DB; 219 220 $badge = new badge($this->badgeid); 221 222 $newid1 = $badge->make_clone(); 223 $newid2 = $badge->make_clone(); 224 $newid3 = $badge->make_clone(); 225 226 // Insert related badges to badge 1. 227 $badge->add_related_badges([$newid1, $newid2, $newid3]); 228 229 // Another badge. 230 $badge2 = new badge($newid2); 231 // Make badge 1 related for badge 2. 232 $badge2->add_related_badges([$this->badgeid]); 233 234 // Confirm that the records about this badge about its relations have been removed as well. 235 $relatedsql = 'badgeid = :badgeid OR relatedbadgeid = :relatedbadgeid'; 236 $relatedparams = array( 237 'badgeid' => $this->badgeid, 238 'relatedbadgeid' => $this->badgeid 239 ); 240 // Badge 1 has 4 related records. 3 where it's the badgeid, 1 where it's the relatedbadgeid. 241 $this->assertEquals(4, $DB->count_records_select('badge_related', $relatedsql, $relatedparams)); 242 243 // Delete the badge for real. 244 $badge->delete(false); 245 246 // Confirm that the badge itself has been removed. 247 $this->assertFalse($DB->record_exists('badge', ['id' => $this->badgeid])); 248 249 // Confirm that the records about this badge about its relations have been removed as well. 250 $this->assertFalse($DB->record_exists_select('badge_related', $relatedsql, $relatedparams)); 251 } 252 253 public function test_create_badge_criteria() { 254 $badge = new badge($this->badgeid); 255 $criteria_overall = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_OVERALL, 'badgeid' => $badge->id)); 256 $criteria_overall->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ALL)); 257 258 $this->assertCount(1, $badge->get_criteria()); 259 260 $criteria_profile = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_PROFILE, 'badgeid' => $badge->id)); 261 $params = array('agg' => BADGE_CRITERIA_AGGREGATION_ALL, 'field_address' => 'address'); 262 $criteria_profile->save($params); 263 264 $this->assertCount(2, $badge->get_criteria()); 265 } 266 267 public function test_add_badge_criteria_description() { 268 $criteriaoverall = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_OVERALL, 'badgeid' => $this->badgeid)); 269 $criteriaoverall->save(array( 270 'agg' => BADGE_CRITERIA_AGGREGATION_ALL, 271 'description' => 'Overall description', 272 'descriptionformat' => FORMAT_HTML 273 )); 274 275 $criteriaprofile = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_PROFILE, 'badgeid' => $this->badgeid)); 276 $params = array( 277 'agg' => BADGE_CRITERIA_AGGREGATION_ALL, 278 'field_address' => 'address', 279 'description' => 'Description', 280 'descriptionformat' => FORMAT_HTML 281 ); 282 $criteriaprofile->save($params); 283 284 $badge = new badge($this->badgeid); 285 $this->assertEquals('Overall description', $badge->criteria[BADGE_CRITERIA_TYPE_OVERALL]->description); 286 $this->assertEquals('Description', $badge->criteria[BADGE_CRITERIA_TYPE_PROFILE]->description); 287 } 288 289 public function test_delete_badge_criteria() { 290 $criteria_overall = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_OVERALL, 'badgeid' => $this->badgeid)); 291 $criteria_overall->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ALL)); 292 $badge = new badge($this->badgeid); 293 294 $this->assertInstanceOf('award_criteria_overall', $badge->criteria[BADGE_CRITERIA_TYPE_OVERALL]); 295 296 $badge->criteria[BADGE_CRITERIA_TYPE_OVERALL]->delete(); 297 $this->assertEmpty($badge->get_criteria()); 298 } 299 300 public function test_badge_awards() { 301 global $DB; 302 $this->preventResetByRollback(); // Messaging is not compatible with transactions. 303 $badge = new badge($this->badgeid); 304 $user1 = $this->getDataGenerator()->create_user(); 305 306 $sink = $this->redirectMessages(); 307 308 $DB->set_field_select('message_processors', 'enabled', 0, "name <> 'email'"); 309 set_user_preference('message_provider_moodle_badgerecipientnotice_enabled', 'email', $user1); 310 311 $badge->issue($user1->id, false); 312 $this->assertDebuggingCalled(); // Expect debugging while baking a badge via phpunit. 313 $this->assertTrue($badge->is_issued($user1->id)); 314 315 $messages = $sink->get_messages(); 316 $sink->close(); 317 $this->assertCount(1, $messages); 318 $message = array_pop($messages); 319 // Check we have the expected data. 320 $customdata = json_decode($message->customdata); 321 $this->assertObjectHasAttribute('notificationiconurl', $customdata); 322 $this->assertObjectHasAttribute('hash', $customdata); 323 324 $user2 = $this->getDataGenerator()->create_user(); 325 $badge->issue($user2->id, true); 326 $this->assertTrue($badge->is_issued($user2->id)); 327 328 $this->assertCount(2, $badge->get_awards()); 329 } 330 331 /** 332 * Test the {@link badges_get_user_badges()} function in lib/badgeslib.php 333 */ 334 public function test_badges_get_user_badges() { 335 global $DB; 336 337 // Messaging is not compatible with transactions. 338 $this->preventResetByRollback(); 339 340 $badges = array(); 341 $user1 = $this->getDataGenerator()->create_user(); 342 $user2 = $this->getDataGenerator()->create_user(); 343 344 // Record the current time, we need to be precise about a couple of things. 345 $now = time(); 346 // Create 11 badges with which to test. 347 for ($i = 1; $i <= 11; $i++) { 348 // Mock up a badge. 349 $badge = new stdClass(); 350 $badge->id = null; 351 $badge->name = "Test badge $i"; 352 $badge->description = "Testing badges $i"; 353 $badge->timecreated = $now - 12; 354 $badge->timemodified = $now - 12; 355 $badge->usercreated = $user1->id; 356 $badge->usermodified = $user1->id; 357 $badge->issuername = "Test issuer"; 358 $badge->issuerurl = "http://issuer-url.domain.co.nz"; 359 $badge->issuercontact = "issuer@example.com"; 360 $badge->expiredate = null; 361 $badge->expireperiod = null; 362 $badge->type = BADGE_TYPE_SITE; 363 $badge->courseid = null; 364 $badge->messagesubject = "Test message subject for badge $i"; 365 $badge->message = "Test message body for badge $i"; 366 $badge->attachment = 1; 367 $badge->notification = 0; 368 $badge->status = BADGE_STATUS_INACTIVE; 369 $badge->version = "Version $i"; 370 $badge->language = "en"; 371 $badge->imagecaption = "Image caption $i"; 372 $badge->imageauthorname = "Image author's name $i"; 373 $badge->imageauthoremail = "author$i@example.com"; 374 $badge->imageauthorname = "Image author's name $i"; 375 376 $badgeid = $DB->insert_record('badge', $badge, true); 377 $badges[$badgeid] = new badge($badgeid); 378 $badges[$badgeid]->issue($user2->id, true); 379 // Check it all actually worked. 380 $this->assertCount(1, $badges[$badgeid]->get_awards()); 381 382 // Hack the database to adjust the time each badge was issued. 383 // The alternative to this is sleep which is a no-no in unit tests. 384 $DB->set_field('badge_issued', 'dateissued', $now - 11 + $i, array('userid' => $user2->id, 'badgeid' => $badgeid)); 385 } 386 387 // Make sure the first user has no badges. 388 $result = badges_get_user_badges($user1->id); 389 $this->assertIsArray($result); 390 $this->assertCount(0, $result); 391 392 // Check that the second user has the expected 11 badges. 393 $result = badges_get_user_badges($user2->id); 394 $this->assertCount(11, $result); 395 396 // Test pagination. 397 // Ordering is by time issued desc, so things will come out with the last awarded badge first. 398 $result = badges_get_user_badges($user2->id, 0, 0, 4); 399 $this->assertCount(4, $result); 400 $lastbadgeissued = reset($result); 401 $this->assertSame('Test badge 11', $lastbadgeissued->name); 402 // Page 2. Expecting 4 results again. 403 $result = badges_get_user_badges($user2->id, 0, 1, 4); 404 $this->assertCount(4, $result); 405 $lastbadgeissued = reset($result); 406 $this->assertSame('Test badge 7', $lastbadgeissued->name); 407 // Page 3. Expecting just three results here. 408 $result = badges_get_user_badges($user2->id, 0, 2, 4); 409 $this->assertCount(3, $result); 410 $lastbadgeissued = reset($result); 411 $this->assertSame('Test badge 3', $lastbadgeissued->name); 412 // Page 4.... there is no page 4. 413 $result = badges_get_user_badges($user2->id, 0, 3, 4); 414 $this->assertCount(0, $result); 415 416 // Test search. 417 $result = badges_get_user_badges($user2->id, 0, 0, 0, 'badge 1'); 418 $this->assertCount(3, $result); 419 $lastbadgeissued = reset($result); 420 $this->assertSame('Test badge 11', $lastbadgeissued->name); 421 // The term Totara doesn't appear anywhere in the badges. 422 $result = badges_get_user_badges($user2->id, 0, 0, 0, 'Totara'); 423 $this->assertCount(0, $result); 424 425 // Issue a user with a course badge and verify its returned based on if 426 // coursebadges are enabled or disabled. 427 $sitebadgeid = key($badges); 428 $badges[$sitebadgeid]->issue($this->user->id, true); 429 430 $badge = new stdClass(); 431 $badge->id = null; 432 $badge->name = "Test course badge"; 433 $badge->description = "Testing course badge"; 434 $badge->timecreated = $now; 435 $badge->timemodified = $now; 436 $badge->usercreated = $user1->id; 437 $badge->usermodified = $user1->id; 438 $badge->issuername = "Test issuer"; 439 $badge->issuerurl = "http://issuer-url.domain.co.nz"; 440 $badge->issuercontact = "issuer@example.com"; 441 $badge->expiredate = null; 442 $badge->expireperiod = null; 443 $badge->type = BADGE_TYPE_COURSE; 444 $badge->courseid = $this->course->id; 445 $badge->messagesubject = "Test message subject for course badge"; 446 $badge->message = "Test message body for course badge"; 447 $badge->attachment = 1; 448 $badge->notification = 0; 449 $badge->status = BADGE_STATUS_ACTIVE; 450 $badge->version = "Version $i"; 451 $badge->language = "en"; 452 $badge->imagecaption = "Image caption"; 453 $badge->imageauthorname = "Image author's name"; 454 $badge->imageauthoremail = "author@example.com"; 455 $badge->imageauthorname = "Image author's name"; 456 457 $badgeid = $DB->insert_record('badge', $badge, true); 458 $badges[$badgeid] = new badge($badgeid); 459 $badges[$badgeid]->issue($this->user->id, true); 460 461 // With coursebadges off, we should only get the site badge. 462 set_config('badges_allowcoursebadges', false); 463 $result = badges_get_user_badges($this->user->id); 464 $this->assertCount(1, $result); 465 466 // With it on, we should get both. 467 set_config('badges_allowcoursebadges', true); 468 $result = badges_get_user_badges($this->user->id); 469 $this->assertCount(2, $result); 470 471 } 472 473 public function data_for_message_from_template() { 474 return array( 475 array( 476 'This is a message with no variables', 477 array(), // no params 478 'This is a message with no variables' 479 ), 480 array( 481 'This is a message with %amissing% variables', 482 array(), // no params 483 'This is a message with %amissing% variables' 484 ), 485 array( 486 'This is a message with %one% variable', 487 array('one' => 'a single'), 488 'This is a message with a single variable' 489 ), 490 array( 491 'This is a message with %one% %two% %three% variables', 492 array('one' => 'more', 'two' => 'than', 'three' => 'one'), 493 'This is a message with more than one variables' 494 ), 495 array( 496 'This is a message with %three% %two% %one%', 497 array('one' => 'variables', 'two' => 'ordered', 'three' => 'randomly'), 498 'This is a message with randomly ordered variables' 499 ), 500 array( 501 'This is a message with %repeated% %one% %repeated% of variables', 502 array('one' => 'and', 'repeated' => 'lots'), 503 'This is a message with lots and lots of variables' 504 ), 505 ); 506 } 507 508 /** 509 * @dataProvider data_for_message_from_template 510 */ 511 public function test_badge_message_from_template($message, $params, $result) { 512 $this->assertEquals(badge_message_from_template($message, $params), $result); 513 } 514 515 /** 516 * Test for working around the 61 tables join limit of mysql in award_criteria_activity in combination with the scheduled task. 517 * 518 * @covers \core_badges\badge::review_all_criteria 519 */ 520 public function test_badge_activity_criteria_with_a_huge_number_of_coursemodules() { 521 global $CFG; 522 require_once($CFG->dirroot.'/completion/criteria/completion_criteria_activity.php'); 523 524 if (!PHPUNIT_LONGTEST) { 525 $this->markTestSkipped('PHPUNIT_LONGTEST is not defined'); 526 } 527 528 // Messaging is not compatible with transactions. 529 $this->preventResetByRollback(); 530 531 // Create more than 61 modules to potentially trigger an mysql db error. 532 $assigncount = 75; 533 $assigns = []; 534 for ($i = 1; $i <= $assigncount; $i++) { 535 $assigns[] = $this->getDataGenerator()->create_module('assign', ['course' => $this->course->id], ['completion' => 1]); 536 } 537 $assigncmids = array_flip(array_map(fn ($assign) => $assign->cmid, $assigns)); 538 $criteriaactivityarray = array_fill_keys(array_keys($assigncmids), 1); 539 540 // Set completion criteria. 541 $criteriadata = (object) [ 542 'id' => $this->course->id, 543 'criteria_activity' => $criteriaactivityarray, 544 ]; 545 $criterion = new completion_criteria_activity(); 546 $criterion->update_config($criteriadata); 547 548 $badge = new badge($this->coursebadge); 549 550 $criteriaoverall = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_OVERALL, 'badgeid' => $badge->id)); 551 $criteriaoverall->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ANY)); 552 $criteriaactivity = award_criteria::build(['criteriatype' => BADGE_CRITERIA_TYPE_ACTIVITY, 'badgeid' => $badge->id]); 553 554 $modulescrit = ['agg' => BADGE_CRITERIA_AGGREGATION_ALL]; 555 foreach ($assigns as $assign) { 556 $modulescrit['module_' . $assign->cmid] = $assign->cmid; 557 } 558 $criteriaactivity->save($modulescrit); 559 560 // Take one assign to complete it later. 561 $assigntemp = array_shift($assigns); 562 563 // Mark the user to complete the modules. 564 foreach ($assigns as $assign) { 565 $cmassign = get_coursemodule_from_id('assign', $assign->cmid); 566 $completion = new \completion_info($this->course); 567 $completion->update_state($cmassign, COMPLETION_COMPLETE, $this->user->id); 568 } 569 570 // Run the scheduled task to issue the badge. But the badge should not be issued. 571 ob_start(); 572 $task = manager::get_scheduled_task('core\task\badges_cron_task'); 573 $task->execute(); 574 ob_end_clean(); 575 576 $this->assertFalse($badge->is_issued($this->user->id)); 577 578 // Now complete the last uncompleted module. 579 $cmassign = get_coursemodule_from_id('assign', $assigntemp->cmid); 580 $completion = new \completion_info($this->course); 581 $completion->update_state($cmassign, COMPLETION_COMPLETE, $this->user->id); 582 583 // Run the scheduled task to issue the badge. Now the badge schould be issued. 584 ob_start(); 585 $task = manager::get_scheduled_task('core\task\badges_cron_task'); 586 $task->execute(); 587 ob_end_clean(); 588 589 $this->assertDebuggingCalled('Error baking badge image!'); 590 $this->assertTrue($badge->is_issued($this->user->id)); 591 } 592 593 /** 594 * Test badges observer when course module completion event id fired. 595 */ 596 public function test_badges_observer_course_module_criteria_review() { 597 $this->preventResetByRollback(); // Messaging is not compatible with transactions. 598 $badge = new badge($this->coursebadge); 599 $this->assertFalse($badge->is_issued($this->user->id)); 600 601 $criteria_overall = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_OVERALL, 'badgeid' => $badge->id)); 602 $criteria_overall->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ANY)); 603 $criteria_overall = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_ACTIVITY, 'badgeid' => $badge->id)); 604 $criteria_overall->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ANY, 'module_'.$this->module->cmid => $this->module->cmid)); 605 606 // Assert the badge will not be issued to the user as is. 607 $badge = new badge($this->coursebadge); 608 $badge->review_all_criteria(); 609 $this->assertFalse($badge->is_issued($this->user->id)); 610 611 // Set completion for forum activity. 612 $c = new completion_info($this->course); 613 $activities = $c->get_activities(); 614 $this->assertEquals(1, count($activities)); 615 $this->assertTrue(isset($activities[$this->module->cmid])); 616 $this->assertEquals($activities[$this->module->cmid]->name, $this->module->name); 617 618 $current = $c->get_data($activities[$this->module->cmid], false, $this->user->id); 619 $current->completionstate = COMPLETION_COMPLETE; 620 $current->timemodified = time(); 621 $sink = $this->redirectEmails(); 622 $c->internal_set_data($activities[$this->module->cmid], $current); 623 $this->assertCount(1, $sink->get_messages()); 624 $sink->close(); 625 626 // Check if badge is awarded. 627 $this->assertDebuggingCalled('Error baking badge image!'); 628 $this->assertTrue($badge->is_issued($this->user->id)); 629 } 630 631 /** 632 * Test badges observer when course_completed event is fired. 633 */ 634 public function test_badges_observer_course_criteria_review() { 635 $this->preventResetByRollback(); // Messaging is not compatible with transactions. 636 $badge = new badge($this->coursebadge); 637 $this->assertFalse($badge->is_issued($this->user->id)); 638 639 $criteria_overall = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_OVERALL, 'badgeid' => $badge->id)); 640 $criteria_overall->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ANY)); 641 $criteria_overall1 = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_COURSE, 'badgeid' => $badge->id)); 642 $criteria_overall1->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ANY, 'course_'.$this->course->id => $this->course->id)); 643 644 $ccompletion = new completion_completion(array('course' => $this->course->id, 'userid' => $this->user->id)); 645 646 // Assert the badge will not be issued to the user as is. 647 $badge = new badge($this->coursebadge); 648 $badge->review_all_criteria(); 649 $this->assertFalse($badge->is_issued($this->user->id)); 650 651 // Mark course as complete. 652 $sink = $this->redirectMessages(); 653 $ccompletion->mark_complete(); 654 // Two messages are generated: One for the course completed and the other one for the badge awarded. 655 $messages = $sink->get_messages(); 656 $this->assertCount(2, $messages); 657 $this->assertEquals('badgerecipientnotice', $messages[0]->eventtype); 658 $this->assertEquals('coursecompleted', $messages[1]->eventtype); 659 $sink->close(); 660 661 // Check if badge is awarded. 662 $this->assertDebuggingCalled('Error baking badge image!'); 663 $this->assertTrue($badge->is_issued($this->user->id)); 664 } 665 666 /** 667 * Test badges observer when user_updated event is fired. 668 */ 669 public function test_badges_observer_profile_criteria_review() { 670 global $CFG, $DB; 671 require_once($CFG->dirroot.'/user/profile/lib.php'); 672 673 // Add a custom field of textarea type. 674 $customprofileid = $this->getDataGenerator()->create_custom_profile_field(array( 675 'shortname' => 'newfield', 'name' => 'Description of new field', 676 'datatype' => 'textarea'))->id; 677 678 $this->preventResetByRollback(); // Messaging is not compatible with transactions. 679 $badge = new badge($this->coursebadge); 680 681 $criteria_overall = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_OVERALL, 'badgeid' => $badge->id)); 682 $criteria_overall->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ANY)); 683 $criteria_overall1 = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_PROFILE, 'badgeid' => $badge->id)); 684 $criteria_overall1->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ALL, 'field_address' => 'address', 685 'field_department' => 'department', 'field_' . $customprofileid => $customprofileid)); 686 687 // Assert the badge will not be issued to the user as is. 688 $badge = new badge($this->coursebadge); 689 $badge->review_all_criteria(); 690 $this->assertFalse($badge->is_issued($this->user->id)); 691 692 // Set the required fields and make sure the badge got issued. 693 $this->user->address = 'Test address'; 694 $this->user->department = 'sillywalks'; 695 $sink = $this->redirectEmails(); 696 profile_save_data((object)array('id' => $this->user->id, 'profile_field_newfield' => 'X')); 697 user_update_user($this->user, false); 698 $this->assertCount(1, $sink->get_messages()); 699 $sink->close(); 700 // Check if badge is awarded. 701 $this->assertDebuggingCalled('Error baking badge image!'); 702 $this->assertTrue($badge->is_issued($this->user->id)); 703 } 704 705 /** 706 * Test badges observer when cohort_member_added event is fired and user required to belong to any cohort. 707 * 708 * @covers \award_criteria_cohort 709 */ 710 public function test_badges_observer_any_cohort_criteria_review() { 711 global $CFG; 712 713 require_once("$CFG->dirroot/cohort/lib.php"); 714 715 $cohort1 = $this->getDataGenerator()->create_cohort(); 716 $cohort2 = $this->getDataGenerator()->create_cohort(); 717 718 $this->preventResetByRollback(); // Messaging is not compatible with transactions. 719 720 $badge = new badge($this->badgeid); 721 $this->assertFalse($badge->is_issued($this->user->id)); 722 $this->assertSame(0, $badge->review_all_criteria()); // Verify award_criteria_cohort->get_completed_criteria_sql(). 723 724 // Set up the badge criteria. 725 $criteriaoverall = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_OVERALL, 'badgeid' => $badge->id)); 726 $criteriaoverall->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ANY)); 727 $criteriaoverall1 = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_COHORT, 'badgeid' => $badge->id)); 728 $criteriaoverall1->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ANY, 729 'cohort_cohorts' => array('0' => $cohort1->id, '1' => $cohort2->id))); 730 $badge->set_status(BADGE_STATUS_ACTIVE); 731 732 // Reload it to contain criteria. 733 $badge = new badge($this->badgeid); 734 $this->assertFalse($badge->is_issued($this->user->id)); 735 $this->assertSame(0, $badge->review_all_criteria()); // Verify award_criteria_cohort->get_completed_criteria_sql(). 736 737 // Add the user to the cohort. 738 cohort_add_member($cohort2->id, $this->user->id); 739 $this->assertDebuggingCalled(); 740 741 // Verify that the badge was awarded. 742 $this->assertTrue($badge->is_issued($this->user->id)); 743 // As the badge has been awarded to user because core_badges_observer been called when the member has been added to the 744 // cohort, there are no other users that can award this badge. 745 $this->assertSame(0, $badge->review_all_criteria()); // Verify award_criteria_cohort->get_completed_criteria_sql(). 746 } 747 748 /** 749 * Test badges observer when cohort_member_added event is fired and user required to belong to multiple (all) cohorts. 750 * 751 * @covers \award_criteria_cohort 752 */ 753 public function test_badges_observer_all_cohort_criteria_review() { 754 global $CFG; 755 756 require_once("$CFG->dirroot/cohort/lib.php"); 757 758 $cohort1 = $this->getDataGenerator()->create_cohort(); 759 $cohort2 = $this->getDataGenerator()->create_cohort(); 760 $cohort3 = $this->getDataGenerator()->create_cohort(); 761 762 // Add user2 to cohort1 and cohort3. 763 $user2 = $this->getDataGenerator()->create_user(); 764 cohort_add_member($cohort3->id, $user2->id); 765 cohort_add_member($cohort1->id, $user2->id); 766 767 // Add user3 to cohort1, cohort2 and cohort3. 768 $user3 = $this->getDataGenerator()->create_user(); 769 cohort_add_member($cohort1->id, $user3->id); 770 cohort_add_member($cohort2->id, $user3->id); 771 cohort_add_member($cohort3->id, $user3->id); 772 773 $this->preventResetByRollback(); // Messaging is not compatible with transactions. 774 775 // Cohort criteria are used in site badges. 776 $badge = new badge($this->badgeid); 777 778 $this->assertFalse($badge->is_issued($this->user->id)); 779 $this->assertSame(0, $badge->review_all_criteria()); // Verify award_criteria_cohort->get_completed_criteria_sql(). 780 781 // Set up the badge criteria. 782 $criteriaoverall = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_OVERALL, 'badgeid' => $badge->id)); 783 $criteriaoverall->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ANY)); 784 $criteriaoverall1 = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_COHORT, 'badgeid' => $badge->id)); 785 $criteriaoverall1->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ALL, 786 'cohort_cohorts' => array('0' => $cohort1->id, '1' => $cohort2->id, '2' => $cohort3->id))); 787 $badge->set_status(BADGE_STATUS_ACTIVE); 788 789 // Reload it to contain criteria. 790 $badge = new badge($this->badgeid); 791 792 // Verify that the badge was not awarded yet (ALL cohorts are needed and review_all_criteria has to be called). 793 $this->assertFalse($badge->is_issued($this->user->id)); 794 $this->assertFalse($badge->is_issued($user2->id)); 795 $this->assertFalse($badge->is_issued($user3->id)); 796 797 // Verify that after calling review_all_criteria, users with the criteria (user3) award the badge instantly. 798 $this->assertSame(1, $badge->review_all_criteria()); // Verify award_criteria_cohort->get_completed_criteria_sql(). 799 $this->assertFalse($badge->is_issued($this->user->id)); 800 $this->assertFalse($badge->is_issued($user2->id)); 801 $this->assertTrue($badge->is_issued($user3->id)); 802 $this->assertDebuggingCalled(); 803 804 // Add the user to the cohort1. 805 cohort_add_member($cohort1->id, $this->user->id); 806 807 // Verify that the badge was not awarded yet (ALL cohorts are needed). 808 $this->assertFalse($badge->is_issued($this->user->id)); 809 $this->assertSame(0, $badge->review_all_criteria()); // Verify award_criteria_cohort->get_completed_criteria_sql(). 810 811 // Add the user to the cohort3. 812 cohort_add_member($cohort3->id, $this->user->id); 813 814 // Verify that the badge was not awarded yet (ALL cohorts are needed). 815 $this->assertFalse($badge->is_issued($this->user->id)); 816 $this->assertSame(0, $badge->review_all_criteria()); // Verify award_criteria_cohort->get_completed_criteria_sql(). 817 818 // Add user to cohort2. 819 cohort_add_member($cohort2->id, $this->user->id); 820 $this->assertDebuggingCalled(); 821 822 // Verify that the badge was awarded (ALL cohorts). 823 $this->assertTrue($badge->is_issued($this->user->id)); 824 // As the badge has been awarded to user because core_badges_observer been called when the member has been added to the 825 // cohort, there are no other users that can award this badge. 826 $this->assertSame(0, $badge->review_all_criteria()); // Verify award_criteria_cohort->get_completed_criteria_sql(). 827 } 828 829 /** 830 * Test badges assertion generated when a badge is issued. 831 */ 832 public function test_badges_assertion() { 833 $this->preventResetByRollback(); // Messaging is not compatible with transactions. 834 $badge = new badge($this->coursebadge); 835 $this->assertFalse($badge->is_issued($this->user->id)); 836 837 $criteria_overall = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_OVERALL, 'badgeid' => $badge->id)); 838 $criteria_overall->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ANY)); 839 $criteria_overall1 = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_PROFILE, 'badgeid' => $badge->id)); 840 $criteria_overall1->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ALL, 'field_address' => 'address')); 841 842 $this->user->address = 'Test address'; 843 $sink = $this->redirectEmails(); 844 user_update_user($this->user, false); 845 $this->assertCount(1, $sink->get_messages()); 846 $sink->close(); 847 // Check if badge is awarded. 848 $this->assertDebuggingCalled('Error baking badge image!'); 849 $awards = $badge->get_awards(); 850 $this->assertCount(1, $awards); 851 852 // Get assertion. 853 $award = reset($awards); 854 $assertion = new core_badges_assertion($award->uniquehash, OPEN_BADGES_V1); 855 $testassertion = $this->assertion; 856 857 // Make sure JSON strings have the same structure. 858 $this->assertStringMatchesFormat($testassertion->badge, json_encode($assertion->get_badge_assertion())); 859 $this->assertStringMatchesFormat($testassertion->class, json_encode($assertion->get_badge_class())); 860 $this->assertStringMatchesFormat($testassertion->issuer, json_encode($assertion->get_issuer())); 861 862 // Test Openbadge specification version 2. 863 // Get assertion version 2. 864 $award = reset($awards); 865 $assertion2 = new core_badges_assertion($award->uniquehash, OPEN_BADGES_V2); 866 $testassertion2 = $this->assertion2; 867 868 // Make sure JSON strings have the same structure. 869 $this->assertStringMatchesFormat($testassertion2->badge, json_encode($assertion2->get_badge_assertion())); 870 $this->assertStringMatchesFormat($testassertion2->class, json_encode($assertion2->get_badge_class())); 871 $this->assertStringMatchesFormat($testassertion2->issuer, json_encode($assertion2->get_issuer())); 872 873 // Test Openbadge specification version 2.1. It has the same format as OBv2.0. 874 // Get assertion version 2.1. 875 $award = reset($awards); 876 $assertion2 = new core_badges_assertion($award->uniquehash, OPEN_BADGES_V2P1); 877 878 // Make sure JSON strings have the same structure. 879 $this->assertStringMatchesFormat($testassertion2->badge, json_encode($assertion2->get_badge_assertion())); 880 $this->assertStringMatchesFormat($testassertion2->class, json_encode($assertion2->get_badge_class())); 881 $this->assertStringMatchesFormat($testassertion2->issuer, json_encode($assertion2->get_issuer())); 882 } 883 884 /** 885 * Tests the core_badges_myprofile_navigation() function. 886 */ 887 public function test_core_badges_myprofile_navigation() { 888 // Set up the test. 889 $tree = new \core_user\output\myprofile\tree(); 890 $this->setAdminUser(); 891 $badge = new badge($this->badgeid); 892 $badge->issue($this->user->id, true); 893 $iscurrentuser = true; 894 $course = null; 895 896 // Enable badges. 897 set_config('enablebadges', true); 898 899 // Check the node tree is correct. 900 core_badges_myprofile_navigation($tree, $this->user, $iscurrentuser, $course); 901 $reflector = new ReflectionObject($tree); 902 $nodes = $reflector->getProperty('nodes'); 903 $nodes->setAccessible(true); 904 $this->assertArrayHasKey('localbadges', $nodes->getValue($tree)); 905 } 906 907 /** 908 * Tests the core_badges_myprofile_navigation() function with badges disabled.. 909 */ 910 public function test_core_badges_myprofile_navigation_badges_disabled() { 911 // Set up the test. 912 $tree = new \core_user\output\myprofile\tree(); 913 $this->setAdminUser(); 914 $badge = new badge($this->badgeid); 915 $badge->issue($this->user->id, true); 916 $iscurrentuser = false; 917 $course = null; 918 919 // Disable badges. 920 set_config('enablebadges', false); 921 922 // Check the node tree is correct. 923 core_badges_myprofile_navigation($tree, $this->user, $iscurrentuser, $course); 924 $reflector = new ReflectionObject($tree); 925 $nodes = $reflector->getProperty('nodes'); 926 $nodes->setAccessible(true); 927 $this->assertArrayNotHasKey('localbadges', $nodes->getValue($tree)); 928 } 929 930 /** 931 * Tests the core_badges_myprofile_navigation() function with a course badge. 932 */ 933 public function test_core_badges_myprofile_navigation_with_course_badge() { 934 // Set up the test. 935 $tree = new \core_user\output\myprofile\tree(); 936 $this->setAdminUser(); 937 $badge = new badge($this->coursebadge); 938 $badge->issue($this->user->id, true); 939 $iscurrentuser = false; 940 941 // Check the node tree is correct. 942 core_badges_myprofile_navigation($tree, $this->user, $iscurrentuser, $this->course); 943 $reflector = new ReflectionObject($tree); 944 $nodes = $reflector->getProperty('nodes'); 945 $nodes->setAccessible(true); 946 $this->assertArrayHasKey('localbadges', $nodes->getValue($tree)); 947 } 948 949 /** 950 * Test insert and update endorsement with a site badge. 951 */ 952 public function test_badge_endorsement() { 953 $badge = new badge($this->badgeid); 954 955 // Insert Endorsement. 956 $endorsement = new stdClass(); 957 $endorsement->badgeid = $this->badgeid; 958 $endorsement->issuername = "Issuer 123"; 959 $endorsement->issueremail = "issuer123@email.com"; 960 $endorsement->issuerurl = "https://example.org/issuer-123"; 961 $endorsement->dateissued = 1524567747; 962 $endorsement->claimid = "https://example.org/robotics-badge.json"; 963 $endorsement->claimcomment = "Test endorser comment"; 964 965 $badge->save_endorsement($endorsement); 966 $endorsement1 = $badge->get_endorsement(); 967 $this->assertEquals($endorsement->badgeid, $endorsement1->badgeid); 968 $this->assertEquals($endorsement->issuername, $endorsement1->issuername); 969 $this->assertEquals($endorsement->issueremail, $endorsement1->issueremail); 970 $this->assertEquals($endorsement->issuerurl, $endorsement1->issuerurl); 971 $this->assertEquals($endorsement->dateissued, $endorsement1->dateissued); 972 $this->assertEquals($endorsement->claimid, $endorsement1->claimid); 973 $this->assertEquals($endorsement->claimcomment, $endorsement1->claimcomment); 974 975 // Update Endorsement. 976 $endorsement1->issuername = "Issuer update"; 977 $badge->save_endorsement($endorsement1); 978 $endorsement2 = $badge->get_endorsement(); 979 $this->assertEquals($endorsement1->id, $endorsement2->id); 980 $this->assertEquals($endorsement1->issuername, $endorsement2->issuername); 981 } 982 983 /** 984 * Test insert and delete related badge with a site badge. 985 */ 986 public function test_badge_related() { 987 $badge = new badge($this->badgeid); 988 $newid1 = $badge->make_clone(); 989 $newid2 = $badge->make_clone(); 990 $newid3 = $badge->make_clone(); 991 992 // Insert an related badge. 993 $badge->add_related_badges([$newid1, $newid2, $newid3]); 994 $this->assertCount(3, $badge->get_related_badges()); 995 996 // Only get related is active. 997 $clonedbage1 = new badge($newid1); 998 $clonedbage1->status = BADGE_STATUS_ACTIVE; 999 $clonedbage1->save(); 1000 $this->assertCount(1, $badge->get_related_badges(true)); 1001 1002 // Delete an related badge. 1003 $badge->delete_related_badge($newid2); 1004 $this->assertCount(2, $badge->get_related_badges()); 1005 } 1006 1007 /** 1008 * Test insert, update, delete alignment with a site badge. 1009 */ 1010 public function test_alignments() { 1011 $badge = new badge($this->badgeid); 1012 1013 // Insert a alignment. 1014 $alignment1 = new stdClass(); 1015 $alignment1->badgeid = $this->badgeid; 1016 $alignment1->targetname = 'CCSS.ELA-Literacy.RST.11-12.3'; 1017 $alignment1->targeturl = 'http://www.corestandards.org/ELA-Literacy/RST/11-12/3'; 1018 $alignment1->targetdescription = 'Test target description'; 1019 $alignment1->targetframework = 'CCSS.RST.11-12.3'; 1020 $alignment1->targetcode = 'CCSS.RST.11-12.3'; 1021 $alignment2 = clone $alignment1; 1022 $newid1 = $badge->save_alignment($alignment1); 1023 $newid2 = $badge->save_alignment($alignment2); 1024 $alignments1 = $badge->get_alignments(); 1025 $this->assertCount(2, $alignments1); 1026 1027 $this->assertEquals($alignment1->badgeid, $alignments1[$newid1]->badgeid); 1028 $this->assertEquals($alignment1->targetname, $alignments1[$newid1]->targetname); 1029 $this->assertEquals($alignment1->targeturl, $alignments1[$newid1]->targeturl); 1030 $this->assertEquals($alignment1->targetdescription, $alignments1[$newid1]->targetdescription); 1031 $this->assertEquals($alignment1->targetframework, $alignments1[$newid1]->targetframework); 1032 $this->assertEquals($alignment1->targetcode, $alignments1[$newid1]->targetcode); 1033 1034 // Update aligment. 1035 $alignments1[$newid1]->targetname = 'CCSS.ELA-Literacy.RST.11-12.3 update'; 1036 $badge->save_alignment($alignments1[$newid1], $alignments1[$newid1]->id); 1037 $alignments2 = $badge->get_alignments(); 1038 $this->assertEquals($alignments1[$newid1]->id, $alignments2[$newid1]->id); 1039 $this->assertEquals($alignments1[$newid1]->targetname, $alignments2[$newid1]->targetname); 1040 1041 // Delete alignment. 1042 $badge->delete_alignment($alignments1[$newid2]->id); 1043 $this->assertCount(1, $badge->get_alignments()); 1044 } 1045 1046 /** 1047 * Test badges_delete_site_backpack(). 1048 * 1049 */ 1050 public function test_badges_delete_site_backpack(): void { 1051 global $DB; 1052 1053 $this->setAdminUser(); 1054 1055 // Create one backpack. 1056 $total = $DB->count_records('badge_external_backpack'); 1057 $this->assertEquals(1, $total); 1058 1059 $data = new \stdClass(); 1060 $data->apiversion = OPEN_BADGES_V2P1; 1061 $data->backpackapiurl = 'https://dc.imsglobal.org/obchost/ims/ob/v2p1'; 1062 $data->backpackweburl = 'https://dc.imsglobal.org'; 1063 badges_create_site_backpack($data); 1064 $backpack = $DB->get_record('badge_external_backpack', ['backpackweburl' => $data->backpackweburl]); 1065 $user1 = $this->getDataGenerator()->create_user(); 1066 $user2 = $this->getDataGenerator()->create_user(); 1067 // User1 is connected to the backpack to be removed and has 2 collections. 1068 $backpackuser1 = helper::create_fake_backpack(['userid' => $user1->id, 'externalbackpackid' => $backpack->id]); 1069 helper::create_fake_backpack_collection(['backpackid' => $backpackuser1->id]); 1070 helper::create_fake_backpack_collection(['backpackid' => $backpackuser1->id]); 1071 // User2 is connected to a different backpack and has 1 collection. 1072 $backpackuser2 = helper::create_fake_backpack(['userid' => $user2->id]); 1073 helper::create_fake_backpack_collection(['backpackid' => $backpackuser2->id]); 1074 1075 $total = $DB->count_records('badge_external_backpack'); 1076 $this->assertEquals(2, $total); 1077 $total = $DB->count_records('badge_backpack'); 1078 $this->assertEquals(2, $total); 1079 $total = $DB->count_records('badge_external'); 1080 $this->assertEquals(3, $total); 1081 1082 // Remove the backpack created previously. 1083 $result = badges_delete_site_backpack($backpack->id); 1084 $this->assertTrue($result); 1085 1086 $total = $DB->count_records('badge_external_backpack'); 1087 $this->assertEquals(1, $total); 1088 1089 $total = $DB->count_records('badge_backpack'); 1090 $this->assertEquals(1, $total); 1091 1092 $total = $DB->count_records('badge_external'); 1093 $this->assertEquals(1, $total); 1094 1095 // Try to remove an non-existent backpack. 1096 $result = badges_delete_site_backpack($backpack->id); 1097 $this->assertFalse($result); 1098 } 1099 1100 /** 1101 * Test to validate badges_save_backpack_credentials. 1102 * 1103 * @dataProvider save_backpack_credentials_provider 1104 * @param bool $addbackpack True if backpack data has to be created; false otherwise (empty data will be used then). 1105 * @param string|null $mail Backpack mail address. 1106 * @param string|null $password Backpack password. 1107 */ 1108 public function test_save_backpack_credentials(bool $addbackpack = true, ?string $mail = null, ?string $password = null) { 1109 global $DB; 1110 1111 $this->resetAfterTest(); 1112 $this->setAdminUser(); 1113 1114 $data = []; 1115 if ($addbackpack) { 1116 $data = new \stdClass(); 1117 $data->apiversion = OPEN_BADGES_V2P1; 1118 $data->backpackapiurl = 'https://dc.imsglobal.org/obchost/ims/ob/v2p1'; 1119 $data->backpackweburl = 'https://dc.imsglobal.org'; 1120 badges_create_site_backpack($data); 1121 $backpack = $DB->get_record('badge_external_backpack', ['backpackweburl' => $data->backpackweburl]); 1122 $user = $this->getDataGenerator()->create_user(); 1123 1124 $data = [ 1125 'externalbackpackid' => $backpack->id, 1126 'userid' => $user->id, 1127 ]; 1128 1129 if (!empty($mail)) { 1130 $data['backpackemail'] = $mail; 1131 } 1132 if (!empty($password)) { 1133 $data['password'] = $password; 1134 } 1135 } 1136 1137 $return = badges_save_backpack_credentials((object) $data); 1138 if (array_key_exists('userid', $data)) { 1139 $record = $DB->get_record('badge_backpack', ['userid' => $user->id]); 1140 } else { 1141 $record = $DB->get_records('badge_backpack'); 1142 } 1143 1144 if (!empty($mail) && !empty($password)) { 1145 // The backpack credentials are created if the given information is right. 1146 $this->assertNotEmpty($record); 1147 $this->assertEquals($data['externalbackpackid'], $return); 1148 } else if ($addbackpack) { 1149 // If no email and password are given, no backpack is created/modified. 1150 $this->assertEmpty($record); 1151 $this->assertEquals($data['externalbackpackid'], $return); 1152 } else { 1153 // There weren't fields to add to the backpack so no DB change is expected. 1154 $this->assertEmpty($record); 1155 $this->assertEquals(0, $return); 1156 } 1157 1158 // Confirm the existing backpack credential can be updated (if it has been created). 1159 if (!empty($record)) { 1160 $data['backpackemail'] = 'modified_' . $mail; 1161 $data['id'] = $record->id; 1162 $return = badges_save_backpack_credentials((object) $data); 1163 $record = $DB->get_record('badge_backpack', ['userid' => $user->id]); 1164 1165 $this->assertNotEmpty($record); 1166 $this->assertEquals($data['backpackemail'], $record->email); 1167 $this->assertEquals($data['externalbackpackid'], $return); 1168 } 1169 } 1170 1171 /** 1172 * Data provider for test_create_backpack_credentials(). 1173 * 1174 * @return array 1175 */ 1176 public function save_backpack_credentials_provider(): array { 1177 return [ 1178 'Empty fields' => [ 1179 false, 1180 ], 1181 'No backpack mail or password are defined' => [ 1182 true, 1183 ], 1184 'Both backpack mail and password are defined' => [ 1185 true, 'test@test.com', '1234', 1186 ], 1187 'Only backpack mail is defined (no password is given)' => [ 1188 true, 'test@test.com', null, 1189 ], 1190 'Only backpack password is defined (no mail is given)' => [ 1191 true, null, '1234' 1192 ], 1193 ]; 1194 } 1195 1196 /** 1197 * Test badges_save_external_backpack. 1198 * 1199 * @dataProvider badges_save_external_backpack_provider 1200 * @param array $data Backpack data to save. 1201 * @param bool $adduser True if a real user has to be used for creating the backpack; false otherwise. 1202 * @param bool $duplicates True if duplicates has to be tested too; false otherwise. 1203 */ 1204 public function test_badges_save_external_backpack(array $data, bool $adduser, bool $duplicates) { 1205 global $DB; 1206 1207 $this->resetAfterTest(); 1208 1209 $userid = 0; 1210 if ($adduser) { 1211 $user = $this->getDataGenerator()->create_user(); 1212 $userid = $user->id; 1213 $data['userid'] = $user->id; 1214 } 1215 1216 $result = badges_save_external_backpack((object) $data); 1217 $this->assertNotEquals(0, $result); 1218 $record = $DB->get_record('badge_external_backpack', ['id' => $result]); 1219 $this->assertEquals($record->backpackweburl, $data['backpackweburl']); 1220 $this->assertEquals($record->backpackapiurl, $data['backpackapiurl']); 1221 1222 $record = $DB->get_record('badge_backpack', ['externalbackpackid' => $result]); 1223 if (!array_key_exists('backpackemail', $data) && !array_key_exists('password', $data)) { 1224 $this->assertEmpty($record); 1225 $total = $DB->count_records('badge_backpack'); 1226 $this->assertEquals(0, $total); 1227 } else { 1228 $this->assertNotEmpty($record); 1229 $this->assertEquals($record->userid, $userid); 1230 } 1231 1232 if ($duplicates) { 1233 // We shouldn't be able to insert multiple external_backpacks with the same values. 1234 $this->expectException('dml_write_exception'); 1235 $result = badges_save_external_backpack((object)$data); 1236 } 1237 } 1238 1239 /** 1240 * Provider for test_badges_save_external_backpack 1241 * 1242 * @return array 1243 */ 1244 public function badges_save_external_backpack_provider() { 1245 $data = [ 1246 'apiversion' => 2, 1247 'backpackapiurl' => 'https://api.ca.badgr.io/v2', 1248 'backpackweburl' => 'https://ca.badgr.io', 1249 ]; 1250 return [ 1251 'Test without user and auth details. Check duplicates too' => [ 1252 'data' => $data, 1253 'adduser' => false, 1254 'duplicates' => true, 1255 ], 1256 'Test without user and auth details. No duplicates' => [ 1257 'data' => $data, 1258 'adduser' => false, 1259 'duplicates' => false, 1260 ], 1261 'Test with user and without auth details' => [ 1262 'data' => $data, 1263 'adduser' => true, 1264 'duplicates' => false, 1265 ], 1266 'Test with user and without auth details. Check duplicates too' => [ 1267 'data' => $data, 1268 'adduser' => true, 1269 'duplicates' => true, 1270 ], 1271 'Test with empty backpackemail, password and id' => [ 1272 'data' => array_merge($data, [ 1273 'backpackemail' => '', 1274 'password' => '', 1275 'id' => 0, 1276 ]), 1277 'adduser' => false, 1278 'duplicates' => false, 1279 ], 1280 'Test with empty backpackemail, password and id but with user' => [ 1281 'data' => array_merge($data, [ 1282 'backpackemail' => '', 1283 'password' => '', 1284 'id' => 0, 1285 ]), 1286 'adduser' => true, 1287 'duplicates' => false, 1288 ], 1289 'Test with auth details but without user' => [ 1290 'data' => array_merge($data, [ 1291 'backpackemail' => 'test@test.com', 1292 'password' => 'test', 1293 ]), 1294 'adduser' => false, 1295 'duplicates' => false, 1296 ], 1297 'Test with auth details and user' => [ 1298 'data' => array_merge($data, [ 1299 'backpackemail' => 'test@test.com', 1300 'password' => 'test', 1301 ]), 1302 'adduser' => true, 1303 'duplicates' => false, 1304 ], 1305 ]; 1306 } 1307 1308 /** 1309 * Test backpack creation/update with auth details provided 1310 * 1311 * @param boolean $isadmin 1312 * @param boolean $updatetest 1313 * @dataProvider badges_create_site_backpack_provider 1314 */ 1315 public function test_badges_create_site_backpack($isadmin, $updatetest) { 1316 global $DB; 1317 $this->resetAfterTest(); 1318 1319 $data = [ 1320 'apiversion' => 2, 1321 'backpackapiurl' => 'https://api.ca.badgr.io/v2', 1322 'backpackweburl' => 'https://ca.badgr.io', 1323 ]; 1324 1325 $data['backpackemail'] = 'test@test.com'; 1326 $data['password'] = 'test'; 1327 if ($isadmin || $updatetest) { 1328 $this->setAdminUser(); 1329 $lastmax = $DB->get_field_sql('SELECT MAX(sortorder) FROM {badge_external_backpack}'); 1330 $backpack = badges_create_site_backpack((object) $data); 1331 } 1332 1333 if ($isadmin) { 1334 if ($updatetest) { 1335 $record = $DB->get_record('badge_backpack', ['userid' => 0]); 1336 $data['badgebackpack'] = $record->id; 1337 $data['backpackapiurl'] = 'https://api.ca.badgr.io/v3'; 1338 badges_update_site_backpack($backpack, (object)$data); 1339 } 1340 $record = $DB->get_record('badge_external_backpack', ['id' => $backpack]); 1341 $this->assertEquals($data['backpackweburl'], $record->backpackweburl); 1342 $this->assertEquals($data['backpackapiurl'], $record->backpackapiurl); 1343 $this->assertEquals($lastmax + 1, $record->sortorder); 1344 $record = $DB->get_record('badge_backpack', ['userid' => 0]); 1345 $this->assertNotEmpty($record); 1346 } else { 1347 $user = $this->getDataGenerator()->create_user(); 1348 $this->setUser($user); 1349 $this->expectException('required_capability_exception'); 1350 if ($updatetest) { 1351 $result = badges_update_site_backpack($backpack, (object) $data); 1352 } else { 1353 $result = badges_create_site_backpack((object)$data); 1354 } 1355 } 1356 } 1357 1358 /** 1359 * Provider for test_badges_(create/update)_site_backpack 1360 */ 1361 public function badges_create_site_backpack_provider() { 1362 return [ 1363 "Test as admin user - creation test" => [true, true], 1364 "Test as admin user - update test" => [true, false], 1365 "Test as normal user - creation test" => [false, true], 1366 "Test as normal user - update test" => [false, false], 1367 ]; 1368 } 1369 1370 /** 1371 * Test the badges_open_badges_backpack_api with different backpacks 1372 */ 1373 public function test_badges_open_badges_backpack_api() { 1374 $this->resetAfterTest(); 1375 1376 $data = [ 1377 'apiversion' => 2, 1378 'backpackapiurl' => 'https://api.ca.badgr.io/v2', 1379 'backpackweburl' => 'https://ca.badgr.io', 1380 'sortorder' => 2, 1381 ]; 1382 1383 // Given a complete set of unique data, a new backpack and auth records should exist in the tables. 1384 $data['backpackemail'] = 'test@test.com'; 1385 $data['password'] = 'test'; 1386 $backpack1 = badges_save_external_backpack((object) $data); 1387 $data['backpackweburl'] = 'https://eu.badgr.io'; 1388 $data['backpackapiurl'] = 'https://api.eu.badgr.io/v2'; 1389 $data['apiversion'] = '2.1'; 1390 $data['sortorder'] = 3; 1391 $backpack2 = badges_save_external_backpack((object) $data); 1392 1393 // Move backpack2 to the first position to set it as primary site backpack. 1394 $this->move_backpack_to_first_position($backpack2); 1395 1396 // The default response should check the default site backpack api version. 1397 $this->assertEquals(2.1, badges_open_badges_backpack_api()); 1398 // Check the api version for the other backpack created. 1399 $this->assertEquals(2, badges_open_badges_backpack_api($backpack1)); 1400 $this->assertEquals(2.1, badges_open_badges_backpack_api($backpack2)); 1401 } 1402 1403 /** 1404 * Test the badges_get_site_backpack function 1405 */ 1406 public function test_badges_get_site_backpack() { 1407 $this->resetAfterTest(); 1408 $user = $this->getDataGenerator()->create_user(); 1409 $data = [ 1410 'apiversion' => '2', 1411 'backpackapiurl' => 'https://api.ca.badgr.io/v2', 1412 'backpackweburl' => 'https://ca.badgr.io', 1413 ]; 1414 $backpack1 = badges_save_external_backpack((object) $data); 1415 $data2 = array_merge($data, [ 1416 'backpackapiurl' => 'https://api.eu.badgr.io/v2', 1417 'backpackweburl' => 'https://eu.badgr.io', 1418 'backpackemail' => 'test@test.com', 1419 'password' => 'test', 1420 ]); 1421 $backpack2 = badges_save_external_backpack((object) $data2); 1422 $data3 = array_merge($data2, [ 1423 'userid' => $user->id, 1424 'externalbackpackid' => $backpack2, 1425 'backpackemail' => 'test2@test.com' 1426 ]); 1427 // In the following case, the id returned below equals backpack2. So we aren't storing it. 1428 badges_save_backpack_credentials((object) $data3); 1429 unset($data3['userid']); 1430 1431 // Get a site back based on the id returned from creation and no user id provided. 1432 $this->assertEquals($data, array_intersect($data, (array) badges_get_site_backpack($backpack1))); 1433 $this->assertEquals($data2, array_intersect($data2, (array) badges_get_site_backpack($backpack2))); 1434 $this->assertEquals($data2, array_intersect($data2, (array) badges_get_site_backpack($backpack2, 0))); 1435 $this->assertEquals($data3, array_intersect($data3, (array) badges_get_site_backpack($backpack2, $user->id))); 1436 1437 // Non-existent user backpack should return only configuration details and not auth details. 1438 $userbackpack = badges_get_site_backpack($backpack1, $user->id); 1439 $this->assertNull($userbackpack->badgebackpack); 1440 $this->assertNull($userbackpack->password); 1441 $this->assertNull($userbackpack->backpackemail); 1442 } 1443 1444 /** 1445 * Test the badges_get_user_backpack function 1446 */ 1447 public function test_badges_get_user_backpack() { 1448 $this->resetAfterTest(); 1449 $user = $this->getDataGenerator()->create_user(); 1450 $data = [ 1451 'apiversion' => '2', 1452 'backpackapiurl' => 'https://api.ca.badgr.io/v2', 1453 'backpackweburl' => 'https://ca.badgr.io', 1454 ]; 1455 $backpack1 = badges_save_external_backpack((object) $data); 1456 $data2 = array_merge($data, [ 1457 'backpackapiurl' => 'https://api.eu.badgr.io/v2', 1458 'backpackweburl' => 'https://eu.badgr.io', 1459 'backpackemail' => 'test@test.com', 1460 'password' => 'test', 1461 ]); 1462 $backpack2 = badges_save_external_backpack((object) $data2); 1463 $data3 = array_merge($data2, [ 1464 'userid' => $user->id, 1465 'externalbackpackid' => $backpack2, 1466 'backpackemail' => 'test2@test.com' 1467 ]); 1468 // In the following case, the id returned below equals backpack2. So we aren't storing it. 1469 badges_save_backpack_credentials((object) $data3); 1470 unset($data3['userid']); 1471 1472 // Currently logged in as admin. 1473 $this->assertEquals($data2, array_intersect($data2, (array) badges_get_user_backpack())); 1474 $this->assertEquals($data2, array_intersect($data2, (array) badges_get_user_backpack(0))); 1475 $this->assertEquals($data3, array_intersect($data3, (array) badges_get_user_backpack($user->id))); 1476 1477 // Non-existent user backpack should return nothing. 1478 $this->assertFalse(badges_get_user_backpack($backpack1, $user->id)); 1479 1480 // Login as user. 1481 $this->setUser($user); 1482 $this->assertEquals($data3, array_intersect($data3, (array) badges_get_user_backpack())); 1483 } 1484 1485 /** 1486 * Test the badges_get_site_primary_backpack function 1487 * 1488 * @param boolean $withauth Testing with authentication or not. 1489 * @dataProvider badges_get_site_primary_backpack_provider 1490 */ 1491 public function test_badges_get_site_primary_backpack($withauth) { 1492 $data = [ 1493 'apiversion' => '2', 1494 'backpackapiurl' => 'https://api.ca.badgr.io/v2', 1495 'backpackweburl' => 'https://ca.badgr.io', 1496 'sortorder' => '2', 1497 ]; 1498 if ($withauth) { 1499 $data = array_merge($data, [ 1500 'backpackemail' => 'test@test.com', 1501 'password' => 'test', 1502 ]); 1503 } 1504 $backpack = badges_save_external_backpack((object) $data); 1505 1506 // Check the backpack created is not the primary one. 1507 $sitebackpack = badges_get_site_primary_backpack(); 1508 $this->assertNotEquals($backpack, $sitebackpack->id); 1509 1510 // Move backpack to the first position to set it as primary site backpack. 1511 $this->move_backpack_to_first_position($backpack); 1512 1513 $sitebackpack = badges_get_site_primary_backpack(); 1514 $this->assertEquals($backpack, $sitebackpack->id); 1515 1516 if ($withauth) { 1517 $this->assertEquals($data, array_intersect($data, (array) $sitebackpack)); 1518 $this->assertEquals($data['password'], $sitebackpack->password); 1519 $this->assertEquals($data['backpackemail'], $sitebackpack->backpackemail); 1520 } else { 1521 $this->assertNull($sitebackpack->badgebackpack); 1522 $this->assertNull($sitebackpack->password); 1523 $this->assertNull($sitebackpack->backpackemail); 1524 } 1525 } 1526 1527 /** 1528 * Test the test_badges_get_site_primary_backpack function. 1529 * 1530 * @return array 1531 */ 1532 public function badges_get_site_primary_backpack_provider() { 1533 return [ 1534 "Test with auth details" => [true], 1535 "Test without auth details" => [false], 1536 ]; 1537 } 1538 1539 /** 1540 * Test badges_change_sortorder_backpacks(). 1541 * 1542 * @dataProvider badges_change_sortorder_backpacks_provider 1543 * @covers ::badges_change_sortorder_backpacks 1544 * 1545 * @param int $backpacktomove Backpack index to move (from 0 to 5). 1546 * @param int $direction Direction to move the backpack. 1547 * @param int|null $expectedsortorder Expected sortorder or null if an exception is expected. 1548 */ 1549 public function test_badges_change_sortorder_backpacks(int $backpacktomove, int $direction, ?int $expectedsortorder): void { 1550 global $DB; 1551 1552 $this->resetAfterTest(); 1553 $this->setAdminUser(); 1554 1555 // Create 5 more backpacks. 1556 for ($i = 0; $i < 5; $i++) { 1557 $data = new \stdClass(); 1558 $data->apiversion = OPEN_BADGES_V2P1; 1559 $data->backpackapiurl = "https://myurl$i.cat/ob/v2p1"; 1560 $data->backpackweburl = "https://myurl$i.cat"; 1561 badges_create_site_backpack($data); 1562 } 1563 1564 // Check there are 6 backpacks (1 pre-existing + 5 news). 1565 $total = $DB->count_records('badge_external_backpack'); 1566 $this->assertEquals(6, $total); 1567 $backpacks = array_values(badges_get_site_backpacks()); 1568 1569 if (is_null($expectedsortorder)) { 1570 $this->expectException('moodle_exception'); 1571 } 1572 1573 // Move the backpack. 1574 badges_change_sortorder_backpacks($backpacks[$backpacktomove]->id, $direction); 1575 1576 if (!is_null($expectedsortorder)) { 1577 $backpack = badges_get_site_backpack($backpacks[$backpacktomove]->id); 1578 $this->assertEquals($expectedsortorder, $backpack->sortorder); 1579 } 1580 } 1581 1582 /** 1583 * Provider for test_badges_change_sortorder_backpacks. 1584 * 1585 * @return array 1586 */ 1587 public function badges_change_sortorder_backpacks_provider(): array { 1588 return [ 1589 "Test up" => [ 1590 'backpacktomove' => 1, 1591 'direction' => BACKPACK_MOVE_UP, 1592 'expectedsortorder' => 1, 1593 ], 1594 "Test down" => [ 1595 'backpacktomove' => 1, 1596 'direction' => BACKPACK_MOVE_DOWN, 1597 'expectedsortorder' => 3, 1598 ], 1599 "Test up the very first element" => [ 1600 'backpacktomove' => 0, 1601 'direction' => BACKPACK_MOVE_UP, 1602 'expectedsortorder' => 1, 1603 ], 1604 "Test down the very last element" => [ 1605 'backpacktomove' => 5, 1606 'direction' => BACKPACK_MOVE_DOWN, 1607 'expectedsortorder' => 6, 1608 ], 1609 "Test with an invalid direction value" => [ 1610 'backpacktomove' => 1, 1611 'direction' => 10, 1612 'expectedsortorder' => null, 1613 ], 1614 ]; 1615 } 1616 1617 /** 1618 * Test the Badgr URL generator function 1619 * 1620 * @param mixed $type Type corresponding to the badge entites 1621 * @param string $expected Expected string result 1622 * @dataProvider badgr_open_url_generator 1623 */ 1624 public function test_badges_generate_badgr_open_url($type, $expected) { 1625 $data = [ 1626 'apiversion' => '2', 1627 'backpackapiurl' => 'https://api.ca.badgr.io/v2', 1628 'backpackweburl' => 'https://ca.badgr.io', 1629 'backpackemail' => 'test@test.com', 1630 'password' => 'test', 1631 ]; 1632 $backpack2 = badges_save_external_backpack((object) $data); 1633 $backpack = badges_get_site_backpack($backpack2); 1634 $this->assertEquals($expected, badges_generate_badgr_open_url($backpack, $type, 123455)); 1635 } 1636 1637 /** 1638 * Data provider for test_badges_generate_badgr_open_url 1639 * @return array 1640 */ 1641 public function badgr_open_url_generator() { 1642 return [ 1643 'Badgr Assertion URL test' => [ 1644 OPEN_BADGES_V2_TYPE_ASSERTION, "https://api.ca.badgr.io/public/assertions/123455" 1645 ], 1646 'Badgr Issuer URL test' => [ 1647 OPEN_BADGES_V2_TYPE_ISSUER, "https://api.ca.badgr.io/public/issuers/123455" 1648 ], 1649 'Badgr Badge URL test' => [ 1650 OPEN_BADGES_V2_TYPE_BADGE, "https://api.ca.badgr.io/public/badges/123455" 1651 ] 1652 ]; 1653 } 1654 1655 /** 1656 * Test badges_external_get_mapping function 1657 * 1658 * @param int $internalid The internal id of the mapping 1659 * @param int $externalid The external / remote ref to the mapping 1660 * @param mixed $expected The expected result from the function 1661 * @param string|null $field The field we are passing to the function. Null if we don't want to pass anything.ss 1662 * 1663 * @dataProvider badges_external_get_mapping_provider 1664 */ 1665 public function test_badges_external_get_mapping($internalid, $externalid, $expected, $field = null) { 1666 $data = [ 1667 'apiversion' => '2', 1668 'backpackapiurl' => 'https://api.ca.badgr.io/v2', 1669 'backpackweburl' => 'https://ca.badgr.io', 1670 'backpackemail' => 'test@test.com', 1671 'password' => 'test', 1672 ]; 1673 $backpack2 = badges_save_external_backpack((object) $data); 1674 badges_external_create_mapping($backpack2, OPEN_BADGES_V2_TYPE_BADGE, $internalid, $externalid); 1675 $expected = $expected == "id" ? $backpack2 : $expected; 1676 if ($field) { 1677 $this->assertEquals($expected, badges_external_get_mapping($backpack2, OPEN_BADGES_V2_TYPE_BADGE, $internalid, $field)); 1678 } else { 1679 $this->assertEquals($expected, badges_external_get_mapping($backpack2, OPEN_BADGES_V2_TYPE_BADGE, $internalid)); 1680 } 1681 } 1682 1683 /** 1684 * Data provider for badges_external_get_mapping_provider 1685 * 1686 * @return array 1687 */ 1688 public function badges_external_get_mapping_provider() { 1689 return [ 1690 "Get the site backpack value" => [ 1691 1234, 4321, 'id', 'sitebackpackid' 1692 ], 1693 "Get the type of the mapping" => [ 1694 1234, 4321, OPEN_BADGES_V2_TYPE_BADGE, 'type' 1695 ], 1696 "Get the externalid of the mapping" => [ 1697 1234, 4321, 4321, 'externalid' 1698 ], 1699 "Get the externalid of the mapping without providing a param" => [ 1700 1234, 4321, 4321, null 1701 ], 1702 "Get the internalid of the mapping" => [ 1703 1234, 4321, 1234, 'internalid' 1704 ] 1705 ]; 1706 } 1707 1708 /** 1709 * Move the backpack to the first position, to set it as primary site backpack. 1710 * 1711 * @param int $backpackid The backpack identifier. 1712 */ 1713 private function move_backpack_to_first_position(int $backpackid): void { 1714 $backpack = badges_get_site_backpack($backpackid); 1715 while ($backpack->sortorder > 1) { 1716 badges_change_sortorder_backpacks($backpackid, BACKPACK_MOVE_UP); 1717 $backpack = badges_get_site_backpack($backpackid); 1718 } 1719 } 1720 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body