Merge branch 'MDL-58278-master' of git://github.com/damyon/moodle
authorDavid Monllao <davidm@moodle.com>
Thu, 20 Apr 2017 06:05:39 +0000 (14:05 +0800)
committerDavid Monllao <davidm@moodle.com>
Thu, 20 Apr 2017 06:05:39 +0000 (14:05 +0800)
1  2 
mod/assign/locallib.php

diff --combined mod/assign/locallib.php
@@@ -68,12 -68,6 +68,12 @@@ define("ASSIGN_MAX_EVENT_LENGTH", "4320
  // Name of file area for intro attachments.
  define('ASSIGN_INTROATTACHMENT_FILEAREA', 'introattachment');
  
 +// Event types.
 +define('ASSIGN_EVENT_TYPE_DUE', 'due');
 +define('ASSIGN_EVENT_TYPE_GRADINGDUE', 'gradingdue');
 +define('ASSIGN_EVENT_TYPE_OPEN', 'open');
 +define('ASSIGN_EVENT_TYPE_CLOSE', 'close');
 +
  require_once($CFG->libdir . '/accesslib.php');
  require_once($CFG->libdir . '/formslib.php');
  require_once($CFG->dirroot . '/repository/lib.php');
@@@ -641,7 -635,6 +641,7 @@@ class assign 
          }
          $update->duedate = $formdata->duedate;
          $update->cutoffdate = $formdata->cutoffdate;
 +        $update->gradingduedate = $formdata->gradingduedate;
          $update->allowsubmissionsfromdate = $formdata->allowsubmissionsfromdate;
          $update->grade = $formdata->grade;
          $update->completionsubmit = !empty($formdata->completionsubmit);
  
          require_once($CFG->dirroot . '/calendar/lib.php');
  
 -        $cm = get_coursemodule_from_instance('assign', $this->get_context()->id, $this->get_context()->course);
 +        $cm = $this->get_course_module();
 +        if (empty($cm)) {
 +            $instance = $this->get_instance();
 +            $cm = get_coursemodule_from_instance('assign', $instance->id, $instance->course);
 +        }
  
          $override = $DB->get_record('assign_overrides', array('id' => $overrideid), '*', MUST_EXIST);
  
          // Delete the events.
 -        $conds = array('modulename' => 'assign',
 -            'instance' => $this->get_context()->id);
 +        $conds = array('modulename' => 'assign', 'instance' => $this->get_instance()->id);
          if (isset($override->userid)) {
              $conds['userid'] = $override->userid;
          } else {
      public function delete_all_overrides() {
          global $DB;
  
 -        $overrides = $DB->get_records('assign_overrides', array('assignid' => $this->get_context()->id), 'id');
 +        $overrides = $DB->get_records('assign_overrides', array('assignid' => $this->get_instance()->id), 'id');
          foreach ($overrides as $override) {
              $this->delete_override($override->id);
          }
          // Special case for add_instance as the coursemodule has not been set yet.
          $instance = $this->get_instance();
  
 -        $eventtype = 'due';
 +        // Start with creating the event.
 +        $event = new stdClass();
 +        $event->modulename  = 'assign';
 +        $event->courseid = $instance->course;
 +        $event->groupid = 0;
 +        $event->userid  = 0;
 +        $event->instance  = $instance->id;
 +        $event->name = $instance->name;
 +        $event->type = CALENDAR_EVENT_TYPE_ACTION;
 +
 +        // Convert the links to pluginfile. It is a bit hacky but at this stage the files
 +        // might not have been saved in the module area yet.
 +        $intro = $instance->intro;
 +        if ($draftid = file_get_submitted_draft_itemid('introeditor')) {
 +            $intro = file_rewrite_urls_to_pluginfile($intro, $draftid);
 +        }
 +
 +        // We need to remove the links to files as the calendar is not ready
 +        // to support module events with file areas.
 +        $intro = strip_pluginfile_content($intro);
 +        if ($this->show_intro()) {
 +            $event->description = array(
 +                'text' => $intro,
 +                'format' => $instance->introformat
 +            );
 +        } else {
 +            $event->description = array(
 +                'text' => '',
 +                'format' => $instance->introformat
 +            );
 +        }
  
 +        $eventtype = ASSIGN_EVENT_TYPE_DUE;
          if ($instance->duedate) {
 -            $event = new stdClass();
 -
 -            // Fetch the original due date event. It will have a non-zero course ID and a zero group ID.
 +            $event->eventtype = $eventtype;
 +            $event->timestart = $instance->duedate;
 +            $event->timesort = $instance->duedate;
              $select = "modulename = :modulename
                         AND instance = :instance
                         AND eventtype = :eventtype
                         AND courseid <> 0";
              $params = array('modulename' => 'assign', 'instance' => $instance->id, 'eventtype' => $eventtype);
              $event->id = $DB->get_field_select('event', 'id', $select, $params);
 -            $event->name = $instance->name;
 -            $event->timestart = $instance->duedate;
  
 -            // Convert the links to pluginfile. It is a bit hacky but at this stage the files
 -            // might not have been saved in the module area yet.
 -            $intro = $instance->intro;
 -            if ($draftid = file_get_submitted_draft_itemid('introeditor')) {
 -                $intro = file_rewrite_urls_to_pluginfile($intro, $draftid);
 -            }
 -
 -            // We need to remove the links to files as the calendar is not ready
 -            // to support module events with file areas.
 -            $intro = strip_pluginfile_content($intro);
 -            if ($this->show_intro()) {
 -                $event->description = array(
 -                    'text' => $intro,
 -                    'format' => $instance->introformat
 -                );
 +            // Now process the event.
 +            if ($event->id) {
 +                $calendarevent = calendar_event::load($event->id);
 +                $calendarevent->update($event);
              } else {
 -                $event->description = array(
 -                    'text' => '',
 -                    'format' => $instance->introformat
 -                );
 +                calendar_event::create($event);
              }
 +        } else {
 +            $DB->delete_records('event', array('modulename' => 'assign', 'instance' => $instance->id,
 +                'eventtype' => $eventtype));
 +        }
 +
 +        $eventtype = ASSIGN_EVENT_TYPE_GRADINGDUE;
 +        if ($instance->gradingduedate) {
 +            $event->eventtype = $eventtype;
 +            $event->timestart = $instance->gradingduedate;
 +            $event->timesort = $instance->gradingduedate;
 +            $event->id = $DB->get_field('event', 'id', array('modulename' => 'assign',
 +                'instance' => $instance->id, 'eventtype' => $event->eventtype));
  
 +            // Now process the event.
              if ($event->id) {
                  $calendarevent = calendar_event::load($event->id);
                  $calendarevent->update($event);
              } else {
 -                unset($event->id);
 -                $event->courseid    = $instance->course;
 -                $event->groupid     = 0;
 -                $event->userid      = 0;
 -                $event->modulename  = 'assign';
 -                $event->instance    = $instance->id;
 -                $event->eventtype   = $eventtype;
 -                $event->timeduration = 0;
                  calendar_event::create($event);
              }
          } else {
 -            $DB->delete_records('event', array('modulename' => 'assign', 'instance' => $instance->id, 'eventtype' => $eventtype));
 +            $DB->delete_records('event', array('modulename' => 'assign', 'instance' => $instance->id,
 +                'eventtype' => $eventtype));
          }
 -    }
  
 +        return true;
 +    }
  
      /**
       * Update this instance in the database.
          }
          $update->duedate = $formdata->duedate;
          $update->cutoffdate = $formdata->cutoffdate;
 +        $update->gradingduedate = $formdata->gradingduedate;
          $update->allowsubmissionsfromdate = $formdata->allowsubmissionsfromdate;
          $update->grade = $formdata->grade;
          if (!empty($formdata->completionunlocked)) {
  
              if ($instance->markingworkflow &&
                      $instance->markingallocation &&
 -                    !has_capability('mod/assign:manageallocations', $this->get_context())) {
 +                    !has_capability('mod/assign:manageallocations', $this->get_context()) &&
 +                    has_capability('mod/assign:grade', $this->get_context())) {
  
                  $additionaljoins .= ' LEFT JOIN {assign_user_flags} uf
                                       ON u.id = uf.userid
  
          $params['assignid'] = $this->get_instance()->id;
          $params['submitted'] = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
 +        $sqlscalegrade = $this->get_instance()->grade < 0 ? ' OR g.grade = -1' : '';
  
          $sql = 'SELECT COUNT(s.userid)
                     FROM {assign_submission} s
                          s.assignment = :assignid AND
                          s.timemodified IS NOT NULL AND
                          s.status = :submitted AND
 -                        (s.timemodified >= g.timemodified OR g.timemodified IS NULL OR g.grade IS NULL)';
 +                        (s.timemodified >= g.timemodified OR g.timemodified IS NULL OR g.grade IS NULL '
 +                            . $sqlscalegrade . ')';
  
          return $DB->count_records_sql($sql, $params);
      }
       * Throw an error if the permissions to view this users submission are missing.
       *
       * @throws required_capability_exception
 -     * @return void
 +     * @return none
       */
      public function require_view_submission($userid) {
          if (!$this->can_view_submission($userid)) {
       * Throw an error if the permissions to view grades in this assignment are missing.
       *
       * @throws required_capability_exception
 -     * @return void
 +     * @return none
       */
      public function require_view_grades() {
          if (!$this->can_view_grades()) {
          return false;
      }
  
 +    /**
 +     * Perform an access check to see if the current $USER can edit this group submission.
 +     *
 +     * @param int $groupid
 +     * @return bool
 +     */
 +    public function can_edit_group_submission($groupid) {
 +        global $USER;
 +
 +        $members = $this->get_submission_group_members($groupid, true);
 +        foreach ($members as $member) {
 +            // If we can edit any members submission, we can edit the submission for the group.
 +            if ($this->can_edit_submission($member->id)) {
 +                return true;
 +            }
 +        }
 +        return false;
 +    }
 +
      /**
       * Perform an access check to see if the current $USER can view this group submission.
       *
      public function get_shared_group_members($cm, $userid) {
          if (!isset($this->sharedgroupmembers[$userid])) {
              $this->sharedgroupmembers[$userid] = array();
 -            $groupsids = array_keys(groups_get_activity_allowed_groups($cm, $userid));
 -            foreach ($groupsids as $groupid) {
 -                $members = array_keys(groups_get_members($groupid, 'u.id'));
 -                $this->sharedgroupmembers[$userid] = array_merge($this->sharedgroupmembers[$userid], $members);
 +            if ($members = groups_get_activity_shared_group_members($cm, $userid)) {
 +                $this->sharedgroupmembers[$userid] = array_keys($members);
              }
          }
  
          }
  
          // Do not show if we are editing a previous attempt.
 -        if ($attemptnumber == -1 && $this->get_instance()->attemptreopenmethod != ASSIGN_ATTEMPT_REOPEN_METHOD_NONE) {
 +        if (($attemptnumber == -1 ||
 +            ($attemptnumber + 1) == count($this->get_all_submissions($userid))) &&
 +            $this->get_instance()->attemptreopenmethod != ASSIGN_ATTEMPT_REOPEN_METHOD_NONE) {
              $mform->addElement('header', 'attemptsettings', get_string('attemptsettings', 'assign'));
              $attemptreopenmethod = get_string('attemptreopenmethod_' . $this->get_instance()->attemptreopenmethod, 'assign');
              $mform->addElement('static', 'attemptreopenmethod', get_string('attemptreopenmethod', 'assign'), $attemptreopenmethod);
                  $feedbackmodified) {
              $this->update_grade($grade, !empty($formdata->addattempt));
          }
+         // We never send notifications if we have marking workflow and the grade is not released.
+         if ($this->get_instance()->markingworkflow &&
+                 isset($formdata->workflowstate) &&
+                 $formdata->workflowstate != ASSIGN_MARKING_WORKFLOW_STATE_RELEASED) {
+             $formdata->sendstudentnotifications = false;
+         }
          // Note the default if not provided for this option is true (e.g. webservices).
          // This is for backwards compatibility.
          if (!isset($formdata->sendstudentnotifications) || $formdata->sendstudentnotifications) {