Commit | Line | Data |
---|---|---|
bbd0e548 DW |
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 | * This file contains the definition for the grading table which subclassses easy_table | |
19 | * | |
20 | * @package mod_assign | |
21 | * @copyright 2012 NetSpot {@link http://www.netspot.com.au} | |
22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | |
23 | */ | |
24 | ||
25 | defined('MOODLE_INTERNAL') || die(); | |
26 | ||
27 | require_once($CFG->libdir.'/tablelib.php'); | |
28 | require_once($CFG->libdir.'/gradelib.php'); | |
29 | require_once($CFG->dirroot.'/mod/assign/locallib.php'); | |
30 | ||
31 | /** | |
32 | * Extends table_sql to provide a table of assignment submissions | |
33 | * | |
34 | * @package mod_assign | |
35 | * @copyright 2012 NetSpot {@link http://www.netspot.com.au} | |
36 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | |
37 | */ | |
38 | class assign_grading_table extends table_sql implements renderable { | |
39 | /** @var assign $assignment */ | |
40 | private $assignment = null; | |
41 | /** @var int $perpage */ | |
42 | private $perpage = 10; | |
43 | /** @var int $rownum (global index of current row in table) */ | |
44 | private $rownum = -1; | |
45 | /** @var renderer_base for getting output */ | |
46 | private $output = null; | |
47 | /** @var stdClass gradinginfo */ | |
48 | private $gradinginfo = null; | |
49 | /** @var int $tablemaxrows */ | |
50 | private $tablemaxrows = 10000; | |
bf78ebd6 DW |
51 | /** @var boolean $quickgrading */ |
52 | private $quickgrading = false; | |
9e795179 DW |
53 | /** @var boolean $hasgrantextension - Only do the capability check once for the entire table */ |
54 | private $hasgrantextension = false; | |
4a47008c DW |
55 | /** @var boolean $hasgrade - Only do the capability check once for the entire table */ |
56 | private $hasgrade = false; | |
cd01491c DW |
57 | /** @var array $groupsubmissions - A static cache of group submissions */ |
58 | private $groupsubmissions = array(); | |
59 | /** @var array $submissiongroups - A static cache of submission groups */ | |
60 | private $submissiongroups = array(); | |
df47b77f DW |
61 | /** @var string $plugingradingbatchoperations - List of plugin supported batch operations */ |
62 | public $plugingradingbatchoperations = array(); | |
63 | /** @var array $plugincache - A cache of plugin lookups to match a column name to a plugin efficiently */ | |
64 | private $plugincache = array(); | |
65 | /** @var array $scale - A list of the keys and descriptions for the custom scale */ | |
66 | private $scale = null; | |
bbd0e548 DW |
67 | |
68 | /** | |
69 | * overridden constructor keeps a reference to the assignment class that is displaying this table | |
70 | * | |
71 | * @param assign $assignment The assignment class | |
72 | * @param int $perpage how many per page | |
73 | * @param string $filter The current filter | |
74 | * @param int $rowoffset For showing a subsequent page of results | |
bf78ebd6 | 75 | * @param bool $quickgrading Is this table wrapped in a quickgrading form? |
1561a37c | 76 | * @param string $downloadfilename |
bbd0e548 | 77 | */ |
e5403f8c DW |
78 | public function __construct(assign $assignment, |
79 | $perpage, | |
80 | $filter, | |
81 | $rowoffset, | |
82 | $quickgrading, | |
83 | $downloadfilename = null) { | |
f8d107b3 | 84 | global $CFG, $PAGE, $DB, $USER; |
bbd0e548 DW |
85 | parent::__construct('mod_assign_grading'); |
86 | $this->assignment = $assignment; | |
df47b77f | 87 | |
4a47008c DW |
88 | // Check permissions up front. |
89 | $this->hasgrantextension = has_capability('mod/assign:grantextension', | |
90 | $this->assignment->get_context()); | |
91 | $this->hasgrade = $this->assignment->can_grade(); | |
92 | ||
323f221b MH |
93 | // Check if we have the elevated view capablities to see the blind details. |
94 | $this->hasviewblind = has_capability('mod/assign:viewblinddetails', | |
95 | $this->assignment->get_context()); | |
96 | ||
df47b77f DW |
97 | foreach ($assignment->get_feedback_plugins() as $plugin) { |
98 | if ($plugin->is_visible() && $plugin->is_enabled()) { | |
99 | foreach ($plugin->get_grading_batch_operations() as $action => $description) { | |
100 | if (empty($this->plugingradingbatchoperations)) { | |
101 | $this->plugingradingbatchoperations[$plugin->get_type()] = array(); | |
102 | } | |
103 | $this->plugingradingbatchoperations[$plugin->get_type()][$action] = $description; | |
104 | } | |
105 | } | |
106 | } | |
bbd0e548 | 107 | $this->perpage = $perpage; |
4a47008c | 108 | $this->quickgrading = $quickgrading && $this->hasgrade; |
bbd0e548 DW |
109 | $this->output = $PAGE->get_renderer('mod_assign'); |
110 | ||
e5403f8c DW |
111 | $urlparams = array('action'=>'grading', 'id'=>$assignment->get_course_module()->id); |
112 | $url = new moodle_url($CFG->wwwroot . '/mod/assign/view.php', $urlparams); | |
113 | $this->define_baseurl($url); | |
bbd0e548 | 114 | |
e5403f8c | 115 | // Do some business - then set the sql. |
bbd0e548 DW |
116 | $currentgroup = groups_get_activity_group($assignment->get_course_module(), true); |
117 | ||
118 | if ($rowoffset) { | |
119 | $this->rownum = $rowoffset - 1; | |
120 | } | |
121 | ||
122 | $users = array_keys( $assignment->list_participants($currentgroup, true)); | |
123 | if (count($users) == 0) { | |
e5403f8c | 124 | // Insert a record that will never match to the sql is still valid. |
bbd0e548 DW |
125 | $users[] = -1; |
126 | } | |
127 | ||
128 | $params = array(); | |
a3dbdc2c DW |
129 | $params['assignmentid1'] = (int)$this->assignment->get_instance()->id; |
130 | $params['assignmentid2'] = (int)$this->assignment->get_instance()->id; | |
df211804 | 131 | $params['assignmentid3'] = (int)$this->assignment->get_instance()->id; |
bbd0e548 | 132 | |
d08e6c31 DW |
133 | $extrauserfields = get_extra_user_fields($this->assignment->get_context()); |
134 | ||
135 | $fields = user_picture::fields('u', $extrauserfields) . ', '; | |
9e795179 DW |
136 | $fields .= 'u.id as userid, '; |
137 | $fields .= 's.status as status, '; | |
138 | $fields .= 's.id as submissionid, '; | |
139 | $fields .= 's.timecreated as firstsubmission, '; | |
140 | $fields .= 's.timemodified as timesubmitted, '; | |
df211804 | 141 | $fields .= 's.attemptnumber as attemptnumber, '; |
9e795179 DW |
142 | $fields .= 'g.id as gradeid, '; |
143 | $fields .= 'g.grade as grade, '; | |
144 | $fields .= 'g.timemodified as timemarked, '; | |
145 | $fields .= 'g.timecreated as firstmarked, '; | |
df211804 DW |
146 | $fields .= 'uf.mailed as mailed, '; |
147 | $fields .= 'uf.locked as locked, '; | |
f8d107b3 DM |
148 | $fields .= 'uf.extensionduedate as extensionduedate, '; |
149 | $fields .= 'uf.workflowstate as workflowstate, '; | |
150 | $fields .= 'uf.allocatedmarker as allocatedmarker '; | |
df211804 | 151 | |
df211804 | 152 | $from = '{user} u |
df211804 DW |
153 | LEFT JOIN {assign_submission} s ON |
154 | u.id = s.userid AND | |
155 | s.assignment = :assignmentid1 AND | |
ad030ab4 | 156 | s.latest = 1 |
df211804 DW |
157 | LEFT JOIN {assign_grades} g ON |
158 | u.id = g.userid AND | |
159 | g.assignment = :assignmentid2 AND | |
ad030ab4 | 160 | g.attemptnumber = s.attemptnumber |
df211804 | 161 | LEFT JOIN {assign_user_flags} uf ON u.id = uf.userid AND uf.assignment = :assignmentid3'; |
bbd0e548 DW |
162 | |
163 | $userparams = array(); | |
a3dbdc2c DW |
164 | $userindex = 0; |
165 | ||
166 | list($userwhere, $userparams) = $DB->get_in_or_equal($users, SQL_PARAMS_NAMED, 'user'); | |
167 | $where = 'u.id ' . $userwhere; | |
168 | $params = array_merge($params, $userparams); | |
9682626e | 169 | |
93d1de6d DW |
170 | // The filters do not make sense when there are no submissions, so do not apply them. |
171 | if ($this->assignment->is_any_submission_plugin_enabled()) { | |
172 | if ($filter == ASSIGN_FILTER_SUBMITTED) { | |
77755451 DW |
173 | $where .= ' AND (s.timemodified IS NOT NULL AND |
174 | s.status = :submitted) '; | |
175 | $params['submitted'] = ASSIGN_SUBMISSION_STATUS_SUBMITTED; | |
176 | ||
c80d59f2 | 177 | } else if ($filter == ASSIGN_FILTER_NOT_SUBMITTED) { |
8f165230 WL |
178 | $where .= ' AND (s.timemodified IS NULL OR s.status != :submitted) '; |
179 | $params['submitted'] = ASSIGN_SUBMISSION_STATUS_SUBMITTED; | |
77755451 | 180 | } else if ($filter == ASSIGN_FILTER_REQUIRE_GRADING) { |
93d1de6d DW |
181 | $where .= ' AND (s.timemodified IS NOT NULL AND |
182 | s.status = :submitted AND | |
183 | (s.timemodified > g.timemodified OR g.timemodified IS NULL))'; | |
184 | $params['submitted'] = ASSIGN_SUBMISSION_STATUS_SUBMITTED; | |
77755451 DW |
185 | |
186 | } else if (strpos($filter, ASSIGN_FILTER_SINGLE_USER) === 0) { | |
93d1de6d DW |
187 | $userfilter = (int) array_pop(explode('=', $filter)); |
188 | $where .= ' AND (u.id = :userid)'; | |
189 | $params['userid'] = $userfilter; | |
190 | } | |
bbd0e548 | 191 | } |
df211804 | 192 | |
5a96486b DM |
193 | if ($this->assignment->get_instance()->markingworkflow && |
194 | $this->assignment->get_instance()->markingallocation) { | |
f8d107b3 | 195 | if (has_capability('mod/assign:manageallocations', $this->assignment->get_context())) { |
13e82f1c | 196 | // Check to see if marker filter is set. |
f8d107b3 DM |
197 | $markerfilter = (int)get_user_preferences('assign_markerfilter', ''); |
198 | if (!empty($markerfilter)) { | |
c80d59f2 JF |
199 | if ($markerfilter == ASSIGN_MARKER_FILTER_NO_MARKER) { |
200 | $where .= ' AND (uf.allocatedmarker IS NULL OR uf.allocatedmarker = 0)'; | |
201 | } else { | |
202 | $where .= ' AND uf.allocatedmarker = :markerid'; | |
203 | $params['markerid'] = $markerfilter; | |
204 | } | |
f8d107b3 DM |
205 | } |
206 | } else { // Only show users allocated to this marker. | |
207 | $where .= ' AND uf.allocatedmarker = :markerid'; | |
208 | $params['markerid'] = $USER->id; | |
209 | } | |
210 | } | |
211 | ||
212 | if ($this->assignment->get_instance()->markingworkflow) { | |
213 | $workflowstates = $this->assignment->get_marking_workflow_states_for_current_user(); | |
214 | if (!empty($workflowstates)) { | |
215 | $workflowfilter = get_user_preferences('assign_workflowfilter', ''); | |
13e82f1c DW |
216 | if ($workflowfilter == ASSIGN_MARKING_WORKFLOW_STATE_NOTMARKED) { |
217 | $where .= ' AND (uf.workflowstate = :workflowstate OR uf.workflowstate IS NULL OR '. | |
218 | $DB->sql_isempty('assign_user_flags', 'workflowstate', true, true).')'; | |
219 | $params['workflowstate'] = $workflowfilter; | |
220 | } else if (array_key_exists($workflowfilter, $workflowstates)) { | |
221 | $where .= ' AND uf.workflowstate = :workflowstate'; | |
222 | $params['workflowstate'] = $workflowfilter; | |
f8d107b3 DM |
223 | } |
224 | } | |
225 | } | |
226 | ||
bbd0e548 DW |
227 | $this->set_sql($fields, $from, $where, $params); |
228 | ||
df47b77f DW |
229 | if ($downloadfilename) { |
230 | $this->is_downloading('csv', $downloadfilename); | |
231 | } | |
232 | ||
bbd0e548 DW |
233 | $columns = array(); |
234 | $headers = array(); | |
235 | ||
df47b77f | 236 | // Select. |
4a47008c | 237 | if (!$this->is_downloading() && $this->hasgrade) { |
df47b77f DW |
238 | $columns[] = 'select'; |
239 | $headers[] = get_string('select') . | |
7400be1b RT |
240 | '<div class="selectall"><label class="accesshide" for="selectall">' . get_string('selectall') . '</label> |
241 | <input type="checkbox" id="selectall" name="selectall" title="' . get_string('selectall') . '"/></div>'; | |
bbd0e548 DW |
242 | } |
243 | ||
b473171a | 244 | // User picture. |
323f221b | 245 | if ($this->hasviewblind || !$this->assignment->is_blind_marking()) { |
df47b77f DW |
246 | if (!$this->is_downloading()) { |
247 | $columns[] = 'picture'; | |
248 | $headers[] = get_string('pictureofuser'); | |
249 | } else { | |
250 | $columns[] = 'recordid'; | |
251 | $headers[] = get_string('recordid', 'assign'); | |
252 | } | |
b473171a DW |
253 | |
254 | // Fullname. | |
255 | $columns[] = 'fullname'; | |
256 | $headers[] = get_string('fullname'); | |
d08e6c31 DW |
257 | |
258 | foreach ($extrauserfields as $extrafield) { | |
259 | $columns[] = $extrafield; | |
260 | $headers[] = get_user_field_name($extrafield); | |
261 | } | |
b473171a DW |
262 | } else { |
263 | // Record ID. | |
264 | $columns[] = 'recordid'; | |
265 | $headers[] = get_string('recordid', 'assign'); | |
266 | } | |
bbd0e548 | 267 | |
e5403f8c | 268 | // Submission status. |
bbd0e548 DW |
269 | if ($assignment->is_any_submission_plugin_enabled()) { |
270 | $columns[] = 'status'; | |
8137e049 | 271 | $headers[] = get_string('status', 'assign'); |
f8d107b3 DM |
272 | } else if ($this->assignment->get_instance()->markingworkflow) { |
273 | $columns[] = 'workflowstatus'; | |
8137e049 | 274 | $headers[] = get_string('status', 'assign'); |
bbd0e548 DW |
275 | } |
276 | ||
e5403f8c | 277 | // Team submission columns. |
12a1a0da DW |
278 | if ($assignment->get_instance()->teamsubmission) { |
279 | $columns[] = 'team'; | |
280 | $headers[] = get_string('submissionteam', 'assign'); | |
12a1a0da | 281 | } |
13e82f1c | 282 | // Allocated marker. |
5a96486b DM |
283 | if ($this->assignment->get_instance()->markingworkflow && |
284 | $this->assignment->get_instance()->markingallocation && | |
f8d107b3 DM |
285 | has_capability('mod/assign:manageallocations', $this->assignment->get_context())) { |
286 | // Add a column for the allocated marker. | |
287 | $columns[] = 'allocatedmarker'; | |
288 | $headers[] = get_string('marker', 'assign'); | |
289 | } | |
e5403f8c | 290 | // Grade. |
bbd0e548 DW |
291 | $columns[] = 'grade'; |
292 | $headers[] = get_string('grade'); | |
df47b77f DW |
293 | if ($this->is_downloading()) { |
294 | if ($this->assignment->get_instance()->grade >= 0) { | |
295 | $columns[] = 'grademax'; | |
296 | $headers[] = get_string('maxgrade', 'assign'); | |
297 | } else { | |
298 | // This is a custom scale. | |
299 | $columns[] = 'scale'; | |
300 | $headers[] = get_string('scale', 'assign'); | |
301 | } | |
f8d107b3 DM |
302 | |
303 | if ($this->assignment->get_instance()->markingworkflow) { | |
304 | // Add a column for the marking workflow state. | |
305 | $columns[] = 'workflowstate'; | |
306 | $headers[] = get_string('markingworkflowstate', 'assign'); | |
307 | } | |
308 | // Add a column for the list of valid marking workflow states. | |
309 | $columns[] = 'gradecanbechanged'; | |
310 | $headers[] = get_string('gradecanbechanged', 'assign'); | |
df47b77f | 311 | } |
4a47008c | 312 | if (!$this->is_downloading() && $this->hasgrade) { |
2bda0460 NK |
313 | // We have to call this column userid so we can use userid as a default sortable column. |
314 | $columns[] = 'userid'; | |
315 | $headers[] = get_string('edit'); | |
316 | } | |
bbd0e548 | 317 | |
e5403f8c | 318 | // Submission plugins. |
bbd0e548 DW |
319 | if ($assignment->is_any_submission_plugin_enabled()) { |
320 | $columns[] = 'timesubmitted'; | |
321 | $headers[] = get_string('lastmodifiedsubmission', 'assign'); | |
322 | ||
323 | foreach ($this->assignment->get_submission_plugins() as $plugin) { | |
df47b77f DW |
324 | if ($this->is_downloading()) { |
325 | if ($plugin->is_visible() && $plugin->is_enabled()) { | |
326 | foreach ($plugin->get_editor_fields() as $field => $description) { | |
327 | $index = 'plugin' . count($this->plugincache); | |
328 | $this->plugincache[$index] = array($plugin, $field); | |
329 | $columns[] = $index; | |
330 | $headers[] = $plugin->get_name(); | |
331 | } | |
332 | } | |
333 | } else { | |
334 | if ($plugin->is_visible() && $plugin->is_enabled() && $plugin->has_user_summary()) { | |
335 | $index = 'plugin' . count($this->plugincache); | |
336 | $this->plugincache[$index] = array($plugin); | |
337 | $columns[] = $index; | |
338 | $headers[] = $plugin->get_name(); | |
339 | } | |
bbd0e548 DW |
340 | } |
341 | } | |
342 | } | |
343 | ||
e5403f8c | 344 | // Time marked. |
bbd0e548 DW |
345 | $columns[] = 'timemarked'; |
346 | $headers[] = get_string('lastmodifiedgrade', 'assign'); | |
347 | ||
e5403f8c | 348 | // Feedback plugins. |
bbd0e548 | 349 | foreach ($this->assignment->get_feedback_plugins() as $plugin) { |
df47b77f DW |
350 | if ($this->is_downloading()) { |
351 | if ($plugin->is_visible() && $plugin->is_enabled()) { | |
352 | foreach ($plugin->get_editor_fields() as $field => $description) { | |
353 | $index = 'plugin' . count($this->plugincache); | |
354 | $this->plugincache[$index] = array($plugin, $field); | |
355 | $columns[] = $index; | |
356 | $headers[] = $description; | |
357 | } | |
358 | } | |
359 | } else if ($plugin->is_visible() && $plugin->is_enabled() && $plugin->has_user_summary()) { | |
360 | $index = 'plugin' . count($this->plugincache); | |
361 | $this->plugincache[$index] = array($plugin); | |
362 | $columns[] = $index; | |
bbd0e548 DW |
363 | $headers[] = $plugin->get_name(); |
364 | } | |
365 | } | |
366 | ||
9f484b98 RW |
367 | // Exclude 'Final grade' column in downloaded grading worksheets. |
368 | if (!$this->is_downloading()) { | |
369 | // Final grade. | |
370 | $columns[] = 'finalgrade'; | |
371 | $headers[] = get_string('finalgrade', 'grades'); | |
372 | } | |
bbd0e548 | 373 | |
e5403f8c DW |
374 | // Load the grading info for all users. |
375 | $this->gradinginfo = grade_get_grades($this->assignment->get_course()->id, | |
376 | 'mod', | |
377 | 'assign', | |
378 | $this->assignment->get_instance()->id, | |
379 | $users); | |
a769a001 DW |
380 | |
381 | if (!empty($CFG->enableoutcomes) && !empty($this->gradinginfo->outcomes)) { | |
382 | $columns[] = 'outcomes'; | |
383 | $headers[] = get_string('outcomes', 'grades'); | |
384 | } | |
bbd0e548 | 385 | |
e5403f8c | 386 | // Set the columns. |
bbd0e548 DW |
387 | $this->define_columns($columns); |
388 | $this->define_headers($headers); | |
d08e6c31 DW |
389 | foreach ($extrauserfields as $extrafield) { |
390 | $this->column_class($extrafield, $extrafield); | |
391 | } | |
f9e62127 DW |
392 | // We require at least one unique column for the sort. |
393 | $this->sortable(true, 'userid'); | |
394 | $this->no_sorting('recordid'); | |
bbd0e548 | 395 | $this->no_sorting('finalgrade'); |
f9e62127 | 396 | $this->no_sorting('userid'); |
bbd0e548 | 397 | $this->no_sorting('select'); |
a769a001 DW |
398 | $this->no_sorting('outcomes'); |
399 | ||
12a1a0da DW |
400 | if ($assignment->get_instance()->teamsubmission) { |
401 | $this->no_sorting('team'); | |
12a1a0da DW |
402 | } |
403 | ||
f9e62127 | 404 | $plugincolumnindex = 0; |
bbd0e548 | 405 | foreach ($this->assignment->get_submission_plugins() as $plugin) { |
df47b77f | 406 | if ($plugin->is_visible() && $plugin->is_enabled() && $plugin->has_user_summary()) { |
f9e62127 DW |
407 | $submissionpluginindex = 'plugin' . $plugincolumnindex++; |
408 | $this->no_sorting($submissionpluginindex); | |
bbd0e548 DW |
409 | } |
410 | } | |
411 | foreach ($this->assignment->get_feedback_plugins() as $plugin) { | |
df47b77f | 412 | if ($plugin->is_visible() && $plugin->is_enabled() && $plugin->has_user_summary()) { |
f9e62127 DW |
413 | $feedbackpluginindex = 'plugin' . $plugincolumnindex++; |
414 | $this->no_sorting($feedbackpluginindex); | |
bbd0e548 DW |
415 | } |
416 | } | |
417 | ||
5fc59630 RW |
418 | // When there is no data we still want the column headers printed in the csv file. |
419 | if ($this->is_downloading()) { | |
420 | $this->start_output(); | |
421 | } | |
bbd0e548 DW |
422 | } |
423 | ||
61cf3253 | 424 | /** |
e5403f8c | 425 | * Before adding each row to the table make sure rownum is incremented. |
61cf3253 DW |
426 | * |
427 | * @param array $row row of data from db used to make one row of the table. | |
428 | * @return array one row for the table | |
429 | */ | |
e5403f8c | 430 | public function format_row($row) { |
61cf3253 DW |
431 | if ($this->rownum < 0) { |
432 | $this->rownum = $this->currpage * $this->pagesize; | |
433 | } else { | |
434 | $this->rownum += 1; | |
435 | } | |
436 | ||
437 | return parent::format_row($row); | |
438 | } | |
439 | ||
b473171a | 440 | /** |
e5403f8c | 441 | * Add a column with an ID that uniquely identifies this user in this assignment. |
b473171a | 442 | * |
1561a37c | 443 | * @param stdClass $row |
b473171a DW |
444 | * @return string |
445 | */ | |
e5403f8c DW |
446 | public function col_recordid(stdClass $row) { |
447 | return get_string('hiddenuser', 'assign') . | |
448 | $this->assignment->get_uniqueid_for_user($row->userid); | |
449 | } | |
b473171a DW |
450 | |
451 | ||
bbd0e548 | 452 | /** |
e5403f8c | 453 | * Add the userid to the row class so it can be updated via ajax. |
bbd0e548 DW |
454 | * |
455 | * @param stdClass $row The row of data | |
456 | * @return string The row class | |
457 | */ | |
e5403f8c | 458 | public function get_row_class($row) { |
bbd0e548 DW |
459 | return 'user' . $row->userid; |
460 | } | |
461 | ||
462 | /** | |
e5403f8c | 463 | * Return the number of rows to display on a single page. |
bbd0e548 DW |
464 | * |
465 | * @return int The number of rows per page | |
466 | */ | |
e5403f8c | 467 | public function get_rows_per_page() { |
bbd0e548 DW |
468 | return $this->perpage; |
469 | } | |
470 | ||
f8d107b3 DM |
471 | /** |
472 | * list current marking workflow state | |
473 | * | |
474 | * @param stdClass $row | |
475 | * @return string | |
476 | */ | |
477 | public function col_workflowstatus(stdClass $row) { | |
478 | $o = ''; | |
479 | ||
480 | $gradingdisabled = $this->assignment->grading_disabled($row->id); | |
e24c2c1a AA |
481 | // The function in the assignment keeps a static cache of this list of states. |
482 | $workflowstates = $this->assignment->get_marking_workflow_states_for_current_user(); | |
483 | $workflowstate = $row->workflowstate; | |
484 | if (empty($workflowstate)) { | |
485 | $workflowstate = ASSIGN_MARKING_WORKFLOW_STATE_NOTMARKED; | |
486 | } | |
487 | if ($this->quickgrading && !$gradingdisabled) { | |
488 | $notmarked = get_string('markingworkflowstatenotmarked', 'assign'); | |
489 | $name = 'quickgrade_' . $row->id . '_workflowstate'; | |
490 | $o .= html_writer::select($workflowstates, $name, $workflowstate, array('' => $notmarked)); | |
491 | // Check if this user is a marker that can't manage allocations and doesn't have the marker column added. | |
5a96486b DM |
492 | if ($this->assignment->get_instance()->markingworkflow && |
493 | $this->assignment->get_instance()->markingallocation && | |
e24c2c1a AA |
494 | !has_capability('mod/assign:manageallocations', $this->assignment->get_context())) { |
495 | ||
496 | $name = 'quickgrade_' . $row->id . '_allocatedmarker'; | |
497 | $o .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => $name, | |
498 | 'value' => $row->allocatedmarker)); | |
f8d107b3 | 499 | } |
e24c2c1a AA |
500 | } else { |
501 | $o .= $this->output->container(get_string('markingworkflowstate' . $workflowstate, 'assign'), $workflowstate); | |
f8d107b3 DM |
502 | } |
503 | return $o; | |
504 | } | |
505 | ||
506 | /** | |
507 | * For download only - list current marking workflow state | |
508 | * | |
509 | * @param stdClass $row - The row of data | |
510 | * @return string The current marking workflow state | |
511 | */ | |
512 | public function col_workflowstate($row) { | |
513 | $state = $row->workflowstate; | |
514 | if (empty($state)) { | |
515 | $state = ASSIGN_MARKING_WORKFLOW_STATE_NOTMARKED; | |
516 | } | |
517 | ||
518 | return get_string('markingworkflowstate' . $state, 'assign'); | |
519 | } | |
520 | ||
521 | /** | |
522 | * list current marker | |
523 | * | |
524 | * @param stdClass $row - The row of data | |
525 | * @return id the user->id of the marker. | |
526 | */ | |
13e82f1c | 527 | public function col_allocatedmarker(stdClass $row) { |
f8d107b3 DM |
528 | static $markers = null; |
529 | static $markerlist = array(); | |
530 | if ($markers === null) { | |
531 | $markers = get_users_by_capability($this->assignment->get_context(), 'mod/assign:grade'); | |
532 | $markerlist[0] = get_string('choosemarker', 'assign'); | |
533 | foreach ($markers as $marker) { | |
534 | $markerlist[$marker->id] = fullname($marker); | |
535 | } | |
536 | } | |
537 | if (empty($markerlist)) { | |
538 | // TODO: add some form of notification here that no markers are available. | |
539 | return ''; | |
540 | } | |
541 | if ($this->is_downloading()) { | |
60a601db JF |
542 | if (isset($markers[$row->allocatedmarker])) { |
543 | return fullname($markers[$row->allocatedmarker]); | |
544 | } else { | |
545 | return ''; | |
546 | } | |
f8d107b3 DM |
547 | } |
548 | ||
549 | if ($this->quickgrading && has_capability('mod/assign:manageallocations', $this->assignment->get_context()) && | |
550 | (empty($row->workflowstate) || | |
551 | $row->workflowstate == ASSIGN_MARKING_WORKFLOW_STATE_INMARKING || | |
552 | $row->workflowstate == ASSIGN_MARKING_WORKFLOW_STATE_NOTMARKED)) { | |
553 | ||
554 | $name = 'quickgrade_' . $row->id . '_allocatedmarker'; | |
555 | return html_writer::select($markerlist, $name, $row->allocatedmarker, false); | |
556 | } else if (!empty($row->allocatedmarker)) { | |
557 | $output = ''; | |
558 | if ($this->quickgrading) { // Add hidden field for quickgrading page. | |
559 | $name = 'quickgrade_' . $row->id . '_allocatedmarker'; | |
560 | $output .= html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>$name, 'value'=>$row->allocatedmarker)); | |
561 | } | |
562 | $output .= $markerlist[$row->allocatedmarker]; | |
563 | return $output; | |
564 | } | |
565 | } | |
df47b77f DW |
566 | /** |
567 | * For download only - list all the valid options for this custom scale. | |
568 | * | |
569 | * @param stdClass $row - The row of data | |
570 | * @return string A list of valid options for the current scale | |
571 | */ | |
7a2b911c | 572 | public function col_scale($row) { |
df47b77f DW |
573 | global $DB; |
574 | ||
575 | if (empty($this->scale)) { | |
e5403f8c DW |
576 | $dbparams = array('id'=>-($this->assignment->get_instance()->grade)); |
577 | $this->scale = $DB->get_record('scale', $dbparams); | |
df47b77f DW |
578 | } |
579 | ||
580 | if (!empty($this->scale->scale)) { | |
581 | return implode("\n", explode(',', $this->scale->scale)); | |
582 | } | |
583 | return ''; | |
584 | } | |
585 | ||
bbd0e548 DW |
586 | /** |
587 | * Display a grade with scales etc. | |
588 | * | |
589 | * @param string $grade | |
bf78ebd6 | 590 | * @param boolean $editable |
2a4fbc32 SH |
591 | * @param int $userid The user id of the user this grade belongs to |
592 | * @param int $modified Timestamp showing when the grade was last modified | |
bbd0e548 DW |
593 | * @return string The formatted grade |
594 | */ | |
e5403f8c | 595 | public function display_grade($grade, $editable, $userid, $modified) { |
bbd0e548 | 596 | if ($this->is_downloading()) { |
df47b77f DW |
597 | if ($this->assignment->get_instance()->grade >= 0) { |
598 | if ($grade == -1 || $grade === null) { | |
599 | return ''; | |
600 | } | |
7688a319 | 601 | return format_float($grade, 2); |
df47b77f DW |
602 | } else { |
603 | // This is a custom scale. | |
604 | $scale = $this->assignment->display_grade($grade, false); | |
605 | if ($scale == '-') { | |
606 | $scale = ''; | |
607 | } | |
608 | return $scale; | |
609 | } | |
bbd0e548 | 610 | } |
df47b77f | 611 | return $this->assignment->display_grade($grade, $editable, $userid, $modified); |
bbd0e548 DW |
612 | } |
613 | ||
12a1a0da | 614 | /** |
e5403f8c | 615 | * Get the team info for this user. |
12a1a0da DW |
616 | * |
617 | * @param stdClass $row | |
618 | * @return string The team name | |
619 | */ | |
e5403f8c | 620 | public function col_team(stdClass $row) { |
cd01491c DW |
621 | $submission = false; |
622 | $group = false; | |
5ef72f85 | 623 | $this->get_group_and_submission($row->id, $group, $submission, -1); |
12a1a0da DW |
624 | if ($group) { |
625 | return $group->name; | |
626 | } | |
627 | return get_string('defaultteam', 'assign'); | |
628 | } | |
629 | ||
630 | /** | |
cd01491c DW |
631 | * Use a static cache to try and reduce DB calls. |
632 | * | |
633 | * @param int $userid The user id for this submission | |
1561a37c DW |
634 | * @param int $group The groupid (returned) |
635 | * @param stdClass|false $submission The stdClass submission or false (returned) | |
5ef72f85 | 636 | * @param int $attemptnumber Return a specific attempt number (-1 for latest) |
cd01491c | 637 | */ |
5ef72f85 | 638 | protected function get_group_and_submission($userid, &$group, &$submission, $attemptnumber) { |
cd01491c DW |
639 | $group = false; |
640 | if (isset($this->submissiongroups[$userid])) { | |
641 | $group = $this->submissiongroups[$userid]; | |
642 | } else { | |
643 | $group = $this->assignment->get_submission_group($userid, false); | |
644 | $this->submissiongroups[$userid] = $group; | |
645 | } | |
646 | ||
647 | $groupid = 0; | |
648 | if ($group) { | |
649 | $groupid = $group->id; | |
650 | } | |
651 | ||
5ef72f85 DW |
652 | // Static cache is keyed by groupid and attemptnumber. |
653 | // We may need both the latest and previous attempt in the same page. | |
654 | if (isset($this->groupsubmissions[$groupid . ':' . $attemptnumber])) { | |
655 | $submission = $this->groupsubmissions[$groupid . ':' . $attemptnumber]; | |
cd01491c | 656 | } else { |
5ef72f85 DW |
657 | $submission = $this->assignment->get_group_submission($userid, $groupid, false, $attemptnumber); |
658 | $this->groupsubmissions[$groupid . ':' . $attemptnumber] = $submission; | |
cd01491c DW |
659 | } |
660 | } | |
661 | ||
a769a001 | 662 | /** |
e5403f8c | 663 | * Format a list of outcomes. |
a769a001 DW |
664 | * |
665 | * @param stdClass $row | |
666 | * @return string | |
667 | */ | |
e5403f8c | 668 | public function col_outcomes(stdClass $row) { |
a769a001 | 669 | $outcomes = ''; |
e5403f8c | 670 | foreach ($this->gradinginfo->outcomes as $index => $outcome) { |
a769a001 DW |
671 | $options = make_grades_menu(-$outcome->scaleid); |
672 | ||
673 | $options[0] = get_string('nooutcome', 'grades'); | |
2c6a3dbf | 674 | if ($this->quickgrading && !($outcome->grades[$row->userid]->locked)) { |
bf78ebd6 DW |
675 | $select = '<select name="outcome_' . $index . '_' . $row->userid . '" class="quickgrade">'; |
676 | foreach ($options as $optionindex => $optionvalue) { | |
677 | $selected = ''; | |
678 | if ($outcome->grades[$row->userid]->grade == $optionindex) { | |
679 | $selected = 'selected="selected"'; | |
680 | } | |
681 | $select .= '<option value="' . $optionindex . '"' . $selected . '>' . $optionvalue . '</option>'; | |
682 | } | |
683 | $select .= '</select>'; | |
684 | $outcomes .= $this->output->container($outcome->name . ': ' . $select, 'outcome'); | |
685 | } else { | |
e5403f8c | 686 | $name = $outcome->name . ': ' . $options[$outcome->grades[$row->userid]->grade]; |
6b7aa837 TL |
687 | if ($this->is_downloading()) { |
688 | $outcomes .= $name; | |
689 | } else { | |
690 | $outcomes .= $this->output->container($name, 'outcome'); | |
691 | } | |
bf78ebd6 | 692 | } |
a769a001 DW |
693 | } |
694 | ||
695 | return $outcomes; | |
696 | } | |
697 | ||
698 | ||
bbd0e548 | 699 | /** |
e5403f8c | 700 | * Format a user picture for display. |
bbd0e548 DW |
701 | * |
702 | * @param stdClass $row | |
703 | * @return string | |
704 | */ | |
e5403f8c | 705 | public function col_picture(stdClass $row) { |
bbd0e548 DW |
706 | if ($row->picture) { |
707 | return $this->output->user_picture($row); | |
708 | } | |
709 | return ''; | |
710 | } | |
711 | ||
712 | /** | |
e5403f8c | 713 | * Format a user record for display (link to profile). |
bbd0e548 DW |
714 | * |
715 | * @param stdClass $row | |
716 | * @return string | |
717 | */ | |
e5403f8c | 718 | public function col_fullname($row) { |
df47b77f DW |
719 | if (!$this->is_downloading()) { |
720 | $courseid = $this->assignment->get_course()->id; | |
721 | $link= new moodle_url('/user/view.php', array('id' =>$row->id, 'course'=>$courseid)); | |
d63e7470 | 722 | $fullname = $this->output->action_link($link, $this->assignment->fullname($row)); |
df47b77f | 723 | } else { |
d63e7470 | 724 | $fullname = $this->assignment->fullname($row); |
df47b77f | 725 | } |
a69944eb | 726 | |
1ecb8044 | 727 | if (!$this->assignment->is_active_user($row->id)) { |
a69944eb | 728 | $suspendedstring = get_string('userenrolmentsuspended', 'grades'); |
1ecb8044 | 729 | $fullname .= ' ' . html_writer::empty_tag('img', array('src' => $this->output->pix_url('i/enrolmentsuspended'), |
a69944eb RT |
730 | 'title' => $suspendedstring, 'alt' => $suspendedstring, 'class' => 'usersuspendedicon')); |
731 | $fullname = html_writer::tag('span', $fullname, array('class' => 'usersuspended')); | |
732 | } | |
733 | return $fullname; | |
bbd0e548 DW |
734 | } |
735 | ||
736 | /** | |
e5403f8c | 737 | * Insert a checkbox for selecting the current row for batch operations. |
bbd0e548 DW |
738 | * |
739 | * @param stdClass $row | |
740 | * @return string | |
741 | */ | |
e5403f8c DW |
742 | public function col_select(stdClass $row) { |
743 | $selectcol = '<label class="accesshide" for="selectuser_' . $row->userid . '">'; | |
d63e7470 | 744 | $selectcol .= get_string('selectuser', 'assign', $this->assignment->fullname($row)); |
e5403f8c DW |
745 | $selectcol .= '</label>'; |
746 | $selectcol .= '<input type="checkbox" | |
747 | id="selectuser_' . $row->userid . '" | |
748 | name="selectedusers" | |
749 | value="' . $row->userid . '"/>'; | |
a6fd2e2c DW |
750 | $selectcol .= '<input type="hidden" |
751 | name="grademodified_' . $row->userid . '" | |
752 | value="' . $row->timemarked . '"/>'; | |
e5403f8c | 753 | return $selectcol; |
bbd0e548 DW |
754 | } |
755 | ||
756 | /** | |
e5403f8c | 757 | * Return a users grades from the listing of all grade data for this assignment. |
bbd0e548 DW |
758 | * |
759 | * @param int $userid | |
760 | * @return mixed stdClass or false | |
761 | */ | |
762 | private function get_gradebook_data_for_user($userid) { | |
763 | if (isset($this->gradinginfo->items[0]) && $this->gradinginfo->items[0]->grades[$userid]) { | |
764 | return $this->gradinginfo->items[0]->grades[$userid]; | |
765 | } | |
766 | return false; | |
767 | } | |
768 | ||
df47b77f | 769 | /** |
e5403f8c | 770 | * Format a column of data for display. |
df47b77f DW |
771 | * |
772 | * @param stdClass $row | |
773 | * @return string | |
774 | */ | |
f8d107b3 DM |
775 | public function col_gradecanbechanged(stdClass $row) { |
776 | $gradingdisabled = $this->assignment->grading_disabled($row->id); | |
777 | if ($gradingdisabled) { | |
778 | return get_string('no'); | |
779 | } else { | |
780 | return get_string('yes'); | |
781 | } | |
782 | } | |
783 | ||
784 | /** | |
785 | * Format a column of data for display | |
786 | * | |
787 | * @param stdClass $row | |
788 | * @return string | |
789 | */ | |
7a2b911c DW |
790 | public function col_grademax(stdClass $row) { |
791 | return format_float($this->assignment->get_instance()->grade, 2); | |
df47b77f DW |
792 | } |
793 | ||
bbd0e548 | 794 | /** |
e5403f8c | 795 | * Format a column of data for display. |
bbd0e548 DW |
796 | * |
797 | * @param stdClass $row | |
798 | * @return string | |
799 | */ | |
e5403f8c | 800 | public function col_grade(stdClass $row) { |
bbd0e548 DW |
801 | $o = ''; |
802 | ||
803 | $link = ''; | |
f8d107b3 | 804 | $separator = $this->output->spacer(array(), true); |
bbd0e548 | 805 | $grade = ''; |
df47b77f | 806 | $gradingdisabled = $this->assignment->grading_disabled($row->id); |
bbd0e548 | 807 | |
4a47008c | 808 | if (!$this->is_downloading() && $this->hasgrade) { |
d63e7470 | 809 | $name = $this->assignment->fullname($row); |
e5403f8c DW |
810 | $icon = $this->output->pix_icon('gradefeedback', |
811 | get_string('gradeuser', 'assign', $name), | |
812 | 'mod_assign'); | |
813 | $urlparams = array('id' => $this->assignment->get_course_module()->id, | |
814 | 'rownum'=>$this->rownum, | |
815 | 'action'=>'grade'); | |
816 | $url = new moodle_url('/mod/assign/view.php', $urlparams); | |
bbd0e548 | 817 | $link = $this->output->action_link($url, $icon); |
f8d107b3 | 818 | $grade .= $link . $separator; |
bbd0e548 | 819 | } |
bbd0e548 | 820 | |
f8d107b3 DM |
821 | $grade .= $this->display_grade($row->grade, |
822 | $this->quickgrading && !$gradingdisabled, | |
823 | $row->userid, | |
824 | $row->timemarked); | |
825 | ||
826 | return $grade; | |
bbd0e548 DW |
827 | } |
828 | ||
829 | /** | |
e5403f8c | 830 | * Format a column of data for display. |
bbd0e548 DW |
831 | * |
832 | * @param stdClass $row | |
833 | * @return string | |
834 | */ | |
e5403f8c | 835 | public function col_finalgrade(stdClass $row) { |
bbd0e548 DW |
836 | $o = ''; |
837 | ||
838 | $grade = $this->get_gradebook_data_for_user($row->userid); | |
839 | if ($grade) { | |
bf78ebd6 | 840 | $o = $this->display_grade($grade->grade, false, $row->userid, $row->timemarked); |
bbd0e548 DW |
841 | } |
842 | ||
843 | return $o; | |
844 | } | |
845 | ||
846 | /** | |
e5403f8c | 847 | * Format a column of data for display. |
bbd0e548 DW |
848 | * |
849 | * @param stdClass $row | |
850 | * @return string | |
851 | */ | |
e5403f8c | 852 | public function col_timemarked(stdClass $row) { |
bbd0e548 DW |
853 | $o = '-'; |
854 | ||
e5403f8c | 855 | if ($row->timemarked && $row->grade !== null && $row->grade >= 0) { |
bbd0e548 DW |
856 | $o = userdate($row->timemarked); |
857 | } | |
7688a319 DW |
858 | if ($row->timemarked && $this->is_downloading()) { |
859 | // Force it for downloads as it affects import. | |
860 | $o = userdate($row->timemarked); | |
861 | } | |
bbd0e548 DW |
862 | |
863 | return $o; | |
864 | } | |
865 | ||
866 | /** | |
e5403f8c | 867 | * Format a column of data for display. |
bbd0e548 DW |
868 | * |
869 | * @param stdClass $row | |
870 | * @return string | |
871 | */ | |
e5403f8c | 872 | public function col_timesubmitted(stdClass $row) { |
bbd0e548 DW |
873 | $o = '-'; |
874 | ||
79397b56 DB |
875 | $group = false; |
876 | $submission = false; | |
877 | $this->get_group_and_submission($row->id, $group, $submission, -1); | |
878 | if ($group && $submission && $submission->timemodified) { | |
879 | $o = userdate($submission->timemodified); | |
880 | } else if ($row->timesubmitted) { | |
bbd0e548 DW |
881 | $o = userdate($row->timesubmitted); |
882 | } | |
883 | ||
884 | return $o; | |
885 | } | |
886 | ||
887 | /** | |
888 | * Format a column of data for display | |
889 | * | |
890 | * @param stdClass $row | |
891 | * @return string | |
892 | */ | |
e5403f8c | 893 | public function col_status(stdClass $row) { |
bbd0e548 DW |
894 | $o = ''; |
895 | ||
e5403f8c DW |
896 | $instance = $this->assignment->get_instance(); |
897 | ||
556483d4 GF |
898 | $due = $instance->duedate; |
899 | if ($row->extensionduedate) { | |
900 | $due = $row->extensionduedate; | |
901 | } | |
902 | ||
79397b56 DB |
903 | $group = false; |
904 | $submission = false; | |
905 | $this->get_group_and_submission($row->id, $group, $submission, -1); | |
906 | if ($group && $submission) { | |
907 | $timesubmitted = $submission->timemodified; | |
908 | $status = $submission->status; | |
909 | } else { | |
910 | $timesubmitted = $row->timesubmitted; | |
911 | $status = $row->status; | |
912 | } | |
913 | ||
bbd0e548 DW |
914 | if ($this->assignment->is_any_submission_plugin_enabled()) { |
915 | ||
79397b56 DB |
916 | $o .= $this->output->container(get_string('submissionstatus_' . $status, 'assign'), |
917 | array('class'=>'submissionstatus' .$status)); | |
918 | if ($due && $timesubmitted > $due) { | |
919 | $usertime = format_time($timesubmitted - $due); | |
556483d4 GF |
920 | $latemessage = get_string('submittedlateshort', |
921 | 'assign', | |
922 | $usertime); | |
923 | $o .= $this->output->container($latemessage, 'latesubmission'); | |
bbd0e548 DW |
924 | } |
925 | if ($row->locked) { | |
e5403f8c DW |
926 | $lockedstr = get_string('submissionslockedshort', 'assign'); |
927 | $o .= $this->output->container($lockedstr, 'lockedsubmission'); | |
bbd0e548 | 928 | } |
e24c2c1a AA |
929 | |
930 | // Add status of "grading", use markflow if enabled. | |
931 | if ($instance->markingworkflow) { | |
932 | $o .= $this->col_workflowstatus($row); | |
933 | } else if ($row->grade !== null && $row->grade >= 0) { | |
934 | $o .= $this->output->container(get_string('graded', 'assign'), 'submissiongraded'); | |
79397b56 | 935 | } else if (!$timesubmitted) { |
9e795179 | 936 | $now = time(); |
9e795179 | 937 | if ($due && ($now > $due)) { |
e5403f8c DW |
938 | $overduestr = get_string('overdue', 'assign', format_time($now - $due)); |
939 | $o .= $this->output->container($overduestr, 'overduesubmission'); | |
9e795179 DW |
940 | } |
941 | } | |
79397b56 | 942 | |
9e795179 | 943 | if ($row->extensionduedate) { |
e5403f8c DW |
944 | $userdate = userdate($row->extensionduedate); |
945 | $extensionstr = get_string('userextensiondate', 'assign', $userdate); | |
946 | $o .= $this->output->container($extensionstr, 'extensiondate'); | |
9e795179 | 947 | } |
bbd0e548 DW |
948 | } |
949 | ||
df47b77f DW |
950 | if ($this->is_downloading()) { |
951 | $o = strip_tags(str_replace('</div>', "\n", $o)); | |
952 | } | |
953 | ||
bbd0e548 DW |
954 | return $o; |
955 | } | |
956 | ||
957 | /** | |
e5403f8c | 958 | * Format a column of data for display. |
bbd0e548 DW |
959 | * |
960 | * @param stdClass $row | |
961 | * @return string | |
962 | */ | |
e5403f8c | 963 | public function col_userid(stdClass $row) { |
57fbd5f9 DW |
964 | global $USER; |
965 | ||
bbd0e548 | 966 | $edit = ''; |
bbd0e548 DW |
967 | |
968 | $actions = array(); | |
969 | ||
e5403f8c DW |
970 | $urlparams = array('id'=>$this->assignment->get_course_module()->id, |
971 | 'rownum'=>$this->rownum, | |
972 | 'action'=>'grade'); | |
973 | $url = new moodle_url('/mod/assign/view.php', $urlparams); | |
e9ddbae9 | 974 | $noimage = null; |
e5403f8c | 975 | |
bbd0e548 | 976 | if (!$row->grade) { |
e5403f8c DW |
977 | $description = get_string('grade'); |
978 | } else { | |
979 | $description = get_string('updategrade', 'assign'); | |
bbd0e548 | 980 | } |
e9ddbae9 DW |
981 | $actions['grade'] = new action_menu_link_secondary( |
982 | $url, | |
983 | $noimage, | |
984 | $description | |
985 | ); | |
bbd0e548 | 986 | |
c70de965 DW |
987 | // Everything we need is in the row. |
988 | $submission = $row; | |
989 | $flags = $row; | |
990 | if ($this->assignment->get_instance()->teamsubmission) { | |
991 | // Use the cache for this. | |
992 | $submission = false; | |
993 | $group = false; | |
994 | $this->get_group_and_submission($row->id, $group, $submission, -1); | |
995 | } | |
996 | ||
997 | $submissionsopen = $this->assignment->submissions_open($row->id, | |
998 | true, | |
999 | $submission, | |
1000 | $flags, | |
1001 | $this->gradinginfo); | |
57fbd5f9 DW |
1002 | $caneditsubmission = $this->assignment->can_edit_submission($row->id, $USER->id); |
1003 | ||
9e795179 DW |
1004 | // Hide for offline assignments. |
1005 | if ($this->assignment->is_any_submission_plugin_enabled()) { | |
1006 | if (!$row->status || | |
1007 | $row->status == ASSIGN_SUBMISSION_STATUS_DRAFT || | |
1008 | !$this->assignment->get_instance()->submissiondrafts) { | |
1009 | ||
1010 | if (!$row->locked) { | |
e5403f8c DW |
1011 | $urlparams = array('id' => $this->assignment->get_course_module()->id, |
1012 | 'userid'=>$row->id, | |
1013 | 'action'=>'lock', | |
1014 | 'sesskey'=>sesskey(), | |
1015 | 'page'=>$this->currpage); | |
1016 | $url = new moodle_url('/mod/assign/view.php', $urlparams); | |
1017 | ||
9e795179 | 1018 | $description = get_string('preventsubmissionsshort', 'assign'); |
e9ddbae9 DW |
1019 | $actions['lock'] = new action_menu_link_secondary( |
1020 | $url, | |
1021 | $noimage, | |
1022 | $description | |
1023 | ); | |
9e795179 | 1024 | } else { |
e5403f8c DW |
1025 | $urlparams = array('id' => $this->assignment->get_course_module()->id, |
1026 | 'userid'=>$row->id, | |
1027 | 'action'=>'unlock', | |
1028 | 'sesskey'=>sesskey(), | |
1029 | 'page'=>$this->currpage); | |
1030 | $url = new moodle_url('/mod/assign/view.php', $urlparams); | |
9e795179 | 1031 | $description = get_string('allowsubmissionsshort', 'assign'); |
e9ddbae9 DW |
1032 | $actions['unlock'] = new action_menu_link_secondary( |
1033 | $url, | |
1034 | $noimage, | |
1035 | $description | |
1036 | ); | |
9e795179 DW |
1037 | } |
1038 | } | |
1039 | ||
1040 | if (($this->assignment->get_instance()->duedate || | |
1041 | $this->assignment->get_instance()->cutoffdate) && | |
1042 | $this->hasgrantextension) { | |
e5403f8c DW |
1043 | $urlparams = array('id' => $this->assignment->get_course_module()->id, |
1044 | 'userid'=>$row->id, | |
1045 | 'action'=>'grantextension', | |
1046 | 'sesskey'=>sesskey(), | |
1047 | 'page'=>$this->currpage); | |
1048 | $url = new moodle_url('/mod/assign/view.php', $urlparams); | |
9e795179 | 1049 | $description = get_string('grantextension', 'assign'); |
e9ddbae9 DW |
1050 | $actions['grantextension'] = new action_menu_link_secondary( |
1051 | $url, | |
1052 | $noimage, | |
1053 | $description | |
1054 | ); | |
bbd0e548 | 1055 | } |
57fbd5f9 DW |
1056 | if ($submissionsopen && |
1057 | $USER->id != $row->id && | |
1058 | $caneditsubmission) { | |
1059 | $urlparams = array('id' => $this->assignment->get_course_module()->id, | |
1060 | 'userid'=>$row->id, | |
1061 | 'action'=>'editsubmission', | |
1062 | 'sesskey'=>sesskey(), | |
1063 | 'page'=>$this->currpage); | |
1064 | $url = new moodle_url('/mod/assign/view.php', $urlparams); | |
1065 | $description = get_string('editsubmission', 'assign'); | |
e9ddbae9 DW |
1066 | $actions['editsubmission'] = new action_menu_link_secondary( |
1067 | $url, | |
1068 | $noimage, | |
1069 | $description | |
1070 | ); | |
57fbd5f9 | 1071 | } |
bbd0e548 | 1072 | } |
e5403f8c DW |
1073 | if ($row->status == ASSIGN_SUBMISSION_STATUS_SUBMITTED && |
1074 | $this->assignment->get_instance()->submissiondrafts) { | |
1075 | $urlparams = array('id' => $this->assignment->get_course_module()->id, | |
1076 | 'userid'=>$row->id, | |
1077 | 'action'=>'reverttodraft', | |
1078 | 'sesskey'=>sesskey(), | |
1079 | 'page'=>$this->currpage); | |
1080 | $url = new moodle_url('/mod/assign/view.php', $urlparams); | |
bbd0e548 | 1081 | $description = get_string('reverttodraftshort', 'assign'); |
e9ddbae9 DW |
1082 | $actions['reverttodraft'] = new action_menu_link_secondary( |
1083 | $url, | |
1084 | $noimage, | |
1085 | $description | |
1086 | ); | |
bbd0e548 | 1087 | } |
57fbd5f9 DW |
1088 | if ($row->status == ASSIGN_SUBMISSION_STATUS_DRAFT && |
1089 | $this->assignment->get_instance()->submissiondrafts && | |
1090 | $caneditsubmission && | |
1091 | $submissionsopen && | |
1092 | $row->id != $USER->id) { | |
1093 | $urlparams = array('id' => $this->assignment->get_course_module()->id, | |
1094 | 'userid'=>$row->id, | |
1095 | 'action'=>'submitotherforgrading', | |
1096 | 'sesskey'=>sesskey(), | |
1097 | 'page'=>$this->currpage); | |
1098 | $url = new moodle_url('/mod/assign/view.php', $urlparams); | |
1099 | $description = get_string('submitforgrading', 'assign'); | |
e9ddbae9 DW |
1100 | $actions['submitforgrading'] = new action_menu_link_secondary( |
1101 | $url, | |
1102 | $noimage, | |
1103 | $description | |
1104 | ); | |
57fbd5f9 | 1105 | } |
bbd0e548 | 1106 | |
df211804 DW |
1107 | $ismanual = $this->assignment->get_instance()->attemptreopenmethod == ASSIGN_ATTEMPT_REOPEN_METHOD_MANUAL; |
1108 | $hassubmission = !empty($row->status); | |
1109 | $notreopened = $hassubmission && $row->status != ASSIGN_SUBMISSION_STATUS_REOPENED; | |
1110 | $isunlimited = $this->assignment->get_instance()->maxattempts == ASSIGN_UNLIMITED_ATTEMPTS; | |
1111 | $hasattempts = $isunlimited || $row->attemptnumber < $this->assignment->get_instance()->maxattempts - 1; | |
1112 | ||
1113 | if ($ismanual && $hassubmission && $notreopened && $hasattempts) { | |
1114 | $urlparams = array('id' => $this->assignment->get_course_module()->id, | |
1115 | 'userid'=>$row->id, | |
1116 | 'action'=>'addattempt', | |
1117 | 'sesskey'=>sesskey(), | |
1118 | 'page'=>$this->currpage); | |
1119 | $url = new moodle_url('/mod/assign/view.php', $urlparams); | |
1120 | $description = get_string('addattempt', 'assign'); | |
e9ddbae9 DW |
1121 | $actions['addattempt'] = new action_menu_link_secondary( |
1122 | $url, | |
1123 | $noimage, | |
1124 | $description | |
1125 | ); | |
df211804 DW |
1126 | } |
1127 | ||
e9ddbae9 DW |
1128 | $menu = new action_menu(); |
1129 | $menu->set_owner_selector('.gradingtable-actionmenu'); | |
1130 | $menu->set_alignment(action_menu::TL, action_menu::BL); | |
1131 | $menu->set_constraint('.gradingtable > .no-overflow'); | |
1132 | $menu->set_menu_trigger(get_string('edit')); | |
1133 | foreach ($actions as $action) { | |
1134 | $menu->add($action); | |
1135 | } | |
bbd0e548 | 1136 | |
e9ddbae9 DW |
1137 | // Prioritise the menu ahead of all other actions. |
1138 | $menu->prioritise = true; | |
bbd0e548 | 1139 | |
e9ddbae9 | 1140 | $edit .= $this->output->render($menu); |
bbd0e548 DW |
1141 | |
1142 | return $edit; | |
1143 | } | |
1144 | ||
1145 | /** | |
1146 | * Write the plugin summary with an optional link to view the full feedback/submission. | |
1147 | * | |
1148 | * @param assign_plugin $plugin Submission plugin or feedback plugin | |
1149 | * @param stdClass $item Submission or grade | |
e5403f8c DW |
1150 | * @param string $returnaction The return action to pass to the |
1151 | * view_submission page (the current page) | |
1152 | * @param string $returnparams The return params to pass to the view_submission | |
1153 | * page (the current page) | |
bbd0e548 DW |
1154 | * @return string The summary with an optional link |
1155 | */ | |
e5403f8c DW |
1156 | private function format_plugin_summary_with_link(assign_plugin $plugin, |
1157 | stdClass $item, | |
1158 | $returnaction, | |
1159 | $returnparams) { | |
bbd0e548 DW |
1160 | $link = ''; |
1161 | $showviewlink = false; | |
2c6a3dbf | 1162 | |
bbd0e548 DW |
1163 | $summary = $plugin->view_summary($item, $showviewlink); |
1164 | $separator = ''; | |
1165 | if ($showviewlink) { | |
e5403f8c DW |
1166 | $viewstr = get_string('view' . substr($plugin->get_subtype(), strlen('assign')), 'assign'); |
1167 | $icon = $this->output->pix_icon('t/preview', $viewstr); | |
1168 | $urlparams = array('id' => $this->assignment->get_course_module()->id, | |
bbd0e548 DW |
1169 | 'sid'=>$item->id, |
1170 | 'gid'=>$item->id, | |
1171 | 'plugin'=>$plugin->get_type(), | |
1172 | 'action'=>'viewplugin' . $plugin->get_subtype(), | |
1173 | 'returnaction'=>$returnaction, | |
e5403f8c DW |
1174 | 'returnparams'=>http_build_query($returnparams)); |
1175 | $url = new moodle_url('/mod/assign/view.php', $urlparams); | |
1176 | $link = $this->output->action_link($url, $icon); | |
bbd0e548 DW |
1177 | $separator = $this->output->spacer(array(), true); |
1178 | } | |
1179 | ||
1180 | return $link . $separator . $summary; | |
1181 | } | |
1182 | ||
1183 | ||
1184 | /** | |
e5403f8c | 1185 | * Format the submission and feedback columns. |
bbd0e548 DW |
1186 | * |
1187 | * @param string $colname The column name | |
1188 | * @param stdClass $row The submission row | |
1189 | * @return mixed string or NULL | |
1190 | */ | |
e5403f8c | 1191 | public function other_cols($colname, $row) { |
d08e6c31 DW |
1192 | // For extra user fields the result is already in $row. |
1193 | if (empty($this->plugincache[$colname])) { | |
1194 | return $row->$colname; | |
1195 | } | |
1196 | ||
1197 | // This must be a plugin field. | |
df47b77f | 1198 | $plugincache = $this->plugincache[$colname]; |
2c6a3dbf | 1199 | |
df47b77f DW |
1200 | $plugin = $plugincache[0]; |
1201 | ||
1202 | $field = null; | |
1203 | if (isset($plugincache[1])) { | |
1204 | $field = $plugincache[1]; | |
1205 | } | |
1206 | ||
1207 | if ($plugin->is_visible() && $plugin->is_enabled()) { | |
1208 | if ($plugin->get_subtype() == 'assignsubmission') { | |
cd01491c DW |
1209 | if ($this->assignment->get_instance()->teamsubmission) { |
1210 | $group = false; | |
1211 | $submission = false; | |
5ef72f85 DW |
1212 | |
1213 | $this->get_group_and_submission($row->id, $group, $submission, -1); | |
cd01491c | 1214 | if ($submission) { |
5ef72f85 DW |
1215 | if ($submission->status == ASSIGN_SUBMISSION_STATUS_REOPENED) { |
1216 | // For a newly reopened submission - we want to show the previous submission in the table. | |
1217 | $this->get_group_and_submission($row->id, $group, $submission, $submission->attemptnumber-1); | |
1218 | } | |
df47b77f DW |
1219 | if (isset($field)) { |
1220 | return $plugin->get_editor_text($field, $submission->id); | |
1221 | } | |
e5403f8c DW |
1222 | return $this->format_plugin_summary_with_link($plugin, |
1223 | $submission, | |
1224 | 'grading', | |
1225 | array()); | |
cd01491c DW |
1226 | } |
1227 | } else if ($row->submissionid) { | |
5ef72f85 DW |
1228 | if ($row->status == ASSIGN_SUBMISSION_STATUS_REOPENED) { |
1229 | // For a newly reopened submission - we want to show the previous submission in the table. | |
1230 | $submission = $this->assignment->get_user_submission($row->userid, false, $row->attemptnumber - 1); | |
1231 | } else { | |
1232 | $submission = new stdClass(); | |
1233 | $submission->id = $row->submissionid; | |
1234 | $submission->timecreated = $row->firstsubmission; | |
1235 | $submission->timemodified = $row->timesubmitted; | |
1236 | $submission->assignment = $this->assignment->get_instance()->id; | |
1237 | $submission->userid = $row->userid; | |
5c386472 | 1238 | $submission->attemptnumber = $row->attemptnumber; |
5ef72f85 DW |
1239 | } |
1240 | // Field is used for only for import/export and refers the the fieldname for the text editor. | |
df47b77f | 1241 | if (isset($field)) { |
5ef72f85 | 1242 | return $plugin->get_editor_text($field, $submission->id); |
df47b77f | 1243 | } |
e5403f8c DW |
1244 | return $this->format_plugin_summary_with_link($plugin, |
1245 | $submission, | |
1246 | 'grading', | |
1247 | array()); | |
bbd0e548 | 1248 | } |
df47b77f | 1249 | } else { |
2c6a3dbf | 1250 | $grade = null; |
df47b77f DW |
1251 | if (isset($field)) { |
1252 | return $plugin->get_editor_text($field, $row->gradeid); | |
1253 | } | |
1254 | ||
bbd0e548 DW |
1255 | if ($row->gradeid) { |
1256 | $grade = new stdClass(); | |
1257 | $grade->id = $row->gradeid; | |
1258 | $grade->timecreated = $row->firstmarked; | |
1259 | $grade->timemodified = $row->timemarked; | |
1260 | $grade->assignment = $this->assignment->get_instance()->id; | |
1261 | $grade->userid = $row->userid; | |
1262 | $grade->grade = $row->grade; | |
1263 | $grade->mailed = $row->mailed; | |
5c386472 | 1264 | $grade->attemptnumber = $row->attemptnumber; |
2c6a3dbf DW |
1265 | } |
1266 | if ($this->quickgrading && $plugin->supports_quickgrading()) { | |
1267 | return $plugin->get_quickgrading_html($row->userid, $grade); | |
1268 | } else if ($grade) { | |
e5403f8c DW |
1269 | return $this->format_plugin_summary_with_link($plugin, |
1270 | $grade, | |
1271 | 'grading', | |
1272 | array()); | |
bbd0e548 DW |
1273 | } |
1274 | } | |
bbd0e548 | 1275 | } |
df47b77f | 1276 | return ''; |
bbd0e548 DW |
1277 | } |
1278 | ||
1279 | /** | |
e5403f8c | 1280 | * Using the current filtering and sorting - load all rows and return a single column from them. |
bbd0e548 DW |
1281 | * |
1282 | * @param string $columnname The name of the raw column data | |
1283 | * @return array of data | |
1284 | */ | |
e5403f8c | 1285 | public function get_column_data($columnname) { |
bbd0e548 DW |
1286 | $this->setup(); |
1287 | $this->currpage = 0; | |
1288 | $this->query_db($this->tablemaxrows); | |
1289 | $result = array(); | |
1290 | foreach ($this->rawdata as $row) { | |
1291 | $result[] = $row->$columnname; | |
1292 | } | |
1293 | return $result; | |
1294 | } | |
bbd0e548 DW |
1295 | |
1296 | /** | |
e5403f8c | 1297 | * Return things to the renderer. |
bbd0e548 DW |
1298 | * |
1299 | * @return string the assignment name | |
1300 | */ | |
e5403f8c | 1301 | public function get_assignment_name() { |
bbd0e548 DW |
1302 | return $this->assignment->get_instance()->name; |
1303 | } | |
1304 | ||
1305 | /** | |
e5403f8c | 1306 | * Return things to the renderer. |
bbd0e548 DW |
1307 | * |
1308 | * @return int the course module id | |
1309 | */ | |
e5403f8c | 1310 | public function get_course_module_id() { |
bbd0e548 DW |
1311 | return $this->assignment->get_course_module()->id; |
1312 | } | |
1313 | ||
1314 | /** | |
e5403f8c | 1315 | * Return things to the renderer. |
bbd0e548 DW |
1316 | * |
1317 | * @return int the course id | |
1318 | */ | |
e5403f8c | 1319 | public function get_course_id() { |
bbd0e548 DW |
1320 | return $this->assignment->get_course()->id; |
1321 | } | |
1322 | ||
1323 | /** | |
e5403f8c | 1324 | * Return things to the renderer. |
bbd0e548 DW |
1325 | * |
1326 | * @return stdClass The course context | |
1327 | */ | |
e5403f8c | 1328 | public function get_course_context() { |
bbd0e548 DW |
1329 | return $this->assignment->get_course_context(); |
1330 | } | |
1331 | ||
1332 | /** | |
e5403f8c | 1333 | * Return things to the renderer. |
bbd0e548 DW |
1334 | * |
1335 | * @return bool Does this assignment accept submissions | |
1336 | */ | |
e5403f8c | 1337 | public function submissions_enabled() { |
bbd0e548 DW |
1338 | return $this->assignment->is_any_submission_plugin_enabled(); |
1339 | } | |
1340 | ||
1341 | /** | |
e5403f8c | 1342 | * Return things to the renderer. |
bbd0e548 DW |
1343 | * |
1344 | * @return bool Can this user view all grades (the gradebook) | |
1345 | */ | |
e5403f8c DW |
1346 | public function can_view_all_grades() { |
1347 | $context = $this->assignment->get_course_context(); | |
1348 | return has_capability('gradereport/grader:view', $context) && | |
1349 | has_capability('moodle/grade:viewall', $context); | |
bbd0e548 DW |
1350 | } |
1351 | ||
1352 | /** | |
e5403f8c | 1353 | * Override the table show_hide_link to not show for select column. |
bbd0e548 DW |
1354 | * |
1355 | * @param string $column the column name, index into various names. | |
1356 | * @param int $index numerical index of the column. | |
1357 | * @return string HTML fragment. | |
1358 | */ | |
1359 | protected function show_hide_link($column, $index) { | |
4a47008c | 1360 | if ($index > 0 || !$this->hasgrade) { |
bbd0e548 DW |
1361 | return parent::show_hide_link($column, $index); |
1362 | } | |
1363 | return ''; | |
1364 | } | |
1365 | } |