Search moodle.org's
Developer Documentation

  • Bug fixes for general core bugs in 3.11.x will end 14 Nov 2022 (12 months plus 6 months extension).
  • Bug fixes for security issues in 3.11.x will end 13 Nov 2023 (18 months plus 12 months extension).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is supported too.
  • Differences Between: [Versions 310 and 311] [Versions 311 and 400] [Versions 37 and 311] [Versions 38 and 311] [Versions 39 and 311]

       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   * Settings form for overrides in the assign module.
      19   *
      20   * @package    mod_assign
      21   * @copyright  2016 Ilya Tregubov
      22   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
      23   */
      24  
      25  
      26  defined('MOODLE_INTERNAL') || die();
      27  
      28  require_once($CFG->libdir . '/formslib.php');
      29  require_once($CFG->dirroot . '/mod/assign/mod_form.php');
      30  
      31  
      32  /**
      33   * Form for editing settings overrides.
      34   *
      35   * @copyright  2016 Ilya Tregubov
      36   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
      37   */
      38  class assign_override_form extends moodleform {
      39  
      40      /** @var object course module object. */
      41      protected $cm;
      42  
      43      /** @var object the assign settings object. */
      44      protected $assign;
      45  
      46      /** @var context the assign context. */
      47      protected $context;
      48  
      49      /** @var bool editing group override (true) or user override (false). */
      50      protected $groupmode;
      51  
      52      /** @var int groupid, if provided. */
      53      protected $groupid;
      54  
      55      /** @var int userid, if provided. */
      56      protected $userid;
      57  
      58      /** @var int sortorder, if provided. */
      59      protected $sortorder;
      60  
      61      /** @var int selecteduserid, if provided. */
      62      protected $selecteduserid;
      63  
      64      /**
      65       * Constructor.
      66       * @param moodle_url $submiturl the form action URL.
      67       * @param object $cm course module object.
      68       * @param object $assign the assign settings object.
      69       * @param object $context the assign context.
      70       * @param bool $groupmode editing group override (true) or user override (false).
      71       * @param object $override the override being edited, if it already exists.
      72       * @param int $selecteduserid the user selected in the form, if any.
      73       */
      74      public function __construct($submiturl, $cm, $assign, $context, $groupmode, $override, $selecteduserid = null) {
      75  
      76          $this->cm = $cm;
      77          $this->assign = $assign;
      78          $this->context = $context;
      79          $this->groupmode = $groupmode;
      80          $this->groupid = empty($override->groupid) ? 0 : $override->groupid;
      81          $this->userid = empty($override->userid) ? 0 : $override->userid;
      82          $this->sortorder = empty($override->sortorder) ? null : $override->sortorder;
      83          $this->selecteduserid = $selecteduserid;
      84  
      85          parent::__construct($submiturl, null, 'post');
      86  
      87      }
      88  
      89      /**
      90       * Define this form - called by the parent constructor
      91       */
      92      protected function definition() {
      93          global $DB, $OUTPUT, $PAGE;
      94  
      95          $cm = $this->cm;
      96          $mform = $this->_form;
      97          $userid = $this->selecteduserid ?? $this->userid ?: null;
      98          $assigninstance = $this->assign->get_instance($userid);
      99          $inrelativedatesmode = !empty($this->assign->get_course()->relativedatesmode);
     100  
     101          $mform->addElement('header', 'override', get_string('override', 'assign'));
     102  
     103          $assigngroupmode = groups_get_activity_groupmode($cm);
     104          $accessallgroups = ($assigngroupmode == NOGROUPS) || has_capability('moodle/site:accessallgroups', $this->context);
     105  
     106          if ($this->groupmode) {
     107              // Group override.
     108              if ($this->groupid) {
     109                  // There is already a groupid, so freeze the selector.
     110                  $groupchoices = array();
     111                  $groupchoices[$this->groupid] = groups_get_group_name($this->groupid);
     112                  $mform->addElement('select', 'groupid',
     113                          get_string('overridegroup', 'assign'), $groupchoices);
     114                  $mform->freeze('groupid');
     115                  // Add a sortorder element.
     116                  $mform->addElement('hidden', 'sortorder', $this->sortorder);
     117                  $mform->setType('sortorder', PARAM_INT);
     118                  $mform->freeze('sortorder');
     119              } else {
     120                  // Prepare the list of groups.
     121                  // Only include the groups the current can access.
     122                  $groups = $accessallgroups ? groups_get_all_groups($cm->course) : groups_get_activity_allowed_groups($cm);
     123                  if (empty($groups)) {
     124                      // Generate an error.
     125                      $link = new moodle_url('/mod/assign/overrides.php', array('cmid' => $cm->id));
     126                      print_error('groupsnone', 'assign', $link);
     127                  }
     128  
     129                  $groupchoices = array();
     130                  foreach ($groups as $group) {
     131                      $groupchoices[$group->id] = $group->name;
     132                  }
     133                  unset($groups);
     134  
     135                  if (count($groupchoices) == 0) {
     136                      $groupchoices[0] = get_string('none');
     137                  }
     138  
     139                  $mform->addElement('select', 'groupid',
     140                          get_string('overridegroup', 'assign'), $groupchoices);
     141                  $mform->addRule('groupid', get_string('required'), 'required', null, 'client');
     142              }
     143          } else {
     144              // User override.
     145              if ($this->userid) {
     146                  // There is already a userid, so freeze the selector.
     147                  $user = $DB->get_record('user', array('id' => $this->userid));
     148                  $userchoices = array();
     149                  $userchoices[$this->userid] = fullname($user);
     150                  $mform->addElement('select', 'userid',
     151                          get_string('overrideuser', 'assign'), $userchoices);
     152                  $mform->freeze('userid');
     153              } else {
     154                  // Prepare the list of users.
     155                  $users = [];
     156                  list($sort) = users_order_by_sql('u');
     157  
     158                  // Get the list of appropriate users, depending on whether and how groups are used.
     159                  $userfieldsapi = \core_user\fields::for_name();
     160                  if ($accessallgroups) {
     161                      $users = get_enrolled_users($this->context, '', 0,
     162                              'u.id, u.email, ' . $userfieldsapi->get_sql('u', false, '', '', false)->selects, $sort);
     163                  } else if ($groups = groups_get_activity_allowed_groups($cm)) {
     164                      $enrolledjoin = get_enrolled_join($this->context, 'u.id');
     165                      $userfields = 'u.id, u.email, ' . $userfieldsapi->get_sql('u', false, '', '', false)->selects;
     166                      list($ingroupsql, $ingroupparams) = $DB->get_in_or_equal(array_keys($groups), SQL_PARAMS_NAMED);
     167                      $params = $enrolledjoin->params + $ingroupparams;
     168                      $sql = "SELECT $userfields
     169                                FROM {user} u
     170                                JOIN {groups_members} gm ON gm.userid = u.id
     171                                     {$enrolledjoin->joins}
     172                               WHERE gm.groupid $ingroupsql
     173                                     AND {$enrolledjoin->wheres}
     174                            ORDER BY $sort";
     175                      $users = $DB->get_records_sql($sql, $params);
     176                  }
     177  
     178                  // Filter users based on any fixed restrictions (groups, profile).
     179                  $info = new \core_availability\info_module($cm);
     180                  $users = $info->filter_user_list($users);
     181  
     182                  if (empty($users)) {
     183                      // Generate an error.
     184                      $link = new moodle_url('/mod/assign/overrides.php', array('cmid' => $cm->id));
     185                      print_error('usersnone', 'assign', $link);
     186                  }
     187  
     188                  $userchoices = array();
     189                  // TODO Does not support custom user profile fields (MDL-70456).
     190                  $canviewemail = in_array('email', \core_user\fields::get_identity_fields($this->context, false));
     191                  foreach ($users as $id => $user) {
     192                      if (empty($invalidusers[$id]) || (!empty($override) &&
     193                              $id == $override->userid)) {
     194                          if ($canviewemail) {
     195                              $userchoices[$id] = fullname($user) . ', ' . $user->email;
     196                          } else {
     197                              $userchoices[$id] = fullname($user);
     198                          }
     199                      }
     200                  }
     201                  unset($users);
     202  
     203                  if (count($userchoices) == 0) {
     204                      $userchoices[0] = get_string('none');
     205                  }
     206                  $mform->addElement('searchableselector', 'userid',
     207                          get_string('overrideuser', 'assign'), $userchoices);
     208                  $mform->addRule('userid', get_string('required'), 'required', null, 'client');
     209  
     210                  if ($inrelativedatesmode) {
     211                      // If in relative dates mode then add the JS to reload the page when the user
     212                      // selection is changed to ensure that the correct dates are displayed.
     213                      $PAGE->requires->js_call_amd('mod_assign/override_form', 'init', [
     214                          $mform->getAttribute('id'),
     215                          'userid'
     216                      ]);
     217                  }
     218              }
     219  
     220              if ($inrelativedatesmode) {
     221                  if ($userid) {
     222                      $templatecontext = [
     223                          'allowsubmissionsfromdate' => $assigninstance->allowsubmissionsfromdate,
     224                          'duedate' => $assigninstance->duedate,
     225                          'cutoffdate' => $assigninstance->cutoffdate
     226                      ];
     227                      $html = $OUTPUT->render_from_template('mod_assign/override_form_user_defaults', $templatecontext);
     228                  } else {
     229                      $html = get_string('noselection', 'form');
     230                  }
     231  
     232                  $groupelements = [];
     233                  $groupelements[] = $mform->createElement('html', $html);
     234                  $mform->addGroup($groupelements, null, get_string('userassignmentdefaults', 'mod_assign'), null, false);
     235              }
     236          }
     237  
     238          $users = $DB->get_fieldset_select('groups_members', 'userid', 'groupid = ?', array($this->groupid));
     239          array_push($users, $this->userid);
     240          $extensionmax = 0;
     241          foreach ($users as $value) {
     242              $extension = $DB->get_record('assign_user_flags', array('assignment' => $assigninstance->id,
     243                  'userid' => $value));
     244              if ($extension) {
     245                  if ($extensionmax < $extension->extensionduedate) {
     246                      $extensionmax = $extension->extensionduedate;
     247                  }
     248              }
     249          }
     250  
     251          if ($extensionmax) {
     252              $assigninstance->extensionduedate = $extensionmax;
     253          }
     254  
     255          // Open and close dates.
     256          $mform->addElement('date_time_selector', 'allowsubmissionsfromdate',
     257              get_string('allowsubmissionsfromdate', 'assign'), array('optional' => true));
     258          $mform->setDefault('allowsubmissionsfromdate', $assigninstance->allowsubmissionsfromdate);
     259  
     260          $mform->addElement('date_time_selector', 'duedate', get_string('duedate', 'assign'), array('optional' => true));
     261          $mform->setDefault('duedate', $assigninstance->duedate);
     262  
     263          $mform->addElement('date_time_selector', 'cutoffdate', get_string('cutoffdate', 'assign'), array('optional' => true));
     264          $mform->setDefault('cutoffdate', $assigninstance->cutoffdate);
     265  
     266          if (isset($assigninstance->extensionduedate)) {
     267              $mform->addElement('static', 'extensionduedate', get_string('extensionduedate', 'assign'),
     268                  userdate($assigninstance->extensionduedate));
     269          }
     270  
     271          // Submit buttons.
     272          $mform->addElement('submit', 'resetbutton',
     273                  get_string('reverttodefaults', 'assign'));
     274  
     275          $buttonarray = array();
     276          $buttonarray[] = $mform->createElement('submit', 'submitbutton',
     277                  get_string('save', 'assign'));
     278          $buttonarray[] = $mform->createElement('submit', 'againbutton',
     279                  get_string('saveoverrideandstay', 'assign'));
     280          $buttonarray[] = $mform->createElement('cancel');
     281  
     282          $mform->addGroup($buttonarray, 'buttonbar', '', array(' '), false);
     283          $mform->closeHeaderBefore('buttonbar');
     284  
     285      }
     286  
     287      /**
     288       * Validate the submitted form data.
     289       *
     290       * @param array $data array of ("fieldname"=>value) of submitted data
     291       * @param array $files array of uploaded files "element_name"=>tmp_file_path
     292       * @return array of "element_name"=>"error_description" if there are errors
     293       */
     294      public function validation($data, $files) {
     295          $errors = parent::validation($data, $files);
     296  
     297          $mform =& $this->_form;
     298          $userid = $this->selecteduserid ?? $this->userid ?: null;
     299          $assigninstance = $this->assign->get_instance($userid);
     300  
     301          if ($mform->elementExists('userid')) {
     302              if (empty($data['userid'])) {
     303                  $errors['userid'] = get_string('required');
     304              }
     305          }
     306  
     307          if ($mform->elementExists('groupid')) {
     308              if (empty($data['groupid'])) {
     309                  $errors['groupid'] = get_string('required');
     310              }
     311          }
     312  
     313          // Ensure that the dates make sense.
     314          if (!empty($data['allowsubmissionsfromdate']) && !empty($data['cutoffdate'])) {
     315              if ($data['cutoffdate'] < $data['allowsubmissionsfromdate']) {
     316                  $errors['cutoffdate'] = get_string('cutoffdatefromdatevalidation', 'assign');
     317              }
     318          }
     319  
     320          if (!empty($data['allowsubmissionsfromdate']) && !empty($data['duedate'])) {
     321              if ($data['duedate'] < $data['allowsubmissionsfromdate']) {
     322                  $errors['duedate'] = get_string('duedatevalidation', 'assign');
     323              }
     324          }
     325  
     326          if (!empty($data['cutoffdate']) && !empty($data['duedate'])) {
     327              if ($data['cutoffdate'] < $data['duedate'] ) {
     328                  $errors['cutoffdate'] = get_string('cutoffdatevalidation', 'assign');
     329              }
     330          }
     331  
     332          // Ensure that override duedate/allowsubmissionsfromdate are before extension date if exist.
     333          if (!empty($assigninstance->extensionduedate) && !empty($data['duedate'])) {
     334              if ($assigninstance->extensionduedate < $data['duedate']) {
     335                  $errors['duedate'] = get_string('extensionnotafterduedate', 'assign');
     336              }
     337          }
     338          if (!empty($assigninstance->extensionduedate) && !empty($data['allowsubmissionsfromdate'])) {
     339              if ($assigninstance->extensionduedate < $data['allowsubmissionsfromdate']) {
     340                  $errors['allowsubmissionsfromdate'] = get_string('extensionnotafterfromdate', 'assign');
     341              }
     342          }
     343  
     344          // Ensure that at least one assign setting was changed.
     345          $changed = false;
     346          $keys = array('duedate', 'cutoffdate', 'allowsubmissionsfromdate');
     347          foreach ($keys as $key) {
     348              if ($data[$key] != $assigninstance->{$key}) {
     349                  $changed = true;
     350                  break;
     351              }
     352          }
     353  
     354          if (!$changed) {
     355              $errors['allowsubmissionsfromdate'] = get_string('nooverridedata', 'assign');
     356          }
     357  
     358          return $errors;
     359      }
     360  }