[ Index ]

PHP Cross Reference of Unnamed Project

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 <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  }


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1