[ Index ]

PHP Cross Reference of moodle-2.8

title

Body

[close]

/mod/workshop/ -> lib.php (source)

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


Generated: Fri Nov 28 20:29:05 2014 Cross-referenced by PHPXref 0.7.1