Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.

Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401] [Versions 400 and 401]

   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  /**
  18   * Edit a user's grade for a particular activity
  19   *
  20   * @package   core_grades
  21   * @copyright 2007 Petr Skoda
  22   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  require_once '../../../config.php';
  26  require_once $CFG->dirroot.'/grade/lib.php';
  27  require_once $CFG->dirroot.'/grade/report/lib.php';
  28  require_once  'grade_form.php';
  29  
  30  $courseid = required_param('courseid', PARAM_INT);
  31  $id       = optional_param('id', 0, PARAM_INT);
  32  $itemid   = optional_param('itemid', 0, PARAM_INT);
  33  $userid   = optional_param('userid', 0, PARAM_INT);
  34  
  35  $url = new moodle_url('/grade/edit/tree/grade.php', array('courseid'=>$courseid));
  36  if ($id !== 0) {
  37      $url->param('id', $id);
  38  }
  39  if ($itemid !== 0) {
  40      $url->param('itemid', $itemid);
  41  }
  42  if ($userid !== 0) {
  43      $url->param('userid', $userid);
  44  }
  45  $PAGE->set_url($url);
  46  
  47  if (!$course = $DB->get_record('course', array('id' => $courseid))) {
  48      throw new \moodle_exception('invalidcourseid');
  49  }
  50  
  51  $PAGE->set_pagelayout('incourse');
  52  require_login($course);
  53  $context = context_course::instance($course->id);
  54  if (!has_capability('moodle/grade:manage', $context)) {
  55      require_capability('moodle/grade:edit', $context);
  56  }
  57  
  58  // default return url
  59  $gpr = new grade_plugin_return();
  60  $returnurl = $gpr->get_return_url($CFG->wwwroot.'/grade/report/index.php?id='.$course->id);
  61  
  62  // security checks!
  63  if (!empty($id)) {
  64      if (!$grade = $DB->get_record('grade_grades', array('id' => $id))) {
  65          throw new \moodle_exception('invalidgroupid');
  66      }
  67  
  68      if (!empty($itemid) and $itemid != $grade->itemid) {
  69          throw new \moodle_exception('invaliditemid');
  70      }
  71      $itemid = $grade->itemid;
  72  
  73      if (!empty($userid) and $userid != $grade->userid) {
  74          throw new \moodle_exception('invaliduser');
  75      }
  76      $userid = $grade->userid;
  77  
  78      unset($grade);
  79  
  80  } else if (empty($userid) or empty($itemid)) {
  81      throw new \moodle_exception('missinguseranditemid');
  82  }
  83  
  84  if (!$grade_item = grade_item::fetch(array('id'=>$itemid, 'courseid'=>$courseid))) {
  85      throw new \moodle_exception('cannotfindgradeitem');
  86  }
  87  
  88  // now verify grading user has access to all groups or is member of the same group when separate groups used in course
  89  if (groups_get_course_groupmode($COURSE) == SEPARATEGROUPS and !has_capability('moodle/site:accessallgroups', $context)) {
  90      if ($groups = groups_get_all_groups($COURSE->id, $userid)) {
  91          $ok = false;
  92          foreach ($groups as $group) {
  93              if (groups_is_member($group->id, $USER->id)) {
  94                  $ok = true;
  95              }
  96          }
  97          if (!$ok) {
  98              throw new \moodle_exception('cannotgradeuser');
  99          }
 100      } else {
 101          throw new \moodle_exception('cannotgradeuser');
 102      }
 103  }
 104  
 105  $mform = new edit_grade_form(null, array('grade_item'=>$grade_item, 'gpr'=>$gpr));
 106  
 107  if ($grade = $DB->get_record('grade_grades', array('itemid' => $grade_item->id, 'userid' => $userid))) {
 108  
 109      // always clean existing feedback - grading should not have XSS risk
 110      if (empty($grade->feedback)) {
 111          $grade->feedback  = '';
 112      } else {
 113          $options = new stdClass();
 114          $options->smiley  = false;
 115          $options->filter  = false;
 116          $options->noclean = false;
 117          $options->para    = false;
 118          $grade->feedback  = format_text($grade->feedback, $grade->feedbackformat, $options);
 119      }
 120      $grade->feedbackformat = FORMAT_HTML;
 121  
 122      $grade->locked      = $grade->locked     > 0 ? 1:0;
 123      $grade->overridden  = $grade->overridden > 0 ? 1:0;
 124      $grade->excluded    = $grade->excluded   > 0 ? 1:0;
 125  
 126      if ($grade->hidden > 1) {
 127          $grade->hiddenuntil = $grade->hidden;
 128          $grade->hidden = 1;
 129      } else {
 130          $grade->hiddenuntil = 0;
 131      }
 132  
 133      if ($grade_item->is_hidden()) {
 134          $grade->hidden = 1;
 135      }
 136  
 137      if ($grade_item->is_locked()) {
 138          $grade->locked = 1;
 139      }
 140  
 141      // normalize the final grade value
 142      if ($grade_item->gradetype == GRADE_TYPE_SCALE) {
 143          if (empty($grade->finalgrade)) {
 144              $grade->finalgrade = -1;
 145          } else {
 146              $grade->finalgrade = (int)$grade->finalgrade;
 147          }
 148      } else if ($grade_item->gradetype == GRADE_TYPE_VALUE) {
 149          $grade->finalgrade = format_float($grade->finalgrade, $grade_item->get_decimals());
 150      }
 151  
 152      $grade->oldgrade    = $grade->finalgrade;
 153      $grade->oldfeedback = $grade->feedback;
 154  
 155      $grade->feedback = array('text'=>$grade->feedback, 'format'=>$grade->feedbackformat);
 156  
 157      $mform->set_data($grade);
 158  } else {
 159      $grade = new stdClass();
 160      $grade->feedback = array('text'=>'', 'format'=>FORMAT_HTML);
 161      $mform->set_data(array('itemid'=>$itemid, 'userid'=>$userid, 'locked'=>$grade_item->locked, 'locktime'=>$grade_item->locktime));
 162  }
 163  
 164  if ($mform->is_cancelled()) {
 165      redirect($returnurl);
 166  
 167  // form processing
 168  } else if ($data = $mform->get_data(false)) {
 169  
 170      if (isset($data->feedback) && is_array($data->feedback)) {
 171          $data->feedbackformat = $data->feedback['format'];
 172          $data->feedback = $data->feedback['text'];
 173      }
 174  
 175      $old_grade_grade = new grade_grade(array('userid'=>$data->userid, 'itemid'=>$grade_item->id), true); //might not exist yet
 176  
 177      // fix no grade for scales
 178      if (!isset($data->finalgrade) or $data->finalgrade == $data->oldgrade) {
 179          $data->finalgrade = $old_grade_grade->finalgrade;
 180  
 181      } else if ($grade_item->gradetype == GRADE_TYPE_SCALE) {
 182          if ($data->finalgrade < 1) {
 183              $data->finalgrade = NULL;
 184          }
 185  
 186      } else if ($grade_item->gradetype == GRADE_TYPE_VALUE) {
 187          $data->finalgrade = unformat_float($data->finalgrade);
 188  
 189      } else {
 190          //this should not happen
 191          $data->finalgrade = $old_grade_grade->finalgrade;
 192      }
 193  
 194      // the overriding of feedback is tricky - we have to care about external items only
 195      if (!property_exists($data, 'feedback') or $data->feedback == $data->oldfeedback) {
 196          $data->feedback       = $old_grade_grade->feedback;
 197          $data->feedbackformat = $old_grade_grade->feedbackformat;
 198      }
 199  
 200      // update final grade or feedback
 201      // when we set override grade the first time, it happens here
 202      $grade_item->update_final_grade($data->userid, $data->finalgrade, 'editgrade', $data->feedback, $data->feedbackformat);
 203  
 204      $grade_grade = new grade_grade(array('userid'=>$data->userid, 'itemid'=>$grade_item->id), true);
 205      $grade_grade->grade_item =& $grade_item; // no db fetching
 206  
 207      if (has_capability('moodle/grade:manage', $context) or has_capability('moodle/grade:edit', $context)) {
 208          // change overridden flag
 209          if (!isset($data->overridden)) {
 210              $data->overridden = 0; // checkbox unticked
 211          }
 212          $grade_grade->set_overridden($data->overridden);
 213      }
 214  
 215      if (has_capability('moodle/grade:manage', $context) or has_capability('moodle/grade:hide', $context)) {
 216          $hidden      = empty($data->hidden) ? 0: $data->hidden;
 217          $hiddenuntil = empty($data->hiddenuntil) ? 0: $data->hiddenuntil;
 218  
 219          if ($grade_item->is_hidden()) {
 220              if ($old_grade_grade->hidden == 1 and $hiddenuntil == 0) {
 221                  //nothing to do - grade was originally hidden, we want to keep it that way
 222              } else {
 223                  $grade_grade->set_hidden($hiddenuntil);
 224              }
 225          } else {
 226              if ($hiddenuntil) {
 227                  $grade_grade->set_hidden($hiddenuntil);
 228              } else {
 229                  $grade_grade->set_hidden($hidden); // checkbox data might be undefined
 230              }
 231          }
 232      }
 233  
 234      if (isset($data->locked) and !$grade_item->is_locked()) {
 235          if (($old_grade_grade->locked or $old_grade_grade->locktime)
 236            and (!has_capability('moodle/grade:manage', $context) and !has_capability('moodle/grade:unlock', $context))) {
 237              //ignore data
 238  
 239          } else if ((!$old_grade_grade->locked and !$old_grade_grade->locktime)
 240            and (!has_capability('moodle/grade:manage', $context) and !has_capability('moodle/grade:lock', $context))) {
 241              //ignore data
 242  
 243          } else {
 244              $grade_grade->set_locktime($data->locktime); //set_lock may reset locktime
 245              $grade_grade->set_locked($data->locked, false, true);
 246              // reload grade in case it was regraded from activity
 247              $grade_grade = new grade_grade(array('userid'=>$data->userid, 'itemid'=>$grade_item->id), true);
 248              $grade_grade->grade_item =& $grade_item; // no db fetching
 249          }
 250      }
 251  
 252      if (isset($data->excluded) and has_capability('moodle/grade:manage', $context)) {
 253          $grade_grade->set_excluded($data->excluded);
 254      }
 255  
 256      // detect cases when we need to do full regrading
 257      if ($old_grade_grade->excluded != $grade_grade->excluded) {
 258          $parent = $grade_item->get_parent_category();
 259          $parent->force_regrading();
 260  
 261      } else if ($old_grade_grade->overridden != $grade_grade->overridden and empty($grade_grade->overridden)) { // only when unoverridding
 262          $grade_item->force_regrading();
 263  
 264      } else if ($old_grade_grade->locktime != $grade_grade->locktime) {
 265          $grade_item->force_regrading();
 266      }
 267  
 268      redirect($returnurl);
 269  }
 270  
 271  $strgrades       = get_string('grades');
 272  $strgraderreport = get_string('graderreport', 'grades');
 273  $strgradeedit    = get_string('editgrade', 'grades');
 274  $struser         = get_string('user');
 275  
 276  grade_build_nav(__FILE__, $strgradeedit, array('courseid' => $courseid));
 277  
 278  /*********** BEGIN OUTPUT *************/
 279  $PAGE->set_title($strgrades . ': ' . $strgraderreport . ': ' . $strgradeedit);
 280  $PAGE->set_heading($course->fullname);
 281  
 282  echo $OUTPUT->header();
 283  echo $OUTPUT->heading($strgradeedit);
 284  
 285  echo $OUTPUT->box_start();
 286  
 287  // Form if in edit or add modes
 288  $mform->display();
 289  
 290  echo $OUTPUT->box_end();
 291  
 292  echo $OUTPUT->footer();
 293  die;