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 namespace tool_uploadcourse; 18 19 use tool_uploadcourse_processor; 20 use tool_uploadcourse_course; 21 22 /** 23 * Course test case. 24 * 25 * @package tool_uploadcourse 26 * @copyright 2013 Frédéric Massart 27 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or late 28 */ 29 class course_test extends \advanced_testcase { 30 31 public function test_proceed_without_prepare() { 32 $this->resetAfterTest(true); 33 $mode = tool_uploadcourse_processor::MODE_CREATE_NEW; 34 $updatemode = tool_uploadcourse_processor::UPDATE_NOTHING; 35 $data = array(); 36 $co = new tool_uploadcourse_course($mode, $updatemode, $data); 37 $this->expectException(\coding_exception::class); 38 $co->proceed(); 39 } 40 41 public function test_proceed_when_prepare_failed() { 42 $this->resetAfterTest(true); 43 $mode = tool_uploadcourse_processor::MODE_CREATE_NEW; 44 $updatemode = tool_uploadcourse_processor::UPDATE_NOTHING; 45 $data = array(); 46 $co = new tool_uploadcourse_course($mode, $updatemode, $data); 47 $this->assertFalse($co->prepare()); 48 $this->expectException(\moodle_exception::class); 49 $co->proceed(); 50 } 51 52 public function test_proceed_when_already_started() { 53 $this->resetAfterTest(true); 54 $mode = tool_uploadcourse_processor::MODE_CREATE_NEW; 55 $updatemode = tool_uploadcourse_processor::UPDATE_NOTHING; 56 $data = array('shortname' => 'test', 'fullname' => 'New course', 'summary' => 'New', 'category' => 1); 57 $co = new tool_uploadcourse_course($mode, $updatemode, $data); 58 $this->assertTrue($co->prepare()); 59 $co->proceed(); 60 $this->expectException('coding_exception'); 61 $co->proceed(); 62 } 63 64 public function test_invalid_shortname() { 65 $this->resetAfterTest(true); 66 $mode = tool_uploadcourse_processor::MODE_CREATE_NEW; 67 $updatemode = tool_uploadcourse_processor::UPDATE_NOTHING; 68 $data = array('shortname' => '<invalid>', 'fullname' => 'New course', 'summary' => 'New', 'category' => 1); 69 $co = new tool_uploadcourse_course($mode, $updatemode, $data); 70 $this->assertFalse($co->prepare()); 71 $this->assertArrayHasKey('invalidshortname', $co->get_errors()); 72 } 73 74 public function test_invalid_shortname_too_long() { 75 $this->resetAfterTest(); 76 77 $mode = tool_uploadcourse_processor::MODE_CREATE_NEW; 78 $updatemode = tool_uploadcourse_processor::UPDATE_NOTHING; 79 80 $upload = new tool_uploadcourse_course($mode, $updatemode, [ 81 'category' => 1, 82 'fullname' => 'New course', 83 'shortname' => str_repeat('X', 2000), 84 ]); 85 86 $this->assertFalse($upload->prepare()); 87 $this->assertArrayHasKey('invalidshortnametoolong', $upload->get_errors()); 88 } 89 90 public function test_invalid_fullname_too_long() { 91 $this->resetAfterTest(); 92 93 $mode = tool_uploadcourse_processor::MODE_CREATE_NEW; 94 $updatemode = tool_uploadcourse_processor::UPDATE_NOTHING; 95 96 $upload = new tool_uploadcourse_course($mode, $updatemode, [ 97 'category' => 1, 98 'fullname' => str_repeat('X', 2000), 99 ]); 100 101 $this->assertFalse($upload->prepare()); 102 $this->assertArrayHasKey('invalidfullnametoolong', $upload->get_errors()); 103 } 104 105 public function test_invalid_visibility() { 106 $this->resetAfterTest(true); 107 $mode = tool_uploadcourse_processor::MODE_CREATE_NEW; 108 $updatemode = tool_uploadcourse_processor::UPDATE_NOTHING; 109 $data = array('shortname' => 'test', 'fullname' => 'New course', 'summary' => 'New', 'category' => 1, 'visible' => 2); 110 $co = new tool_uploadcourse_course($mode, $updatemode, $data); 111 $this->assertFalse($co->prepare()); 112 $this->assertArrayHasKey('invalidvisibilitymode', $co->get_errors()); 113 } 114 115 /** 116 * Test setting 'downloadcontent' field when the feature is globally disabled 117 */ 118 public function test_downloadcontent_disabled(): void { 119 $this->resetAfterTest(); 120 $this->setAdminUser(); 121 122 set_config('downloadcoursecontentallowed', 0); 123 124 $mode = tool_uploadcourse_processor::MODE_CREATE_NEW; 125 $updatemode = tool_uploadcourse_processor::UPDATE_NOTHING; 126 127 $upload = new tool_uploadcourse_course($mode, $updatemode, [ 128 'category' => 1, 129 'fullname' => 'Testing', 130 'shortname' => 'T101', 131 'downloadcontent' => DOWNLOAD_COURSE_CONTENT_ENABLED, 132 ]); 133 134 $this->assertFalse($upload->prepare()); 135 $this->assertArrayHasKey('downloadcontentnotallowed', $upload->get_errors()); 136 } 137 138 /** 139 * Test setting 'downloadcontent' field when user doesn't have required capability 140 */ 141 public function test_downloadcontent_capability(): void { 142 global $DB; 143 144 $this->resetAfterTest(); 145 146 set_config('downloadcoursecontentallowed', 1); 147 148 // Create category in which to create the new course. 149 $category = $this->getDataGenerator()->create_category(); 150 $categorycontext = \context_coursecat::instance($category->id); 151 152 $user = $this->getDataGenerator()->create_user(); 153 $this->setUser($user); 154 155 // Assign the user as a manager of the category, disable ability to configure course content download. 156 $roleid = $DB->get_field('role', 'id', ['shortname' => 'manager']); 157 role_assign($roleid, $user->id, $categorycontext); 158 role_change_permission($roleid, $categorycontext, 'moodle/course:configuredownloadcontent', CAP_PROHIBIT); 159 160 $mode = tool_uploadcourse_processor::MODE_CREATE_NEW; 161 $updatemode = tool_uploadcourse_processor::UPDATE_NOTHING; 162 163 $upload = new tool_uploadcourse_course($mode, $updatemode, [ 164 'category' => $category->id, 165 'fullname' => 'Testing', 166 'shortname' => 'T101', 167 'downloadcontent' => DOWNLOAD_COURSE_CONTENT_ENABLED, 168 ]); 169 170 $this->assertFalse($upload->prepare()); 171 $this->assertArrayHasKey('downloadcontentnotallowed', $upload->get_errors()); 172 } 173 174 /** 175 * Test setting 'downloadcontent' field to an invalid value 176 */ 177 public function test_downloadcontent_invalid(): void { 178 $this->resetAfterTest(); 179 $this->setAdminUser(); 180 181 set_config('downloadcoursecontentallowed', 1); 182 183 $mode = tool_uploadcourse_processor::MODE_CREATE_NEW; 184 $updatemode = tool_uploadcourse_processor::UPDATE_NOTHING; 185 186 $upload = new tool_uploadcourse_course($mode, $updatemode, [ 187 'category' => 1, 188 'fullname' => 'Testing', 189 'shortname' => 'T101', 190 'downloadcontent' => 42, 191 ]); 192 193 $this->assertFalse($upload->prepare()); 194 $this->assertArrayHasKey('invaliddownloadcontent', $upload->get_errors()); 195 } 196 197 public function test_create() { 198 global $DB; 199 $this->resetAfterTest(true); 200 201 // Existing course. 202 $c1 = $this->getDataGenerator()->create_course(array('shortname' => 'c1', 'summary' => 'Yay!')); 203 $this->assertTrue($DB->record_exists('course', array('shortname' => 'c1'))); 204 205 $updatemode = tool_uploadcourse_processor::UPDATE_NOTHING; 206 207 // Try to add a new course. 208 $mode = tool_uploadcourse_processor::MODE_CREATE_NEW; 209 $data = array('shortname' => 'newcourse', 'fullname' => 'New course', 'summary' => 'New', 'category' => 1); 210 $co = new tool_uploadcourse_course($mode, $updatemode, $data); 211 $this->assertTrue($co->prepare()); 212 $this->assertFalse($DB->record_exists('course', array('shortname' => 'newcourse'))); 213 $co->proceed(); 214 $course = $DB->get_record('course', array('shortname' => 'newcourse'), '*', MUST_EXIST); 215 $this->assertEquals(0, course_get_format($course)->get_course()->coursedisplay); 216 217 // Try to add a new course, that already exists. 218 $coursecount = $DB->count_records('course', array()); 219 $mode = tool_uploadcourse_processor::MODE_CREATE_NEW; 220 $data = array('shortname' => 'c1', 'fullname' => 'C1FN', 'summary' => 'C1', 'category' => 1); 221 $co = new tool_uploadcourse_course($mode, $updatemode, $data); 222 $this->assertFalse($co->prepare()); 223 $this->assertArrayHasKey('courseexistsanduploadnotallowed', $co->get_errors()); 224 $this->assertEquals($coursecount, $DB->count_records('course', array())); 225 $this->assertNotEquals('C1', $DB->get_field_select('course', 'summary', 'shortname = :s', array('s' => 'c1'))); 226 227 // Try to add new with shortname incrementation. 228 $mode = tool_uploadcourse_processor::MODE_CREATE_ALL; 229 $data = array('shortname' => 'c1', 'fullname' => 'C1FN', 'summary' => 'C1', 'category' => 1); 230 $co = new tool_uploadcourse_course($mode, $updatemode, $data); 231 $this->assertTrue($co->prepare()); 232 $co->proceed(); 233 $this->assertTrue($DB->record_exists('course', array('shortname' => 'c2'))); 234 235 // Add a new course with non-default course format option. 236 $mode = tool_uploadcourse_processor::MODE_CREATE_NEW; 237 $data = array('shortname' => 'c3', 'fullname' => 'C3', 'summary' => 'New c3', 'category' => 1, 238 'format' => 'weeks', 'coursedisplay' => 1); 239 $co = new tool_uploadcourse_course($mode, $updatemode, $data); 240 $this->assertTrue($co->prepare()); 241 $co->proceed(); 242 $course = $DB->get_record('course', array('shortname' => 'c3'), '*', MUST_EXIST); 243 $this->assertEquals(1, course_get_format($course)->get_course()->coursedisplay); 244 } 245 246 public function test_create_with_sections() { 247 global $DB; 248 $this->resetAfterTest(true); 249 $updatemode = tool_uploadcourse_processor::UPDATE_NOTHING; 250 $defaultnumsections = get_config('moodlecourse', 'numsections'); 251 252 // Add new course, make sure default number of sections is created. 253 $mode = tool_uploadcourse_processor::MODE_CREATE_NEW; 254 $data = array('shortname' => 'newcourse1', 'fullname' => 'New course1', 'format' => 'topics', 'category' => 1); 255 $co = new tool_uploadcourse_course($mode, $updatemode, $data); 256 $this->assertTrue($co->prepare()); 257 $co->proceed(); 258 $courseid = $DB->get_field('course', 'id', array('shortname' => 'newcourse1')); 259 $this->assertNotEmpty($courseid); 260 $this->assertEquals($defaultnumsections + 1, 261 $DB->count_records('course_sections', ['course' => $courseid])); 262 263 // Add new course specifying number of sections. 264 $mode = tool_uploadcourse_processor::MODE_CREATE_NEW; 265 $data = array('shortname' => 'newcourse2', 'fullname' => 'New course2', 'format' => 'topics', 'category' => 1, 266 'numsections' => 15); 267 $co = new tool_uploadcourse_course($mode, $updatemode, $data); 268 $this->assertTrue($co->prepare()); 269 $co->proceed(); 270 $courseid = $DB->get_field('course', 'id', array('shortname' => 'newcourse2')); 271 $this->assertNotEmpty($courseid); 272 $this->assertEquals(15 + 1, 273 $DB->count_records('course_sections', ['course' => $courseid])); 274 } 275 276 public function test_delete() { 277 global $DB; 278 $this->resetAfterTest(true); 279 280 $c1 = $this->getDataGenerator()->create_course(); 281 $c2 = $this->getDataGenerator()->create_course(); 282 283 $this->assertTrue($DB->record_exists('course', array('shortname' => $c1->shortname))); 284 $this->assertFalse($DB->record_exists('course', array('shortname' => 'DoesNotExist'))); 285 286 $mode = tool_uploadcourse_processor::MODE_CREATE_OR_UPDATE; 287 $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY; 288 289 // Try delete when option not available. 290 $importoptions = array('candelete' => false); 291 $data = array('shortname' => $c1->shortname, 'delete' => 1); 292 $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions); 293 $this->assertFalse($co->prepare()); 294 $this->assertArrayHasKey('coursedeletionnotallowed', $co->get_errors()); 295 $this->assertTrue($DB->record_exists('course', array('shortname' => $c1->shortname))); 296 297 // Try delete when not requested. 298 $importoptions = array('candelete' => true); 299 $data = array('shortname' => $c1->shortname, 'delete' => 0); 300 $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions); 301 $this->assertTrue($co->prepare()); 302 $co->proceed(); 303 $this->assertTrue($DB->record_exists('course', array('shortname' => $c1->shortname))); 304 305 // Try delete when requested. 306 $importoptions = array('candelete' => true); 307 $data = array('shortname' => $c1->shortname, 'delete' => 1); 308 $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions); 309 $this->assertTrue($co->prepare()); 310 $co->proceed(); 311 $this->assertFalse($DB->record_exists('course', array('shortname' => $c1->shortname))); 312 $this->assertTrue($DB->record_exists('course', array('shortname' => $c2->shortname))); 313 314 // Try deleting non-existing record, this should not fail. 315 $data = array('shortname' => 'DoesNotExist', 'delete' => 1); 316 $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions); 317 $this->assertFalse($co->prepare()); 318 $this->assertArrayHasKey('cannotdeletecoursenotexist', $co->get_errors()); 319 } 320 321 public function test_update() { 322 global $DB; 323 $this->resetAfterTest(true); 324 325 $c1 = $this->getDataGenerator()->create_course(array('shortname' => 'c1')); 326 327 // Try to update with existing shortnames, not allowing creation, and updating nothing. 328 $mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY; 329 $updatemode = tool_uploadcourse_processor::UPDATE_NOTHING; 330 $data = array('shortname' => 'c1', 'fullname' => 'New fullname'); 331 $co = new tool_uploadcourse_course($mode, $updatemode, $data); 332 $this->assertFalse($co->prepare()); 333 $this->assertArrayHasKey('updatemodedoessettonothing', $co->get_errors()); 334 335 // Try to update with non-existing shortnames. 336 $mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY; 337 $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY; 338 $data = array('shortname' => 'DoesNotExist', 'fullname' => 'New fullname'); 339 $co = new tool_uploadcourse_course($mode, $updatemode, $data); 340 $this->assertFalse($co->prepare()); 341 $this->assertArrayHasKey('coursedoesnotexistandcreatenotallowed', $co->get_errors()); 342 343 // Try a proper update. 344 $mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY; 345 $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY; 346 $data = array('shortname' => 'c1', 'fullname' => 'New fullname'); 347 $co = new tool_uploadcourse_course($mode, $updatemode, $data); 348 $this->assertTrue($co->prepare()); 349 $co->proceed(); 350 $this->assertEquals('New fullname', $DB->get_field_select('course', 'fullname', 'shortname = :s', array('s' => 'c1'))); 351 352 // Try a proper update with defaults. 353 $mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY; 354 $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_OR_DEFAUTLS; 355 $data = array('shortname' => 'c1', 'fullname' => 'Another fullname'); 356 $defaults = array('fullname' => 'Not this one', 'summary' => 'Awesome summary'); 357 $co = new tool_uploadcourse_course($mode, $updatemode, $data, $defaults); 358 $this->assertTrue($co->prepare()); 359 $co->proceed(); 360 $this->assertEquals('Another fullname', $DB->get_field_select('course', 'fullname', 'shortname = :s', array('s' => 'c1'))); 361 $this->assertEquals('Awesome summary', $DB->get_field_select('course', 'summary', 'shortname = :s', array('s' => 'c1'))); 362 363 // Try a proper update missing only. 364 $mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY; 365 $updatemode = tool_uploadcourse_processor::UPDATE_MISSING_WITH_DATA_OR_DEFAUTLS; 366 $DB->set_field('course', 'summary', '', array('shortname' => 'c1')); 367 $this->assertEquals('', $DB->get_field_select('course', 'summary', 'shortname = :s', array('s' => 'c1'))); 368 $data = array('shortname' => 'c1', 'summary' => 'Fill in summary'); 369 $defaults = array('summary' => 'Do not use this summary'); 370 $co = new tool_uploadcourse_course($mode, $updatemode, $data, $defaults); 371 $this->assertTrue($co->prepare()); 372 $co->proceed(); 373 $this->assertEquals('Fill in summary', $DB->get_field_select('course', 'summary', 'shortname = :s', array('s' => 'c1'))); 374 375 // Try a proper update missing only using defaults. 376 $mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY; 377 $updatemode = tool_uploadcourse_processor::UPDATE_MISSING_WITH_DATA_OR_DEFAUTLS; 378 $DB->set_field('course', 'summary', '', array('shortname' => 'c1')); 379 $this->assertEquals('', $DB->get_field_select('course', 'summary', 'shortname = :s', array('s' => 'c1'))); 380 $data = array('shortname' => 'c1'); 381 $defaults = array('summary' => 'Use this summary'); 382 $co = new tool_uploadcourse_course($mode, $updatemode, $data, $defaults); 383 $this->assertTrue($co->prepare()); 384 $co->proceed(); 385 $this->assertEquals('Use this summary', $DB->get_field_select('course', 'summary', 'shortname = :s', array('s' => 'c1'))); 386 387 // Update course format option. 388 $mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY; 389 $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY; 390 $data = array('shortname' => 'c1', 'coursedisplay' => 1); 391 $co = new tool_uploadcourse_course($mode, $updatemode, $data); 392 $this->assertTrue($co->prepare()); 393 $co->proceed(); 394 $course = $DB->get_record('course', array('shortname' => 'c1'), '*', MUST_EXIST); 395 $this->assertEquals(1, course_get_format($course)->get_course()->coursedisplay); 396 } 397 398 public function test_data_saved() { 399 global $DB; 400 401 $this->resetAfterTest(true); 402 $this->setAdminUser(); // To avoid warnings related to 'moodle/course:setforcedlanguage' capability check. 403 404 set_config('downloadcoursecontentallowed', 1); 405 406 // Create. 407 $mode = tool_uploadcourse_processor::MODE_CREATE_NEW; 408 $updatemode = tool_uploadcourse_processor::UPDATE_NOTHING; 409 $data = array( 410 'shortname' => 'c1', 411 'fullname' => 'Fullname', 412 'category' => '1', 413 'visible' => '0', 414 'downloadcontent' => DOWNLOAD_COURSE_CONTENT_DISABLED, 415 'idnumber' => '123abc', 416 'summary' => 'Summary', 417 'format' => 'topics', 418 'theme' => 'afterburner', 419 'lang' => 'en', 420 'newsitems' => '7', 421 'showgrades' => '0', 422 'showreports' => '1', 423 'legacyfiles' => '1', 424 'maxbytes' => '1234', 425 'groupmode' => '2', 426 'groupmodeforce' => '1', 427 'enablecompletion' => '1', 428 'showactivitydates' => '1', 429 'tags' => 'Cat, Dog', 430 431 'role_teacher' => 'Knight', 432 'role_manager' => 'Jedi', 433 434 'enrolment_1' => 'guest', 435 'enrolment_2' => 'self', 436 'enrolment_2_roleid' => '1', 437 'enrolment_3' => 'manual', 438 'enrolment_3_disable' => '1', 439 ); 440 441 // There should be a start date if there is a end date. 442 $data['enddate'] = '7 June 1990'; 443 $co = new tool_uploadcourse_course($mode, $updatemode, $data); 444 $this->assertFalse($co->prepare()); 445 $this->assertArrayHasKey('nostartdatenoenddate', $co->get_errors()); 446 447 $data['startdate'] = '8 June 1990'; 448 $co = new tool_uploadcourse_course($mode, $updatemode, $data); 449 $this->assertFalse($co->prepare()); 450 $this->assertArrayHasKey('enddatebeforestartdate', $co->get_errors()); 451 452 // They are correct now. 453 $data['enddate'] = '18 June 1990'; 454 455 $this->assertFalse($DB->record_exists('course', array('shortname' => 'c1'))); 456 $co = new tool_uploadcourse_course($mode, $updatemode, $data); 457 $this->assertTrue($co->prepare()); 458 $co->proceed(); 459 $this->assertTrue($DB->record_exists('course', array('shortname' => 'c1'))); 460 $course = $DB->get_record('course', array('shortname' => 'c1')); 461 $ctx = \context_course::instance($course->id); 462 463 $this->assertEquals($data['fullname'], $course->fullname); 464 $this->assertEquals($data['category'], $course->category); 465 $this->assertEquals($data['visible'], $course->visible); 466 $this->assertEquals($data['downloadcontent'], $course->downloadcontent); 467 $this->assertEquals(mktime(0, 0, 0, 6, 8, 1990), $course->startdate); 468 $this->assertEquals(mktime(0, 0, 0, 6, 18, 1990), $course->enddate); 469 $this->assertEquals($data['idnumber'], $course->idnumber); 470 $this->assertEquals($data['summary'], $course->summary); 471 $this->assertEquals($data['format'], $course->format); 472 $this->assertEquals($data['theme'], $course->theme); 473 $this->assertEquals($data['lang'], $course->lang); 474 $this->assertEquals($data['newsitems'], $course->newsitems); 475 $this->assertEquals($data['showgrades'], $course->showgrades); 476 $this->assertEquals($data['showreports'], $course->showreports); 477 $this->assertEquals($data['legacyfiles'], $course->legacyfiles); 478 $this->assertEquals($data['maxbytes'], $course->maxbytes); 479 $this->assertEquals($data['groupmode'], $course->groupmode); 480 $this->assertEquals($data['groupmodeforce'], $course->groupmodeforce); 481 $this->assertEquals($data['enablecompletion'], $course->enablecompletion); 482 $this->assertEquals($data['showactivitydates'], $course->showactivitydates); 483 $this->assertEquals($data['tags'], join(', ', \core_tag_tag::get_item_tags_array('core', 'course', $course->id))); 484 485 // Roles. 486 $roleids = array(); 487 $roles = get_all_roles(); 488 foreach ($roles as $role) { 489 $roleids[$role->shortname] = $role->id; 490 } 491 $this->assertEquals('Knight', $DB->get_field_select('role_names', 'name', 492 'roleid = :roleid AND contextid = :ctxid', array('ctxid' => $ctx->id, 'roleid' => $roleids['teacher']))); 493 $this->assertEquals('Jedi', $DB->get_field_select('role_names', 'name', 494 'roleid = :roleid AND contextid = :ctxid', array('ctxid' => $ctx->id, 'roleid' => $roleids['manager']))); 495 496 // Enrolment methods. 497 $enroldata = array(); 498 $instances = enrol_get_instances($course->id, false); 499 $this->assertCount(3, $instances); 500 foreach ($instances as $instance) { 501 $enroldata[$instance->enrol] = $instance; 502 } 503 504 $this->assertNotEmpty($enroldata['guest']); 505 $this->assertEquals(ENROL_INSTANCE_ENABLED, $enroldata['guest']->status); 506 $this->assertNotEmpty($enroldata['self']); 507 $this->assertEquals($data['enrolment_2_roleid'], $enroldata['self']->roleid); 508 $this->assertEquals(ENROL_INSTANCE_ENABLED, $enroldata['self']->status); 509 $this->assertNotEmpty($enroldata['manual']); 510 $this->assertEquals(ENROL_INSTANCE_DISABLED, $enroldata['manual']->status); 511 512 // Update existing course. 513 $cat = $this->getDataGenerator()->create_category(); 514 $mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY; 515 $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY; 516 $data = array( 517 'shortname' => 'c1', 518 'fullname' => 'Fullname 2', 519 'category' => $cat->id, 520 'visible' => '1', 521 'downloadcontent' => DOWNLOAD_COURSE_CONTENT_ENABLED, 522 'idnumber' => 'changeidn', 523 'summary' => 'Summary 2', 524 'format' => 'topics', 525 'theme' => 'classic', 526 'lang' => '', 527 'newsitems' => '2', 528 'showgrades' => '1', 529 'showreports' => '0', 530 'legacyfiles' => '0', 531 'maxbytes' => '4321', 532 'groupmode' => '1', 533 'groupmodeforce' => '0', 534 'enablecompletion' => '0', 535 'showactivitydates' => '0', 536 537 'role_teacher' => 'Teacher', 538 'role_manager' => 'Manager', 539 540 'enrolment_1' => 'guest', 541 'enrolment_1_disable' => '1', 542 'enrolment_2' => 'self', 543 'enrolment_2_roleid' => '2', 544 'enrolment_3' => 'manual', 545 'enrolment_3_delete' => '1', 546 ); 547 548 $this->assertTrue($DB->record_exists('course', array('shortname' => 'c1'))); 549 550 $data['enddate'] = '31 June 1984'; 551 // Previous start and end dates are 8 and 18 June 1990. 552 $co = new tool_uploadcourse_course($mode, $updatemode, $data); 553 $this->assertFalse($co->prepare()); 554 $this->assertArrayHasKey('enddatebeforestartdate', $co->get_errors()); 555 556 $data['startdate'] = '19 June 1990'; 557 $co = new tool_uploadcourse_course($mode, $updatemode, $data); 558 $this->assertFalse($co->prepare()); 559 $this->assertArrayHasKey('enddatebeforestartdate', $co->get_errors()); 560 561 // They are correct now. 562 $data['startdate'] = '11 June 1984'; 563 564 $co = new tool_uploadcourse_course($mode, $updatemode, $data); 565 $this->assertTrue($co->prepare()); 566 $co->proceed(); 567 $course = $DB->get_record('course', array('shortname' => 'c1')); 568 $ctx = \context_course::instance($course->id); 569 570 $this->assertEquals($data['fullname'], $course->fullname); 571 $this->assertEquals($data['category'], $course->category); 572 $this->assertEquals($data['visible'], $course->visible); 573 $this->assertEquals($data['downloadcontent'], $course->downloadcontent); 574 $this->assertEquals(mktime(0, 0, 0, 6, 11, 1984), $course->startdate); 575 $this->assertEquals(mktime(0, 0, 0, 6, 31, 1984), $course->enddate); 576 $this->assertEquals($data['idnumber'], $course->idnumber); 577 $this->assertEquals($data['summary'], $course->summary); 578 $this->assertEquals($data['format'], $course->format); 579 $this->assertEquals($data['theme'], $course->theme); 580 $this->assertEquals($data['lang'], $course->lang); 581 $this->assertEquals($data['newsitems'], $course->newsitems); 582 $this->assertEquals($data['showgrades'], $course->showgrades); 583 $this->assertEquals($data['showreports'], $course->showreports); 584 $this->assertEquals($data['legacyfiles'], $course->legacyfiles); 585 $this->assertEquals($data['maxbytes'], $course->maxbytes); 586 $this->assertEquals($data['groupmode'], $course->groupmode); 587 $this->assertEquals($data['groupmodeforce'], $course->groupmodeforce); 588 $this->assertEquals($data['enablecompletion'], $course->enablecompletion); 589 $this->assertEquals($data['showactivitydates'], $course->showactivitydates); 590 591 // Roles. 592 $roleids = array(); 593 $roles = get_all_roles(); 594 foreach ($roles as $role) { 595 $roleids[$role->shortname] = $role->id; 596 } 597 $this->assertEquals('Teacher', $DB->get_field_select('role_names', 'name', 598 'roleid = :roleid AND contextid = :ctxid', array('ctxid' => $ctx->id, 'roleid' => $roleids['teacher']))); 599 $this->assertEquals('Manager', $DB->get_field_select('role_names', 'name', 600 'roleid = :roleid AND contextid = :ctxid', array('ctxid' => $ctx->id, 'roleid' => $roleids['manager']))); 601 602 // Enrolment methods. 603 $enroldata = array(); 604 $instances = enrol_get_instances($course->id, false); 605 $this->assertCount(2, $instances); 606 foreach ($instances as $instance) { 607 $enroldata[$instance->enrol] = $instance; 608 } 609 610 $this->assertNotEmpty($enroldata['guest']); 611 $this->assertEquals(ENROL_INSTANCE_DISABLED, $enroldata['guest']->status); 612 $this->assertNotEmpty($enroldata['self']); 613 $this->assertEquals($data['enrolment_2_roleid'], $enroldata['self']->roleid); 614 $this->assertEquals(ENROL_INSTANCE_ENABLED, $enroldata['self']->status); 615 } 616 617 public function test_default_data_saved() { 618 global $DB; 619 620 $this->resetAfterTest(true); 621 $this->setAdminUser(); 622 623 set_config('downloadcoursecontentallowed', 1); 624 625 // Create. 626 $mode = tool_uploadcourse_processor::MODE_CREATE_NEW; 627 $updatemode = tool_uploadcourse_processor::UPDATE_NOTHING; 628 $data = array( 629 'shortname' => 'c1', 630 ); 631 $defaultdata = array( 632 'fullname' => 'Fullname', 633 'category' => '1', 634 'visible' => '0', 635 'downloadcontent' => DOWNLOAD_COURSE_CONTENT_DISABLED, 636 'startdate' => 644803200, 637 'enddate' => 645667200, 638 'idnumber' => '123abc', 639 'summary' => 'Summary', 640 'format' => 'topics', 641 'theme' => 'afterburner', 642 'lang' => 'en', 643 'newsitems' => '7', 644 'showgrades' => '0', 645 'showreports' => '1', 646 'legacyfiles' => '1', 647 'maxbytes' => '1234', 648 'groupmode' => '2', 649 'groupmodeforce' => '1', 650 'enablecompletion' => '1', 651 'showactivitydates' => '1', 652 ); 653 654 $this->assertFalse($DB->record_exists('course', array('shortname' => 'c1'))); 655 $co = new tool_uploadcourse_course($mode, $updatemode, $data, $defaultdata); 656 $this->assertTrue($co->prepare()); 657 $co->proceed(); 658 $this->assertTrue($DB->record_exists('course', array('shortname' => 'c1'))); 659 $course = $DB->get_record('course', array('shortname' => 'c1')); 660 $ctx = \context_course::instance($course->id); 661 662 $this->assertEquals($defaultdata['fullname'], $course->fullname); 663 $this->assertEquals($defaultdata['category'], $course->category); 664 $this->assertEquals($defaultdata['visible'], $course->visible); 665 $this->assertEquals($defaultdata['downloadcontent'], $course->downloadcontent); 666 $this->assertEquals($defaultdata['startdate'], $course->startdate); 667 $this->assertEquals($defaultdata['enddate'], $course->enddate); 668 $this->assertEquals($defaultdata['idnumber'], $course->idnumber); 669 $this->assertEquals($defaultdata['summary'], $course->summary); 670 $this->assertEquals($defaultdata['format'], $course->format); 671 $this->assertEquals($defaultdata['theme'], $course->theme); 672 $this->assertEquals($defaultdata['lang'], $course->lang); 673 $this->assertEquals($defaultdata['newsitems'], $course->newsitems); 674 $this->assertEquals($defaultdata['showgrades'], $course->showgrades); 675 $this->assertEquals($defaultdata['showreports'], $course->showreports); 676 $this->assertEquals($defaultdata['legacyfiles'], $course->legacyfiles); 677 $this->assertEquals($defaultdata['maxbytes'], $course->maxbytes); 678 $this->assertEquals($defaultdata['groupmode'], $course->groupmode); 679 $this->assertEquals($defaultdata['groupmodeforce'], $course->groupmodeforce); 680 $this->assertEquals($defaultdata['enablecompletion'], $course->enablecompletion); 681 $this->assertEquals($defaultdata['showactivitydates'], $course->showactivitydates); 682 683 // Update. 684 $cat = $this->getDataGenerator()->create_category(); 685 $mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY; 686 $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_OR_DEFAUTLS; 687 $data = array( 688 'shortname' => 'c1', 689 ); 690 $defaultdata = array( 691 'fullname' => 'Fullname 2', 692 'category' => $cat->id, 693 'visible' => '1', 694 'downloadcontent' => DOWNLOAD_COURSE_CONTENT_ENABLED, 695 'startdate' => 455760000, 696 'enddate' => 457488000, 697 'idnumber' => 'changedid', 698 'summary' => 'Summary 2', 699 'format' => 'topics', 700 'theme' => 'classic', 701 'lang' => '', 702 'newsitems' => '2', 703 'showgrades' => '1', 704 'showreports' => '0', 705 'legacyfiles' => '0', 706 'maxbytes' => '1111', 707 'groupmode' => '1', 708 'groupmodeforce' => '0', 709 'enablecompletion' => '0', 710 'showactivitydates' => '0', 711 ); 712 713 $this->assertTrue($DB->record_exists('course', array('shortname' => 'c1'))); 714 $co = new tool_uploadcourse_course($mode, $updatemode, $data, $defaultdata); 715 $this->assertTrue($co->prepare()); 716 $co->proceed(); 717 $this->assertTrue($DB->record_exists('course', array('shortname' => 'c1'))); 718 $course = $DB->get_record('course', array('shortname' => 'c1')); 719 $ctx = \context_course::instance($course->id); 720 721 $this->assertEquals($defaultdata['fullname'], $course->fullname); 722 $this->assertEquals($defaultdata['category'], $course->category); 723 $this->assertEquals($defaultdata['visible'], $course->visible); 724 $this->assertEquals($defaultdata['downloadcontent'], $course->downloadcontent); 725 $this->assertEquals($defaultdata['startdate'], $course->startdate); 726 $this->assertEquals($defaultdata['enddate'], $course->enddate); 727 $this->assertEquals($defaultdata['idnumber'], $course->idnumber); 728 $this->assertEquals($defaultdata['summary'], $course->summary); 729 $this->assertEquals($defaultdata['format'], $course->format); 730 $this->assertEquals($defaultdata['theme'], $course->theme); 731 $this->assertEquals($defaultdata['lang'], $course->lang); 732 $this->assertEquals($defaultdata['newsitems'], $course->newsitems); 733 $this->assertEquals($defaultdata['showgrades'], $course->showgrades); 734 $this->assertEquals($defaultdata['showreports'], $course->showreports); 735 $this->assertEquals($defaultdata['legacyfiles'], $course->legacyfiles); 736 $this->assertEquals($defaultdata['maxbytes'], $course->maxbytes); 737 $this->assertEquals($defaultdata['groupmode'], $course->groupmode); 738 $this->assertEquals($defaultdata['groupmodeforce'], $course->groupmodeforce); 739 $this->assertEquals($defaultdata['enablecompletion'], $course->enablecompletion); 740 $this->assertEquals($defaultdata['showactivitydates'], $course->showactivitydates); 741 } 742 743 public function test_rename() { 744 global $DB; 745 $this->resetAfterTest(true); 746 747 $c1 = $this->getDataGenerator()->create_course(array('shortname' => 'c1')); 748 $c2 = $this->getDataGenerator()->create_course(array('shortname' => 'c2')); 749 750 // Cannot rename when creating. 751 $mode = tool_uploadcourse_processor::MODE_CREATE_NEW; 752 $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY; 753 $importoptions = array('canrename' => true); 754 $data = array('shortname' => 'c1', 'rename' => 'newshortname'); 755 $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions); 756 $this->assertFalse($co->prepare()); 757 $this->assertArrayHasKey('courseexistsanduploadnotallowed', $co->get_errors()); 758 759 // Cannot rename when creating. 760 $mode = tool_uploadcourse_processor::MODE_CREATE_ALL; 761 $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY; 762 $importoptions = array('canrename' => true); 763 $data = array('shortname' => 'c1', 'rename' => 'newshortname', 'category' => 1, 'summary' => 'S', 'fullname' => 'F'); 764 $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions); 765 $this->assertFalse($co->prepare()); 766 $this->assertArrayHasKey('canonlyrenameinupdatemode', $co->get_errors()); 767 768 // Error when not allowed to rename the course. 769 $mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY; 770 $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY; 771 $importoptions = array('canrename' => false); 772 $data = array('shortname' => 'c1', 'rename' => 'newshortname'); 773 $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions); 774 $this->assertFalse($co->prepare()); 775 $this->assertArrayHasKey('courserenamingnotallowed', $co->get_errors()); 776 777 // Can rename when updating. 778 $mode = tool_uploadcourse_processor::MODE_CREATE_OR_UPDATE; 779 $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY; 780 $importoptions = array('canrename' => true); 781 $data = array('shortname' => 'c1', 'rename' => 'newshortname'); 782 $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions); 783 $this->assertTrue($co->prepare()); 784 $co->proceed(); 785 $this->assertEquals('newshortname', $DB->get_field_select('course', 'shortname', 'id = :id', array('id' => $c1->id))); 786 787 // Can rename when updating. 788 $mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY; 789 $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY; 790 $importoptions = array('canrename' => true); 791 $data = array('shortname' => 'newshortname', 'rename' => 'newshortname2'); 792 $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions); 793 $this->assertTrue($co->prepare()); 794 $co->proceed(); 795 $this->assertEquals('newshortname2', $DB->get_field_select('course', 'shortname', 'id = :id', array('id' => $c1->id))); 796 797 // Error when course does not exist. 798 $mode = tool_uploadcourse_processor::MODE_CREATE_OR_UPDATE; 799 $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY; 800 $importoptions = array('canrename' => true); 801 $data = array('shortname' => 'DoesNotExist', 'rename' => 'c1', 'category' => 1, 'summary' => 'S', 'fullname' => 'F'); 802 $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions); 803 $this->assertFalse($co->prepare()); 804 $this->assertArrayHasKey('cannotrenamecoursenotexist', $co->get_errors()); 805 806 // Renaming still updates the other values. 807 $mode = tool_uploadcourse_processor::MODE_CREATE_OR_UPDATE; 808 $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_OR_DEFAUTLS; 809 $importoptions = array('canrename' => true); 810 $data = array('shortname' => 'newshortname2', 'rename' => 'c1', 'fullname' => 'Another fullname!'); 811 $defaultdata = array('summary' => 'New summary!'); 812 $co = new tool_uploadcourse_course($mode, $updatemode, $data, $defaultdata, $importoptions); 813 $this->assertTrue($co->prepare()); 814 $co->proceed(); 815 $this->assertEquals('c1', $DB->get_field_select('course', 'shortname', 'id = :id', array('id' => $c1->id))); 816 $this->assertEquals('New summary!', $DB->get_field_select('course', 'summary', 'id = :id', array('id' => $c1->id))); 817 $this->assertEquals('Another fullname!', $DB->get_field_select('course', 'fullname', 'id = :id', array('id' => $c1->id))); 818 819 // Renaming with invalid shortname. 820 $mode = tool_uploadcourse_processor::MODE_CREATE_OR_UPDATE; 821 $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY; 822 $importoptions = array('canrename' => true); 823 $data = array('shortname' => 'c1', 'rename' => '<span>invalid</span>'); 824 $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions); 825 $this->assertFalse($co->prepare()); 826 $this->assertArrayHasKey('invalidshortname', $co->get_errors()); 827 828 // Renaming with invalid shortname. 829 $mode = tool_uploadcourse_processor::MODE_CREATE_OR_UPDATE; 830 $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY; 831 $importoptions = array('canrename' => true); 832 $data = array('shortname' => 'c1', 'rename' => 'c2'); 833 $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions); 834 $this->assertFalse($co->prepare()); 835 $this->assertArrayHasKey('cannotrenameshortnamealreadyinuse', $co->get_errors()); 836 } 837 838 public function test_restore_course() { 839 global $DB; 840 $this->resetAfterTest(true); 841 $this->setAdminUser(); 842 843 $c1 = $this->getDataGenerator()->create_course(); 844 $c1f1 = $this->getDataGenerator()->create_module('forum', array('course' => $c1->id)); 845 846 $mode = tool_uploadcourse_processor::MODE_CREATE_NEW; 847 $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY; 848 $data = array('shortname' => 'A1', 'templatecourse' => $c1->shortname, 'summary' => 'A', 'category' => 1, 849 'fullname' => 'A1'); 850 $co = new tool_uploadcourse_course($mode, $updatemode, $data); 851 $this->assertTrue($co->prepare()); 852 $co->proceed(); 853 $course = $DB->get_record('course', array('shortname' => 'A1')); 854 $modinfo = get_fast_modinfo($course); 855 $found = false; 856 foreach ($modinfo->get_cms() as $cmid => $cm) { 857 if ($cm->modname == 'forum' && $cm->name == $c1f1->name) { 858 $found = true; 859 break; 860 } 861 } 862 $this->assertTrue($found); 863 864 // Restoring twice from the same course should work. 865 $data = array('shortname' => 'B1', 'templatecourse' => $c1->shortname, 'summary' => 'B', 'category' => 1, 866 'fullname' => 'B1'); 867 $co = new tool_uploadcourse_course($mode, $updatemode, $data); 868 $this->assertTrue($co->prepare()); 869 $co->proceed(); 870 $course = $DB->get_record('course', array('shortname' => 'B1')); 871 $modinfo = get_fast_modinfo($course); 872 $found = false; 873 foreach ($modinfo->get_cms() as $cmid => $cm) { 874 if ($cm->modname == 'forum' && $cm->name == $c1f1->name) { 875 $found = true; 876 break; 877 } 878 } 879 $this->assertTrue($found); 880 } 881 882 public function test_restore_file() { 883 global $DB; 884 $this->resetAfterTest(true); 885 $this->setAdminUser(); 886 887 $c1 = $this->getDataGenerator()->create_course(); 888 $c1f1 = $this->getDataGenerator()->create_module('forum', array('course' => $c1->id)); 889 890 // Restore from a file, checking that the file takes priority over the templatecourse. 891 $mode = tool_uploadcourse_processor::MODE_CREATE_NEW; 892 $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY; 893 $data = array('shortname' => 'A1', 'backupfile' => __DIR__ . '/fixtures/backup.mbz', 894 'summary' => 'A', 'category' => 1, 'fullname' => 'A1', 'templatecourse' => $c1->shortname); 895 $co = new tool_uploadcourse_course($mode, $updatemode, $data); 896 $this->assertTrue($co->prepare()); 897 $co->proceed(); 898 $course = $DB->get_record('course', array('shortname' => 'A1')); 899 $modinfo = get_fast_modinfo($course); 900 $found = false; 901 foreach ($modinfo->get_cms() as $cmid => $cm) { 902 if ($cm->modname == 'glossary' && $cm->name == 'Imported Glossary') { 903 $found = true; 904 } else if ($cm->modname == 'forum' && $cm->name == $c1f1->name) { 905 // We should not find this! 906 $this->assertTrue(false); 907 } 908 } 909 $this->assertTrue($found); 910 911 // Restoring twice from the same file should work. 912 $data = array('shortname' => 'B1', 'backupfile' => __DIR__ . '/fixtures/backup.mbz', 913 'summary' => 'B', 'category' => 1, 'fullname' => 'B1'); 914 $co = new tool_uploadcourse_course($mode, $updatemode, $data); 915 $this->assertTrue($co->prepare()); 916 $co->proceed(); 917 $course = $DB->get_record('course', array('shortname' => 'B1')); 918 $modinfo = get_fast_modinfo($course); 919 $found = false; 920 foreach ($modinfo->get_cms() as $cmid => $cm) { 921 if ($cm->modname == 'glossary' && $cm->name == 'Imported Glossary') { 922 $found = true; 923 } else if ($cm->modname == 'forum' && $cm->name == $c1f1->name) { 924 // We should not find this! 925 $this->assertTrue(false); 926 } 927 } 928 $this->assertTrue($found); 929 } 930 931 /** 932 * Test that specifying course template respects default restore settings 933 */ 934 public function test_restore_file_settings() { 935 global $DB; 936 $this->resetAfterTest(true); 937 $this->setAdminUser(); 938 939 // Set admin config setting so that activities are not restored by default. 940 set_config('restore_general_activities', 0, 'restore'); 941 942 $c1 = $this->getDataGenerator()->create_course(); 943 944 $mode = tool_uploadcourse_processor::MODE_CREATE_NEW; 945 $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY; 946 $data = array('shortname' => 'A1', 'backupfile' => __DIR__ . '/fixtures/backup.mbz', 947 'summary' => 'A', 'category' => 1, 'fullname' => 'A1', 'templatecourse' => $c1->shortname); 948 $co = new tool_uploadcourse_course($mode, $updatemode, $data); 949 $this->assertTrue($co->prepare()); 950 $co->proceed(); 951 $course = $DB->get_record('course', array('shortname' => 'A1')); 952 953 // Make sure the glossary is not restored. 954 $modinfo = get_fast_modinfo($course); 955 $this->assertEmpty($modinfo->get_instances_of('glossary')); 956 } 957 958 public function test_restore_invalid_file() { 959 $this->resetAfterTest(); 960 961 // Restore from a non-existing file should not be allowed. 962 $mode = tool_uploadcourse_processor::MODE_CREATE_NEW; 963 $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY; 964 $data = array('shortname' => 'A1', 'backupfile' => '/lead/no/where', 965 'category' => 1, 'fullname' => 'A1'); 966 $co = new tool_uploadcourse_course($mode, $updatemode, $data); 967 $this->assertFalse($co->prepare()); 968 $this->assertArrayHasKey('cannotreadbackupfile', $co->get_errors()); 969 970 // Restore from an invalid file should not be allowed. 971 $mode = tool_uploadcourse_processor::MODE_CREATE_NEW; 972 $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY; 973 $data = array('shortname' => 'A1', 'backupfile' => __FILE__, 974 'category' => 1, 'fullname' => 'A1'); 975 $co = new tool_uploadcourse_course($mode, $updatemode, $data); 976 977 $this->assertFalse($co->prepare()); 978 $this->assertArrayHasKey('invalidbackupfile', $co->get_errors()); 979 980 // Zip packer throws a debugging message, this assertion is only here to prevent 981 // the message from being displayed. 982 $this->assertDebuggingCalled(); 983 } 984 985 public function test_restore_invalid_course() { 986 $this->resetAfterTest(); 987 988 // Restore from an invalid file should not be allowed. 989 $mode = tool_uploadcourse_processor::MODE_CREATE_NEW; 990 $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY; 991 $data = array('shortname' => 'A1', 'templatecourse' => 'iamnotavalidcourse', 992 'category' => 1, 'fullname' => 'A1'); 993 $co = new tool_uploadcourse_course($mode, $updatemode, $data); 994 $this->assertFalse($co->prepare()); 995 $this->assertArrayHasKey('coursetorestorefromdoesnotexist', $co->get_errors()); 996 } 997 998 /** 999 * Testing the reset on groups, group members and enrolments. 1000 */ 1001 public function test_reset() { 1002 global $DB; 1003 $this->resetAfterTest(true); 1004 1005 $c1 = $this->getDataGenerator()->create_course(); 1006 $c1ctx = \context_course::instance($c1->id); 1007 $studentrole = $DB->get_record('role', array('shortname' => 'student')); 1008 $teacherrole = $DB->get_record('role', array('shortname' => 'teacher')); 1009 1010 $u1 = $this->getDataGenerator()->create_user(); 1011 $this->getDataGenerator()->enrol_user($u1->id, $c1->id, $studentrole->id); 1012 $this->assertCount(1, get_enrolled_users($c1ctx)); 1013 1014 $g1 = $this->getDataGenerator()->create_group(array('courseid' => $c1->id)); 1015 $this->getDataGenerator()->create_group_member(array('groupid' => $g1->id, 'userid' => $u1->id)); 1016 $this->assertEquals(1, $DB->count_records('groups', array('courseid' => $c1->id))); 1017 $this->assertTrue($DB->record_exists('groups_members', array('groupid' => $g1->id, 'userid' => $u1->id))); 1018 1019 // Wrong mode. 1020 $mode = tool_uploadcourse_processor::MODE_CREATE_NEW; 1021 $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY; 1022 $data = array('shortname' => 'DoesNotExist', 'reset' => '1', 'summary' => 'summary', 'fullname' => 'FN', 'category' => 1); 1023 $co = new tool_uploadcourse_course($mode, $updatemode, $data); 1024 $this->assertFalse($co->prepare()); 1025 $this->assertArrayHasKey('canonlyresetcourseinupdatemode', $co->get_errors()); 1026 $this->assertTrue($DB->record_exists('groups', array('id' => $g1->id))); 1027 $this->assertTrue($DB->record_exists('groups_members', array('groupid' => $g1->id, 'userid' => $u1->id))); 1028 $this->assertCount(1, get_enrolled_users($c1ctx)); 1029 1030 // Reset not allowed. 1031 $mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY; 1032 $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY; 1033 $data = array('shortname' => $c1->shortname, 'reset' => '1'); 1034 $importoptions = array('canreset' => false); 1035 $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions); 1036 $this->assertFalse($co->prepare()); 1037 $this->assertArrayHasKey('courseresetnotallowed', $co->get_errors()); 1038 $this->assertTrue($DB->record_exists('groups', array('id' => $g1->id))); 1039 $this->assertTrue($DB->record_exists('groups_members', array('groupid' => $g1->id, 'userid' => $u1->id))); 1040 $this->assertCount(1, get_enrolled_users($c1ctx)); 1041 1042 // Reset allowed but not requested. 1043 $mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY; 1044 $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY; 1045 $data = array('shortname' => $c1->shortname, 'reset' => '0'); 1046 $importoptions = array('canreset' => true); 1047 $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions); 1048 $this->assertTrue($co->prepare()); 1049 $co->proceed(); 1050 $this->assertTrue($DB->record_exists('groups', array('id' => $g1->id))); 1051 $this->assertTrue($DB->record_exists('groups_members', array('groupid' => $g1->id, 'userid' => $u1->id))); 1052 $this->assertCount(1, get_enrolled_users($c1ctx)); 1053 1054 // Reset passed as a default parameter, should not be taken in account. 1055 $mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY; 1056 $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY; 1057 $data = array('shortname' => $c1->shortname); 1058 $importoptions = array('canreset' => true); 1059 $co = new tool_uploadcourse_course($mode, $updatemode, $data, array('reset' => 1), $importoptions); 1060 $this->assertTrue($co->prepare()); 1061 $co->proceed(); 1062 $this->assertTrue($DB->record_exists('groups', array('id' => $g1->id))); 1063 $this->assertTrue($DB->record_exists('groups_members', array('groupid' => $g1->id, 'userid' => $u1->id))); 1064 $this->assertCount(1, get_enrolled_users($c1ctx)); 1065 1066 // Reset executed from data. 1067 $mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY; 1068 $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY; 1069 $data = array('shortname' => $c1->shortname, 'reset' => 1); 1070 $importoptions = array('canreset' => true); 1071 $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions); 1072 $this->assertTrue($co->prepare()); 1073 $co->proceed(); 1074 $this->assertFalse($DB->record_exists('groups', array('id' => $g1->id))); 1075 $this->assertFalse($DB->record_exists('groups_members', array('groupid' => $g1->id, 'userid' => $u1->id))); 1076 $this->assertCount(0, get_enrolled_users($c1ctx)); 1077 1078 // Reset executed from import option. 1079 $mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY; 1080 $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY; 1081 $data = array('shortname' => $c1->shortname, 'reset' => 0); 1082 $importoptions = array('reset' => 1, 'canreset' => true); 1083 $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions); 1084 1085 $g1 = $this->getDataGenerator()->create_group(array('courseid' => $c1->id)); 1086 $this->getDataGenerator()->create_group_member(array('groupid' => $g1->id, 'userid' => $u1->id)); 1087 $this->assertEquals(1, $DB->count_records('groups', array('courseid' => $c1->id))); 1088 $this->assertTrue($co->prepare()); 1089 $co->proceed(); 1090 $this->assertFalse($DB->record_exists('groups', array('id' => $g1->id))); 1091 } 1092 1093 public function test_create_bad_category() { 1094 global $DB; 1095 $this->resetAfterTest(true); 1096 1097 // Ensure fails when category cannot be resolved upon creation. 1098 $mode = tool_uploadcourse_processor::MODE_CREATE_NEW; 1099 $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY; 1100 $data = array('shortname' => 'c1', 'summary' => 'summary', 'fullname' => 'FN', 'category' => 'Wrong cat'); 1101 $co = new tool_uploadcourse_course($mode, $updatemode, $data); 1102 $this->assertFalse($co->prepare()); 1103 $this->assertArrayHasKey('couldnotresolvecatgorybyid', $co->get_errors()); 1104 1105 // Ensure fails when category is 0 on create. 1106 $mode = tool_uploadcourse_processor::MODE_CREATE_NEW; 1107 $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY; 1108 $data = array('shortname' => 'c1', 'summary' => 'summary', 'fullname' => 'FN', 'category' => '0'); 1109 $co = new tool_uploadcourse_course($mode, $updatemode, $data); 1110 $this->assertFalse($co->prepare()); 1111 $this->assertArrayHasKey('missingmandatoryfields', $co->get_errors()); 1112 1113 // Ensure fails when category cannot be resolved upon update. 1114 $c1 = $this->getDataGenerator()->create_course(); 1115 $mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY; 1116 $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY; 1117 $data = array('shortname' => $c1->shortname, 'category' => 'Wrong cat'); 1118 $co = new tool_uploadcourse_course($mode, $updatemode, $data); 1119 $this->assertFalse($co->prepare()); 1120 $this->assertArrayHasKey('couldnotresolvecatgorybyid', $co->get_errors()); 1121 1122 // Ensure does not update the category when it is 0. 1123 $c1 = $this->getDataGenerator()->create_course(); 1124 $mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY; 1125 $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY; 1126 $data = array('shortname' => $c1->shortname, 'category' => '0'); 1127 $co = new tool_uploadcourse_course($mode, $updatemode, $data); 1128 $this->assertTrue($co->prepare()); 1129 $this->assertEmpty($co->get_errors()); 1130 $this->assertEmpty($co->get_statuses()); 1131 $co->proceed(); 1132 $this->assertEquals($c1->category, $DB->get_field('course', 'category', array('id' => $c1->id))); 1133 1134 // Ensure does not update the category when it is set to 0 in the defaults. 1135 $c1 = $this->getDataGenerator()->create_course(); 1136 $mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY; 1137 $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_OR_DEFAUTLS; 1138 $data = array('shortname' => $c1->shortname); 1139 $defaults = array('category' => '0'); 1140 $co = new tool_uploadcourse_course($mode, $updatemode, $data, $defaults); 1141 $this->assertTrue($co->prepare()); 1142 $this->assertEmpty($co->get_errors()); 1143 $this->assertEmpty($co->get_statuses()); 1144 $co->proceed(); 1145 $this->assertEquals($c1->category, $DB->get_field('course', 'category', array('id' => $c1->id))); 1146 } 1147 1148 public function test_enrolment_data() { 1149 $this->resetAfterTest(true); 1150 1151 // We need to set the current user as one with the capability to edit manual enrolment instances in the new course. 1152 $this->setAdminUser(); 1153 1154 $mode = tool_uploadcourse_processor::MODE_CREATE_NEW; 1155 $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY; 1156 $data = array('shortname' => 'c1', 'summary' => 'S', 'fullname' => 'FN', 'category' => '1'); 1157 $data['enrolment_1'] = 'manual'; 1158 $data['enrolment_1_role'] = 'teacher'; 1159 $data['enrolment_1_startdate'] = '2nd July 2013'; 1160 $data['enrolment_1_enddate'] = '2nd August 2013'; 1161 $data['enrolment_1_enrolperiod'] = '10 days'; 1162 $co = new tool_uploadcourse_course($mode, $updatemode, $data); 1163 $this->assertTrue($co->prepare()); 1164 $co->proceed(); 1165 1166 // Enrolment methods. 1167 $enroldata = array(); 1168 $instances = enrol_get_instances($co->get_id(), false); 1169 foreach ($instances as $instance) { 1170 $enroldata[$instance->enrol] = $instance; 1171 } 1172 1173 $this->assertNotEmpty($enroldata['manual']); 1174 $this->assertEquals(ENROL_INSTANCE_ENABLED, $enroldata['manual']->status); 1175 $this->assertEquals(strtotime($data['enrolment_1_startdate']), $enroldata['manual']->enrolstartdate); 1176 $this->assertEquals(strtotime('1970-01-01 GMT + ' . $data['enrolment_1_enrolperiod']), $enroldata['manual']->enrolperiod); 1177 $this->assertEquals(strtotime('12th July 2013'), $enroldata['manual']->enrolenddate); 1178 } 1179 1180 /** 1181 * Data provider for testing enrolment errors 1182 * 1183 * @return array 1184 */ 1185 public function enrolment_uploaddata_error_provider(): array { 1186 return [ 1187 ['errorcannotcreateorupdateenrolment', [ 1188 'shortname' => 'C1', 1189 'enrolment_1' => 'manual', 1190 ]], 1191 ['errorcannotdeleteenrolment', [ 1192 'shortname' => 'C1', 1193 'enrolment_1' => 'manual', 1194 'enrolment_1_delete' => '1', 1195 ]], 1196 ['errorcannotdisableenrolment', [ 1197 'shortname' => 'C1', 1198 'enrolment_1' => 'manual', 1199 'enrolment_1_disable' => '1', 1200 ]], 1201 ]; 1202 } 1203 1204 /** 1205 * Test that user without permission, cannot modify enrolment instances when creating courses 1206 * 1207 * @param string $expectederror 1208 * @param array $uploaddata 1209 * 1210 * @dataProvider enrolment_uploaddata_error_provider 1211 */ 1212 public function test_enrolment_error_create_course(string $expectederror, array $uploaddata): void { 1213 global $DB; 1214 1215 $this->resetAfterTest(); 1216 1217 // Create category in which to create the new course. 1218 $category = $this->getDataGenerator()->create_category(); 1219 $categorycontext = \context_coursecat::instance($category->id); 1220 1221 $user = $this->getDataGenerator()->create_user(); 1222 $this->setUser($user); 1223 1224 // Assign the user as a manager of the category, disable ability to configure manual enrolment instances. 1225 $roleid = $DB->get_field('role', 'id', ['shortname' => 'manager']); 1226 role_assign($roleid, $user->id, $categorycontext); 1227 role_change_permission($roleid, $categorycontext, 'enrol/manual:config', CAP_PROHIBIT); 1228 1229 $mode = tool_uploadcourse_processor::MODE_CREATE_NEW; 1230 $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY; 1231 1232 $upload = new tool_uploadcourse_course($mode, $updatemode, array_merge($uploaddata, [ 1233 'category' => $category->id, 1234 'fullname' => 'My course', 1235 ])); 1236 1237 // Enrolment validation isn't performed during 'prepare' for new courses. 1238 $this->assertTrue($upload->prepare()); 1239 $upload->proceed(); 1240 1241 $errors = $upload->get_errors(); 1242 $this->assertArrayHasKey($expectederror, $errors); 1243 1244 $this->assertEquals(get_string($expectederror, 'tool_uploadcourse', 'Manual enrolments'), 1245 (string) $errors[$expectederror]); 1246 } 1247 1248 /** 1249 * Test that user without permission, cannot modify enrolment instances when updating courses 1250 * 1251 * @param string $expectederror 1252 * @param array $uploaddata 1253 * 1254 * @dataProvider enrolment_uploaddata_error_provider 1255 */ 1256 public function test_enrolment_error_update_course(string $expectederror, array $uploaddata): void { 1257 global $DB; 1258 1259 $this->resetAfterTest(); 1260 1261 // Create category in which to create the new course. 1262 $category = $this->getDataGenerator()->create_category(); 1263 $categorycontext = \context_coursecat::instance($category->id); 1264 1265 $course = $this->getDataGenerator()->create_course([ 1266 'category' => $category->id, 1267 'shortname' => $uploaddata['shortname'], 1268 ]); 1269 1270 $user = $this->getDataGenerator()->create_user(); 1271 $this->setUser($user); 1272 1273 // Assign the user as a manager of the category, disable ability to configure manual enrolment instances. 1274 $roleid = $DB->get_field('role', 'id', ['shortname' => 'manager']); 1275 role_assign($roleid, $user->id, $categorycontext); 1276 role_change_permission($roleid, $categorycontext, 'enrol/manual:config', CAP_PROHIBIT); 1277 1278 // Sanity check. 1279 $instances = enrol_get_instances($course->id, true); 1280 $this->assertCount(1, $instances); 1281 $this->assertEquals('manual', reset($instances)->enrol); 1282 1283 $mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY; 1284 $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY; 1285 1286 $upload = new tool_uploadcourse_course($mode, $updatemode, $uploaddata); 1287 1288 $this->assertFalse($upload->prepare()); 1289 1290 $errors = $upload->get_errors(); 1291 $this->assertArrayHasKey($expectederror, $errors); 1292 1293 $this->assertEquals(get_string($expectederror, 'tool_uploadcourse', 'Manual enrolments'), 1294 (string) $errors[$expectederror]); 1295 } 1296 1297 /** 1298 * Test upload processing of course custom fields 1299 */ 1300 public function test_custom_fields_data() { 1301 $this->resetAfterTest(); 1302 $this->setAdminUser(); 1303 1304 $course = $this->getDataGenerator()->create_course(['shortname' => 'C1']); 1305 1306 // Create our custom fields. 1307 $category = $this->get_customfield_generator()->create_category(); 1308 $this->create_custom_field($category, 'date', 'mydatefield'); 1309 $this->create_custom_field($category, 'text', 'mytextfield'); 1310 $this->create_custom_field($category, 'textarea', 'mytextareafield'); 1311 1312 // Perform upload. 1313 $mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY; 1314 $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY; 1315 $dataupload = [ 1316 'shortname' => $course->shortname, 1317 'customfield_mydatefield' => '2020-04-01 16:00', 1318 'customfield_mytextfield' => 'Hello', 1319 'customfield_mytextareafield' => 'Is it me you\'re looking for?', 1320 ]; 1321 1322 $uploader = new tool_uploadcourse_course($mode, $updatemode, $dataupload); 1323 $this->assertTrue($uploader->prepare()); 1324 $uploader->proceed(); 1325 1326 // Confirm presence of course custom fields. 1327 $data = \core_course\customfield\course_handler::create()->export_instance_data_object($course->id); 1328 $this->assertEqualsIgnoringCase('Wednesday, 1 April 2020, 4:00 PM', $data->mydatefield); 1329 $this->assertEquals($dataupload['customfield_mytextfield'], $data->mytextfield); 1330 $this->assertStringContainsString($dataupload['customfield_mytextareafield'], $data->mytextareafield); 1331 } 1332 1333 /** 1334 * Test upload processing of course custom field that is required but empty 1335 */ 1336 public function test_custom_fields_data_required() { 1337 $this->resetAfterTest(); 1338 $this->setAdminUser(); 1339 1340 $course = $this->getDataGenerator()->create_course(['shortname' => 'C1']); 1341 1342 // Create our custom field. 1343 $category = $this->get_customfield_generator()->create_category(); 1344 $this->create_custom_field($category, 'select', 'myselect', ['required' => true, 'options' => "Cat\nDog"]); 1345 1346 $mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY; 1347 $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY; 1348 $dataupload = [ 1349 'shortname' => $course->shortname, 1350 'customfield_myselect' => null, 1351 ]; 1352 1353 $uploader = new tool_uploadcourse_course($mode, $updatemode, $dataupload); 1354 $this->assertFalse($uploader->prepare()); 1355 $this->assertArrayHasKey('customfieldinvalid', $uploader->get_errors()); 1356 1357 // Try again with a default value. 1358 $defaults = [ 1359 'customfield_myselect' => 2, // Our second option: Dog. 1360 ]; 1361 1362 $uploader = new tool_uploadcourse_course($mode, $updatemode, $dataupload, $defaults); 1363 $this->assertTrue($uploader->prepare()); 1364 $uploader->proceed(); 1365 1366 // Confirm presence of course custom fields. 1367 $data = \core_course\customfield\course_handler::create()->export_instance_data_object($course->id); 1368 $this->assertEquals('Dog', $data->myselect); 1369 } 1370 1371 /** 1372 * Test upload processing of course custom field with an invalid select option 1373 */ 1374 public function test_custom_fields_data_invalid_select_option() { 1375 $this->resetAfterTest(); 1376 $this->setAdminUser(); 1377 1378 $course = $this->getDataGenerator()->create_course(['shortname' => 'C1']); 1379 1380 // Create our custom field. 1381 $category = $this->get_customfield_generator()->create_category(); 1382 $this->create_custom_field($category, 'select', 'myselect', 1383 ['required' => true, 'options' => "Cat\nDog", 'defaultvalue' => 'Cat']); 1384 1385 $mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY; 1386 $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY; 1387 $dataupload = [ 1388 'shortname' => $course->shortname, 1389 'customfield_myselect' => 'Fish', // No, invalid. 1390 ]; 1391 1392 $uploader = new tool_uploadcourse_course($mode, $updatemode, $dataupload); 1393 $this->assertTrue($uploader->prepare()); 1394 $uploader->proceed(); 1395 1396 // Confirm presence of course custom fields. 1397 $data = \core_course\customfield\course_handler::create()->export_instance_data_object($course->id); 1398 $this->assertEquals('Cat', $data->myselect); 1399 } 1400 1401 /** 1402 * Test upload processing of course custom field with an out of range date 1403 */ 1404 public function test_custom_fields_data_invalid_date() { 1405 $this->resetAfterTest(); 1406 $this->setAdminUser(); 1407 1408 $course = $this->getDataGenerator()->create_course(['shortname' => 'C1']); 1409 1410 // Create our custom field. 1411 $category = $this->get_customfield_generator()->create_category(); 1412 $this->create_custom_field($category, 'date', 'mydate', 1413 ['mindate' => strtotime('2020-04-01'), 'maxdate' => '2020-04-30']); 1414 1415 $mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY; 1416 $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY; 1417 $dataupload = [ 1418 'shortname' => $course->shortname, 1419 'customfield_mydate' => '2020-05-06', // Out of range. 1420 ]; 1421 1422 $uploader = new tool_uploadcourse_course($mode, $updatemode, $dataupload); 1423 $this->assertFalse($uploader->prepare()); 1424 $this->assertArrayHasKey('customfieldinvalid', $uploader->get_errors()); 1425 } 1426 1427 public function test_idnumber_problems() { 1428 $this->resetAfterTest(true); 1429 1430 $c1 = $this->getDataGenerator()->create_course(array('shortname' => 'sntaken', 'idnumber' => 'taken')); 1431 $c2 = $this->getDataGenerator()->create_course(); 1432 1433 // Create with existing ID number. 1434 $mode = tool_uploadcourse_processor::MODE_CREATE_NEW; 1435 $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY; 1436 $data = array('shortname' => 'c2', 'summary' => 'summary', 'fullname' => 'FN', 'category' => '1', 1437 'idnumber' => $c1->idnumber); 1438 $co = new tool_uploadcourse_course($mode, $updatemode, $data); 1439 $this->assertFalse($co->prepare()); 1440 $this->assertArrayHasKey('idnumberalreadyinuse', $co->get_errors()); 1441 1442 // Rename to existing ID number. 1443 $mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY; 1444 $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY; 1445 $data = array('shortname' => $c2->shortname, 'rename' => 'SN', 'idnumber' => $c1->idnumber); 1446 $importoptions = array('canrename' => true); 1447 $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions); 1448 $this->assertFalse($co->prepare()); 1449 $this->assertArrayHasKey('cannotrenameidnumberconflict', $co->get_errors()); 1450 1451 // Incrementing shortname increments idnumber. 1452 $mode = tool_uploadcourse_processor::MODE_CREATE_ALL; 1453 $updatemode = tool_uploadcourse_processor::UPDATE_NOTHING; 1454 $data = array('shortname' => $c1->shortname, 'idnumber' => $c1->idnumber, 'summary' => 'S', 'fullname' => 'F', 1455 'category' => 1); 1456 $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), array()); 1457 $this->assertTrue($co->prepare()); 1458 $this->assertArrayHasKey('courseshortnameincremented', $co->get_statuses()); 1459 $this->assertArrayHasKey('courseidnumberincremented', $co->get_statuses()); 1460 $data = $co->get_data(); 1461 $this->assertEquals('sntaken_2', $data['shortname']); 1462 $this->assertEquals('taken_2', $data['idnumber']); 1463 1464 // Incrementing shortname increments idnumber unless available. 1465 $mode = tool_uploadcourse_processor::MODE_CREATE_ALL; 1466 $updatemode = tool_uploadcourse_processor::UPDATE_NOTHING; 1467 $data = array('shortname' => $c1->shortname, 'idnumber' => 'nottaken', 'summary' => 'S', 'fullname' => 'F', 1468 'category' => 1); 1469 $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), array()); 1470 $this->assertTrue($co->prepare()); 1471 $this->assertArrayHasKey('courseshortnameincremented', $co->get_statuses()); 1472 $this->assertArrayNotHasKey('courseidnumberincremented', $co->get_statuses()); 1473 $data = $co->get_data(); 1474 $this->assertEquals('sntaken_2', $data['shortname']); 1475 $this->assertEquals('nottaken', $data['idnumber']); 1476 } 1477 1478 public function test_generate_shortname() { 1479 $this->resetAfterTest(true); 1480 1481 $c1 = $this->getDataGenerator()->create_course(array('shortname' => 'taken')); 1482 1483 // Generate a shortname. 1484 $mode = tool_uploadcourse_processor::MODE_CREATE_NEW; 1485 $updatemode = tool_uploadcourse_processor::UPDATE_NOTHING; 1486 $data = array('summary' => 'summary', 'fullname' => 'FN', 'category' => '1', 'idnumber' => 'IDN'); 1487 $importoptions = array('shortnametemplate' => '%i'); 1488 $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions); 1489 $this->assertTrue($co->prepare()); 1490 $this->assertArrayHasKey('courseshortnamegenerated', $co->get_statuses()); 1491 1492 // Generate a shortname without a template. 1493 $mode = tool_uploadcourse_processor::MODE_CREATE_NEW; 1494 $updatemode = tool_uploadcourse_processor::UPDATE_NOTHING; 1495 $data = array('summary' => 'summary', 'fullname' => 'FN', 'category' => '1'); 1496 $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), array()); 1497 $this->assertFalse($co->prepare()); 1498 $this->assertArrayHasKey('missingshortnamenotemplate', $co->get_errors()); 1499 1500 // Generate a shortname in update mode. 1501 $mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY; 1502 $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY; 1503 $data = array('summary' => 'summary', 'fullname' => 'FN', 'category' => '1'); 1504 $importoptions = array('shortnametemplate' => '%f'); 1505 $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions); 1506 $this->assertFalse($co->prepare()); 1507 // Commented because we never get here as the course without shortname does not exist. 1508 // $this->assertArrayHasKey('cannotgenerateshortnameupdatemode', $co->get_errors()); 1509 1510 // Generate a shortname to a course that already exists. 1511 $mode = tool_uploadcourse_processor::MODE_CREATE_NEW; 1512 $updatemode = tool_uploadcourse_processor::UPDATE_NOTHING; 1513 $data = array('summary' => 'summary', 'fullname' => 'taken', 'category' => '1'); 1514 $importoptions = array('shortnametemplate' => '%f'); 1515 $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions); 1516 $this->assertFalse($co->prepare()); 1517 $this->assertArrayHasKey('generatedshortnamealreadyinuse', $co->get_errors()); 1518 1519 // Generate a shortname to a course that already exists will be incremented. 1520 $mode = tool_uploadcourse_processor::MODE_CREATE_ALL; 1521 $updatemode = tool_uploadcourse_processor::UPDATE_NOTHING; 1522 $data = array('summary' => 'summary', 'fullname' => 'taken', 'category' => '1'); 1523 $importoptions = array('shortnametemplate' => '%f'); 1524 $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions); 1525 $this->assertTrue($co->prepare()); 1526 $this->assertArrayHasKey('courseshortnamegenerated', $co->get_statuses()); 1527 $this->assertArrayHasKey('courseshortnameincremented', $co->get_statuses()); 1528 } 1529 1530 public function test_mess_with_frontpage() { 1531 global $SITE; 1532 $this->resetAfterTest(true); 1533 1534 // Updating the front page. 1535 $mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY; 1536 $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY; 1537 $data = array('shortname' => $SITE->shortname, 'idnumber' => 'NewIDN'); 1538 $importoptions = array(); 1539 $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions); 1540 $this->assertFalse($co->prepare()); 1541 $this->assertArrayHasKey('cannotupdatefrontpage', $co->get_errors()); 1542 1543 // Updating the front page. 1544 $mode = tool_uploadcourse_processor::MODE_CREATE_OR_UPDATE; 1545 $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY; 1546 $data = array('shortname' => $SITE->shortname, 'idnumber' => 'NewIDN'); 1547 $importoptions = array(); 1548 $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions); 1549 $this->assertFalse($co->prepare()); 1550 $this->assertArrayHasKey('cannotupdatefrontpage', $co->get_errors()); 1551 1552 // Generating a shortname should not be allowed in update mode, and so we cannot update the front page. 1553 $mode = tool_uploadcourse_processor::MODE_CREATE_OR_UPDATE; 1554 $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY; 1555 $data = array('idnumber' => 'NewIDN', 'fullname' => 'FN', 'category' => 1); 1556 $importoptions = array('shortnametemplate' => $SITE->shortname); 1557 $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions); 1558 $this->assertFalse($co->prepare()); 1559 $this->assertArrayHasKey('cannotgenerateshortnameupdatemode', $co->get_errors()); 1560 1561 // Renaming to the front page should not be allowed. 1562 $c1 = $this->getDataGenerator()->create_course(); 1563 $mode = tool_uploadcourse_processor::MODE_CREATE_OR_UPDATE; 1564 $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY; 1565 $data = array('shortname' => $c1->shortname, 'fullname' => 'FN', 'idnumber' => 'NewIDN', 'rename' => $SITE->shortname); 1566 $importoptions = array('canrename' => true); 1567 $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions); 1568 $this->assertFalse($co->prepare()); 1569 $this->assertArrayHasKey('cannotrenameshortnamealreadyinuse', $co->get_errors()); 1570 } 1571 1572 /** 1573 * Test when role doesn't exist. 1574 * 1575 * @covers \tool_uploadcourse_course::prepare 1576 */ 1577 public function test_role_not_exist() { 1578 $this->resetAfterTest(); 1579 $this->setAdminUser(); 1580 1581 $mode = tool_uploadcourse_processor::MODE_CREATE_NEW; 1582 $updatemode = tool_uploadcourse_processor::UPDATE_NOTHING; 1583 1584 $upload = new tool_uploadcourse_course($mode, $updatemode, [ 1585 'category' => 1, 1586 'fullname' => 'Testing', 1587 'shortname' => 'T101', 1588 'enrolment_1' => 'manual', 1589 'enrolment_1_role' => 'notexist' 1590 ]); 1591 1592 $this->assertFalse($upload->prepare()); 1593 $this->assertArrayHasKey('invalidroles', $upload->get_errors()); 1594 } 1595 1596 /** 1597 * Test when role not allowed in course context. 1598 * 1599 * @covers \tool_uploadcourse_course::proceed 1600 */ 1601 public function test_role_not_allowed() { 1602 $this->resetAfterTest(); 1603 $this->setAdminUser(); 1604 1605 $roleid = create_role('New student role', 'student2', 'New student description', 'student'); 1606 set_role_contextlevels($roleid, [CONTEXT_BLOCK]); 1607 1608 $mode = tool_uploadcourse_processor::MODE_CREATE_NEW; 1609 $updatemode = tool_uploadcourse_processor::UPDATE_NOTHING; 1610 1611 $upload = new tool_uploadcourse_course($mode, $updatemode, [ 1612 'category' => 1, 1613 'fullname' => 'Testing', 1614 'shortname' => 'T101', 1615 'enrolment_1' => 'manual', 1616 'enrolment_1_role' => 'student2' 1617 ]); 1618 1619 $this->assertFalse($upload->prepare()); 1620 $this->assertArrayHasKey('contextrolenotallowed', $upload->get_errors()); 1621 } 1622 1623 /** 1624 * Test when role is allowed. 1625 * 1626 * @covers \tool_uploadcourse_course::proceed 1627 */ 1628 public function test_role_allowed() { 1629 global $DB; 1630 1631 $this->resetAfterTest(); 1632 $this->setAdminUser(); 1633 1634 $mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY; 1635 $updatemode = tool_uploadcourse_processor::UPDATE_MISSING_WITH_DATA_OR_DEFAUTLS; 1636 1637 $course = $this->getDataGenerator()->create_course([ 1638 'shortname' => 'c1', 1639 ]); 1640 1641 $instances = enrol_get_instances($course->id, true); 1642 $studentrole = $DB->get_record('role', ['shortname' => 'student']); 1643 $teacherrole = $DB->get_record('role', ['shortname' => 'teacher']); 1644 $instance = reset($instances); 1645 $this->assertEquals($studentrole->id, $instance->roleid); 1646 1647 $upload = new tool_uploadcourse_course($mode, $updatemode, [ 1648 'shortname' => 'c1', 1649 'enrolment_1' => 'manual', 1650 'enrolment_1_role' => 'teacher' 1651 ]); 1652 1653 $this->assertTrue($upload->prepare()); 1654 $upload->proceed(); 1655 $instances = enrol_get_instances($course->id, true); 1656 $instance = reset($instances); 1657 $this->assertEquals($teacherrole->id, $instance->roleid); 1658 } 1659 1660 /** 1661 * Get custom field plugin generator 1662 * 1663 * @return core_customfield_generator 1664 */ 1665 protected function get_customfield_generator() : \core_customfield_generator { 1666 return $this->getDataGenerator()->get_plugin_generator('core_customfield'); 1667 } 1668 1669 /** 1670 * Helper method to create custom course field 1671 * 1672 * @param \core_customfield\category_controller $category 1673 * @param string $type 1674 * @param string $shortname 1675 * @param array $configdata 1676 * @return \core_customfield\field_controller 1677 */ 1678 protected function create_custom_field(\core_customfield\category_controller $category, string $type, string $shortname, 1679 array $configdata = []) : \core_customfield\field_controller { 1680 1681 return $this->get_customfield_generator()->create_field([ 1682 'categoryid' => $category->get('id'), 1683 'type' => $type, 1684 'shortname' => $shortname, 1685 'configdata' => $configdata, 1686 ]); 1687 } 1688 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body