[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
1 <?php 2 3 // This file is part of Moodle - http://moodle.org/ 4 // 5 // Moodle is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // Moodle is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU General Public License for more details. 14 // 15 // You should have received a copy of the GNU General Public License 16 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 17 18 /** 19 * Library of workshop module functions needed by Moodle core and other subsystems 20 * 21 * All the functions neeeded by Moodle core, gradebook, file subsystem etc 22 * are placed here. 23 * 24 * @package mod_workshop 25 * @copyright 2009 David Mudrak <david.mudrak@gmail.com> 26 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 27 */ 28 29 defined('MOODLE_INTERNAL') || die(); 30 31 require_once($CFG->dirroot . '/calendar/lib.php'); 32 33 //////////////////////////////////////////////////////////////////////////////// 34 // Moodle core API // 35 //////////////////////////////////////////////////////////////////////////////// 36 37 /** 38 * Returns the information if the module supports a feature 39 * 40 * @see plugin_supports() in lib/moodlelib.php 41 * @param string $feature FEATURE_xx constant for requested feature 42 * @return mixed true if the feature is supported, null if unknown 43 */ 44 function workshop_supports($feature) { 45 switch($feature) { 46 case FEATURE_GRADE_HAS_GRADE: return true; 47 case FEATURE_GROUPS: return true; 48 case FEATURE_GROUPINGS: return true; 49 case FEATURE_MOD_INTRO: return true; 50 case FEATURE_BACKUP_MOODLE2: return true; 51 case FEATURE_COMPLETION_TRACKS_VIEWS: 52 return true; 53 case FEATURE_SHOW_DESCRIPTION: return true; 54 case FEATURE_PLAGIARISM: return true; 55 default: return null; 56 } 57 } 58 59 /** 60 * Saves a new instance of the workshop into the database 61 * 62 * Given an object containing all the necessary data, 63 * (defined by the form in mod_form.php) this function 64 * will save a new instance and return the id number 65 * of the new instance. 66 * 67 * @param stdClass $workshop An object from the form in mod_form.php 68 * @return int The id of the newly inserted workshop record 69 */ 70 function workshop_add_instance(stdclass $workshop) { 71 global $CFG, $DB; 72 require_once (__DIR__ . '/locallib.php'); 73 74 $workshop->phase = workshop::PHASE_SETUP; 75 $workshop->timecreated = time(); 76 $workshop->timemodified = $workshop->timecreated; 77 $workshop->useexamples = (int)!empty($workshop->useexamples); 78 $workshop->usepeerassessment = 1; 79 $workshop->useselfassessment = (int)!empty($workshop->useselfassessment); 80 $workshop->latesubmissions = (int)!empty($workshop->latesubmissions); 81 $workshop->phaseswitchassessment = (int)!empty($workshop->phaseswitchassessment); 82 $workshop->evaluation = 'best'; 83 84 if (isset($workshop->gradinggradepass)) { 85 $workshop->gradinggradepass = (float)unformat_float($workshop->gradinggradepass); 86 } 87 88 if (isset($workshop->submissiongradepass)) { 89 $workshop->submissiongradepass = (float)unformat_float($workshop->submissiongradepass); 90 } 91 92 if (isset($workshop->submissionfiletypes)) { 93 $workshop->submissionfiletypes = workshop::clean_file_extensions($workshop->submissionfiletypes); 94 } 95 96 if (isset($workshop->overallfeedbackfiletypes)) { 97 $workshop->overallfeedbackfiletypes = workshop::clean_file_extensions($workshop->overallfeedbackfiletypes); 98 } 99 100 // insert the new record so we get the id 101 $workshop->id = $DB->insert_record('workshop', $workshop); 102 103 // we need to use context now, so we need to make sure all needed info is already in db 104 $cmid = $workshop->coursemodule; 105 $DB->set_field('course_modules', 'instance', $workshop->id, array('id' => $cmid)); 106 $context = context_module::instance($cmid); 107 108 // process the custom wysiwyg editors 109 if ($draftitemid = $workshop->instructauthorseditor['itemid']) { 110 $workshop->instructauthors = file_save_draft_area_files($draftitemid, $context->id, 'mod_workshop', 'instructauthors', 111 0, workshop::instruction_editors_options($context), $workshop->instructauthorseditor['text']); 112 $workshop->instructauthorsformat = $workshop->instructauthorseditor['format']; 113 } 114 115 if ($draftitemid = $workshop->instructreviewerseditor['itemid']) { 116 $workshop->instructreviewers = file_save_draft_area_files($draftitemid, $context->id, 'mod_workshop', 'instructreviewers', 117 0, workshop::instruction_editors_options($context), $workshop->instructreviewerseditor['text']); 118 $workshop->instructreviewersformat = $workshop->instructreviewerseditor['format']; 119 } 120 121 if ($draftitemid = $workshop->conclusioneditor['itemid']) { 122 $workshop->conclusion = file_save_draft_area_files($draftitemid, $context->id, 'mod_workshop', 'conclusion', 123 0, workshop::instruction_editors_options($context), $workshop->conclusioneditor['text']); 124 $workshop->conclusionformat = $workshop->conclusioneditor['format']; 125 } 126 127 // re-save the record with the replaced URLs in editor fields 128 $DB->update_record('workshop', $workshop); 129 130 // create gradebook items 131 workshop_grade_item_update($workshop); 132 workshop_grade_item_category_update($workshop); 133 134 // create calendar events 135 workshop_calendar_update($workshop, $workshop->coursemodule); 136 137 return $workshop->id; 138 } 139 140 /** 141 * Given an object containing all the necessary data, 142 * (defined by the form in mod_form.php) this function 143 * will update an existing instance with new data. 144 * 145 * @param stdClass $workshop An object from the form in mod_form.php 146 * @return bool success 147 */ 148 function workshop_update_instance(stdclass $workshop) { 149 global $CFG, $DB; 150 require_once (__DIR__ . '/locallib.php'); 151 152 $workshop->timemodified = time(); 153 $workshop->id = $workshop->instance; 154 $workshop->useexamples = (int)!empty($workshop->useexamples); 155 $workshop->usepeerassessment = 1; 156 $workshop->useselfassessment = (int)!empty($workshop->useselfassessment); 157 $workshop->latesubmissions = (int)!empty($workshop->latesubmissions); 158 $workshop->phaseswitchassessment = (int)!empty($workshop->phaseswitchassessment); 159 160 if (isset($workshop->gradinggradepass)) { 161 $workshop->gradinggradepass = (float)unformat_float($workshop->gradinggradepass); 162 } 163 164 if (isset($workshop->submissiongradepass)) { 165 $workshop->submissiongradepass = (float)unformat_float($workshop->submissiongradepass); 166 } 167 168 if (isset($workshop->submissionfiletypes)) { 169 $workshop->submissionfiletypes = workshop::clean_file_extensions($workshop->submissionfiletypes); 170 } 171 172 if (isset($workshop->overallfeedbackfiletypes)) { 173 $workshop->overallfeedbackfiletypes = workshop::clean_file_extensions($workshop->overallfeedbackfiletypes); 174 } 175 176 // todo - if the grading strategy is being changed, we may want to replace all aggregated peer grades with nulls 177 178 $DB->update_record('workshop', $workshop); 179 $context = context_module::instance($workshop->coursemodule); 180 181 // process the custom wysiwyg editors 182 if ($draftitemid = $workshop->instructauthorseditor['itemid']) { 183 $workshop->instructauthors = file_save_draft_area_files($draftitemid, $context->id, 'mod_workshop', 'instructauthors', 184 0, workshop::instruction_editors_options($context), $workshop->instructauthorseditor['text']); 185 $workshop->instructauthorsformat = $workshop->instructauthorseditor['format']; 186 } 187 188 if ($draftitemid = $workshop->instructreviewerseditor['itemid']) { 189 $workshop->instructreviewers = file_save_draft_area_files($draftitemid, $context->id, 'mod_workshop', 'instructreviewers', 190 0, workshop::instruction_editors_options($context), $workshop->instructreviewerseditor['text']); 191 $workshop->instructreviewersformat = $workshop->instructreviewerseditor['format']; 192 } 193 194 if ($draftitemid = $workshop->conclusioneditor['itemid']) { 195 $workshop->conclusion = file_save_draft_area_files($draftitemid, $context->id, 'mod_workshop', 'conclusion', 196 0, workshop::instruction_editors_options($context), $workshop->conclusioneditor['text']); 197 $workshop->conclusionformat = $workshop->conclusioneditor['format']; 198 } 199 200 // re-save the record with the replaced URLs in editor fields 201 $DB->update_record('workshop', $workshop); 202 203 // update gradebook items 204 workshop_grade_item_update($workshop); 205 workshop_grade_item_category_update($workshop); 206 207 // update calendar events 208 workshop_calendar_update($workshop, $workshop->coursemodule); 209 210 return true; 211 } 212 213 /** 214 * Given an ID of an instance of this module, 215 * this function will permanently delete the instance 216 * and any data that depends on it. 217 * 218 * @param int $id Id of the module instance 219 * @return boolean Success/Failure 220 */ 221 function workshop_delete_instance($id) { 222 global $CFG, $DB; 223 require_once($CFG->libdir.'/gradelib.php'); 224 225 if (! $workshop = $DB->get_record('workshop', array('id' => $id))) { 226 return false; 227 } 228 229 // delete all associated aggregations 230 $DB->delete_records('workshop_aggregations', array('workshopid' => $workshop->id)); 231 232 // get the list of ids of all submissions 233 $submissions = $DB->get_records('workshop_submissions', array('workshopid' => $workshop->id), '', 'id'); 234 235 // get the list of all allocated assessments 236 $assessments = $DB->get_records_list('workshop_assessments', 'submissionid', array_keys($submissions), '', 'id'); 237 238 // delete the associated records from the workshop core tables 239 $DB->delete_records_list('workshop_grades', 'assessmentid', array_keys($assessments)); 240 $DB->delete_records_list('workshop_assessments', 'id', array_keys($assessments)); 241 $DB->delete_records_list('workshop_submissions', 'id', array_keys($submissions)); 242 243 // call the static clean-up methods of all available subplugins 244 $strategies = core_component::get_plugin_list('workshopform'); 245 foreach ($strategies as $strategy => $path) { 246 require_once ($path.'/lib.php'); 247 $classname = 'workshop_'.$strategy.'_strategy'; 248 call_user_func($classname.'::delete_instance', $workshop->id); 249 } 250 251 $allocators = core_component::get_plugin_list('workshopallocation'); 252 foreach ($allocators as $allocator => $path) { 253 require_once ($path.'/lib.php'); 254 $classname = 'workshop_'.$allocator.'_allocator'; 255 call_user_func($classname.'::delete_instance', $workshop->id); 256 } 257 258 $evaluators = core_component::get_plugin_list('workshopeval'); 259 foreach ($evaluators as $evaluator => $path) { 260 require_once ($path.'/lib.php'); 261 $classname = 'workshop_'.$evaluator.'_evaluation'; 262 call_user_func($classname.'::delete_instance', $workshop->id); 263 } 264 265 // delete the calendar events 266 $events = $DB->get_records('event', array('modulename' => 'workshop', 'instance' => $workshop->id)); 267 foreach ($events as $event) { 268 $event = calendar_event::load($event); 269 $event->delete(); 270 } 271 272 // finally remove the workshop record itself 273 $DB->delete_records('workshop', array('id' => $workshop->id)); 274 275 // gradebook cleanup 276 grade_update('mod/workshop', $workshop->course, 'mod', 'workshop', $workshop->id, 0, null, array('deleted' => true)); 277 grade_update('mod/workshop', $workshop->course, 'mod', 'workshop', $workshop->id, 1, null, array('deleted' => true)); 278 279 return true; 280 } 281 282 /** 283 * List the actions that correspond to a view of this module. 284 * This is used by the participation report. 285 * 286 * Note: This is not used by new logging system. Event with 287 * crud = 'r' and edulevel = LEVEL_PARTICIPATING will 288 * be considered as view action. 289 * 290 * @return array 291 */ 292 function workshop_get_view_actions() { 293 return array('view', 'view all', 'view submission', 'view example'); 294 } 295 296 /** 297 * List the actions that correspond to a post of this module. 298 * This is used by the participation report. 299 * 300 * Note: This is not used by new logging system. Event with 301 * crud = ('c' || 'u' || 'd') and edulevel = LEVEL_PARTICIPATING 302 * will be considered as post action. 303 * 304 * @return array 305 */ 306 function workshop_get_post_actions() { 307 return array('add', 'add assessment', 'add example', 'add submission', 308 'update', 'update assessment', 'update example', 'update submission'); 309 } 310 311 /** 312 * Return a small object with summary information about what a 313 * user has done with a given particular instance of this module 314 * Used for user activity reports. 315 * $return->time = the time they did it 316 * $return->info = a short text description 317 * 318 * @param stdClass $course The course record. 319 * @param stdClass $user The user record. 320 * @param cm_info|stdClass $mod The course module info object or record. 321 * @param stdClass $workshop The workshop instance record. 322 * @return stdclass|null 323 */ 324 function workshop_user_outline($course, $user, $mod, $workshop) { 325 global $CFG, $DB; 326 require_once($CFG->libdir.'/gradelib.php'); 327 328 $grades = grade_get_grades($course->id, 'mod', 'workshop', $workshop->id, $user->id); 329 330 $submissiongrade = null; 331 $assessmentgrade = null; 332 333 $info = ''; 334 $time = 0; 335 336 if (!empty($grades->items[0]->grades)) { 337 $submissiongrade = reset($grades->items[0]->grades); 338 $info .= get_string('submissiongrade', 'workshop') . ': ' . $submissiongrade->str_long_grade . html_writer::empty_tag('br'); 339 $time = max($time, $submissiongrade->dategraded); 340 } 341 if (!empty($grades->items[1]->grades)) { 342 $assessmentgrade = reset($grades->items[1]->grades); 343 $info .= get_string('gradinggrade', 'workshop') . ': ' . $assessmentgrade->str_long_grade; 344 $time = max($time, $assessmentgrade->dategraded); 345 } 346 347 if (!empty($info) and !empty($time)) { 348 $return = new stdclass(); 349 $return->time = $time; 350 $return->info = $info; 351 return $return; 352 } 353 354 return null; 355 } 356 357 /** 358 * Print a detailed representation of what a user has done with 359 * a given particular instance of this module, for user activity reports. 360 * 361 * @param stdClass $course The course record. 362 * @param stdClass $user The user record. 363 * @param cm_info|stdClass $mod The course module info object or record. 364 * @param stdClass $workshop The workshop instance record. 365 * @return string HTML 366 */ 367 function workshop_user_complete($course, $user, $mod, $workshop) { 368 global $CFG, $DB, $OUTPUT; 369 require_once (__DIR__.'/locallib.php'); 370 require_once($CFG->libdir.'/gradelib.php'); 371 372 $workshop = new workshop($workshop, $mod, $course); 373 $grades = grade_get_grades($course->id, 'mod', 'workshop', $workshop->id, $user->id); 374 375 if (!empty($grades->items[0]->grades)) { 376 $submissiongrade = reset($grades->items[0]->grades); 377 $info = get_string('submissiongrade', 'workshop') . ': ' . $submissiongrade->str_long_grade; 378 echo html_writer::tag('li', $info, array('class'=>'submissiongrade')); 379 } 380 if (!empty($grades->items[1]->grades)) { 381 $assessmentgrade = reset($grades->items[1]->grades); 382 $info = get_string('gradinggrade', 'workshop') . ': ' . $assessmentgrade->str_long_grade; 383 echo html_writer::tag('li', $info, array('class'=>'gradinggrade')); 384 } 385 386 if (has_capability('mod/workshop:viewallsubmissions', $workshop->context)) { 387 $canviewsubmission = true; 388 if (groups_get_activity_groupmode($workshop->cm) == SEPARATEGROUPS) { 389 // user must have accessallgroups or share at least one group with the submission author 390 if (!has_capability('moodle/site:accessallgroups', $workshop->context)) { 391 $usersgroups = groups_get_activity_allowed_groups($workshop->cm); 392 $authorsgroups = groups_get_all_groups($workshop->course->id, $user->id, $workshop->cm->groupingid, 'g.id'); 393 $sharedgroups = array_intersect_key($usersgroups, $authorsgroups); 394 if (empty($sharedgroups)) { 395 $canviewsubmission = false; 396 } 397 } 398 } 399 if ($canviewsubmission and $submission = $workshop->get_submission_by_author($user->id)) { 400 $title = format_string($submission->title); 401 $url = $workshop->submission_url($submission->id); 402 $link = html_writer::link($url, $title); 403 $info = get_string('submission', 'workshop').': '.$link; 404 echo html_writer::tag('li', $info, array('class'=>'submission')); 405 } 406 } 407 408 if (has_capability('mod/workshop:viewallassessments', $workshop->context)) { 409 if ($assessments = $workshop->get_assessments_by_reviewer($user->id)) { 410 foreach ($assessments as $assessment) { 411 $a = new stdclass(); 412 $a->submissionurl = $workshop->submission_url($assessment->submissionid)->out(); 413 $a->assessmenturl = $workshop->assess_url($assessment->id)->out(); 414 $a->submissiontitle = s($assessment->submissiontitle); 415 echo html_writer::tag('li', get_string('assessmentofsubmission', 'workshop', $a)); 416 } 417 } 418 } 419 } 420 421 /** 422 * Given a course and a time, this module should find recent activity 423 * that has occurred in workshop activities and print it out. 424 * Return true if there was output, or false is there was none. 425 * 426 * @param stdClass $course 427 * @param bool $viewfullnames 428 * @param int $timestart 429 * @return boolean 430 */ 431 function workshop_print_recent_activity($course, $viewfullnames, $timestart) { 432 global $CFG, $USER, $DB, $OUTPUT; 433 434 $authoramefields = get_all_user_name_fields(true, 'author', null, 'author'); 435 $reviewerfields = get_all_user_name_fields(true, 'reviewer', null, 'reviewer'); 436 437 $sql = "SELECT s.id AS submissionid, s.title AS submissiontitle, s.timemodified AS submissionmodified, 438 author.id AS authorid, $authoramefields, a.id AS assessmentid, a.timemodified AS assessmentmodified, 439 reviewer.id AS reviewerid, $reviewerfields, cm.id AS cmid 440 FROM {workshop} w 441 INNER JOIN {course_modules} cm ON cm.instance = w.id 442 INNER JOIN {modules} md ON md.id = cm.module 443 INNER JOIN {workshop_submissions} s ON s.workshopid = w.id 444 INNER JOIN {user} author ON s.authorid = author.id 445 LEFT JOIN {workshop_assessments} a ON a.submissionid = s.id 446 LEFT JOIN {user} reviewer ON a.reviewerid = reviewer.id 447 WHERE cm.course = ? 448 AND md.name = 'workshop' 449 AND s.example = 0 450 AND (s.timemodified > ? OR a.timemodified > ?) 451 ORDER BY s.timemodified"; 452 453 $rs = $DB->get_recordset_sql($sql, array($course->id, $timestart, $timestart)); 454 455 $modinfo = get_fast_modinfo($course); // reference needed because we might load the groups 456 457 $submissions = array(); // recent submissions indexed by submission id 458 $assessments = array(); // recent assessments indexed by assessment id 459 $users = array(); 460 461 foreach ($rs as $activity) { 462 if (!array_key_exists($activity->cmid, $modinfo->cms)) { 463 // this should not happen but just in case 464 continue; 465 } 466 467 $cm = $modinfo->cms[$activity->cmid]; 468 if (!$cm->uservisible) { 469 continue; 470 } 471 472 // remember all user names we can use later 473 if (empty($users[$activity->authorid])) { 474 $u = new stdclass(); 475 $users[$activity->authorid] = username_load_fields_from_object($u, $activity, 'author'); 476 } 477 if ($activity->reviewerid and empty($users[$activity->reviewerid])) { 478 $u = new stdclass(); 479 $users[$activity->reviewerid] = username_load_fields_from_object($u, $activity, 'reviewer'); 480 } 481 482 $context = context_module::instance($cm->id); 483 $groupmode = groups_get_activity_groupmode($cm, $course); 484 485 if ($activity->submissionmodified > $timestart and empty($submissions[$activity->submissionid])) { 486 $s = new stdclass(); 487 $s->title = $activity->submissiontitle; 488 $s->authorid = $activity->authorid; 489 $s->timemodified = $activity->submissionmodified; 490 $s->cmid = $activity->cmid; 491 if ($activity->authorid == $USER->id || has_capability('mod/workshop:viewauthornames', $context)) { 492 $s->authornamevisible = true; 493 } else { 494 $s->authornamevisible = false; 495 } 496 497 // the following do-while wrapper allows to break from deeply nested if-statements 498 do { 499 if ($s->authorid === $USER->id) { 500 // own submissions always visible 501 $submissions[$activity->submissionid] = $s; 502 break; 503 } 504 505 if (has_capability('mod/workshop:viewallsubmissions', $context)) { 506 if ($groupmode == SEPARATEGROUPS and !has_capability('moodle/site:accessallgroups', $context)) { 507 if (isguestuser()) { 508 // shortcut - guest user does not belong into any group 509 break; 510 } 511 512 // this might be slow - show only submissions by users who share group with me in this cm 513 if (!$modinfo->get_groups($cm->groupingid)) { 514 break; 515 } 516 $authorsgroups = groups_get_all_groups($course->id, $s->authorid, $cm->groupingid); 517 if (is_array($authorsgroups)) { 518 $authorsgroups = array_keys($authorsgroups); 519 $intersect = array_intersect($authorsgroups, $modinfo->get_groups($cm->groupingid)); 520 if (empty($intersect)) { 521 break; 522 } else { 523 // can see all submissions and shares a group with the author 524 $submissions[$activity->submissionid] = $s; 525 break; 526 } 527 } 528 529 } else { 530 // can see all submissions from all groups 531 $submissions[$activity->submissionid] = $s; 532 } 533 } 534 } while (0); 535 } 536 537 if ($activity->assessmentmodified > $timestart and empty($assessments[$activity->assessmentid])) { 538 $a = new stdclass(); 539 $a->submissionid = $activity->submissionid; 540 $a->submissiontitle = $activity->submissiontitle; 541 $a->reviewerid = $activity->reviewerid; 542 $a->timemodified = $activity->assessmentmodified; 543 $a->cmid = $activity->cmid; 544 if ($activity->reviewerid == $USER->id || has_capability('mod/workshop:viewreviewernames', $context)) { 545 $a->reviewernamevisible = true; 546 } else { 547 $a->reviewernamevisible = false; 548 } 549 550 // the following do-while wrapper allows to break from deeply nested if-statements 551 do { 552 if ($a->reviewerid === $USER->id) { 553 // own assessments always visible 554 $assessments[$activity->assessmentid] = $a; 555 break; 556 } 557 558 if (has_capability('mod/workshop:viewallassessments', $context)) { 559 if ($groupmode == SEPARATEGROUPS and !has_capability('moodle/site:accessallgroups', $context)) { 560 if (isguestuser()) { 561 // shortcut - guest user does not belong into any group 562 break; 563 } 564 565 // this might be slow - show only submissions by users who share group with me in this cm 566 if (!$modinfo->get_groups($cm->groupingid)) { 567 break; 568 } 569 $reviewersgroups = groups_get_all_groups($course->id, $a->reviewerid, $cm->groupingid); 570 if (is_array($reviewersgroups)) { 571 $reviewersgroups = array_keys($reviewersgroups); 572 $intersect = array_intersect($reviewersgroups, $modinfo->get_groups($cm->groupingid)); 573 if (empty($intersect)) { 574 break; 575 } else { 576 // can see all assessments and shares a group with the reviewer 577 $assessments[$activity->assessmentid] = $a; 578 break; 579 } 580 } 581 582 } else { 583 // can see all assessments from all groups 584 $assessments[$activity->assessmentid] = $a; 585 } 586 } 587 } while (0); 588 } 589 } 590 $rs->close(); 591 592 $shown = false; 593 594 if (!empty($submissions)) { 595 $shown = true; 596 echo $OUTPUT->heading(get_string('recentsubmissions', 'workshop'), 3); 597 foreach ($submissions as $id => $submission) { 598 $link = new moodle_url('/mod/workshop/submission.php', array('id'=>$id, 'cmid'=>$submission->cmid)); 599 if ($submission->authornamevisible) { 600 $author = $users[$submission->authorid]; 601 } else { 602 $author = null; 603 } 604 print_recent_activity_note($submission->timemodified, $author, $submission->title, $link->out(), false, $viewfullnames); 605 } 606 } 607 608 if (!empty($assessments)) { 609 $shown = true; 610 echo $OUTPUT->heading(get_string('recentassessments', 'workshop'), 3); 611 core_collator::asort_objects_by_property($assessments, 'timemodified'); 612 foreach ($assessments as $id => $assessment) { 613 $link = new moodle_url('/mod/workshop/assessment.php', array('asid' => $id)); 614 if ($assessment->reviewernamevisible) { 615 $reviewer = $users[$assessment->reviewerid]; 616 } else { 617 $reviewer = null; 618 } 619 print_recent_activity_note($assessment->timemodified, $reviewer, $assessment->submissiontitle, $link->out(), false, $viewfullnames); 620 } 621 } 622 623 if ($shown) { 624 return true; 625 } 626 627 return false; 628 } 629 630 /** 631 * Returns all activity in course workshops since a given time 632 * 633 * @param array $activities sequentially indexed array of objects 634 * @param int $index 635 * @param int $timestart 636 * @param int $courseid 637 * @param int $cmid 638 * @param int $userid defaults to 0 639 * @param int $groupid defaults to 0 640 * @return void adds items into $activities and increases $index 641 */ 642 function workshop_get_recent_mod_activity(&$activities, &$index, $timestart, $courseid, $cmid, $userid=0, $groupid=0) { 643 global $CFG, $COURSE, $USER, $DB; 644 645 if ($COURSE->id == $courseid) { 646 $course = $COURSE; 647 } else { 648 $course = $DB->get_record('course', array('id'=>$courseid)); 649 } 650 651 $modinfo = get_fast_modinfo($course); 652 653 $cm = $modinfo->cms[$cmid]; 654 655 $params = array(); 656 if ($userid) { 657 $userselect = "AND (author.id = :authorid OR reviewer.id = :reviewerid)"; 658 $params['authorid'] = $userid; 659 $params['reviewerid'] = $userid; 660 } else { 661 $userselect = ""; 662 } 663 664 if ($groupid) { 665 $groupselect = "AND (authorgroupmembership.groupid = :authorgroupid OR reviewergroupmembership.groupid = :reviewergroupid)"; 666 $groupjoin = "LEFT JOIN {groups_members} authorgroupmembership ON authorgroupmembership.userid = author.id 667 LEFT JOIN {groups_members} reviewergroupmembership ON reviewergroupmembership.userid = reviewer.id"; 668 $params['authorgroupid'] = $groupid; 669 $params['reviewergroupid'] = $groupid; 670 } else { 671 $groupselect = ""; 672 $groupjoin = ""; 673 } 674 675 $params['cminstance'] = $cm->instance; 676 $params['submissionmodified'] = $timestart; 677 $params['assessmentmodified'] = $timestart; 678 679 $authornamefields = get_all_user_name_fields(true, 'author', null, 'author'); 680 $reviewerfields = get_all_user_name_fields(true, 'reviewer', null, 'reviewer'); 681 682 $sql = "SELECT s.id AS submissionid, s.title AS submissiontitle, s.timemodified AS submissionmodified, 683 author.id AS authorid, $authornamefields, author.picture AS authorpicture, author.imagealt AS authorimagealt, 684 author.email AS authoremail, a.id AS assessmentid, a.timemodified AS assessmentmodified, 685 reviewer.id AS reviewerid, $reviewerfields, reviewer.picture AS reviewerpicture, 686 reviewer.imagealt AS reviewerimagealt, reviewer.email AS revieweremail 687 FROM {workshop_submissions} s 688 INNER JOIN {workshop} w ON s.workshopid = w.id 689 INNER JOIN {user} author ON s.authorid = author.id 690 LEFT JOIN {workshop_assessments} a ON a.submissionid = s.id 691 LEFT JOIN {user} reviewer ON a.reviewerid = reviewer.id 692 $groupjoin 693 WHERE w.id = :cminstance 694 AND s.example = 0 695 $userselect $groupselect 696 AND (s.timemodified > :submissionmodified OR a.timemodified > :assessmentmodified) 697 ORDER BY s.timemodified ASC, a.timemodified ASC"; 698 699 $rs = $DB->get_recordset_sql($sql, $params); 700 701 $groupmode = groups_get_activity_groupmode($cm, $course); 702 $context = context_module::instance($cm->id); 703 $grader = has_capability('moodle/grade:viewall', $context); 704 $accessallgroups = has_capability('moodle/site:accessallgroups', $context); 705 $viewauthors = has_capability('mod/workshop:viewauthornames', $context); 706 $viewreviewers = has_capability('mod/workshop:viewreviewernames', $context); 707 708 $submissions = array(); // recent submissions indexed by submission id 709 $assessments = array(); // recent assessments indexed by assessment id 710 $users = array(); 711 712 foreach ($rs as $activity) { 713 714 // remember all user names we can use later 715 if (empty($users[$activity->authorid])) { 716 $u = new stdclass(); 717 $additionalfields = explode(',', user_picture::fields()); 718 $u = username_load_fields_from_object($u, $activity, 'author', $additionalfields); 719 $users[$activity->authorid] = $u; 720 } 721 if ($activity->reviewerid and empty($users[$activity->reviewerid])) { 722 $u = new stdclass(); 723 $additionalfields = explode(',', user_picture::fields()); 724 $u = username_load_fields_from_object($u, $activity, 'reviewer', $additionalfields); 725 $users[$activity->reviewerid] = $u; 726 } 727 728 if ($activity->submissionmodified > $timestart and empty($submissions[$activity->submissionid])) { 729 $s = new stdclass(); 730 $s->id = $activity->submissionid; 731 $s->title = $activity->submissiontitle; 732 $s->authorid = $activity->authorid; 733 $s->timemodified = $activity->submissionmodified; 734 if ($activity->authorid == $USER->id || has_capability('mod/workshop:viewauthornames', $context)) { 735 $s->authornamevisible = true; 736 } else { 737 $s->authornamevisible = false; 738 } 739 740 // the following do-while wrapper allows to break from deeply nested if-statements 741 do { 742 if ($s->authorid === $USER->id) { 743 // own submissions always visible 744 $submissions[$activity->submissionid] = $s; 745 break; 746 } 747 748 if (has_capability('mod/workshop:viewallsubmissions', $context)) { 749 if ($groupmode == SEPARATEGROUPS and !has_capability('moodle/site:accessallgroups', $context)) { 750 if (isguestuser()) { 751 // shortcut - guest user does not belong into any group 752 break; 753 } 754 755 // this might be slow - show only submissions by users who share group with me in this cm 756 if (!$modinfo->get_groups($cm->groupingid)) { 757 break; 758 } 759 $authorsgroups = groups_get_all_groups($course->id, $s->authorid, $cm->groupingid); 760 if (is_array($authorsgroups)) { 761 $authorsgroups = array_keys($authorsgroups); 762 $intersect = array_intersect($authorsgroups, $modinfo->get_groups($cm->groupingid)); 763 if (empty($intersect)) { 764 break; 765 } else { 766 // can see all submissions and shares a group with the author 767 $submissions[$activity->submissionid] = $s; 768 break; 769 } 770 } 771 772 } else { 773 // can see all submissions from all groups 774 $submissions[$activity->submissionid] = $s; 775 } 776 } 777 } while (0); 778 } 779 780 if ($activity->assessmentmodified > $timestart and empty($assessments[$activity->assessmentid])) { 781 $a = new stdclass(); 782 $a->id = $activity->assessmentid; 783 $a->submissionid = $activity->submissionid; 784 $a->submissiontitle = $activity->submissiontitle; 785 $a->reviewerid = $activity->reviewerid; 786 $a->timemodified = $activity->assessmentmodified; 787 if ($activity->reviewerid == $USER->id || has_capability('mod/workshop:viewreviewernames', $context)) { 788 $a->reviewernamevisible = true; 789 } else { 790 $a->reviewernamevisible = false; 791 } 792 793 // the following do-while wrapper allows to break from deeply nested if-statements 794 do { 795 if ($a->reviewerid === $USER->id) { 796 // own assessments always visible 797 $assessments[$activity->assessmentid] = $a; 798 break; 799 } 800 801 if (has_capability('mod/workshop:viewallassessments', $context)) { 802 if ($groupmode == SEPARATEGROUPS and !has_capability('moodle/site:accessallgroups', $context)) { 803 if (isguestuser()) { 804 // shortcut - guest user does not belong into any group 805 break; 806 } 807 808 // this might be slow - show only submissions by users who share group with me in this cm 809 if (!$modinfo->get_groups($cm->groupingid)) { 810 break; 811 } 812 $reviewersgroups = groups_get_all_groups($course->id, $a->reviewerid, $cm->groupingid); 813 if (is_array($reviewersgroups)) { 814 $reviewersgroups = array_keys($reviewersgroups); 815 $intersect = array_intersect($reviewersgroups, $modinfo->get_groups($cm->groupingid)); 816 if (empty($intersect)) { 817 break; 818 } else { 819 // can see all assessments and shares a group with the reviewer 820 $assessments[$activity->assessmentid] = $a; 821 break; 822 } 823 } 824 825 } else { 826 // can see all assessments from all groups 827 $assessments[$activity->assessmentid] = $a; 828 } 829 } 830 } while (0); 831 } 832 } 833 $rs->close(); 834 835 $workshopname = format_string($cm->name, true); 836 837 if ($grader) { 838 require_once($CFG->libdir.'/gradelib.php'); 839 $grades = grade_get_grades($courseid, 'mod', 'workshop', $cm->instance, array_keys($users)); 840 } 841 842 foreach ($submissions as $submission) { 843 $tmpactivity = new stdclass(); 844 $tmpactivity->type = 'workshop'; 845 $tmpactivity->cmid = $cm->id; 846 $tmpactivity->name = $workshopname; 847 $tmpactivity->sectionnum = $cm->sectionnum; 848 $tmpactivity->timestamp = $submission->timemodified; 849 $tmpactivity->subtype = 'submission'; 850 $tmpactivity->content = $submission; 851 if ($grader) { 852 $tmpactivity->grade = $grades->items[0]->grades[$submission->authorid]->str_long_grade; 853 } 854 if ($submission->authornamevisible and !empty($users[$submission->authorid])) { 855 $tmpactivity->user = $users[$submission->authorid]; 856 } 857 $activities[$index++] = $tmpactivity; 858 } 859 860 foreach ($assessments as $assessment) { 861 $tmpactivity = new stdclass(); 862 $tmpactivity->type = 'workshop'; 863 $tmpactivity->cmid = $cm->id; 864 $tmpactivity->name = $workshopname; 865 $tmpactivity->sectionnum = $cm->sectionnum; 866 $tmpactivity->timestamp = $assessment->timemodified; 867 $tmpactivity->subtype = 'assessment'; 868 $tmpactivity->content = $assessment; 869 if ($grader) { 870 $tmpactivity->grade = $grades->items[1]->grades[$assessment->reviewerid]->str_long_grade; 871 } 872 if ($assessment->reviewernamevisible and !empty($users[$assessment->reviewerid])) { 873 $tmpactivity->user = $users[$assessment->reviewerid]; 874 } 875 $activities[$index++] = $tmpactivity; 876 } 877 } 878 879 /** 880 * Print single activity item prepared by {@see workshop_get_recent_mod_activity()} 881 */ 882 function workshop_print_recent_mod_activity($activity, $courseid, $detail, $modnames, $viewfullnames) { 883 global $CFG, $OUTPUT; 884 885 if (!empty($activity->user)) { 886 echo html_writer::tag('div', $OUTPUT->user_picture($activity->user, array('courseid'=>$courseid)), 887 array('style' => 'float: left; padding: 7px;')); 888 } 889 890 if ($activity->subtype == 'submission') { 891 echo html_writer::start_tag('div', array('class'=>'submission', 'style'=>'padding: 7px; float:left;')); 892 893 if ($detail) { 894 echo html_writer::start_tag('h4', array('class'=>'workshop')); 895 $url = new moodle_url('/mod/workshop/view.php', array('id'=>$activity->cmid)); 896 $name = s($activity->name); 897 echo html_writer::empty_tag('img', array('src'=>$OUTPUT->pix_url('icon', $activity->type), 'class'=>'icon', 'alt'=>$name)); 898 echo ' ' . $modnames[$activity->type]; 899 echo html_writer::link($url, $name, array('class'=>'name', 'style'=>'margin-left: 5px')); 900 echo html_writer::end_tag('h4'); 901 } 902 903 echo html_writer::start_tag('div', array('class'=>'title')); 904 $url = new moodle_url('/mod/workshop/submission.php', array('cmid'=>$activity->cmid, 'id'=>$activity->content->id)); 905 $name = s($activity->content->title); 906 echo html_writer::tag('strong', html_writer::link($url, $name)); 907 echo html_writer::end_tag('div'); 908 909 if (!empty($activity->user)) { 910 echo html_writer::start_tag('div', array('class'=>'user')); 911 $url = new moodle_url('/user/view.php', array('id'=>$activity->user->id, 'course'=>$courseid)); 912 $name = fullname($activity->user); 913 $link = html_writer::link($url, $name); 914 echo get_string('submissionby', 'workshop', $link); 915 echo ' - '.userdate($activity->timestamp); 916 echo html_writer::end_tag('div'); 917 } else { 918 echo html_writer::start_tag('div', array('class'=>'anonymous')); 919 echo get_string('submission', 'workshop'); 920 echo ' - '.userdate($activity->timestamp); 921 echo html_writer::end_tag('div'); 922 } 923 924 echo html_writer::end_tag('div'); 925 } 926 927 if ($activity->subtype == 'assessment') { 928 echo html_writer::start_tag('div', array('class'=>'assessment', 'style'=>'padding: 7px; float:left;')); 929 930 if ($detail) { 931 echo html_writer::start_tag('h4', array('class'=>'workshop')); 932 $url = new moodle_url('/mod/workshop/view.php', array('id'=>$activity->cmid)); 933 $name = s($activity->name); 934 echo html_writer::empty_tag('img', array('src'=>$OUTPUT->pix_url('icon', $activity->type), 'class'=>'icon', 'alt'=>$name)); 935 echo ' ' . $modnames[$activity->type]; 936 echo html_writer::link($url, $name, array('class'=>'name', 'style'=>'margin-left: 5px')); 937 echo html_writer::end_tag('h4'); 938 } 939 940 echo html_writer::start_tag('div', array('class'=>'title')); 941 $url = new moodle_url('/mod/workshop/assessment.php', array('asid'=>$activity->content->id)); 942 $name = s($activity->content->submissiontitle); 943 echo html_writer::tag('em', html_writer::link($url, $name)); 944 echo html_writer::end_tag('div'); 945 946 if (!empty($activity->user)) { 947 echo html_writer::start_tag('div', array('class'=>'user')); 948 $url = new moodle_url('/user/view.php', array('id'=>$activity->user->id, 'course'=>$courseid)); 949 $name = fullname($activity->user); 950 $link = html_writer::link($url, $name); 951 echo get_string('assessmentbyfullname', 'workshop', $link); 952 echo ' - '.userdate($activity->timestamp); 953 echo html_writer::end_tag('div'); 954 } else { 955 echo html_writer::start_tag('div', array('class'=>'anonymous')); 956 echo get_string('assessment', 'workshop'); 957 echo ' - '.userdate($activity->timestamp); 958 echo html_writer::end_tag('div'); 959 } 960 961 echo html_writer::end_tag('div'); 962 } 963 964 echo html_writer::empty_tag('br', array('style'=>'clear:both')); 965 } 966 967 /** 968 * Regular jobs to execute via cron 969 * 970 * @return boolean true on success, false otherwise 971 */ 972 function workshop_cron() { 973 global $CFG, $DB; 974 975 $now = time(); 976 977 mtrace(' processing workshop subplugins ...'); 978 cron_execute_plugin_type('workshopallocation', 'workshop allocation methods'); 979 980 // now when the scheduled allocator had a chance to do its job, check if there 981 // are some workshops to switch into the assessment phase 982 $workshops = $DB->get_records_select("workshop", 983 "phase = 20 AND phaseswitchassessment = 1 AND submissionend > 0 AND submissionend < ?", array($now)); 984 985 if (!empty($workshops)) { 986 mtrace('Processing automatic assessment phase switch in '.count($workshops).' workshop(s) ... ', ''); 987 require_once($CFG->dirroot.'/mod/workshop/locallib.php'); 988 foreach ($workshops as $workshop) { 989 $cm = get_coursemodule_from_instance('workshop', $workshop->id, $workshop->course, false, MUST_EXIST); 990 $course = $DB->get_record('course', array('id' => $cm->course), '*', MUST_EXIST); 991 $workshop = new workshop($workshop, $cm, $course); 992 $workshop->switch_phase(workshop::PHASE_ASSESSMENT); 993 994 $params = array( 995 'objectid' => $workshop->id, 996 'context' => $workshop->context, 997 'courseid' => $workshop->course->id, 998 'other' => array( 999 'workshopphase' => $workshop->phase 1000 ) 1001 ); 1002 $event = \mod_workshop\event\phase_switched::create($params); 1003 $event->trigger(); 1004 1005 // disable the automatic switching now so that it is not executed again by accident 1006 // if the teacher changes the phase back to the submission one 1007 $DB->set_field('workshop', 'phaseswitchassessment', 0, array('id' => $workshop->id)); 1008 1009 // todo inform the teachers 1010 } 1011 mtrace('done'); 1012 } 1013 1014 return true; 1015 } 1016 1017 /** 1018 * Is a given scale used by the instance of workshop? 1019 * 1020 * The function asks all installed grading strategy subplugins. The workshop 1021 * core itself does not use scales. Both grade for submission and grade for 1022 * assessments do not use scales. 1023 * 1024 * @param int $workshopid id of workshop instance 1025 * @param int $scaleid id of the scale to check 1026 * @return bool 1027 */ 1028 function workshop_scale_used($workshopid, $scaleid) { 1029 global $CFG; // other files included from here 1030 1031 $strategies = core_component::get_plugin_list('workshopform'); 1032 foreach ($strategies as $strategy => $strategypath) { 1033 $strategylib = $strategypath . '/lib.php'; 1034 if (is_readable($strategylib)) { 1035 require_once($strategylib); 1036 } else { 1037 throw new coding_exception('the grading forms subplugin must contain library ' . $strategylib); 1038 } 1039 $classname = 'workshop_' . $strategy . '_strategy'; 1040 if (method_exists($classname, 'scale_used')) { 1041 if (call_user_func_array(array($classname, 'scale_used'), array($scaleid, $workshopid))) { 1042 // no need to include any other files - scale is used 1043 return true; 1044 } 1045 } 1046 } 1047 1048 return false; 1049 } 1050 1051 /** 1052 * Is a given scale used by any instance of workshop? 1053 * 1054 * The function asks all installed grading strategy subplugins. The workshop 1055 * core itself does not use scales. Both grade for submission and grade for 1056 * assessments do not use scales. 1057 * 1058 * @param int $scaleid id of the scale to check 1059 * @return bool 1060 */ 1061 function workshop_scale_used_anywhere($scaleid) { 1062 global $CFG; // other files included from here 1063 1064 $strategies = core_component::get_plugin_list('workshopform'); 1065 foreach ($strategies as $strategy => $strategypath) { 1066 $strategylib = $strategypath . '/lib.php'; 1067 if (is_readable($strategylib)) { 1068 require_once($strategylib); 1069 } else { 1070 throw new coding_exception('the grading forms subplugin must contain library ' . $strategylib); 1071 } 1072 $classname = 'workshop_' . $strategy . '_strategy'; 1073 if (method_exists($classname, 'scale_used')) { 1074 if (call_user_func(array($classname, 'scale_used'), $scaleid)) { 1075 // no need to include any other files - scale is used 1076 return true; 1077 } 1078 } 1079 } 1080 1081 return false; 1082 } 1083 1084 /** 1085 * Returns all other caps used in the module 1086 * 1087 * @return array 1088 */ 1089 function workshop_get_extra_capabilities() { 1090 return array('moodle/site:accessallgroups'); 1091 } 1092 1093 //////////////////////////////////////////////////////////////////////////////// 1094 // Gradebook API // 1095 //////////////////////////////////////////////////////////////////////////////// 1096 1097 /** 1098 * Creates or updates grade items for the give workshop instance 1099 * 1100 * Needed by grade_update_mod_grades() in lib/gradelib.php. Also used by 1101 * {@link workshop_update_grades()}. 1102 * 1103 * @param stdClass $workshop instance object with extra cmidnumber property 1104 * @param stdClass $submissiongrades data for the first grade item 1105 * @param stdClass $assessmentgrades data for the second grade item 1106 * @return void 1107 */ 1108 function workshop_grade_item_update(stdclass $workshop, $submissiongrades=null, $assessmentgrades=null) { 1109 global $CFG; 1110 require_once($CFG->libdir.'/gradelib.php'); 1111 1112 $a = new stdclass(); 1113 $a->workshopname = clean_param($workshop->name, PARAM_NOTAGS); 1114 1115 $item = array(); 1116 $item['itemname'] = get_string('gradeitemsubmission', 'workshop', $a); 1117 $item['gradetype'] = GRADE_TYPE_VALUE; 1118 $item['grademax'] = $workshop->grade; 1119 $item['grademin'] = 0; 1120 grade_update('mod/workshop', $workshop->course, 'mod', 'workshop', $workshop->id, 0, $submissiongrades , $item); 1121 1122 $item = array(); 1123 $item['itemname'] = get_string('gradeitemassessment', 'workshop', $a); 1124 $item['gradetype'] = GRADE_TYPE_VALUE; 1125 $item['grademax'] = $workshop->gradinggrade; 1126 $item['grademin'] = 0; 1127 grade_update('mod/workshop', $workshop->course, 'mod', 'workshop', $workshop->id, 1, $assessmentgrades, $item); 1128 } 1129 1130 /** 1131 * Update workshop grades in the gradebook 1132 * 1133 * Needed by grade_update_mod_grades() in lib/gradelib.php 1134 * 1135 * @category grade 1136 * @param stdClass $workshop instance object with extra cmidnumber and modname property 1137 * @param int $userid update grade of specific user only, 0 means all participants 1138 * @return void 1139 */ 1140 function workshop_update_grades(stdclass $workshop, $userid=0) { 1141 global $CFG, $DB; 1142 require_once($CFG->libdir.'/gradelib.php'); 1143 1144 $whereuser = $userid ? ' AND authorid = :userid' : ''; 1145 $params = array('workshopid' => $workshop->id, 'userid' => $userid); 1146 $sql = 'SELECT authorid, grade, gradeover, gradeoverby, feedbackauthor, feedbackauthorformat, timemodified, timegraded 1147 FROM {workshop_submissions} 1148 WHERE workshopid = :workshopid AND example=0' . $whereuser; 1149 $records = $DB->get_records_sql($sql, $params); 1150 $submissiongrades = array(); 1151 foreach ($records as $record) { 1152 $grade = new stdclass(); 1153 $grade->userid = $record->authorid; 1154 if (!is_null($record->gradeover)) { 1155 $grade->rawgrade = grade_floatval($workshop->grade * $record->gradeover / 100); 1156 $grade->usermodified = $record->gradeoverby; 1157 } else { 1158 $grade->rawgrade = grade_floatval($workshop->grade * $record->grade / 100); 1159 } 1160 $grade->feedback = $record->feedbackauthor; 1161 $grade->feedbackformat = $record->feedbackauthorformat; 1162 $grade->datesubmitted = $record->timemodified; 1163 $grade->dategraded = $record->timegraded; 1164 $submissiongrades[$record->authorid] = $grade; 1165 } 1166 1167 $whereuser = $userid ? ' AND userid = :userid' : ''; 1168 $params = array('workshopid' => $workshop->id, 'userid' => $userid); 1169 $sql = 'SELECT userid, gradinggrade, timegraded 1170 FROM {workshop_aggregations} 1171 WHERE workshopid = :workshopid' . $whereuser; 1172 $records = $DB->get_records_sql($sql, $params); 1173 $assessmentgrades = array(); 1174 foreach ($records as $record) { 1175 $grade = new stdclass(); 1176 $grade->userid = $record->userid; 1177 $grade->rawgrade = grade_floatval($workshop->gradinggrade * $record->gradinggrade / 100); 1178 $grade->dategraded = $record->timegraded; 1179 $assessmentgrades[$record->userid] = $grade; 1180 } 1181 1182 workshop_grade_item_update($workshop, $submissiongrades, $assessmentgrades); 1183 } 1184 1185 /** 1186 * Update the grade items categories if they are changed via mod_form.php 1187 * 1188 * We must do it manually here in the workshop module because modedit supports only 1189 * single grade item while we use two. 1190 * 1191 * @param stdClass $workshop An object from the form in mod_form.php 1192 */ 1193 function workshop_grade_item_category_update($workshop) { 1194 1195 $gradeitems = grade_item::fetch_all(array( 1196 'itemtype' => 'mod', 1197 'itemmodule' => 'workshop', 1198 'iteminstance' => $workshop->id, 1199 'courseid' => $workshop->course)); 1200 1201 if (!empty($gradeitems)) { 1202 foreach ($gradeitems as $gradeitem) { 1203 if ($gradeitem->itemnumber == 0) { 1204 if (isset($workshop->submissiongradepass) && 1205 $gradeitem->gradepass != $workshop->submissiongradepass) { 1206 $gradeitem->gradepass = $workshop->submissiongradepass; 1207 $gradeitem->update(); 1208 } 1209 if ($gradeitem->categoryid != $workshop->gradecategory) { 1210 $gradeitem->set_parent($workshop->gradecategory); 1211 } 1212 } else if ($gradeitem->itemnumber == 1) { 1213 if (isset($workshop->gradinggradepass) && 1214 $gradeitem->gradepass != $workshop->gradinggradepass) { 1215 $gradeitem->gradepass = $workshop->gradinggradepass; 1216 $gradeitem->update(); 1217 } 1218 if ($gradeitem->categoryid != $workshop->gradinggradecategory) { 1219 $gradeitem->set_parent($workshop->gradinggradecategory); 1220 } 1221 } 1222 } 1223 } 1224 } 1225 1226 //////////////////////////////////////////////////////////////////////////////// 1227 // File API // 1228 //////////////////////////////////////////////////////////////////////////////// 1229 1230 /** 1231 * Returns the lists of all browsable file areas within the given module context 1232 * 1233 * The file area workshop_intro for the activity introduction field is added automatically 1234 * by {@link file_browser::get_file_info_context_module()} 1235 * 1236 * @package mod_workshop 1237 * @category files 1238 * 1239 * @param stdClass $course 1240 * @param stdClass $cm 1241 * @param stdClass $context 1242 * @return array of [(string)filearea] => (string)description 1243 */ 1244 function workshop_get_file_areas($course, $cm, $context) { 1245 $areas = array(); 1246 $areas['instructauthors'] = get_string('areainstructauthors', 'workshop'); 1247 $areas['instructreviewers'] = get_string('areainstructreviewers', 'workshop'); 1248 $areas['submission_content'] = get_string('areasubmissioncontent', 'workshop'); 1249 $areas['submission_attachment'] = get_string('areasubmissionattachment', 'workshop'); 1250 $areas['conclusion'] = get_string('areaconclusion', 'workshop'); 1251 $areas['overallfeedback_content'] = get_string('areaoverallfeedbackcontent', 'workshop'); 1252 $areas['overallfeedback_attachment'] = get_string('areaoverallfeedbackattachment', 'workshop'); 1253 1254 return $areas; 1255 } 1256 1257 /** 1258 * Serves the files from the workshop file areas 1259 * 1260 * Apart from module intro (handled by pluginfile.php automatically), workshop files may be 1261 * media inserted into submission content (like images) and submission attachments. For these two, 1262 * the fileareas submission_content and submission_attachment are used. 1263 * Besides that, areas instructauthors, instructreviewers and conclusion contain the media 1264 * embedded using the mod_form.php. 1265 * 1266 * @package mod_workshop 1267 * @category files 1268 * 1269 * @param stdClass $course the course object 1270 * @param stdClass $cm the course module object 1271 * @param stdClass $context the workshop's context 1272 * @param string $filearea the name of the file area 1273 * @param array $args extra arguments (itemid, path) 1274 * @param bool $forcedownload whether or not force download 1275 * @param array $options additional options affecting the file serving 1276 * @return bool false if the file not found, just send the file otherwise and do not return anything 1277 */ 1278 function workshop_pluginfile($course, $cm, $context, $filearea, array $args, $forcedownload, array $options=array()) { 1279 global $DB, $CFG, $USER; 1280 1281 if ($context->contextlevel != CONTEXT_MODULE) { 1282 return false; 1283 } 1284 1285 require_login($course, true, $cm); 1286 1287 if ($filearea === 'instructauthors') { 1288 array_shift($args); // itemid is ignored here 1289 $relativepath = implode('/', $args); 1290 $fullpath = "/$context->id/mod_workshop/$filearea/0/$relativepath"; 1291 1292 $fs = get_file_storage(); 1293 if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) { 1294 send_file_not_found(); 1295 } 1296 1297 // finally send the file 1298 send_stored_file($file, null, 0, $forcedownload, $options); 1299 1300 } else if ($filearea === 'instructreviewers') { 1301 array_shift($args); // itemid is ignored here 1302 $relativepath = implode('/', $args); 1303 $fullpath = "/$context->id/mod_workshop/$filearea/0/$relativepath"; 1304 1305 $fs = get_file_storage(); 1306 if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) { 1307 send_file_not_found(); 1308 } 1309 1310 // finally send the file 1311 send_stored_file($file, null, 0, $forcedownload, $options); 1312 1313 } else if ($filearea === 'conclusion') { 1314 array_shift($args); // itemid is ignored here 1315 $relativepath = implode('/', $args); 1316 $fullpath = "/$context->id/mod_workshop/$filearea/0/$relativepath"; 1317 1318 $fs = get_file_storage(); 1319 if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) { 1320 send_file_not_found(); 1321 } 1322 1323 // finally send the file 1324 send_stored_file($file, null, 0, $forcedownload, $options); 1325 1326 } else if ($filearea === 'submission_content' or $filearea === 'submission_attachment') { 1327 $itemid = (int)array_shift($args); 1328 if (!$workshop = $DB->get_record('workshop', array('id' => $cm->instance))) { 1329 return false; 1330 } 1331 if (!$submission = $DB->get_record('workshop_submissions', array('id' => $itemid, 'workshopid' => $workshop->id))) { 1332 return false; 1333 } 1334 1335 // make sure the user is allowed to see the file 1336 if (empty($submission->example)) { 1337 if ($USER->id != $submission->authorid) { 1338 if ($submission->published == 1 and $workshop->phase == 50 1339 and has_capability('mod/workshop:viewpublishedsubmissions', $context)) { 1340 // Published submission, we can go (workshop does not take the group mode 1341 // into account in this case yet). 1342 } else if (!$DB->record_exists('workshop_assessments', array('submissionid' => $submission->id, 'reviewerid' => $USER->id))) { 1343 if (!has_capability('mod/workshop:viewallsubmissions', $context)) { 1344 send_file_not_found(); 1345 } else { 1346 $gmode = groups_get_activity_groupmode($cm, $course); 1347 if ($gmode == SEPARATEGROUPS and !has_capability('moodle/site:accessallgroups', $context)) { 1348 // check there is at least one common group with both the $USER 1349 // and the submission author 1350 $sql = "SELECT 'x' 1351 FROM {workshop_submissions} s 1352 JOIN {user} a ON (a.id = s.authorid) 1353 JOIN {groups_members} agm ON (a.id = agm.userid) 1354 JOIN {user} u ON (u.id = ?) 1355 JOIN {groups_members} ugm ON (u.id = ugm.userid) 1356 WHERE s.example = 0 AND s.workshopid = ? AND s.id = ? AND agm.groupid = ugm.groupid"; 1357 $params = array($USER->id, $workshop->id, $submission->id); 1358 if (!$DB->record_exists_sql($sql, $params)) { 1359 send_file_not_found(); 1360 } 1361 } 1362 } 1363 } 1364 } 1365 } 1366 1367 $fs = get_file_storage(); 1368 $relativepath = implode('/', $args); 1369 $fullpath = "/$context->id/mod_workshop/$filearea/$itemid/$relativepath"; 1370 if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) { 1371 return false; 1372 } 1373 // finally send the file 1374 // these files are uploaded by students - forcing download for security reasons 1375 send_stored_file($file, 0, 0, true, $options); 1376 1377 } else if ($filearea === 'overallfeedback_content' or $filearea === 'overallfeedback_attachment') { 1378 $itemid = (int)array_shift($args); 1379 if (!$workshop = $DB->get_record('workshop', array('id' => $cm->instance))) { 1380 return false; 1381 } 1382 if (!$assessment = $DB->get_record('workshop_assessments', array('id' => $itemid))) { 1383 return false; 1384 } 1385 if (!$submission = $DB->get_record('workshop_submissions', array('id' => $assessment->submissionid, 'workshopid' => $workshop->id))) { 1386 return false; 1387 } 1388 1389 if ($USER->id == $assessment->reviewerid) { 1390 // Reviewers can always see their own files. 1391 } else if ($USER->id == $submission->authorid and $workshop->phase == 50) { 1392 // Authors can see the feedback once the workshop is closed. 1393 } else if (!empty($submission->example) and $assessment->weight == 1) { 1394 // Reference assessments of example submissions can be displayed. 1395 } else if (!has_capability('mod/workshop:viewallassessments', $context)) { 1396 send_file_not_found(); 1397 } else { 1398 $gmode = groups_get_activity_groupmode($cm, $course); 1399 if ($gmode == SEPARATEGROUPS and !has_capability('moodle/site:accessallgroups', $context)) { 1400 // Check there is at least one common group with both the $USER 1401 // and the submission author. 1402 $sql = "SELECT 'x' 1403 FROM {workshop_submissions} s 1404 JOIN {user} a ON (a.id = s.authorid) 1405 JOIN {groups_members} agm ON (a.id = agm.userid) 1406 JOIN {user} u ON (u.id = ?) 1407 JOIN {groups_members} ugm ON (u.id = ugm.userid) 1408 WHERE s.example = 0 AND s.workshopid = ? AND s.id = ? AND agm.groupid = ugm.groupid"; 1409 $params = array($USER->id, $workshop->id, $submission->id); 1410 if (!$DB->record_exists_sql($sql, $params)) { 1411 send_file_not_found(); 1412 } 1413 } 1414 } 1415 1416 $fs = get_file_storage(); 1417 $relativepath = implode('/', $args); 1418 $fullpath = "/$context->id/mod_workshop/$filearea/$itemid/$relativepath"; 1419 if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) { 1420 return false; 1421 } 1422 // finally send the file 1423 // these files are uploaded by students - forcing download for security reasons 1424 send_stored_file($file, 0, 0, true, $options); 1425 } 1426 1427 return false; 1428 } 1429 1430 /** 1431 * File browsing support for workshop file areas 1432 * 1433 * @package mod_workshop 1434 * @category files 1435 * 1436 * @param file_browser $browser 1437 * @param array $areas 1438 * @param stdClass $course 1439 * @param stdClass $cm 1440 * @param stdClass $context 1441 * @param string $filearea 1442 * @param int $itemid 1443 * @param string $filepath 1444 * @param string $filename 1445 * @return file_info instance or null if not found 1446 */ 1447 function workshop_get_file_info($browser, $areas, $course, $cm, $context, $filearea, $itemid, $filepath, $filename) { 1448 global $CFG, $DB, $USER; 1449 1450 /** @var array internal cache for author names */ 1451 static $submissionauthors = array(); 1452 1453 $fs = get_file_storage(); 1454 1455 if ($filearea === 'submission_content' or $filearea === 'submission_attachment') { 1456 1457 if (!has_capability('mod/workshop:viewallsubmissions', $context)) { 1458 return null; 1459 } 1460 1461 if (is_null($itemid)) { 1462 // no itemid (submissionid) passed, display the list of all submissions 1463 require_once($CFG->dirroot . '/mod/workshop/fileinfolib.php'); 1464 return new workshop_file_info_submissions_container($browser, $course, $cm, $context, $areas, $filearea); 1465 } 1466 1467 // make sure the user can see the particular submission in separate groups mode 1468 $gmode = groups_get_activity_groupmode($cm, $course); 1469 1470 if ($gmode == SEPARATEGROUPS and !has_capability('moodle/site:accessallgroups', $context)) { 1471 // check there is at least one common group with both the $USER 1472 // and the submission author (this is not expected to be a frequent 1473 // usecase so we can live with pretty ineffective one query per submission here...) 1474 $sql = "SELECT 'x' 1475 FROM {workshop_submissions} s 1476 JOIN {user} a ON (a.id = s.authorid) 1477 JOIN {groups_members} agm ON (a.id = agm.userid) 1478 JOIN {user} u ON (u.id = ?) 1479 JOIN {groups_members} ugm ON (u.id = ugm.userid) 1480 WHERE s.example = 0 AND s.workshopid = ? AND s.id = ? AND agm.groupid = ugm.groupid"; 1481 $params = array($USER->id, $cm->instance, $itemid); 1482 if (!$DB->record_exists_sql($sql, $params)) { 1483 return null; 1484 } 1485 } 1486 1487 // we are inside some particular submission container 1488 1489 $filepath = is_null($filepath) ? '/' : $filepath; 1490 $filename = is_null($filename) ? '.' : $filename; 1491 1492 if (!$storedfile = $fs->get_file($context->id, 'mod_workshop', $filearea, $itemid, $filepath, $filename)) { 1493 if ($filepath === '/' and $filename === '.') { 1494 $storedfile = new virtual_root_file($context->id, 'mod_workshop', $filearea, $itemid); 1495 } else { 1496 // not found 1497 return null; 1498 } 1499 } 1500 1501 // Checks to see if the user can manage files or is the owner. 1502 // TODO MDL-33805 - Do not use userid here and move the capability check above. 1503 if (!has_capability('moodle/course:managefiles', $context) && $storedfile->get_userid() != $USER->id) { 1504 return null; 1505 } 1506 1507 // let us display the author's name instead of itemid (submission id) 1508 1509 if (isset($submissionauthors[$itemid])) { 1510 $topvisiblename = $submissionauthors[$itemid]; 1511 1512 } else { 1513 1514 $sql = "SELECT s.id, u.lastname, u.firstname 1515 FROM {workshop_submissions} s 1516 JOIN {user} u ON (s.authorid = u.id) 1517 WHERE s.example = 0 AND s.workshopid = ?"; 1518 $params = array($cm->instance); 1519 $rs = $DB->get_recordset_sql($sql, $params); 1520 1521 foreach ($rs as $submissionauthor) { 1522 $title = s(fullname($submissionauthor)); // this is generally not unique... 1523 $submissionauthors[$submissionauthor->id] = $title; 1524 } 1525 $rs->close(); 1526 1527 if (!isset($submissionauthors[$itemid])) { 1528 // should not happen 1529 return null; 1530 } else { 1531 $topvisiblename = $submissionauthors[$itemid]; 1532 } 1533 } 1534 1535 $urlbase = $CFG->wwwroot . '/pluginfile.php'; 1536 // do not allow manual modification of any files! 1537 return new file_info_stored($browser, $context, $storedfile, $urlbase, $topvisiblename, true, true, false, false); 1538 } 1539 1540 if ($filearea === 'overallfeedback_content' or $filearea === 'overallfeedback_attachment') { 1541 1542 if (!has_capability('mod/workshop:viewallassessments', $context)) { 1543 return null; 1544 } 1545 1546 if (is_null($itemid)) { 1547 // No itemid (assessmentid) passed, display the list of all assessments. 1548 require_once($CFG->dirroot . '/mod/workshop/fileinfolib.php'); 1549 return new workshop_file_info_overallfeedback_container($browser, $course, $cm, $context, $areas, $filearea); 1550 } 1551 1552 // Make sure the user can see the particular assessment in separate groups mode. 1553 $gmode = groups_get_activity_groupmode($cm, $course); 1554 if ($gmode == SEPARATEGROUPS and !has_capability('moodle/site:accessallgroups', $context)) { 1555 // Check there is at least one common group with both the $USER 1556 // and the submission author. 1557 $sql = "SELECT 'x' 1558 FROM {workshop_submissions} s 1559 JOIN {user} a ON (a.id = s.authorid) 1560 JOIN {groups_members} agm ON (a.id = agm.userid) 1561 JOIN {user} u ON (u.id = ?) 1562 JOIN {groups_members} ugm ON (u.id = ugm.userid) 1563 WHERE s.example = 0 AND s.workshopid = ? AND s.id = ? AND agm.groupid = ugm.groupid"; 1564 $params = array($USER->id, $cm->instance, $itemid); 1565 if (!$DB->record_exists_sql($sql, $params)) { 1566 return null; 1567 } 1568 } 1569 1570 // We are inside a particular assessment container. 1571 $filepath = is_null($filepath) ? '/' : $filepath; 1572 $filename = is_null($filename) ? '.' : $filename; 1573 1574 if (!$storedfile = $fs->get_file($context->id, 'mod_workshop', $filearea, $itemid, $filepath, $filename)) { 1575 if ($filepath === '/' and $filename === '.') { 1576 $storedfile = new virtual_root_file($context->id, 'mod_workshop', $filearea, $itemid); 1577 } else { 1578 // Not found 1579 return null; 1580 } 1581 } 1582 1583 // Check to see if the user can manage files or is the owner. 1584 if (!has_capability('moodle/course:managefiles', $context) and $storedfile->get_userid() != $USER->id) { 1585 return null; 1586 } 1587 1588 $urlbase = $CFG->wwwroot . '/pluginfile.php'; 1589 1590 // Do not allow manual modification of any files. 1591 return new file_info_stored($browser, $context, $storedfile, $urlbase, $itemid, true, true, false, false); 1592 } 1593 1594 if ($filearea == 'instructauthors' or $filearea == 'instructreviewers' or $filearea == 'conclusion') { 1595 // always only itemid 0 1596 1597 $filepath = is_null($filepath) ? '/' : $filepath; 1598 $filename = is_null($filename) ? '.' : $filename; 1599 1600 $urlbase = $CFG->wwwroot.'/pluginfile.php'; 1601 if (!$storedfile = $fs->get_file($context->id, 'mod_workshop', $filearea, 0, $filepath, $filename)) { 1602 if ($filepath === '/' and $filename === '.') { 1603 $storedfile = new virtual_root_file($context->id, 'mod_workshop', $filearea, 0); 1604 } else { 1605 // not found 1606 return null; 1607 } 1608 } 1609 return new file_info_stored($browser, $context, $storedfile, $urlbase, $areas[$filearea], false, true, true, false); 1610 } 1611 } 1612 1613 //////////////////////////////////////////////////////////////////////////////// 1614 // Navigation API // 1615 //////////////////////////////////////////////////////////////////////////////// 1616 1617 /** 1618 * Extends the global navigation tree by adding workshop nodes if there is a relevant content 1619 * 1620 * This can be called by an AJAX request so do not rely on $PAGE as it might not be set up properly. 1621 * 1622 * @param navigation_node $navref An object representing the navigation tree node of the workshop module instance 1623 * @param stdClass $course 1624 * @param stdClass $module 1625 * @param cm_info $cm 1626 */ 1627 function workshop_extend_navigation(navigation_node $navref, stdclass $course, stdclass $module, cm_info $cm) { 1628 global $CFG; 1629 1630 if (has_capability('mod/workshop:submit', context_module::instance($cm->id))) { 1631 $url = new moodle_url('/mod/workshop/submission.php', array('cmid' => $cm->id)); 1632 $mysubmission = $navref->add(get_string('mysubmission', 'workshop'), $url); 1633 $mysubmission->mainnavonly = true; 1634 } 1635 } 1636 1637 /** 1638 * Extends the settings navigation with the Workshop settings 1639 1640 * This function is called when the context for the page is a workshop module. This is not called by AJAX 1641 * so it is safe to rely on the $PAGE. 1642 * 1643 * @param settings_navigation $settingsnav {@link settings_navigation} 1644 * @param navigation_node $workshopnode {@link navigation_node} 1645 */ 1646 function workshop_extend_settings_navigation(settings_navigation $settingsnav, navigation_node $workshopnode=null) { 1647 global $PAGE; 1648 1649 //$workshopobject = $DB->get_record("workshop", array("id" => $PAGE->cm->instance)); 1650 1651 if (has_capability('mod/workshop:editdimensions', $PAGE->cm->context)) { 1652 $url = new moodle_url('/mod/workshop/editform.php', array('cmid' => $PAGE->cm->id)); 1653 $workshopnode->add(get_string('editassessmentform', 'workshop'), $url, settings_navigation::TYPE_SETTING); 1654 } 1655 if (has_capability('mod/workshop:allocate', $PAGE->cm->context)) { 1656 $url = new moodle_url('/mod/workshop/allocation.php', array('cmid' => $PAGE->cm->id)); 1657 $workshopnode->add(get_string('allocate', 'workshop'), $url, settings_navigation::TYPE_SETTING); 1658 } 1659 } 1660 1661 /** 1662 * Return a list of page types 1663 * @param string $pagetype current page type 1664 * @param stdClass $parentcontext Block's parent context 1665 * @param stdClass $currentcontext Current context of block 1666 */ 1667 function workshop_page_type_list($pagetype, $parentcontext, $currentcontext) { 1668 $module_pagetype = array('mod-workshop-*'=>get_string('page-mod-workshop-x', 'workshop')); 1669 return $module_pagetype; 1670 } 1671 1672 //////////////////////////////////////////////////////////////////////////////// 1673 // Calendar API // 1674 //////////////////////////////////////////////////////////////////////////////// 1675 1676 /** 1677 * Updates the calendar events associated to the given workshop 1678 * 1679 * @param stdClass $workshop the workshop instance record 1680 * @param int $cmid course module id 1681 */ 1682 function workshop_calendar_update(stdClass $workshop, $cmid) { 1683 global $DB; 1684 1685 // get the currently registered events so that we can re-use their ids 1686 $currentevents = $DB->get_records('event', array('modulename' => 'workshop', 'instance' => $workshop->id)); 1687 1688 // the common properties for all events 1689 $base = new stdClass(); 1690 $base->description = format_module_intro('workshop', $workshop, $cmid, false); 1691 $base->courseid = $workshop->course; 1692 $base->groupid = 0; 1693 $base->userid = 0; 1694 $base->modulename = 'workshop'; 1695 $base->eventtype = 'pluginname'; 1696 $base->instance = $workshop->id; 1697 $base->visible = instance_is_visible('workshop', $workshop); 1698 $base->timeduration = 0; 1699 1700 if ($workshop->submissionstart) { 1701 $event = clone($base); 1702 $event->name = get_string('submissionstartevent', 'mod_workshop', $workshop->name); 1703 $event->timestart = $workshop->submissionstart; 1704 if ($reusedevent = array_shift($currentevents)) { 1705 $event->id = $reusedevent->id; 1706 } else { 1707 // should not be set but just in case 1708 unset($event->id); 1709 } 1710 // update() will reuse a db record if the id field is set 1711 $eventobj = new calendar_event($event); 1712 $eventobj->update($event, false); 1713 } 1714 1715 if ($workshop->submissionend) { 1716 $event = clone($base); 1717 $event->name = get_string('submissionendevent', 'mod_workshop', $workshop->name); 1718 $event->timestart = $workshop->submissionend; 1719 if ($reusedevent = array_shift($currentevents)) { 1720 $event->id = $reusedevent->id; 1721 } else { 1722 // should not be set but just in case 1723 unset($event->id); 1724 } 1725 // update() will reuse a db record if the id field is set 1726 $eventobj = new calendar_event($event); 1727 $eventobj->update($event, false); 1728 } 1729 1730 if ($workshop->assessmentstart) { 1731 $event = clone($base); 1732 $event->name = get_string('assessmentstartevent', 'mod_workshop', $workshop->name); 1733 $event->timestart = $workshop->assessmentstart; 1734 if ($reusedevent = array_shift($currentevents)) { 1735 $event->id = $reusedevent->id; 1736 } else { 1737 // should not be set but just in case 1738 unset($event->id); 1739 } 1740 // update() will reuse a db record if the id field is set 1741 $eventobj = new calendar_event($event); 1742 $eventobj->update($event, false); 1743 } 1744 1745 if ($workshop->assessmentend) { 1746 $event = clone($base); 1747 $event->name = get_string('assessmentendevent', 'mod_workshop', $workshop->name); 1748 $event->timestart = $workshop->assessmentend; 1749 if ($reusedevent = array_shift($currentevents)) { 1750 $event->id = $reusedevent->id; 1751 } else { 1752 // should not be set but just in case 1753 unset($event->id); 1754 } 1755 // update() will reuse a db record if the id field is set 1756 $eventobj = new calendar_event($event); 1757 $eventobj->update($event, false); 1758 } 1759 1760 // delete any leftover events 1761 foreach ($currentevents as $oldevent) { 1762 $oldevent = calendar_event::load($oldevent); 1763 $oldevent->delete(); 1764 } 1765 } 1766 1767 //////////////////////////////////////////////////////////////////////////////// 1768 // Course reset API // 1769 //////////////////////////////////////////////////////////////////////////////// 1770 1771 /** 1772 * Extends the course reset form with workshop specific settings. 1773 * 1774 * @param MoodleQuickForm $mform 1775 */ 1776 function workshop_reset_course_form_definition($mform) { 1777 1778 $mform->addElement('header', 'workshopheader', get_string('modulenameplural', 'mod_workshop')); 1779 1780 $mform->addElement('advcheckbox', 'reset_workshop_submissions', get_string('resetsubmissions', 'mod_workshop')); 1781 $mform->addHelpButton('reset_workshop_submissions', 'resetsubmissions', 'mod_workshop'); 1782 1783 $mform->addElement('advcheckbox', 'reset_workshop_assessments', get_string('resetassessments', 'mod_workshop')); 1784 $mform->addHelpButton('reset_workshop_assessments', 'resetassessments', 'mod_workshop'); 1785 $mform->disabledIf('reset_workshop_assessments', 'reset_workshop_submissions', 'checked'); 1786 1787 $mform->addElement('advcheckbox', 'reset_workshop_phase', get_string('resetphase', 'mod_workshop')); 1788 $mform->addHelpButton('reset_workshop_phase', 'resetphase', 'mod_workshop'); 1789 } 1790 1791 /** 1792 * Provides default values for the workshop settings in the course reset form. 1793 * 1794 * @param stdClass $course The course to be reset. 1795 */ 1796 function workshop_reset_course_form_defaults(stdClass $course) { 1797 1798 $defaults = array( 1799 'reset_workshop_submissions' => 1, 1800 'reset_workshop_assessments' => 1, 1801 'reset_workshop_phase' => 1, 1802 ); 1803 1804 return $defaults; 1805 } 1806 1807 /** 1808 * Performs the reset of all workshop instances in the course. 1809 * 1810 * @param stdClass $data The actual course reset settings. 1811 * @return array List of results, each being array[(string)component, (string)item, (string)error] 1812 */ 1813 function workshop_reset_userdata(stdClass $data) { 1814 global $CFG, $DB; 1815 1816 if (empty($data->reset_workshop_submissions) 1817 and empty($data->reset_workshop_assessments) 1818 and empty($data->reset_workshop_phase) ) { 1819 // Nothing to do here. 1820 return array(); 1821 } 1822 1823 $workshoprecords = $DB->get_records('workshop', array('course' => $data->courseid)); 1824 1825 if (empty($workshoprecords)) { 1826 // What a boring course - no workshops here! 1827 return array(); 1828 } 1829 1830 require_once($CFG->dirroot . '/mod/workshop/locallib.php'); 1831 1832 $course = $DB->get_record('course', array('id' => $data->courseid), '*', MUST_EXIST); 1833 $status = array(); 1834 1835 foreach ($workshoprecords as $workshoprecord) { 1836 $cm = get_coursemodule_from_instance('workshop', $workshoprecord->id, $course->id, false, MUST_EXIST); 1837 $workshop = new workshop($workshoprecord, $cm, $course); 1838 $status = array_merge($status, $workshop->reset_userdata($data)); 1839 } 1840 1841 return $status; 1842 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |