Merge branch 'MDL-81073' of https://github.com/paulholden/moodle
[moodle.git] / mod / assign / override_form.php
blob8f5f7cf49019b36e6b329510918b85aac544ec03
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.
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/>.
17 /**
18 * Settings form for overrides in the assign module.
20 * @package mod_assign
21 * @copyright 2016 Ilya Tregubov
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
26 defined('MOODLE_INTERNAL') || die();
28 require_once($CFG->libdir . '/formslib.php');
29 require_once($CFG->dirroot . '/mod/assign/mod_form.php');
32 /**
33 * Form for editing settings overrides.
35 * @copyright 2016 Ilya Tregubov
36 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
38 class assign_override_form extends moodleform {
40 /** @var object course module object. */
41 protected $cm;
43 /** @var object the assign settings object. */
44 protected $assign;
46 /** @var context the assign context. */
47 protected $context;
49 /** @var bool editing group override (true) or user override (false). */
50 protected $groupmode;
52 /** @var int groupid, if provided. */
53 protected $groupid;
55 /** @var int userid, if provided. */
56 protected $userid;
58 /** @var int sortorder, if provided. */
59 protected $sortorder;
61 /** @var int selecteduserid, if provided. */
62 protected $selecteduserid;
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.
74 public function __construct($submiturl, $cm, $assign, $context, $groupmode, $override, $selecteduserid = null) {
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;
85 parent::__construct($submiturl, null, 'post');
89 /**
90 * Define this form - called by the parent constructor
92 protected function definition() {
93 global $DB, $OUTPUT, $PAGE;
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);
101 $assigngroupmode = groups_get_activity_groupmode($cm);
102 $accessallgroups = ($assigngroupmode == NOGROUPS) || has_capability('moodle/site:accessallgroups', $this->context);
104 if ($this->groupmode) {
105 $mform->addElement('header', 'override', get_string('groupoverrides', 'assign'));
106 // Group override.
107 if ($this->groupid) {
108 // There is already a groupid, so freeze the selector.
109 $groupchoices = [
110 $this->groupid => format_string(groups_get_group_name($this->groupid), true, ['context' => $this->context]),
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 throw new \moodle_exception('groupsnone', 'assign', $link);
129 $groupchoices = array();
130 foreach ($groups as $group) {
131 if ($group->visibility != GROUPS_VISIBILITY_NONE) {
132 $groupchoices[$group->id] = format_string($group->name, true, ['context' => $this->context]);
135 unset($groups);
137 if (count($groupchoices) == 0) {
138 $groupchoices[0] = get_string('none');
141 $mform->addElement('select', 'groupid',
142 get_string('overridegroup', 'assign'), $groupchoices);
143 $mform->addRule('groupid', get_string('required'), 'required', null, 'client');
145 } else {
146 $mform->addElement('header', 'override', get_string('useroverrides', 'assign'));
147 // User override.
148 if ($this->userid) {
149 // There is already a userid, so freeze the selector.
150 $user = $DB->get_record('user', array('id' => $this->userid));
151 $userchoices = array();
152 $userchoices[$this->userid] = fullname($user);
153 $mform->addElement('select', 'userid',
154 get_string('overrideuser', 'assign'), $userchoices);
155 $mform->freeze('userid');
156 } else {
157 // Prepare the list of users.
158 $users = [];
159 list($sort) = users_order_by_sql('u');
161 // Get the list of appropriate users, depending on whether and how groups are used.
162 $userfieldsapi = \core_user\fields::for_name();
163 $userfields = 'u.id, u.email, ' . $userfieldsapi->get_sql('u', false, '', '', false)->selects;
164 $groupids = 0;
165 if (!$accessallgroups) {
166 $groups = groups_get_activity_allowed_groups($cm);
167 $groupids = array_keys($groups);
169 $users = get_enrolled_users($this->context, '',
170 $groupids, $userfields, $sort);
172 // Filter users based on any fixed restrictions (groups, profile).
173 $info = new \core_availability\info_module($cm);
174 $users = $info->filter_user_list($users);
176 if (empty($users)) {
177 // Generate an error.
178 $link = new moodle_url('/mod/assign/overrides.php', array('cmid' => $cm->id));
179 throw new \moodle_exception('usersnone', 'assign', $link);
182 $userchoices = array();
183 // TODO Does not support custom user profile fields (MDL-70456).
184 $canviewemail = in_array('email', \core_user\fields::get_identity_fields($this->context, false));
185 foreach ($users as $id => $user) {
186 if (empty($invalidusers[$id]) || (!empty($override) &&
187 $id == $override->userid)) {
188 if ($canviewemail) {
189 $userchoices[$id] = fullname($user) . ', ' . $user->email;
190 } else {
191 $userchoices[$id] = fullname($user);
195 unset($users);
197 if (count($userchoices) == 0) {
198 $userchoices[0] = get_string('none');
200 $mform->addElement('searchableselector', 'userid',
201 get_string('overrideuser', 'assign'), $userchoices);
202 $mform->addRule('userid', get_string('required'), 'required', null, 'client');
204 if ($inrelativedatesmode) {
205 // If in relative dates mode then add the JS to reload the page when the user
206 // selection is changed to ensure that the correct dates are displayed.
207 $PAGE->requires->js_call_amd('mod_assign/override_form', 'init', [
208 $mform->getAttribute('id'),
209 'userid'
214 if ($inrelativedatesmode) {
215 if ($userid) {
216 $templatecontext = [
217 'allowsubmissionsfromdate' => $assigninstance->allowsubmissionsfromdate,
218 'duedate' => $assigninstance->duedate,
219 'cutoffdate' => $assigninstance->cutoffdate
221 $html = $OUTPUT->render_from_template('mod_assign/override_form_user_defaults', $templatecontext);
222 } else {
223 $html = get_string('noselection', 'form');
226 $groupelements = [];
227 $groupelements[] = $mform->createElement('html', $html);
228 $mform->addGroup($groupelements, null, get_string('userassignmentdefaults', 'mod_assign'), null, false);
232 $users = $DB->get_fieldset_select('groups_members', 'userid', 'groupid = ?', array($this->groupid));
233 array_push($users, $this->userid);
234 $extensionmax = 0;
235 foreach ($users as $value) {
236 $extension = $DB->get_record('assign_user_flags', array('assignment' => $assigninstance->id,
237 'userid' => $value));
238 if ($extension) {
239 if ($extensionmax < $extension->extensionduedate) {
240 $extensionmax = $extension->extensionduedate;
245 if ($extensionmax) {
246 $assigninstance->extensionduedate = $extensionmax;
249 // Open and close dates.
250 $mform->addElement('date_time_selector', 'allowsubmissionsfromdate',
251 get_string('allowsubmissionsfromdate', 'assign'), array('optional' => true));
252 $mform->setDefault('allowsubmissionsfromdate', $assigninstance->allowsubmissionsfromdate);
254 $mform->addElement('date_time_selector', 'duedate', get_string('duedate', 'assign'), array('optional' => true));
255 $mform->setDefault('duedate', $assigninstance->duedate);
257 $mform->addElement('date_time_selector', 'cutoffdate', get_string('cutoffdate', 'assign'), array('optional' => true));
258 $mform->setDefault('cutoffdate', $assigninstance->cutoffdate);
260 if (isset($assigninstance->extensionduedate)) {
261 $mform->addElement('static', 'extensionduedate', get_string('extensionduedate', 'assign'),
262 userdate($assigninstance->extensionduedate));
265 // Time limit.
266 $timelimitenabled = get_config('assign', 'enabletimelimit');
267 if ($timelimitenabled) {
268 $mform->addElement('duration', 'timelimit',
269 get_string('timelimit', 'assign'), array('optional' => true));
270 $mform->setDefault('timelimit', $assigninstance->timelimit);
273 // Submit buttons.
274 $mform->addElement('submit', 'resetbutton',
275 get_string('reverttodefaults', 'assign'));
277 $buttonarray = array();
278 $buttonarray[] = $mform->createElement('submit', 'submitbutton',
279 get_string('save', 'assign'));
280 $buttonarray[] = $mform->createElement('submit', 'againbutton',
281 get_string('saveoverrideandstay', 'assign'));
282 $buttonarray[] = $mform->createElement('cancel');
284 $mform->addGroup($buttonarray, 'buttonbar', '', array(' '), false);
285 $mform->closeHeaderBefore('buttonbar');
290 * Validate the submitted form data.
292 * @param array $data array of ("fieldname"=>value) of submitted data
293 * @param array $files array of uploaded files "element_name"=>tmp_file_path
294 * @return array of "element_name"=>"error_description" if there are errors
296 public function validation($data, $files) {
297 $errors = parent::validation($data, $files);
299 $mform =& $this->_form;
300 $userid = $this->selecteduserid ?? $this->userid ?: null;
301 $assigninstance = $this->assign->get_instance($userid);
303 if ($mform->elementExists('userid')) {
304 if (empty($data['userid'])) {
305 $errors['userid'] = get_string('required');
309 if ($mform->elementExists('groupid')) {
310 if (empty($data['groupid'])) {
311 $errors['groupid'] = get_string('required');
315 // Ensure that the dates make sense.
316 if (!empty($data['allowsubmissionsfromdate']) && !empty($data['cutoffdate'])) {
317 if ($data['cutoffdate'] < $data['allowsubmissionsfromdate']) {
318 $errors['cutoffdate'] = get_string('cutoffdatefromdatevalidation', 'assign');
322 if (!empty($data['allowsubmissionsfromdate']) && !empty($data['duedate'])) {
323 if ($data['duedate'] <= $data['allowsubmissionsfromdate']) {
324 $errors['duedate'] = get_string('duedateaftersubmissionvalidation', 'assign');
328 if (!empty($data['cutoffdate']) && !empty($data['duedate'])) {
329 if ($data['cutoffdate'] < $data['duedate'] ) {
330 $errors['cutoffdate'] = get_string('cutoffdatevalidation', 'assign');
334 // Ensure that override duedate/allowsubmissionsfromdate are before extension date if exist.
335 if (!empty($assigninstance->extensionduedate) && !empty($data['duedate'])) {
336 if ($assigninstance->extensionduedate < $data['duedate']) {
337 $errors['duedate'] = get_string('extensionnotafterduedate', 'assign');
340 if (!empty($assigninstance->extensionduedate) && !empty($data['allowsubmissionsfromdate'])) {
341 if ($assigninstance->extensionduedate < $data['allowsubmissionsfromdate']) {
342 $errors['allowsubmissionsfromdate'] = get_string('extensionnotafterfromdate', 'assign');
346 // Ensure that at least one assign setting was changed.
347 $changed = false;
348 $keys = array('duedate', 'cutoffdate', 'allowsubmissionsfromdate', 'timelimit');
349 foreach ($keys as $key) {
350 if (isset($data[$key]) && $data[$key] != $assigninstance->{$key}) {
351 $changed = true;
352 break;
356 if (!$changed) {
357 $errors['allowsubmissionsfromdate'] = get_string('nooverridedata', 'assign');
360 return $errors;