5c6b657a |
1 | <?PHP // $Id$ |
b0f2597e |
2 | /** |
3 | * assignment_base is the base class for assignment types |
4 | * |
5 | * This class provides all the functionality for an assignment |
6 | */ |
04eba58f |
7 | |
3b120e46 |
8 | require_once($CFG->libdir.'/eventslib.php'); |
172dd12c |
9 | require_once($CFG->libdir.'/formslib.php'); |
3b120e46 |
10 | |
1884f2a6 |
11 | DEFINE ('ASSIGNMENT_COUNT_WORDS', 1); |
12 | DEFINE ('ASSIGNMENT_COUNT_LETTERS', 2); |
d699cd1e |
13 | |
7af1e882 |
14 | /** |
b0f2597e |
15 | * Standard base class for all assignment submodules (assignment types). |
b0f2597e |
16 | */ |
17 | class assignment_base { |
18 | |
19 | var $cm; |
20 | var $course; |
21 | var $assignment; |
7af1e882 |
22 | var $strassignment; |
23 | var $strassignments; |
24 | var $strsubmissions; |
25 | var $strlastmodified; |
7af1e882 |
26 | var $pagetitle; |
7af1e882 |
27 | var $usehtmleditor; |
28 | var $defaultformat; |
55b4d096 |
29 | var $context; |
0b5a80a1 |
30 | var $type; |
b0f2597e |
31 | |
32 | /** |
33 | * Constructor for the base assignment class |
34 | * |
35 | * Constructor for the base assignment class. |
36 | * If cmid is set create the cm, course, assignment objects. |
7af1e882 |
37 | * If the assignment is hidden and the user is not a teacher then |
38 | * this prints a page header and notice. |
b0f2597e |
39 | * |
40 | * @param cmid integer, the current course module id - not set for new assignments |
73097f07 |
41 | * @param assignment object, usually null, but if we have it we pass it to save db access |
7af1e882 |
42 | * @param cm object, usually null, but if we have it we pass it to save db access |
43 | * @param course object, usually null, but if we have it we pass it to save db access |
b0f2597e |
44 | */ |
7bddd4b7 |
45 | function assignment_base($cmid='staticonly', $assignment=NULL, $cm=NULL, $course=NULL) { |
5053f00f |
46 | global $COURSE, $DB; |
dd97c328 |
47 | |
7bddd4b7 |
48 | if ($cmid == 'staticonly') { |
49 | //use static functions only! |
50 | return; |
51 | } |
b0f2597e |
52 | |
53 | global $CFG; |
54 | |
7bddd4b7 |
55 | if ($cm) { |
56 | $this->cm = $cm; |
57 | } else if (! $this->cm = get_coursemodule_from_id('assignment', $cmid)) { |
a939f681 |
58 | print_error('invalidcoursemodule'); |
7bddd4b7 |
59 | } |
04eba58f |
60 | |
dd97c328 |
61 | $this->context = get_context_instance(CONTEXT_MODULE, $this->cm->id); |
55b4d096 |
62 | |
7bddd4b7 |
63 | if ($course) { |
64 | $this->course = $course; |
dd97c328 |
65 | } else if ($this->cm->course == $COURSE->id) { |
66 | $this->course = $COURSE; |
5053f00f |
67 | } else if (! $this->course = $DB->get_record('course', array('id'=>$this->cm->course))) { |
a939f681 |
68 | print_error('invalidid', 'assignment'); |
7bddd4b7 |
69 | } |
04eba58f |
70 | |
7bddd4b7 |
71 | if ($assignment) { |
72 | $this->assignment = $assignment; |
5053f00f |
73 | } else if (! $this->assignment = $DB->get_record('assignment', array('id'=>$this->cm->instance))) { |
a939f681 |
74 | print_error('invalidid', 'assignment'); |
7bddd4b7 |
75 | } |
76 | |
b5ebd096 |
77 | $this->assignment->cmidnumber = $this->cm->id; // compatibility with modedit assignment obj |
78 | $this->assignment->courseid = $this->course->id; // compatibility with modedit assignment obj |
e6a4906b |
79 | |
7bddd4b7 |
80 | $this->strassignment = get_string('modulename', 'assignment'); |
81 | $this->strassignments = get_string('modulenameplural', 'assignment'); |
82 | $this->strsubmissions = get_string('submissions', 'assignment'); |
83 | $this->strlastmodified = get_string('lastmodified'); |
7bddd4b7 |
84 | $this->pagetitle = strip_tags($this->course->shortname.': '.$this->strassignment.': '.format_string($this->assignment->name,true)); |
85 | |
f36cbf1d |
86 | // visibility handled by require_login() with $cm parameter |
87 | // get current group only when really needed |
e6a4906b |
88 | |
73097f07 |
89 | /// Set up things for a HTML editor if it's needed |
90 | if ($this->usehtmleditor = can_use_html_editor()) { |
91 | $this->defaultformat = FORMAT_HTML; |
92 | } else { |
93 | $this->defaultformat = FORMAT_MOODLE; |
e6a4906b |
94 | } |
95 | } |
96 | |
7af1e882 |
97 | /** |
98 | * Display the assignment, used by view.php |
99 | * |
100 | * This in turn calls the methods producing individual parts of the page |
b0f2597e |
101 | */ |
b0f2597e |
102 | function view() { |
45fa3412 |
103 | |
dabfd0ed |
104 | $context = get_context_instance(CONTEXT_MODULE,$this->cm->id); |
0468976c |
105 | require_capability('mod/assignment:view', $context); |
45fa3412 |
106 | |
107 | add_to_log($this->course->id, "assignment", "view", "view.php?id={$this->cm->id}", |
b0f2597e |
108 | $this->assignment->id, $this->cm->id); |
04eba58f |
109 | |
73097f07 |
110 | $this->view_header(); |
04eba58f |
111 | |
f77cfb73 |
112 | $this->view_intro(); |
04eba58f |
113 | |
f77cfb73 |
114 | $this->view_dates(); |
04eba58f |
115 | |
b0f2597e |
116 | $this->view_feedback(); |
117 | |
f77cfb73 |
118 | $this->view_footer(); |
36eb856f |
119 | } |
120 | |
7af1e882 |
121 | /** |
122 | * Display the header and top of a page |
123 | * |
124 | * (this doesn't change much for assignment types) |
125 | * This is used by the view() method to print the header of view.php but |
126 | * it can be used on other pages in which case the string to denote the |
127 | * page in the navigation trail should be passed as an argument |
128 | * |
129 | * @param $subpage string Description of subpage to be used in navigation trail |
73097f07 |
130 | */ |
131 | function view_header($subpage='') { |
132 | |
133 | global $CFG; |
134 | |
45fa3412 |
135 | |
73097f07 |
136 | if ($subpage) { |
38e179a4 |
137 | $navigation = build_navigation($subpage, $this->cm); |
73097f07 |
138 | } else { |
38e179a4 |
139 | $navigation = build_navigation('', $this->cm); |
73097f07 |
140 | } |
45fa3412 |
141 | |
45fa3412 |
142 | print_header($this->pagetitle, $this->course->fullname, $navigation, '', '', |
143 | true, update_module_button($this->cm->id, $this->course->id, $this->strassignment), |
73097f07 |
144 | navmenu($this->course, $this->cm)); |
145 | |
ba3dc7b4 |
146 | groups_print_activity_menu($this->cm, 'view.php?id=' . $this->cm->id); |
45fa3412 |
147 | |
73097f07 |
148 | echo '<div class="reportlink">'.$this->submittedlink().'</div>'; |
7bddd4b7 |
149 | echo '<div class="clearer"></div>'; |
73097f07 |
150 | } |
151 | |
152 | |
7af1e882 |
153 | /** |
f77cfb73 |
154 | * Display the assignment intro |
7af1e882 |
155 | * |
156 | * This will most likely be extended by assignment type plug-ins |
157 | * The default implementation prints the assignment description in a box |
f77cfb73 |
158 | */ |
159 | function view_intro() { |
32776fef |
160 | print_simple_box_start('center', '', '', 0, 'generalbox', 'intro'); |
1e4343a0 |
161 | $formatoptions = new stdClass; |
162 | $formatoptions->noclean = true; |
163 | echo format_text($this->assignment->description, $this->assignment->format, $formatoptions); |
f77cfb73 |
164 | print_simple_box_end(); |
165 | } |
166 | |
7af1e882 |
167 | /** |
f77cfb73 |
168 | * Display the assignment dates |
7af1e882 |
169 | * |
170 | * Prints the assignment start and end dates in a box. |
171 | * This will be suitable for most assignment types |
f77cfb73 |
172 | */ |
173 | function view_dates() { |
174 | if (!$this->assignment->timeavailable && !$this->assignment->timedue) { |
175 | return; |
176 | } |
177 | |
32776fef |
178 | print_simple_box_start('center', '', '', 0, 'generalbox', 'dates'); |
f77cfb73 |
179 | echo '<table>'; |
180 | if ($this->assignment->timeavailable) { |
181 | echo '<tr><td class="c0">'.get_string('availabledate','assignment').':</td>'; |
182 | echo ' <td class="c1">'.userdate($this->assignment->timeavailable).'</td></tr>'; |
183 | } |
184 | if ($this->assignment->timedue) { |
185 | echo '<tr><td class="c0">'.get_string('duedate','assignment').':</td>'; |
186 | echo ' <td class="c1">'.userdate($this->assignment->timedue).'</td></tr>'; |
187 | } |
188 | echo '</table>'; |
189 | print_simple_box_end(); |
190 | } |
191 | |
192 | |
7af1e882 |
193 | /** |
194 | * Display the bottom and footer of a page |
195 | * |
196 | * This default method just prints the footer. |
197 | * This will be suitable for most assignment types |
73097f07 |
198 | */ |
199 | function view_footer() { |
200 | print_footer($this->course); |
201 | } |
202 | |
7af1e882 |
203 | /** |
204 | * Display the feedback to the student |
205 | * |
206 | * This default method prints the teacher picture and name, date when marked, |
ea6432fe |
207 | * grade and teacher submissioncomment. |
7af1e882 |
208 | * |
209 | * @param $submission object The submission object or NULL in which case it will be loaded |
210 | */ |
73097f07 |
211 | function view_feedback($submission=NULL) { |
5053f00f |
212 | global $USER, $CFG, $DB; |
5978010d |
213 | require_once($CFG->libdir.'/gradelib.php'); |
214 | |
215 | if (!has_capability('mod/assignment:submit', $this->context, $USER->id, false)) { |
216 | // can not submit assignments -> no feedback |
217 | return; |
218 | } |
e6a4906b |
219 | |
73097f07 |
220 | if (!$submission) { /// Get submission for this assignment |
221 | $submission = $this->get_submission($USER->id); |
70b2c772 |
222 | } |
223 | |
5978010d |
224 | $grading_info = grade_get_grades($this->course->id, 'mod', 'assignment', $this->assignment->id, $USER->id); |
225 | $item = $grading_info->items[0]; |
226 | $grade = $item->grades[$USER->id]; |
227 | |
228 | if ($grade->hidden or $grade->grade === false) { // hidden or error |
229 | return; |
230 | } |
231 | |
30d61820 |
232 | if ($grade->grade === null and empty($grade->str_feedback)) { /// Nothing to show yet |
70b2c772 |
233 | return; |
9c48354d |
234 | } |
e6a4906b |
235 | |
ced5ee59 |
236 | $graded_date = $grade->dategraded; |
12dce253 |
237 | $graded_by = $grade->usermodified; |
e6a4906b |
238 | |
5978010d |
239 | /// We need the teacher info |
5053f00f |
240 | if (!$teacher = $DB->get_record('user', array('id'=>$graded_by))) { |
a939f681 |
241 | print_error('cannotfindteacher'); |
12dce253 |
242 | } |
5978010d |
243 | |
b0f2597e |
244 | /// Print the feedback |
5978010d |
245 | print_heading(get_string('feedbackfromteacher', 'assignment', $this->course->teacher)); // TODO: fix teacher string |
6d4ecaec |
246 | |
b0f2597e |
247 | echo '<table cellspacing="0" class="feedback">'; |
248 | |
249 | echo '<tr>'; |
250 | echo '<td class="left picture">'; |
5978010d |
251 | if ($teacher) { |
ad1e3409 |
252 | print_user_picture($teacher, $this->course->id, $teacher->picture); |
5978010d |
253 | } |
b0f2597e |
254 | echo '</td>'; |
6d4ecaec |
255 | echo '<td class="topic">'; |
70b2c772 |
256 | echo '<div class="from">'; |
5978010d |
257 | if ($teacher) { |
258 | echo '<div class="fullname">'.fullname($teacher).'</div>'; |
259 | } |
260 | echo '<div class="time">'.userdate($graded_date).'</div>'; |
70b2c772 |
261 | echo '</div>'; |
b0f2597e |
262 | echo '</td>'; |
263 | echo '</tr>'; |
264 | |
265 | echo '<tr>'; |
266 | echo '<td class="left side"> </td>'; |
6d4ecaec |
267 | echo '<td class="content">'; |
5978010d |
268 | echo '<div class="grade">'; |
49292fa0 |
269 | echo get_string("grade").': '.$grade->str_long_grade; |
5978010d |
270 | echo '</div>'; |
271 | echo '<div class="clearer"></div>'; |
dcd338ff |
272 | |
6d4ecaec |
273 | echo '<div class="comment">'; |
5978010d |
274 | echo $grade->str_feedback; |
6d4ecaec |
275 | echo '</div>'; |
b0f2597e |
276 | echo '</tr>'; |
277 | |
278 | echo '</table>'; |
e6a4906b |
279 | } |
e6a4906b |
280 | |
45fa3412 |
281 | /** |
ba16713f |
282 | * Returns a link with info about the state of the assignment submissions |
7af1e882 |
283 | * |
284 | * This is used by view_header to put this link at the top right of the page. |
285 | * For teachers it gives the number of submitted assignments with a link |
286 | * For students it gives the time of their submission. |
287 | * This will be suitable for most assignment types. |
dd97c328 |
288 | * @param bool $allgroup print all groups info if user can access all groups, suitable for index.php |
7af1e882 |
289 | * @return string |
ba16713f |
290 | */ |
dd97c328 |
291 | function submittedlink($allgroups=false) { |
ba16713f |
292 | global $USER; |
e1faf3b9 |
293 | global $CFG; |
ba16713f |
294 | |
295 | $submitted = ''; |
e1faf3b9 |
296 | $urlbase = "{$CFG->wwwroot}/mod/assignment/"; |
ba16713f |
297 | |
bbbf2d40 |
298 | $context = get_context_instance(CONTEXT_MODULE,$this->cm->id); |
1648afb2 |
299 | if (has_capability('mod/assignment:grade', $context)) { |
dd97c328 |
300 | if ($allgroups and has_capability('moodle/site:accessallgroups', $context)) { |
301 | $group = 0; |
ba16713f |
302 | } else { |
f36cbf1d |
303 | $group = groups_get_activity_group($this->cm); |
dd97c328 |
304 | } |
305 | if ($count = $this->count_real_submissions($group)) { |
e1faf3b9 |
306 | $submitted = '<a href="'.$urlbase.'submissions.php?id='.$this->cm->id.'">'. |
dd97c328 |
307 | get_string('viewsubmissions', 'assignment', $count).'</a>'; |
308 | } else { |
e1faf3b9 |
309 | $submitted = '<a href="'.$urlbase.'submissions.php?id='.$this->cm->id.'">'. |
dd97c328 |
310 | get_string('noattempts', 'assignment').'</a>'; |
ba16713f |
311 | } |
ba16713f |
312 | } else { |
86a1ba04 |
313 | if (!empty($USER->id)) { |
ba16713f |
314 | if ($submission = $this->get_submission($USER->id)) { |
315 | if ($submission->timemodified) { |
1e4343a0 |
316 | if ($submission->timemodified <= $this->assignment->timedue || empty($this->assignment->timedue)) { |
ba16713f |
317 | $submitted = '<span class="early">'.userdate($submission->timemodified).'</span>'; |
318 | } else { |
319 | $submitted = '<span class="late">'.userdate($submission->timemodified).'</span>'; |
320 | } |
321 | } |
322 | } |
323 | } |
324 | } |
325 | |
326 | return $submitted; |
327 | } |
328 | |
329 | |
436cfa9f |
330 | function setup_elements(&$mform) { |
45fa3412 |
331 | |
436cfa9f |
332 | } |
333 | |
7af1e882 |
334 | /** |
335 | * Create a new assignment activity |
336 | * |
337 | * Given an object containing all the necessary data, |
7cac0c4b |
338 | * (defined by the form in mod_form.php) this function |
7af1e882 |
339 | * will create a new instance and return the id number |
340 | * of the new instance. |
341 | * The due data is added to the calendar |
342 | * This is common to all assignment types. |
343 | * |
7cac0c4b |
344 | * @param $assignment object The data from the form on mod_form.php |
7af1e882 |
345 | * @return int The id of the assignment |
346 | */ |
b0f2597e |
347 | function add_instance($assignment) { |
c18269c7 |
348 | global $COURSE, $DB; |
b0f2597e |
349 | |
350 | $assignment->timemodified = time(); |
7bddd4b7 |
351 | $assignment->courseid = $assignment->course; |
38147229 |
352 | |
c18269c7 |
353 | if ($returnid = $DB->insert_record("assignment", $assignment)) { |
7bddd4b7 |
354 | $assignment->id = $returnid; |
736f191c |
355 | |
1e4343a0 |
356 | if ($assignment->timedue) { |
7bddd4b7 |
357 | $event = new object(); |
1e4343a0 |
358 | $event->name = $assignment->name; |
359 | $event->description = $assignment->description; |
360 | $event->courseid = $assignment->course; |
361 | $event->groupid = 0; |
362 | $event->userid = 0; |
363 | $event->modulename = 'assignment'; |
364 | $event->instance = $returnid; |
365 | $event->eventtype = 'due'; |
366 | $event->timestart = $assignment->timedue; |
367 | $event->timeduration = 0; |
736f191c |
368 | |
1e4343a0 |
369 | add_event($event); |
370 | } |
7bddd4b7 |
371 | |
612607bd |
372 | assignment_grade_item_update($assignment); |
7bddd4b7 |
373 | |
736f191c |
374 | } |
375 | |
7bddd4b7 |
376 | |
736f191c |
377 | return $returnid; |
b0f2597e |
378 | } |
d699cd1e |
379 | |
7af1e882 |
380 | /** |
381 | * Deletes an assignment activity |
382 | * |
1f8c6549 |
383 | * Deletes all database records, files and calendar events for this assignment. |
7af1e882 |
384 | * @param $assignment object The assignment to be deleted |
385 | * @return boolean False indicates error |
386 | */ |
b0f2597e |
387 | function delete_instance($assignment) { |
c18269c7 |
388 | global $CFG, $DB; |
1f8c6549 |
389 | |
ada917d5 |
390 | $assignment->courseid = $assignment->course; |
391 | |
736f191c |
392 | $result = true; |
393 | |
fa686bc4 |
394 | // now get rid of all files |
dc85b32c |
395 | $fs = get_file_storage(); |
396 | if ($cm = get_coursemodule_from_instance('assignment', $assignment->id)) { |
397 | $context = get_context_instance(CONTEXT_MODULE, $cm->id); |
fa686bc4 |
398 | $fs->delete_area_files($context->id); |
dc85b32c |
399 | } |
400 | |
c18269c7 |
401 | if (! $DB->delete_records('assignment_submissions', array('assignment'=>$assignment->id))) { |
736f191c |
402 | $result = false; |
403 | } |
404 | |
77318f47 |
405 | if (! $DB->delete_records('event', array('modulename'=>'assignment', 'instance'=>$assignment->id))) { |
736f191c |
406 | $result = false; |
407 | } |
408 | |
77318f47 |
409 | if (! $DB->delete_records('assignment', array('id'=>$assignment->id))) { |
736f191c |
410 | $result = false; |
411 | } |
45fa3412 |
412 | |
45fa3412 |
413 | assignment_grade_item_delete($assignment); |
ada917d5 |
414 | |
736f191c |
415 | return $result; |
b0f2597e |
416 | } |
d699cd1e |
417 | |
7af1e882 |
418 | /** |
419 | * Updates a new assignment activity |
420 | * |
421 | * Given an object containing all the necessary data, |
7cac0c4b |
422 | * (defined by the form in mod_form.php) this function |
7af1e882 |
423 | * will update the assignment instance and return the id number |
424 | * The due date is updated in the calendar |
425 | * This is common to all assignment types. |
426 | * |
7cac0c4b |
427 | * @param $assignment object The data from the form on mod_form.php |
7af1e882 |
428 | * @return int The assignment id |
429 | */ |
b0f2597e |
430 | function update_instance($assignment) { |
c18269c7 |
431 | global $COURSE, $DB; |
b0f2597e |
432 | |
38147229 |
433 | $assignment->timemodified = time(); |
38147229 |
434 | |
b0f2597e |
435 | $assignment->id = $assignment->instance; |
7bddd4b7 |
436 | $assignment->courseid = $assignment->course; |
736f191c |
437 | |
c18269c7 |
438 | if (!$DB->update_record('assignment', $assignment)) { |
7bddd4b7 |
439 | return false; |
440 | } |
736f191c |
441 | |
7bddd4b7 |
442 | if ($assignment->timedue) { |
443 | $event = new object(); |
736f191c |
444 | |
c18269c7 |
445 | if ($event->id = $DB->get_field('event', 'id', array('modulename'=>'assignment', 'instance'=>$assignment->id))) { |
736f191c |
446 | |
7bddd4b7 |
447 | $event->name = $assignment->name; |
448 | $event->description = $assignment->description; |
449 | $event->timestart = $assignment->timedue; |
736f191c |
450 | |
7bddd4b7 |
451 | update_event($event); |
47263937 |
452 | } else { |
7bddd4b7 |
453 | $event = new object(); |
454 | $event->name = $assignment->name; |
455 | $event->description = $assignment->description; |
456 | $event->courseid = $assignment->course; |
457 | $event->groupid = 0; |
458 | $event->userid = 0; |
459 | $event->modulename = 'assignment'; |
460 | $event->instance = $assignment->id; |
461 | $event->eventtype = 'due'; |
462 | $event->timestart = $assignment->timedue; |
463 | $event->timeduration = 0; |
464 | |
465 | add_event($event); |
736f191c |
466 | } |
7bddd4b7 |
467 | } else { |
c18269c7 |
468 | $DB->delete_records('event', array('modulename'=>'assignment', 'instance'=>$assignment->id)); |
736f191c |
469 | } |
470 | |
7bddd4b7 |
471 | // get existing grade item |
45fa3412 |
472 | assignment_grade_item_update($assignment); |
7bddd4b7 |
473 | |
474 | return true; |
475 | } |
476 | |
477 | /** |
45fa3412 |
478 | * Update grade item for this submission. |
7bddd4b7 |
479 | */ |
45fa3412 |
480 | function update_grade($submission) { |
612607bd |
481 | assignment_update_grades($this->assignment, $submission->userid); |
b0f2597e |
482 | } |
483 | |
7af1e882 |
484 | /** |
b0f2597e |
485 | * Top-level function for handling of submissions called by submissions.php |
7af1e882 |
486 | * |
487 | * This is for handling the teacher interaction with the grading interface |
488 | * This should be suitable for most assignment types. |
489 | * |
490 | * @param $mode string Specifies the kind of teacher interaction taking place |
b0f2597e |
491 | */ |
492 | function submissions($mode) { |
9bf660b3 |
493 | ///The main switch is changed to facilitate |
494 | ///1) Batch fast grading |
495 | ///2) Skip to the next one on the popup |
496 | ///3) Save and Skip to the next one on the popup |
45fa3412 |
497 | |
9bf660b3 |
498 | //make user global so we can use the id |
499 | global $USER; |
45fa3412 |
500 | |
2dc5d980 |
501 | $mailinfo = optional_param('mailinfo', null, PARAM_BOOL); |
502 | if (is_null($mailinfo)) { |
503 | $mailinfo = get_user_preferences('assignment_mailinfo', 0); |
504 | } else { |
505 | set_user_preference('assignment_mailinfo', $mailinfo); |
506 | } |
507 | |
b0f2597e |
508 | switch ($mode) { |
509 | case 'grade': // We are in a popup window grading |
510 | if ($submission = $this->process_feedback()) { |
5a36be8c |
511 | //IE needs proper header with encoding |
512 | print_header(get_string('feedback', 'assignment').':'.format_string($this->assignment->name)); |
b0f2597e |
513 | print_heading(get_string('changessaved')); |
73963212 |
514 | print $this->update_main_listing($submission); |
b0f2597e |
515 | } |
989a0a52 |
516 | close_window(); |
b0f2597e |
517 | break; |
9cc9b7c1 |
518 | |
b0f2597e |
519 | case 'single': // We are in a popup window displaying submission |
520 | $this->display_submission(); |
521 | break; |
a56d79cd |
522 | |
1648afb2 |
523 | case 'all': // Main window, display everything |
b0f2597e |
524 | $this->display_submissions(); |
525 | break; |
082215e6 |
526 | |
9bf660b3 |
527 | case 'fastgrade': |
082215e6 |
528 | ///do the fast grading stuff - this process should work for all 3 subclasses |
2dc5d980 |
529 | |
39e11905 |
530 | $grading = false; |
16907e53 |
531 | $commenting = false; |
39e11905 |
532 | $col = false; |
ea6432fe |
533 | if (isset($_POST['submissioncomment'])) { |
534 | $col = 'submissioncomment'; |
16907e53 |
535 | $commenting = true; |
536 | } |
537 | if (isset($_POST['menu'])) { |
39e11905 |
538 | $col = 'menu'; |
16907e53 |
539 | $grading = true; |
540 | } |
39e11905 |
541 | if (!$col) { |
ea6432fe |
542 | //both submissioncomment and grade columns collapsed.. |
45fa3412 |
543 | $this->display_submissions(); |
16907e53 |
544 | break; |
545 | } |
2dc5d980 |
546 | |
39e11905 |
547 | foreach ($_POST[$col] as $id => $unusedvalue){ |
77f4b17b |
548 | |
549 | $id = (int)$id; //clean parameter name |
cc03871b |
550 | |
551 | $this->process_outcomes($id); |
552 | |
39e11905 |
553 | if (!$submission = $this->get_submission($id)) { |
554 | $submission = $this->prepare_new_submission($id); |
555 | $newsubmission = true; |
556 | } else { |
557 | $newsubmission = false; |
558 | } |
559 | unset($submission->data1); // Don't need to update this. |
560 | unset($submission->data2); // Don't need to update this. |
16907e53 |
561 | |
9bf660b3 |
562 | //for fast grade, we need to check if any changes take place |
16907e53 |
563 | $updatedb = false; |
564 | |
565 | if ($grading) { |
566 | $grade = $_POST['menu'][$id]; |
39e11905 |
567 | $updatedb = $updatedb || ($submission->grade != $grade); |
568 | $submission->grade = $grade; |
16907e53 |
569 | } else { |
39e11905 |
570 | if (!$newsubmission) { |
571 | unset($submission->grade); // Don't need to update this. |
572 | } |
16907e53 |
573 | } |
574 | if ($commenting) { |
ea6432fe |
575 | $commentvalue = trim($_POST['submissioncomment'][$id]); |
5053f00f |
576 | $updatedb = $updatedb || ($submission->submissioncomment != $commentvalue); |
ea6432fe |
577 | $submission->submissioncomment = $commentvalue; |
16907e53 |
578 | } else { |
ea6432fe |
579 | unset($submission->submissioncomment); // Don't need to update this. |
9bf660b3 |
580 | } |
581 | |
39e11905 |
582 | $submission->teacher = $USER->id; |
2dc5d980 |
583 | if ($updatedb) { |
584 | $submission->mailed = (int)(!$mailinfo); |
585 | } |
586 | |
39e11905 |
587 | $submission->timemarked = time(); |
588 | |
589 | //if it is not an update, we don't change the last modified time etc. |
ea6432fe |
590 | //this will also not write into database if no submissioncomment and grade is entered. |
39e11905 |
591 | |
16907e53 |
592 | if ($updatedb){ |
39e11905 |
593 | if ($newsubmission) { |
39f563ed |
594 | if (!isset($submission->submissioncomment)) { |
595 | $submission->submissioncomment = ''; |
596 | } |
5053f00f |
597 | if (!$sid = $DB->insert_record('assignment_submissions', $submission)) { |
39e11905 |
598 | return false; |
599 | } |
7bddd4b7 |
600 | $submission->id = $sid; |
39e11905 |
601 | } else { |
5053f00f |
602 | if (!$DB->update_record('assignment_submissions', $submission)) { |
39e11905 |
603 | return false; |
604 | } |
7bddd4b7 |
605 | } |
606 | |
607 | // triger grade event |
45fa3412 |
608 | $this->update_grade($submission); |
7bddd4b7 |
609 | |
39e11905 |
610 | //add to log only if updating |
45fa3412 |
611 | add_to_log($this->course->id, 'assignment', 'update grades', |
612 | 'submissions.php?id='.$this->assignment->id.'&user='.$submission->userid, |
613 | $submission->userid, $this->cm->id); |
9bf660b3 |
614 | } |
45fa3412 |
615 | |
616 | } |
cc03871b |
617 | |
fb81abe1 |
618 | $message = notify(get_string('changessaved'), 'notifysuccess', 'center', true); |
619 | |
620 | $this->display_submissions($message); |
9bf660b3 |
621 | break; |
39e11905 |
622 | |
623 | |
9bf660b3 |
624 | case 'next': |
625 | /// We are currently in pop up, but we want to skip to next one without saving. |
626 | /// This turns out to be similar to a single case |
627 | /// The URL used is for the next submission. |
45fa3412 |
628 | |
9bf660b3 |
629 | $this->display_submission(); |
630 | break; |
45fa3412 |
631 | |
9bf660b3 |
632 | case 'saveandnext': |
633 | ///We are in pop up. save the current one and go to the next one. |
634 | //first we save the current changes |
635 | if ($submission = $this->process_feedback()) { |
636 | //print_heading(get_string('changessaved')); |
73963212 |
637 | $extra_javascript = $this->update_main_listing($submission); |
9bf660b3 |
638 | } |
45fa3412 |
639 | |
9bf660b3 |
640 | //then we display the next submission |
73963212 |
641 | $this->display_submission($extra_javascript); |
9bf660b3 |
642 | break; |
45fa3412 |
643 | |
9bf660b3 |
644 | default: |
645 | echo "something seriously is wrong!!"; |
45fa3412 |
646 | break; |
a56d79cd |
647 | } |
b0f2597e |
648 | } |
45fa3412 |
649 | |
7af1e882 |
650 | /** |
651 | * Helper method updating the listing on the main script from popup using javascript |
652 | * |
653 | * @param $submission object The submission whose data is to be updated on the main page |
654 | */ |
be86672d |
655 | function update_main_listing($submission) { |
fbaa56b2 |
656 | global $SESSION, $CFG; |
45fa3412 |
657 | |
73963212 |
658 | $output = ''; |
659 | |
9bf660b3 |
660 | $perpage = get_user_preferences('assignment_perpage', 10); |
be86672d |
661 | |
9bf660b3 |
662 | $quickgrade = get_user_preferences('assignment_quickgrade', 0); |
45fa3412 |
663 | |
be86672d |
664 | /// Run some Javascript to try and update the parent page |
73963212 |
665 | $output .= '<script type="text/javascript">'."\n<!--\n"; |
ea6432fe |
666 | if (empty($SESSION->flextable['mod-assignment-submissions']->collapse['submissioncomment'])) { |
9bf660b3 |
667 | if ($quickgrade){ |
16fc2088 |
668 | $output.= 'opener.document.getElementById("submissioncomment'.$submission->userid.'").value="' |
ea6432fe |
669 | .trim($submission->submissioncomment).'";'."\n"; |
9bf660b3 |
670 | } else { |
73963212 |
671 | $output.= 'opener.document.getElementById("com'.$submission->userid. |
ea6432fe |
672 | '").innerHTML="'.shorten_text(trim(strip_tags($submission->submissioncomment)), 15)."\";\n"; |
9bf660b3 |
673 | } |
be86672d |
674 | } |
9bf660b3 |
675 | |
676 | if (empty($SESSION->flextable['mod-assignment-submissions']->collapse['grade'])) { |
677 | //echo optional_param('menuindex'); |
678 | if ($quickgrade){ |
16fc2088 |
679 | $output.= 'opener.document.getElementById("menumenu'.$submission->userid. |
680 | '").selectedIndex="'.optional_param('menuindex', 0, PARAM_INT).'";'."\n"; |
9bf660b3 |
681 | } else { |
73963212 |
682 | $output.= 'opener.document.getElementById("g'.$submission->userid.'").innerHTML="'. |
9bf660b3 |
683 | $this->display_grade($submission->grade)."\";\n"; |
45fa3412 |
684 | } |
685 | } |
9bf660b3 |
686 | //need to add student's assignments in there too. |
73097f07 |
687 | if (empty($SESSION->flextable['mod-assignment-submissions']->collapse['timemodified']) && |
688 | $submission->timemodified) { |
73963212 |
689 | $output.= 'opener.document.getElementById("ts'.$submission->userid. |
3a935caf |
690 | '").innerHTML="'.addslashes_js($this->print_student_answer($submission->userid)).userdate($submission->timemodified)."\";\n"; |
be86672d |
691 | } |
45fa3412 |
692 | |
73097f07 |
693 | if (empty($SESSION->flextable['mod-assignment-submissions']->collapse['timemarked']) && |
694 | $submission->timemarked) { |
73963212 |
695 | $output.= 'opener.document.getElementById("tt'.$submission->userid. |
be86672d |
696 | '").innerHTML="'.userdate($submission->timemarked)."\";\n"; |
697 | } |
45fa3412 |
698 | |
be86672d |
699 | if (empty($SESSION->flextable['mod-assignment-submissions']->collapse['status'])) { |
73963212 |
700 | $output.= 'opener.document.getElementById("up'.$submission->userid.'").className="s1";'; |
9bf660b3 |
701 | $buttontext = get_string('update'); |
45fa3412 |
702 | $button = link_to_popup_window ('/mod/assignment/submissions.php?id='.$this->cm->id.'&userid='.$submission->userid.'&mode=single'.'&offset='.(optional_param('offset', '', PARAM_INT)-1), |
9bf660b3 |
703 | 'grade'.$submission->userid, $buttontext, 450, 700, $buttontext, 'none', true, 'button'.$submission->userid); |
3a935caf |
704 | $output.= 'opener.document.getElementById("up'.$submission->userid.'").innerHTML="'.addslashes_js($button).'";'; |
45fa3412 |
705 | } |
f1af7aaa |
706 | |
5978010d |
707 | $grading_info = grade_get_grades($this->course->id, 'mod', 'assignment', $this->assignment->id, $submission->userid); |
708 | |
709 | if (empty($SESSION->flextable['mod-assignment-submissions']->collapse['finalgrade'])) { |
710 | $output.= 'opener.document.getElementById("finalgrade_'.$submission->userid. |
711 | '").innerHTML="'.$grading_info->items[0]->grades[$submission->userid]->str_grade.'";'."\n"; |
712 | } |
713 | |
714 | if (!empty($CFG->enableoutcomes) and empty($SESSION->flextable['mod-assignment-submissions']->collapse['outcome'])) { |
fcac8e51 |
715 | |
716 | if (!empty($grading_info->outcomes)) { |
d886a7ea |
717 | foreach($grading_info->outcomes as $n=>$outcome) { |
718 | if ($outcome->grades[$submission->userid]->locked) { |
719 | continue; |
720 | } |
cc03871b |
721 | |
d886a7ea |
722 | if ($quickgrade){ |
723 | $output.= 'opener.document.getElementById("outcome_'.$n.'_'.$submission->userid. |
724 | '").selectedIndex="'.$outcome->grades[$submission->userid]->grade.'";'."\n"; |
725 | |
726 | } else { |
727 | $options = make_grades_menu(-$outcome->scaleid); |
728 | $options[0] = get_string('nooutcome', 'grades'); |
729 | $output.= 'opener.document.getElementById("outcome_'.$n.'_'.$submission->userid.'").innerHTML="'.$options[$outcome->grades[$submission->userid]->grade]."\";\n"; |
730 | } |
cc03871b |
731 | |
732 | } |
733 | } |
734 | } |
735 | |
73963212 |
736 | $output .= "\n-->\n</script>"; |
737 | return $output; |
be86672d |
738 | } |
d699cd1e |
739 | |
7af1e882 |
740 | /** |
741 | * Return a grade in user-friendly form, whether it's a scale or not |
45fa3412 |
742 | * |
7af1e882 |
743 | * @param $grade |
744 | * @return string User-friendly representation of grade |
d59269cf |
745 | */ |
746 | function display_grade($grade) { |
74d7d735 |
747 | global $DB; |
d59269cf |
748 | |
c86aa2a4 |
749 | static $scalegrades = array(); // Cache scales for each assignment - they might have different scales!! |
d59269cf |
750 | |
751 | if ($this->assignment->grade >= 0) { // Normal number |
082215e6 |
752 | if ($grade == -1) { |
753 | return '-'; |
754 | } else { |
755 | return $grade.' / '.$this->assignment->grade; |
756 | } |
d59269cf |
757 | |
758 | } else { // Scale |
c86aa2a4 |
759 | if (empty($scalegrades[$this->assignment->id])) { |
74d7d735 |
760 | if ($scale = $DB->get_record('scale', array('id'=>-($this->assignment->grade)))) { |
c86aa2a4 |
761 | $scalegrades[$this->assignment->id] = make_menu_from_list($scale->scale); |
d59269cf |
762 | } else { |
763 | return '-'; |
764 | } |
765 | } |
c86aa2a4 |
766 | if (isset($scalegrades[$this->assignment->id][$grade])) { |
767 | return $scalegrades[$this->assignment->id][$grade]; |
0f7d4e5e |
768 | } |
39e11905 |
769 | return '-'; |
d59269cf |
770 | } |
771 | } |
772 | |
7af1e882 |
773 | /** |
b0f2597e |
774 | * Display a single submission, ready for grading on a popup window |
7af1e882 |
775 | * |
ea6432fe |
776 | * This default method prints the teacher info and submissioncomment box at the top and |
7af1e882 |
777 | * the student info and submission at the bottom. |
778 | * This method also fetches the necessary data in order to be able to |
779 | * provide a "Next submission" button. |
780 | * Calls preprocess_submission() to give assignment type plug-ins a chance |
781 | * to process submissions before they are graded |
782 | * This method gets its arguments from the page parameters userid and offset |
b0f2597e |
783 | */ |
73963212 |
784 | function display_submission($extra_javascript = '') { |
5053f00f |
785 | global $CFG, $DB; |
cc03871b |
786 | require_once($CFG->libdir.'/gradelib.php'); |
dd97c328 |
787 | require_once($CFG->libdir.'/tablelib.php'); |
45fa3412 |
788 | |
4fdabdc3 |
789 | $userid = required_param('userid', PARAM_INT); |
790 | $offset = required_param('offset', PARAM_INT);//offset for where to start looking for student. |
d699cd1e |
791 | |
5053f00f |
792 | if (!$user = $DB->get_record('user', array('id'=>$userid))) { |
a939f681 |
793 | print_error('nousers'); |
b0f2597e |
794 | } |
d699cd1e |
795 | |
39e11905 |
796 | if (!$submission = $this->get_submission($user->id)) { |
797 | $submission = $this->prepare_new_submission($userid); |
b0f2597e |
798 | } |
b0f2597e |
799 | if ($submission->timemodified > $submission->timemarked) { |
800 | $subtype = 'assignmentnew'; |
801 | } else { |
802 | $subtype = 'assignmentold'; |
803 | } |
d699cd1e |
804 | |
5978010d |
805 | $grading_info = grade_get_grades($this->course->id, 'mod', 'assignment', $this->assignment->id, array($user->id)); |
806 | $disabled = $grading_info->items[0]->grades[$userid]->locked || $grading_info->items[0]->grades[$userid]->overridden; |
807 | |
0cfafdc7 |
808 | /// construct SQL, using current offset to find the data of the next student |
9bf660b3 |
809 | $course = $this->course; |
810 | $assignment = $this->assignment; |
811 | $cm = $this->cm; |
16fc2088 |
812 | $context = get_context_instance(CONTEXT_MODULE, $cm->id); |
d699cd1e |
813 | |
7bddd4b7 |
814 | /// Get all ppl that can submit assignments |
0cfafdc7 |
815 | |
ba3dc7b4 |
816 | $currentgroup = groups_get_activity_group($cm); |
dd97c328 |
817 | if ($users = get_users_by_capability($context, 'mod/assignment:submit', 'u.id', '', '', '', $currentgroup, '', false)) { |
818 | $users = array_keys($users); |
819 | } |
0cfafdc7 |
820 | |
dd97c328 |
821 | // if groupmembersonly used, remove users who are not in any group |
822 | if ($users and !empty($CFG->enablegroupings) and $cm->groupmembersonly) { |
823 | if ($groupingusers = groups_get_grouping_members($cm->groupingid, 'u.id', 'u.id')) { |
824 | $users = array_intersect($users, array_keys($groupingusers)); |
825 | } |
02828119 |
826 | } |
827 | |
082215e6 |
828 | $nextid = 0; |
dd97c328 |
829 | |
830 | if ($users) { |
ad1e3409 |
831 | $select = 'SELECT u.id, u.firstname, u.lastname, u.picture, u.imagealt, |
dd97c328 |
832 | s.id AS submissionid, s.grade, s.submissioncomment, |
833 | s.timemodified, s.timemarked, |
834 | COALESCE(SIGN(SIGN(s.timemarked) + SIGN(s.timemarked - s.timemodified)), 0) AS status '; |
5053f00f |
835 | $sql = 'FROM {user} u '. |
836 | 'LEFT JOIN {assignment_submissions} s ON u.id = s.userid |
dd97c328 |
837 | AND s.assignment = '.$this->assignment->id.' '. |
838 | 'WHERE u.id IN ('.implode(',', $users).') '; |
839 | |
840 | if ($sort = flexible_table::get_sql_sort('mod-assignment-submissions')) { |
841 | $sort = 'ORDER BY '.$sort.' '; |
842 | } |
843 | |
5053f00f |
844 | if (($auser = $DB->get_records_sql($select.$sql.$sort, null, $offset+1, 1)) !== false) { |
dd97c328 |
845 | $nextuser = array_shift($auser); |
846 | /// Calculate user status |
847 | $nextuser->status = ($nextuser->timemarked > 0) && ($nextuser->timemarked >= $nextuser->timemodified); |
848 | $nextid = $nextuser->id; |
849 | } |
9bf660b3 |
850 | } |
81532b92 |
851 | |
9bf660b3 |
852 | print_header(get_string('feedback', 'assignment').':'.fullname($user, true).':'.format_string($this->assignment->name)); |
d699cd1e |
853 | |
73963212 |
854 | /// Print any extra javascript needed for saveandnext |
855 | echo $extra_javascript; |
856 | |
9bf660b3 |
857 | ///SOme javascript to help with setting up >.> |
45fa3412 |
858 | |
c9977d05 |
859 | echo '<script type="text/javascript">'."\n"; |
9bf660b3 |
860 | echo 'function setNext(){'."\n"; |
16fc2088 |
861 | echo 'document.getElementById(\'submitform\').mode.value=\'next\';'."\n"; |
862 | echo 'document.getElementById(\'submitform\').userid.value="'.$nextid.'";'."\n"; |
9bf660b3 |
863 | echo '}'."\n"; |
45fa3412 |
864 | |
9bf660b3 |
865 | echo 'function saveNext(){'."\n"; |
16fc2088 |
866 | echo 'document.getElementById(\'submitform\').mode.value=\'saveandnext\';'."\n"; |
867 | echo 'document.getElementById(\'submitform\').userid.value="'.$nextid.'";'."\n"; |
868 | echo 'document.getElementById(\'submitform\').saveuserid.value="'.$userid.'";'."\n"; |
869 | echo 'document.getElementById(\'submitform\').menuindex.value = document.getElementById(\'submitform\').grade.selectedIndex;'."\n"; |
9bf660b3 |
870 | echo '}'."\n"; |
45fa3412 |
871 | |
9bf660b3 |
872 | echo '</script>'."\n"; |
52436fe1 |
873 | echo '<table cellspacing="0" class="feedback '.$subtype.'" >'; |
d699cd1e |
874 | |
9bf660b3 |
875 | ///Start of teacher info row |
c69cb506 |
876 | |
b0f2597e |
877 | echo '<tr>'; |
141a922c |
878 | echo '<td class="picture teacher">'; |
b0f2597e |
879 | if ($submission->teacher) { |
5053f00f |
880 | $teacher = $DB->get_record('user', array('id'=>$submission->teacher)); |
b0f2597e |
881 | } else { |
882 | global $USER; |
883 | $teacher = $USER; |
884 | } |
ad1e3409 |
885 | print_user_picture($teacher, $this->course->id, $teacher->picture); |
b0f2597e |
886 | echo '</td>'; |
887 | echo '<td class="content">'; |
b7dc2256 |
888 | echo '<form id="submitform" action="submissions.php" method="post">'; |
39bb937a |
889 | echo '<div>'; // xhtml compatibility - invisiblefieldset was breaking layout here |
16fc2088 |
890 | echo '<input type="hidden" name="offset" value="'.($offset+1).'" />'; |
c9977d05 |
891 | echo '<input type="hidden" name="userid" value="'.$userid.'" />'; |
892 | echo '<input type="hidden" name="id" value="'.$this->cm->id.'" />'; |
893 | echo '<input type="hidden" name="mode" value="grade" />'; |
894 | echo '<input type="hidden" name="menuindex" value="0" />';//selected menu index |
45fa3412 |
895 | |
9bf660b3 |
896 | //new hidden field, initialized to -1. |
c9977d05 |
897 | echo '<input type="hidden" name="saveuserid" value="-1" />'; |
1a35ee51 |
898 | |
52436fe1 |
899 | if ($submission->timemarked) { |
900 | echo '<div class="from">'; |
901 | echo '<div class="fullname">'.fullname($teacher, true).'</div>'; |
902 | echo '<div class="time">'.userdate($submission->timemarked).'</div>'; |
903 | echo '</div>'; |
904 | } |
1a35ee51 |
905 | echo '<div class="grade"><label for="menugrade">'.get_string('grade').'</label> '; |
5978010d |
906 | choose_from_menu(make_grades_menu($this->assignment->grade), 'grade', $submission->grade, get_string('nograde'), '', -1, false, $disabled); |
52436fe1 |
907 | echo '</div>'; |
3a5ae660 |
908 | |
5978010d |
909 | echo '<div class="clearer"></div>'; |
910 | echo '<div class="finalgrade">'.get_string('finalgrade', 'grades').': '.$grading_info->items[0]->grades[$userid]->str_grade.'</div>'; |
38f4c3fc |
911 | echo '<div class="clearer"></div>'; |
912 | |
fcac8e51 |
913 | if (!empty($CFG->enableoutcomes)) { |
d886a7ea |
914 | foreach($grading_info->outcomes as $n=>$outcome) { |
915 | echo '<div class="outcome"><label for="menuoutcome_'.$n.'">'.$outcome->name.'</label> '; |
916 | $options = make_grades_menu(-$outcome->scaleid); |
917 | if ($outcome->grades[$submission->userid]->locked) { |
918 | $options[0] = get_string('nooutcome', 'grades'); |
919 | echo $options[$outcome->grades[$submission->userid]->grade]; |
920 | } else { |
921 | choose_from_menu($options, 'outcome_'.$n.'['.$userid.']', $outcome->grades[$submission->userid]->grade, get_string('nooutcome', 'grades'), '', 0, false, false, 0, 'menuoutcome_'.$n); |
3a5ae660 |
922 | } |
d886a7ea |
923 | echo '</div>'; |
924 | echo '<div class="clearer"></div>'; |
3a5ae660 |
925 | } |
3a5ae660 |
926 | } |
927 | |
b0f2597e |
928 | |
01e2fdfe |
929 | $this->preprocess_submission($submission); |
930 | |
5978010d |
931 | if ($disabled) { |
932 | echo '<div class="disabledfeedback">'.$grading_info->items[0]->grades[$userid]->str_feedback.'</div>'; |
ff8f7015 |
933 | |
ff8f7015 |
934 | } else { |
5978010d |
935 | print_textarea($this->usehtmleditor, 14, 58, 0, 0, 'submissioncomment', $submission->submissioncomment, $this->course->id); |
936 | if ($this->usehtmleditor) { |
937 | echo '<input type="hidden" name="format" value="'.FORMAT_HTML.'" />'; |
938 | } else { |
939 | echo '<div class="format">'; |
940 | choose_from_menu(format_text_menu(), "format", $submission->format, ""); |
941 | helpbutton("textformat", get_string("helpformatting")); |
942 | echo '</div>'; |
943 | } |
ff8f7015 |
944 | } |
b0f2597e |
945 | |
03076be4 |
946 | $lastmailinfo = get_user_preferences('assignment_mailinfo', 1) ? 'checked="checked"' : ''; |
2dc5d980 |
947 | |
9bf660b3 |
948 | ///Print Buttons in Single View |
03076be4 |
949 | echo '<input type="hidden" name="mailinfo" value="0" />'; |
950 | echo '<input type="checkbox" id="mailinfo" name="mailinfo" value="1" '.$lastmailinfo.' /><label for="mailinfo">'.get_string('enableemailnotification','assignment').'</label>'; |
141a922c |
951 | echo '<div class="buttons">'; |
16fc2088 |
952 | echo '<input type="submit" name="submit" value="'.get_string('savechanges').'" onclick = "document.getElementById(\'submitform\').menuindex.value = document.getElementById(\'submitform\').grade.selectedIndex" />'; |
b0f2597e |
953 | echo '<input type="submit" name="cancel" value="'.get_string('cancel').'" />'; |
9bf660b3 |
954 | //if there are more to be graded. |
082215e6 |
955 | if ($nextid) { |
5b48244f |
956 | echo '<input type="submit" name="saveandnext" value="'.get_string('saveandnext').'" onclick="saveNext()" />'; |
957 | echo '<input type="submit" name="next" value="'.get_string('next').'" onclick="setNext();" />'; |
9bf660b3 |
958 | } |
73097f07 |
959 | echo '</div>'; |
39bb937a |
960 | echo '</div></form>'; |
55b4d096 |
961 | |
962 | $customfeedback = $this->custom_feedbackform($submission, true); |
963 | if (!empty($customfeedback)) { |
45fa3412 |
964 | echo $customfeedback; |
55b4d096 |
965 | } |
966 | |
73097f07 |
967 | echo '</td></tr>'; |
45fa3412 |
968 | |
9bf660b3 |
969 | ///End of teacher info row, Start of student info row |
970 | echo '<tr>'; |
141a922c |
971 | echo '<td class="picture user">'; |
ad1e3409 |
972 | print_user_picture($user, $this->course->id, $user->picture); |
9bf660b3 |
973 | echo '</td>'; |
974 | echo '<td class="topic">'; |
975 | echo '<div class="from">'; |
976 | echo '<div class="fullname">'.fullname($user, true).'</div>'; |
977 | if ($submission->timemodified) { |
978 | echo '<div class="time">'.userdate($submission->timemodified). |
979 | $this->display_lateness($submission->timemodified).'</div>'; |
980 | } |
981 | echo '</div>'; |
982 | $this->print_user_files($user->id); |
983 | echo '</td>'; |
984 | echo '</tr>'; |
45fa3412 |
985 | |
9bf660b3 |
986 | ///End of student info row |
45fa3412 |
987 | |
73097f07 |
988 | echo '</table>'; |
989 | |
5978010d |
990 | if (!$disabled and $this->usehtmleditor) { |
73097f07 |
991 | use_html_editor(); |
992 | } |
993 | |
b0f2597e |
994 | print_footer('none'); |
d699cd1e |
995 | } |
996 | |
7af1e882 |
997 | /** |
01e2fdfe |
998 | * Preprocess submission before grading |
7af1e882 |
999 | * |
1000 | * Called by display_submission() |
1001 | * The default type does nothing here. |
1002 | * @param $submission object The submission object |
01e2fdfe |
1003 | */ |
1004 | function preprocess_submission(&$submission) { |
1005 | } |
d699cd1e |
1006 | |
7af1e882 |
1007 | /** |
b0f2597e |
1008 | * Display all the submissions ready for grading |
1009 | */ |
fb81abe1 |
1010 | function display_submissions($message='') { |
5053f00f |
1011 | global $CFG, $DB, $USER, $DB; |
cc03871b |
1012 | require_once($CFG->libdir.'/gradelib.php'); |
3446205d |
1013 | |
9bf660b3 |
1014 | /* first we check to see if the form has just been submitted |
1015 | * to request user_preference updates |
1016 | */ |
45fa3412 |
1017 | |
9bf660b3 |
1018 | if (isset($_POST['updatepref'])){ |
16907e53 |
1019 | $perpage = optional_param('perpage', 10, PARAM_INT); |
9bf660b3 |
1020 | $perpage = ($perpage <= 0) ? 10 : $perpage ; |
1021 | set_user_preference('assignment_perpage', $perpage); |
2dc5d980 |
1022 | set_user_preference('assignment_quickgrade', optional_param('quickgrade', 0, PARAM_BOOL)); |
9bf660b3 |
1023 | } |
1b5910c4 |
1024 | |
45fa3412 |
1025 | /* next we get perpage and quickgrade (allow quick grade) params |
9bf660b3 |
1026 | * from database |
1027 | */ |
1028 | $perpage = get_user_preferences('assignment_perpage', 10); |
34e67f76 |
1029 | |
fcac8e51 |
1030 | $quickgrade = get_user_preferences('assignment_quickgrade', 0); |
1031 | |
1032 | $grading_info = grade_get_grades($this->course->id, 'mod', 'assignment', $this->assignment->id); |
45fa3412 |
1033 | |
fcac8e51 |
1034 | if (!empty($CFG->enableoutcomes) and !empty($grading_info->outcomes)) { |
e46f4d11 |
1035 | $uses_outcomes = true; |
1036 | } else { |
1037 | $uses_outcomes = false; |
1038 | } |
1039 | |
16907e53 |
1040 | $page = optional_param('page', 0, PARAM_INT); |
b0f2597e |
1041 | $strsaveallfeedback = get_string('saveallfeedback', 'assignment'); |
d0ac6bc2 |
1042 | |
b0f2597e |
1043 | /// Some shortcuts to make the code read better |
45fa3412 |
1044 | |
b0f2597e |
1045 | $course = $this->course; |
1046 | $assignment = $this->assignment; |
1047 | $cm = $this->cm; |
45fa3412 |
1048 | |
9bf660b3 |
1049 | $tabindex = 1; //tabindex for quick grading tabbing; Not working for dropdowns yet |
91719320 |
1050 | |
b0f2597e |
1051 | add_to_log($course->id, 'assignment', 'view submission', 'submissions.php?id='.$this->assignment->id, $this->assignment->id, $this->cm->id); |
206ab184 |
1052 | |
6dac764d |
1053 | $navigation = build_navigation($this->strsubmissions, $this->cm); |
206ab184 |
1054 | print_header_simple(format_string($this->assignment->name,true), "", $navigation, |
1055 | '', '', true, update_module_button($cm->id, $course->id, $this->strassignment), navmenu($course, $cm)); |
12dce253 |
1056 | |
fb739b77 |
1057 | $course_context = get_context_instance(CONTEXT_COURSE, $course->id); |
1058 | if (has_capability('gradereport/grader:view', $course_context) && has_capability('moodle/grade:viewall', $course_context)) { |
12dce253 |
1059 | echo '<div class="allcoursegrades"><a href="' . $CFG->wwwroot . '/grade/report/grader/index.php?id=' . $course->id . '">' |
b64792f6 |
1060 | . get_string('seeallcoursegrades', 'grades') . '</a></div>'; |
fb739b77 |
1061 | } |
7bddd4b7 |
1062 | |
fb81abe1 |
1063 | if (!empty($message)) { |
1064 | echo $message; // display messages here if any |
1065 | } |
1066 | |
2d7617c6 |
1067 | $context = get_context_instance(CONTEXT_MODULE, $cm->id); |
7bddd4b7 |
1068 | |
dd97c328 |
1069 | /// Check to see if groups are being used in this assignment |
1070 | |
7bddd4b7 |
1071 | /// find out current groups mode |
ba3dc7b4 |
1072 | $groupmode = groups_get_activity_groupmode($cm); |
1073 | $currentgroup = groups_get_activity_group($cm, true); |
1074 | groups_print_activity_menu($cm, 'submissions.php?id=' . $this->cm->id); |
7bddd4b7 |
1075 | |
1076 | /// Get all ppl that are allowed to submit assignments |
dd97c328 |
1077 | if ($users = get_users_by_capability($context, 'mod/assignment:submit', 'u.id', '', '', '', $currentgroup, '', false)) { |
33150205 |
1078 | $users = array_keys($users); |
1079 | } |
ba3dc7b4 |
1080 | |
dd97c328 |
1081 | // if groupmembersonly used, remove users who are not in any group |
1082 | if ($users and !empty($CFG->enablegroupings) and $cm->groupmembersonly) { |
1083 | if ($groupingusers = groups_get_grouping_members($cm->groupingid, 'u.id', 'u.id')) { |
1084 | $users = array_intersect($users, array_keys($groupingusers)); |
1085 | } |
ba3dc7b4 |
1086 | } |
91719320 |
1087 | |
5978010d |
1088 | $tablecolumns = array('picture', 'fullname', 'grade', 'submissioncomment', 'timemodified', 'timemarked', 'status', 'finalgrade'); |
e46f4d11 |
1089 | if ($uses_outcomes) { |
5978010d |
1090 | $tablecolumns[] = 'outcome'; // no sorting based on outcomes column |
fbaa56b2 |
1091 | } |
1092 | |
206ab184 |
1093 | $tableheaders = array('', |
12dce253 |
1094 | get_string('fullname'), |
206ab184 |
1095 | get_string('grade'), |
1096 | get_string('comment', 'assignment'), |
1097 | get_string('lastmodified').' ('.$course->student.')', |
1098 | get_string('lastmodified').' ('.$course->teacher.')', |
5978010d |
1099 | get_string('status'), |
1100 | get_string('finalgrade', 'grades')); |
e46f4d11 |
1101 | if ($uses_outcomes) { |
5978010d |
1102 | $tableheaders[] = get_string('outcome', 'grades'); |
fbaa56b2 |
1103 | } |
91719320 |
1104 | |
b0f2597e |
1105 | require_once($CFG->libdir.'/tablelib.php'); |
1106 | $table = new flexible_table('mod-assignment-submissions'); |
45fa3412 |
1107 | |
b0f2597e |
1108 | $table->define_columns($tablecolumns); |
1109 | $table->define_headers($tableheaders); |
fa22fd5f |
1110 | $table->define_baseurl($CFG->wwwroot.'/mod/assignment/submissions.php?id='.$this->cm->id.'&currentgroup='.$currentgroup); |
45fa3412 |
1111 | |
246444b9 |
1112 | $table->sortable(true, 'lastname');//sorted by lastname by default |
b0f2597e |
1113 | $table->collapsible(true); |
1114 | $table->initialbars(true); |
45fa3412 |
1115 | |
b0f2597e |
1116 | $table->column_suppress('picture'); |
1117 | $table->column_suppress('fullname'); |
45fa3412 |
1118 | |
b0f2597e |
1119 | $table->column_class('picture', 'picture'); |
9437c854 |
1120 | $table->column_class('fullname', 'fullname'); |
1121 | $table->column_class('grade', 'grade'); |
ea6432fe |
1122 | $table->column_class('submissioncomment', 'comment'); |
9437c854 |
1123 | $table->column_class('timemodified', 'timemodified'); |
1124 | $table->column_class('timemarked', 'timemarked'); |
1125 | $table->column_class('status', 'status'); |
5978010d |
1126 | $table->column_class('finalgrade', 'finalgrade'); |
e46f4d11 |
1127 | if ($uses_outcomes) { |
5978010d |
1128 | $table->column_class('outcome', 'outcome'); |
fbaa56b2 |
1129 | } |
45fa3412 |
1130 | |
b0f2597e |
1131 | $table->set_attribute('cellspacing', '0'); |
1132 | $table->set_attribute('id', 'attempts'); |
9437c854 |
1133 | $table->set_attribute('class', 'submissions'); |
f30036d3 |
1134 | $table->set_attribute('width', '100%'); |
d9cb14b8 |
1135 | //$table->set_attribute('align', 'center'); |
45fa3412 |
1136 | |
5978010d |
1137 | $table->no_sorting('finalgrade'); |
1138 | $table->no_sorting('outcome'); |
1139 | |
b0f2597e |
1140 | // Start working -- this is necessary as soon as the niceties are over |
1141 | $table->setup(); |
1142 | |
b0f2597e |
1143 | if (empty($users)) { |
dd97c328 |
1144 | print_heading(get_string('nosubmitusers','assignment')); |
b0f2597e |
1145 | return true; |
1146 | } |
0f1a97c2 |
1147 | |
b0f2597e |
1148 | /// Construct the SQL |
0f1a97c2 |
1149 | |
b0f2597e |
1150 | if ($where = $table->get_sql_where()) { |
b0f2597e |
1151 | $where .= ' AND '; |
1152 | } |
0f1a97c2 |
1153 | |
b0f2597e |
1154 | if ($sort = $table->get_sql_sort()) { |
86f65395 |
1155 | $sort = ' ORDER BY '.$sort; |
b0f2597e |
1156 | } |
9fa49e22 |
1157 | |
d4ba9ef7 |
1158 | $select = 'SELECT u.id, u.firstname, u.lastname, u.picture, u.imagealt, |
45fa3412 |
1159 | s.id AS submissionid, s.grade, s.submissioncomment, |
c9265600 |
1160 | s.timemodified, s.timemarked, |
1161 | COALESCE(SIGN(SIGN(s.timemarked) + SIGN(s.timemarked - s.timemodified)), 0) AS status '; |
5053f00f |
1162 | $sql = 'FROM {user} u '. |
1163 | 'LEFT JOIN {assignment_submissions} s ON u.id = s.userid |
9ad5c91f |
1164 | AND s.assignment = '.$this->assignment->id.' '. |
ba3dc7b4 |
1165 | 'WHERE '.$where.'u.id IN ('.implode(',',$users).') '; |
45fa3412 |
1166 | |
c5d36203 |
1167 | $table->pagesize($perpage, count($users)); |
45fa3412 |
1168 | |
9bf660b3 |
1169 | ///offset used to calculate index of student in that particular query, needed for the pop up to know who's next |
1170 | $offset = $page * $perpage; |
45fa3412 |
1171 | |
b0f2597e |
1172 | $strupdate = get_string('update'); |
9437c854 |
1173 | $strgrade = get_string('grade'); |
b0f2597e |
1174 | $grademenu = make_grades_menu($this->assignment->grade); |
1175 | |
5053f00f |
1176 | if (($ausers = $DB->get_records_sql($select.$sql.$sort, null, $table->get_page_start(), $table->get_page_size())) !== false) { |
fcac8e51 |
1177 | $grading_info = grade_get_grades($this->course->id, 'mod', 'assignment', $this->assignment->id, array_keys($ausers)); |
d59269cf |
1178 | foreach ($ausers as $auser) { |
5978010d |
1179 | $final_grade = $grading_info->items[0]->grades[$auser->id]; |
319b7349 |
1180 | $grademax = $grading_info->items[0]->grademax; |
1181 | $final_grade->formatted_grade = round($final_grade->grade,2) .' / ' . round($grademax,2); |
0036b42f |
1182 | $locked_overridden = 'locked'; |
1183 | if ($final_grade->overridden) { |
1184 | $locked_overridden = 'overridden'; |
1185 | } |
1186 | |
9ad5c91f |
1187 | /// Calculate user status |
2ff44114 |
1188 | $auser->status = ($auser->timemarked > 0) && ($auser->timemarked >= $auser->timemodified); |
d4ba9ef7 |
1189 | $picture = print_user_picture($auser, $course->id, $auser->picture, false, true); |
45fa3412 |
1190 | |
39e11905 |
1191 | if (empty($auser->submissionid)) { |
1192 | $auser->grade = -1; //no submission yet |
9bf660b3 |
1193 | } |
45fa3412 |
1194 | |
d59269cf |
1195 | if (!empty($auser->submissionid)) { |
9bf660b3 |
1196 | ///Prints student answer and student modified date |
1197 | ///attach file or print link to student answer, depending on the type of the assignment. |
45fa3412 |
1198 | ///Refer to print_student_answer in inherited classes. |
1199 | if ($auser->timemodified > 0) { |
206ab184 |
1200 | $studentmodified = '<div id="ts'.$auser->id.'">'.$this->print_student_answer($auser->id) |
1201 | . userdate($auser->timemodified).'</div>'; |
d59269cf |
1202 | } else { |
9437c854 |
1203 | $studentmodified = '<div id="ts'.$auser->id.'"> </div>'; |
d59269cf |
1204 | } |
9bf660b3 |
1205 | ///Print grade, dropdown or text |
d59269cf |
1206 | if ($auser->timemarked > 0) { |
1207 | $teachermodified = '<div id="tt'.$auser->id.'">'.userdate($auser->timemarked).'</div>'; |
45fa3412 |
1208 | |
5978010d |
1209 | if ($final_grade->locked or $final_grade->overridden) { |
0036b42f |
1210 | $grade = '<div id="g'.$auser->id.'" class="'. $locked_overridden .'">'.$final_grade->formatted_grade.'</div>'; |
5978010d |
1211 | } else if ($quickgrade) { |
206ab184 |
1212 | $menu = choose_from_menu(make_grades_menu($this->assignment->grade), |
1213 | 'menu['.$auser->id.']', $auser->grade, |
1214 | get_string('nograde'),'',-1,true,false,$tabindex++); |
1215 | $grade = '<div id="g'.$auser->id.'">'. $menu .'</div>'; |
9bf660b3 |
1216 | } else { |
1217 | $grade = '<div id="g'.$auser->id.'">'.$this->display_grade($auser->grade).'</div>'; |
1218 | } |
1219 | |
b0f2597e |
1220 | } else { |
9437c854 |
1221 | $teachermodified = '<div id="tt'.$auser->id.'"> </div>'; |
5978010d |
1222 | if ($final_grade->locked or $final_grade->overridden) { |
0036b42f |
1223 | $grade = '<div id="g'.$auser->id.'" class="'. $locked_overridden .'">'.$final_grade->formatted_grade.'</div>'; |
5978010d |
1224 | } else if ($quickgrade) { |
206ab184 |
1225 | $menu = choose_from_menu(make_grades_menu($this->assignment->grade), |
1226 | 'menu['.$auser->id.']', $auser->grade, |
1227 | get_string('nograde'),'',-1,true,false,$tabindex++); |
1228 | $grade = '<div id="g'.$auser->id.'">'.$menu.'</div>'; |
9bf660b3 |
1229 | } else { |
1230 | $grade = '<div id="g'.$auser->id.'">'.$this->display_grade($auser->grade).'</div>'; |
1231 | } |
1232 | } |
1233 | ///Print Comment |
5978010d |
1234 | if ($final_grade->locked or $final_grade->overridden) { |
1235 | $comment = '<div id="com'.$auser->id.'">'.shorten_text(strip_tags($final_grade->str_feedback),15).'</div>'; |
1236 | |
1237 | } else if ($quickgrade) { |
206ab184 |
1238 | $comment = '<div id="com'.$auser->id.'">' |
1239 | . '<textarea tabindex="'.$tabindex++.'" name="submissioncomment['.$auser->id.']" id="submissioncomment' |
1240 | . $auser->id.'" rows="2" cols="20">'.($auser->submissioncomment).'</textarea></div>'; |
9bf660b3 |
1241 | } else { |
ea6432fe |
1242 | $comment = '<div id="com'.$auser->id.'">'.shorten_text(strip_tags($auser->submissioncomment),15).'</div>'; |
b0f2597e |
1243 | } |
1244 | } else { |
9437c854 |
1245 | $studentmodified = '<div id="ts'.$auser->id.'"> </div>'; |
1246 | $teachermodified = '<div id="tt'.$auser->id.'"> </div>'; |
9bf660b3 |
1247 | $status = '<div id="st'.$auser->id.'"> </div>'; |
206ab184 |
1248 | |
12dce253 |
1249 | if ($final_grade->locked or $final_grade->overridden) { |
319b7349 |
1250 | $grade = '<div id="g'.$auser->id.'">'.$final_grade->formatted_grade . '</div>'; |
5978010d |
1251 | } else if ($quickgrade) { // allow editing |
206ab184 |
1252 | $menu = choose_from_menu(make_grades_menu($this->assignment->grade), |
1253 | 'menu['.$auser->id.']', $auser->grade, |
1254 | get_string('nograde'),'',-1,true,false,$tabindex++); |
1255 | $grade = '<div id="g'.$auser->id.'">'.$menu.'</div>'; |
9bf660b3 |
1256 | } else { |
39e11905 |
1257 | $grade = '<div id="g'.$auser->id.'">-</div>'; |
9bf660b3 |
1258 | } |
206ab184 |
1259 | |
5978010d |
1260 | if ($final_grade->locked or $final_grade->overridden) { |
1261 | $comment = '<div id="com'.$auser->id.'">'.$final_grade->str_feedback.'</div>'; |
1262 | } else if ($quickgrade) { |
206ab184 |
1263 | $comment = '<div id="com'.$auser->id.'">' |
1264 | . '<textarea tabindex="'.$tabindex++.'" name="submissioncomment['.$auser->id.']" id="submissioncomment' |
1265 | . $auser->id.'" rows="2" cols="20">'.($auser->submissioncomment).'</textarea></div>'; |
9bf660b3 |
1266 | } else { |
1267 | $comment = '<div id="com'.$auser->id.'"> </div>'; |
1268 | } |
b0f2597e |
1269 | } |
9fa49e22 |
1270 | |
9ad5c91f |
1271 | if (empty($auser->status)) { /// Confirm we have exclusively 0 or 1 |
0f7d4e5e |
1272 | $auser->status = 0; |
9ad5c91f |
1273 | } else { |
1274 | $auser->status = 1; |
0f7d4e5e |
1275 | } |
1276 | |
9437c854 |
1277 | $buttontext = ($auser->status == 1) ? $strupdate : $strgrade; |
45fa3412 |
1278 | |
fcac8e51 |
1279 | ///No more buttons, we use popups ;-). |
1280 | $popup_url = '/mod/assignment/submissions.php?id='.$this->cm->id |
1281 | . '&userid='.$auser->id.'&mode=single'.'&offset='.$offset++; |
1282 | $button = link_to_popup_window ($popup_url, 'grade'.$auser->id, $buttontext, 600, 780, |
1283 | $buttontext, 'none', true, 'button'.$auser->id); |
206ab184 |
1284 | |
fcac8e51 |
1285 | $status = '<div id="up'.$auser->id.'" class="s'.$auser->status.'">'.$button.'</div>'; |
cc03871b |
1286 | |
5978010d |
1287 | $finalgrade = '<span id="finalgrade_'.$auser->id.'">'.$final_grade->str_grade.'</span>'; |
1288 | |
cc03871b |
1289 | $outcomes = ''; |
206ab184 |
1290 | |
fcac8e51 |
1291 | if ($uses_outcomes) { |
206ab184 |
1292 | |
d886a7ea |
1293 | foreach($grading_info->outcomes as $n=>$outcome) { |
1294 | $outcomes .= '<div class="outcome"><label>'.$outcome->name.'</label>'; |
1295 | $options = make_grades_menu(-$outcome->scaleid); |
1296 | |
1297 | if ($outcome->grades[$auser->id]->locked or !$quickgrade) { |
1298 | $options[0] = get_string('nooutcome', 'grades'); |
1299 | $outcomes .= ': <span id="outcome_'.$n.'_'.$auser->id.'">'.$options[$outcome->grades[$auser->id]->grade].'</span>'; |
1300 | } else { |
1301 | $outcomes .= ' '; |
1302 | $outcomes .= choose_from_menu($options, 'outcome_'.$n.'['.$auser->id.']', |
1303 | $outcome->grades[$auser->id]->grade, get_string('nooutcome', 'grades'), '', 0, true, false, 0, 'outcome_'.$n.'_'.$auser->id); |
cc03871b |
1304 | } |
d886a7ea |
1305 | $outcomes .= '</div>'; |
cc03871b |
1306 | } |
1307 | } |
1308 | |
e2f51ac6 |
1309 | $userlink = '<a href="' . $CFG->wwwroot . '/user/view.php?id=' . $auser->id . '&course=' . $course->id . '">' . fullname($auser) . '</a>'; |
1310 | $row = array($picture, $userlink, $grade, $comment, $studentmodified, $teachermodified, $status, $finalgrade); |
e46f4d11 |
1311 | if ($uses_outcomes) { |
fbaa56b2 |
1312 | $row[] = $outcomes; |
1313 | } |
1314 | |
d59269cf |
1315 | $table->add_data($row); |
1316 | } |
b0f2597e |
1317 | } |
45fa3412 |
1318 | |
082215e6 |
1319 | /// Print quickgrade form around the table |
1320 | if ($quickgrade){ |
b7dc2256 |
1321 | echo '<form action="submissions.php" id="fastg" method="post">'; |
a1b5dd2b |
1322 | echo '<div>'; |
820aff13 |
1323 | echo '<input type="hidden" name="id" value="'.$this->cm->id.'" />'; |
1324 | echo '<input type="hidden" name="mode" value="fastgrade" />'; |
1325 | echo '<input type="hidden" name="page" value="'.$page.'" />'; |
a1b5dd2b |
1326 | echo '</div>'; |
082215e6 |
1327 | } |
1328 | |
1329 | $table->print_html(); /// Print the whole table |
1330 | |
9bf660b3 |
1331 | if ($quickgrade){ |
03076be4 |
1332 | $lastmailinfo = get_user_preferences('assignment_mailinfo', 1) ? 'checked="checked"' : ''; |
d9cf7323 |
1333 | echo '<div class="fgcontrols">'; |
1334 | echo '<div class="emailnotification">'; |
03076be4 |
1335 | echo '<label for="mailinfo">'.get_string('enableemailnotification','assignment').'</label>'; |
1336 | echo '<input type="hidden" name="mailinfo" value="0" />'; |
1337 | echo '<input type="checkbox" id="mailinfo" name="mailinfo" value="1" '.$lastmailinfo.' />'; |
8aa0c699 |
1338 | helpbutton('emailnotification', get_string('enableemailnotification', 'assignment'), 'assignment').'</p></div>'; |
d9cf7323 |
1339 | echo '</div>'; |
1340 | echo '<div class="fastgbutton"><input type="submit" name="fastg" value="'.get_string('saveallfeedback', 'assignment').'" /></div>'; |
1341 | echo '</div>'; |
082215e6 |
1342 | echo '</form>'; |
9bf660b3 |
1343 | } |
082215e6 |
1344 | /// End of fast grading form |
45fa3412 |
1345 | |
082215e6 |
1346 | /// Mini form for setting user preference |
2dc5d980 |
1347 | echo '<div class="qgprefs">'; |
1348 | echo '<form id="options" action="submissions.php?id='.$this->cm->id.'" method="post"><div>'; |
1349 | echo '<input type="hidden" name="updatepref" value="1" />'; |
1350 | echo '<table id="optiontable">'; |
1351 | echo '<tr><td>'; |
9bf660b3 |
1352 | echo '<label for="perpage">'.get_string('pagesize','assignment').'</label>'; |
2dc5d980 |
1353 | echo '</td>'; |
ee8652f3 |
1354 | echo '<td>'; |
9bf660b3 |
1355 | echo '<input type="text" id="perpage" name="perpage" size="1" value="'.$perpage.'" />'; |
1356 | helpbutton('pagesize', get_string('pagesize','assignment'), 'assignment'); |
1357 | echo '</td></tr>'; |
2dc5d980 |
1358 | echo '<tr><td>'; |
d9cf7323 |
1359 | echo '<label for="quickgrade">'.get_string('quickgrade','assignment').'</label>'; |
2dc5d980 |
1360 | echo '</td>'; |
ee8652f3 |
1361 | echo '<td>'; |
d9cf7323 |
1362 | $checked = $quickgrade ? 'checked="checked"' : ''; |
1363 | echo '<input type="checkbox" id="quickgrade" name="quickgrade" value="1" '.$checked.' />'; |
fcac8e51 |
1364 | helpbutton('quickgrade', get_string('quickgrade', 'assignment'), 'assignment').'</p></div>'; |
1365 | echo '</td></tr>'; |
2dc5d980 |
1366 | echo '<tr><td colspan="2">'; |
9bf660b3 |
1367 | echo '<input type="submit" value="'.get_string('savepreferences').'" />'; |
1368 | echo '</td></tr></table>'; |
2dc5d980 |
1369 | echo '</div></form></div>'; |
9bf660b3 |
1370 | ///End of mini form |
b0f2597e |
1371 | print_footer($this->course); |
8e340cb0 |
1372 | } |
d699cd1e |
1373 | |
7af1e882 |
1374 | /** |
1375 | * Process teacher feedback submission |
1376 | * |
1377 | * This is called by submissions() when a grading even has taken place. |
1378 | * It gets its data from the submitted form. |
1379 | * @return object The updated submission object |
b0f2597e |
1380 | */ |
1381 | function process_feedback() { |
f8c81c01 |
1382 | global $CFG, $USER, $DB; |
5978010d |
1383 | require_once($CFG->libdir.'/gradelib.php'); |
d699cd1e |
1384 | |
294ce987 |
1385 | if (!$feedback = data_submitted()) { // No incoming data? |
b0f2597e |
1386 | return false; |
d699cd1e |
1387 | } |
b7b42874 |
1388 | |
9bf660b3 |
1389 | ///For save and next, we need to know the userid to save, and the userid to go |
1390 | ///We use a new hidden field in the form, and set it to -1. If it's set, we use this |
1391 | ///as the userid to store |
1392 | if ((int)$feedback->saveuserid !== -1){ |
1393 | $feedback->userid = $feedback->saveuserid; |
1394 | } |
1395 | |
b0f2597e |
1396 | if (!empty($feedback->cancel)) { // User hit cancel button |
1397 | return false; |
1398 | } |
d699cd1e |
1399 | |
5978010d |
1400 | $grading_info = grade_get_grades($this->course->id, 'mod', 'assignment', $this->assignment->id, $feedback->userid); |
1401 | |
cc03871b |
1402 | // store outcomes if needed |
1403 | $this->process_outcomes($feedback->userid); |
1404 | |
7af1e882 |
1405 | $submission = $this->get_submission($feedback->userid, true); // Get or make one |
d699cd1e |
1406 | |
5978010d |
1407 | if (!$grading_info->items[0]->grades[$feedback->userid]->locked and |
1408 | !$grading_info->items[0]->grades[$feedback->userid]->overridden) { |
d699cd1e |
1409 | |
5978010d |
1410 | $submission->grade = $feedback->grade; |
1411 | $submission->submissioncomment = $feedback->submissioncomment; |
1412 | $submission->format = $feedback->format; |
1413 | $submission->teacher = $USER->id; |
2dc5d980 |
1414 | $mailinfo = get_user_preferences('assignment_mailinfo', 0); |
1415 | if (!$mailinfo) { |
1416 | $submission->mailed = 1; // treat as already mailed |
1417 | } else { |
1418 | $submission->mailed = 0; // Make sure mail goes out (again, even) |
1419 | } |
5978010d |
1420 | $submission->timemarked = time(); |
d4156e80 |
1421 | |
5978010d |
1422 | unset($submission->data1); // Don't need to update this. |
1423 | unset($submission->data2); // Don't need to update this. |
d699cd1e |
1424 | |
5978010d |
1425 | if (empty($submission->timemodified)) { // eg for offline assignments |
1426 | // $submission->timemodified = time(); |
1427 | } |
d699cd1e |
1428 | |
5053f00f |
1429 | if (! $DB->update_record('assignment_submissions', $submission)) { |
5978010d |
1430 | return false; |
1431 | } |
7bddd4b7 |
1432 | |
5978010d |
1433 | // triger grade event |
1434 | $this->update_grade($submission); |
1435 | |
1436 | add_to_log($this->course->id, 'assignment', 'update grades', |
1437 | 'submissions.php?id='.$this->assignment->id.'&user='.$feedback->userid, $feedback->userid, $this->cm->id); |
1438 | } |
45fa3412 |
1439 | |
7af1e882 |
1440 | return $submission; |
d699cd1e |
1441 | |
d699cd1e |
1442 | } |
d699cd1e |
1443 | |
cc03871b |
1444 | function process_outcomes($userid) { |
1445 | global $CFG, $USER; |
fbaa56b2 |
1446 | |
1447 | if (empty($CFG->enableoutcomes)) { |
1448 | return; |
1449 | } |
1450 | |
cc03871b |
1451 | require_once($CFG->libdir.'/gradelib.php'); |
1452 | |
294ce987 |
1453 | if (!$formdata = data_submitted()) { |
cc03871b |
1454 | return; |
1455 | } |
1456 | |
1457 | $data = array(); |
fcac8e51 |
1458 | $grading_info = grade_get_grades($this->course->id, 'mod', 'assignment', $this->assignment->id, $userid); |
1459 | |
1460 | if (!empty($grading_info->outcomes)) { |
d886a7ea |
1461 | foreach($grading_info->outcomes as $n=>$old) { |
1462 | $name = 'outcome_'.$n; |
1463 | if (isset($formdata->{$name}[$userid]) and $old->grades[$userid]->grade != $formdata->{$name}[$userid]) { |
1464 | $data[$n] = $formdata->{$name}[$userid]; |
cc03871b |
1465 | } |
1466 | } |
1467 | } |
1468 | if (count($data) > 0) { |
1469 | grade_update_outcomes('mod/assignment', $this->course->id, 'mod', 'assignment', $this->assignment->id, $userid, $data); |
1470 | } |
1471 | |
1472 | } |
1473 | |
7af1e882 |
1474 | /** |
1475 | * Load the submission object for a particular user |
1476 | * |
1477 | * @param $userid int The id of the user whose submission we want or 0 in which case USER->id is used |
1478 | * @param $createnew boolean optional Defaults to false. If set to true a new submission object will be created in the database |
03076be4 |
1479 | * @param bool $teachermodified student submission set if false |
7af1e882 |
1480 | * @return object The submission |
1481 | */ |
03076be4 |
1482 | function get_submission($userid=0, $createnew=false, $teachermodified=false) { |
5053f00f |
1483 | global $USER, $DB; |
f77cfb73 |
1484 | |
1485 | if (empty($userid)) { |
1486 | $userid = $USER->id; |
1487 | } |
1488 | |
5053f00f |
1489 | $submission = $DB->get_record('assignment_submissions', array('assignment'=>$this->assignment->id, 'userid'=>$userid)); |
d699cd1e |
1490 | |
b0f2597e |
1491 | if ($submission || !$createnew) { |
1492 | return $submission; |
1493 | } |
03076be4 |
1494 | $newsubmission = $this->prepare_new_submission($userid, $teachermodified); |
5053f00f |
1495 | if (!$DB->insert_record("assignment_submissions", $newsubmission)) { |
a939f681 |
1496 | print_error('cannotinsertempty', 'assignment'); |
b0f2597e |
1497 | } |
d699cd1e |
1498 | |
5053f00f |
1499 | return $DB->get_record('assignment_submissions', array('assignment'=>$this->assignment->id, 'userid'=>$userid)); |
b0f2597e |
1500 | } |
d699cd1e |
1501 | |
7af1e882 |
1502 | /** |
1503 | * Instantiates a new submission object for a given user |
1504 | * |
1505 | * Sets the assignment, userid and times, everything else is set to default values. |
1506 | * @param $userid int The userid for which we want a submission object |
03076be4 |
1507 | * @param bool $teachermodified student submission set if false |
7af1e882 |
1508 | * @return object The submission |
1509 | */ |
03076be4 |
1510 | function prepare_new_submission($userid, $teachermodified=false) { |
45fa3412 |
1511 | $submission = new Object; |
39e11905 |
1512 | $submission->assignment = $this->assignment->id; |
1513 | $submission->userid = $userid; |
45fa3412 |
1514 | //$submission->timecreated = time(); |
16fc2088 |
1515 | $submission->timecreated = ''; |
1516 | // teachers should not be modifying modified date, except offline assignments |
03076be4 |
1517 | if ($teachermodified) { |
1518 | $submission->timemodified = 0; |
1519 | } else { |
1520 | $submission->timemodified = $submission->timecreated; |
1521 | } |
39e11905 |
1522 | $submission->numfiles = 0; |
1523 | $submission->data1 = ''; |
1524 | $submission->data2 = ''; |
1525 | $submission->grade = -1; |
ea6432fe |
1526 | $submission->submissioncomment = ''; |
39e11905 |
1527 | $submission->format = 0; |
1528 | $submission->teacher = 0; |
1529 | $submission->timemarked = 0; |
1530 | $submission->mailed = 0; |
1531 | return $submission; |
1532 | } |
1533 | |
7af1e882 |
1534 | /** |
1535 | * Return all assignment submissions by ENROLLED students (even empty) |
1536 | * |
1537 | * @param $sort string optional field names for the ORDER BY in the sql query |
1538 | * @param $dir string optional specifying the sort direction, defaults to DESC |
1539 | * @return array The submission objects indexed by id |
1540 | */ |
b0f2597e |
1541 | function get_submissions($sort='', $dir='DESC') { |
7af1e882 |
1542 | return assignment_get_all_submissions($this->assignment, $sort, $dir); |
b0f2597e |
1543 | } |
1544 | |
7af1e882 |
1545 | /** |
1546 | * Counts all real assignment submissions by ENROLLED students (not empty ones) |
1547 | * |
1548 | * @param $groupid int optional If nonzero then count is restricted to this group |
1549 | * @return int The number of submissions |
1550 | */ |
b0f2597e |
1551 | function count_real_submissions($groupid=0) { |
dd97c328 |
1552 | return assignment_count_real_submissions($this->cm, $groupid); |
d59269cf |
1553 | } |
d699cd1e |
1554 | |
7af1e882 |
1555 | /** |
1556 | * Alerts teachers by email of new or changed assignments that need grading |
1557 | * |
1558 | * First checks whether the option to email teachers is set for this assignment. |
1559 | * Sends an email to ALL teachers in the course (or in the group if using separate groups). |
1560 | * Uses the methods email_teachers_text() and email_teachers_html() to construct the content. |
1561 | * @param $submission object The submission that has changed |
1562 | */ |
73097f07 |
1563 | function email_teachers($submission) { |
5053f00f |
1564 | global $CFG, $DB; |
73097f07 |
1565 | |
d8199f1d |
1566 | if (empty($this->assignment->emailteachers)) { // No need to do anything |
73097f07 |
1567 | return; |
1568 | } |
1569 | |
5053f00f |
1570 | $user = $DB->get_record('user', array('id'=>$submission->userid)); |
73097f07 |
1571 | |
413efd22 |
1572 | if ($teachers = $this->get_graders($user)) { |
73097f07 |
1573 | |
1574 | $strassignments = get_string('modulenameplural', 'assignment'); |
1575 | $strassignment = get_string('modulename', 'assignment'); |
1576 | $strsubmitted = get_string('submitted', 'assignment'); |
1577 | |
1578 | foreach ($teachers as $teacher) { |
98be6ed8 |
1579 | $info = new object(); |
413efd22 |
1580 | $info->username = fullname($user, true); |
d8199f1d |
1581 | $info->assignment = format_string($this->assignment->name,true); |
1582 | $info->url = $CFG->wwwroot.'/mod/assignment/submissions.php?id='.$this->cm->id; |
1583 | |
1584 | $postsubject = $strsubmitted.': '.$info->username.' -> '.$this->assignment->name; |
1585 | $posttext = $this->email_teachers_text($info); |
1586 | $posthtml = ($teacher->mailformat == 1) ? $this->email_teachers_html($info) : ''; |
73097f07 |
1587 | |
3b120e46 |
1588 | $eventdata = new object(); |
1589 | $eventdata->modulename = 'assignment'; |
1590 | $eventdata->userfrom = $user; |
1591 | $eventdata->userto = $teacher; |
1592 | $eventdata->subject = $postsubject; |
1593 | $eventdata->fullmessage = $posttext; |
1594 | $eventdata->fullmessageformat = FORMAT_PLAIN; |
1595 | $eventdata->fullmessagehtml = $posthtml; |
1596 | $eventdata->smallmessage = ''; |
1597 | if ( events_trigger('message_send', $eventdata) > 0 ){ |
1598 | } |
73097f07 |
1599 | } |
1600 | } |
1601 | } |
1602 | |
172dd12c |
1603 | function send_file($filearea, $args) { |
1604 | debugging('plugin does not implement file sending', DEBUG_DEVELOPER); |
1605 | return false; |
1606 | } |
1607 | |
413efd22 |
1608 | /** |
1609 | * Returns a list of teachers that should be grading given submission |
1610 | */ |
1611 | function get_graders($user) { |
1612 | //potential graders |
7bddd4b7 |
1613 | $potgraders = get_users_by_capability($this->context, 'mod/assignment:grade', '', '', '', '', '', '', false, false); |
1614 | |
413efd22 |
1615 | $graders = array(); |
ba3dc7b4 |
1616 | if (groups_get_activity_groupmode($this->cm) == SEPARATEGROUPS) { // Separate groups are being used |
2c386f82 |
1617 | if ($groups = groups_get_all_groups($this->course->id, $user->id)) { // Try to find all groups |
413efd22 |
1618 | foreach ($groups as $group) { |
1619 | foreach ($potgraders as $t) { |
1620 | if ($t->id == $user->id) { |
1621 | continue; // do not send self |
1622 | } |
1623 | if (groups_is_member($group->id, $t->id)) { |
1624 | $graders[$t->id] = $t; |
1625 | } |
1626 | } |
1627 | } |
1628 | } else { |
1629 | // user not in group, try to find graders without group |
1630 | foreach ($potgraders as $t) { |
1631 | if ($t->id == $user->id) { |
1632 | continue; // do not send self |
1633 | } |
2c386f82 |
1634 | if (!groups_get_all_groups($this->course->id, $t->id)) { //ugly hack |
413efd22 |
1635 | $graders[$t->id] = $t; |
1636 | } |
1637 | } |
1638 | } |
1639 | } else { |
1640 | foreach ($potgraders as $t) { |
1641 | if ($t->id == $user->id) { |
1642 | continue; // do not send self |
1643 | } |
1644 | $graders[$t->id] = $t; |
1645 | } |
1646 | } |
1647 | return $graders; |
1648 | } |
1649 | |
7af1e882 |
1650 | /** |
1651 | * Creates the text content for emails to teachers |
1652 | * |
1653 | * @param $info object The info used by the 'emailteachermail' language string |
1654 | * @return string |
1655 | */ |
d8199f1d |
1656 | function email_teachers_text($info) { |
413efd22 |
1657 | $posttext = format_string($this->course->shortname).' -> '.$this->strassignments.' -> '. |
1658 | format_string($this->assignment->name)."\n"; |
d8199f1d |
1659 | $posttext .= '---------------------------------------------------------------------'."\n"; |
1660 | $posttext .= get_string("emailteachermail", "assignment", $info)."\n"; |
73963212 |
1661 | $posttext .= "\n---------------------------------------------------------------------\n"; |
d8199f1d |
1662 | return $posttext; |
1663 | } |
1664 | |
7af1e882 |
1665 | /** |
1666 | * Creates the html content for emails to teachers |
1667 | * |
1668 | * @param $info object The info used by the 'emailteachermailhtml' language string |
1669 | * @return string |
1670 | */ |
d8199f1d |
1671 | function email_teachers_html($info) { |
3554b5c2 |
1672 | global $CFG; |
d8199f1d |
1673 | $posthtml = '<p><font face="sans-serif">'. |
413efd22 |
1674 | '<a href="'.$CFG->wwwroot.'/course/view.php?id='.$this->course->id.'">'.format_string($this->course->shortname).'</a> ->'. |
d8199f1d |
1675 | '<a href="'.$CFG->wwwroot.'/mod/assignment/index.php?id='.$this->course->id.'">'.$this->strassignments.'</a> ->'. |
413efd22 |
1676 | '<a href="'.$CFG->wwwroot.'/mod/assignment/view.php?id='.$this->cm->id.'">'.format_string($this->assignment->name).'</a></font></p>'; |
d8199f1d |
1677 | $posthtml .= '<hr /><font face="sans-serif">'; |
1678 | $posthtml .= '<p>'.get_string('emailteachermailhtml', 'assignment', $info).'</p>'; |
1679 | $posthtml .= '</font><hr />'; |
815b5ca6 |
1680 | return $posthtml; |
d8199f1d |
1681 | } |
1682 | |
7af1e882 |
1683 | /** |
1684 | * Produces a list of links to the files uploaded by a user |
1685 | * |
1686 | * @param $userid int optional id of the user. If 0 then $USER->id is used. |
1687 | * @param $return boolean optional defaults to false. If true the list is returned rather than printed |
1688 | * @return string optional |
1689 | */ |
d8199f1d |
1690 | function print_user_files($userid=0, $return=false) { |
d8199f1d |
1691 | global $CFG, $USER; |
45fa3412 |
1692 | |
d8199f1d |
1693 | if (!$userid) { |
1694 | if (!isloggedin()) { |
1695 | return ''; |
1696 | } |
1697 | $userid = $USER->id; |
1698 | } |
45fa3412 |
1699 | |
73097f07 |
1700 | $output = ''; |
45fa3412 |
1701 | |
172dd12c |
1702 | $fs = get_file_storage(); |
1703 | $browser = get_file_browser(); |
1704 | |
1705 | $found = false; |
1706 | |
1707 | if ($files = $fs->get_area_files($this->context->id, 'assignment_submission', $userid, "timemodified", false)) { |
1708 | $p = array( |
172dd12c |
1709 | 'assignmentid' => $this->cm->id, |
1710 | ); |
1711 | foreach ($files as $file) { |
1712 | $filename = $file->get_filename(); |
1713 | $found = true; |
1714 | $mimetype = $file->get_mimetype(); |
1715 | $icon = mimeinfo_from_type('icon', $mimetype); |
1716 | $path = $browser->encodepath($CFG->wwwroot.'/pluginfile.php', '/'.$this->context->id.'/assignment_submission/'.$userid.'/'.$filename); |
1717 | $output .= '<a href="'.$path.'" ><img src="'.$CFG->pixpath.'/f/'.$icon.'" class="icon" alt="'.$icon.'" />'.s($filename).'</a>'; |
728e1931 |
1718 | if ($this->portfolio_exportable() && has_capability('mod/assignment:exportownsubmission', $this->context)) { |
d67bfc32 |
1719 | $p['file'] = $file->get_id(); |
866d543f |
1720 | $output .= portfolio_add_button('assignment_portfolio_caller', $p, null, PORTFOLIO_ADD_ICON_LINK, null, true); |
73097f07 |
1721 | } |
172dd12c |
1722 | $output .= '<br />'; |
1723 | } |
728e1931 |
1724 | if ($this->portfolio_exportable() && has_capability('mod/assignment:exportownsubmission', $this->context)) { |
172dd12c |
1725 | unset($p['file']);// for all files |
866d543f |
1726 | $output .= '<br />' . portfolio_add_button('assignment_portfolio_caller', $p, null, PORTFOLIO_ADD_FULL_FORM, null, true); |
73097f07 |
1727 | } |
1728 | } |
1729 | |
1730 | $output = '<div class="files">'.$output.'</div>'; |
1731 | |
1732 | if ($return) { |
1733 | return $output; |
1734 | } |
1735 | echo $output; |
1736 | } |
1737 | |
7af1e882 |
1738 | /** |
1739 | * Count the files uploaded by a given user |
1740 | * |
1741 | * @param $userid int The user id |
1742 | * @return int |
1743 | */ |
70b2c772 |
1744 | function count_user_files($userid) { |
172dd12c |
1745 | $fs = get_file_storage(); |
1746 | $files = $fs->get_area_files($this->context->id, 'assignment_submission', $userid, "id", false); |
1747 | return count($files); |
73097f07 |
1748 | } |
1749 | |
7af1e882 |
1750 | /** |
1751 | * Returns true if the student is allowed to submit |
1752 | * |
1753 | * Checks that the assignment has started and, if the option to prevent late |
1754 | * submissions is set, also checks that the assignment has not yet closed. |
1755 | * @return boolean |
1756 | */ |
f77cfb73 |
1757 | function isopen() { |
1758 | $time = time(); |
1e4343a0 |
1759 | if ($this->assignment->preventlate && $this->assignment->timedue) { |
f77cfb73 |
1760 | return ($this->assignment->timeavailable <= $time && $time <= $this->assignment->timedue); |
1761 | } else { |
1762 | return ($this->assignment->timeavailable <= $time); |
1763 | } |
1764 | } |
1765 | |
0b5a80a1 |
1766 | |
1767 | /** |
dc6cb74e |
1768 | * Return true if is set description is hidden till available date |
1769 | * |
0b5a80a1 |
1770 | * This is needed by calendar so that hidden descriptions do not |
dc6cb74e |
1771 | * come up in upcoming events. |
1772 | * |
0b5a80a1 |
1773 | * Check that description is hidden till available date |
dc6cb74e |
1774 | * By default return false |
1775 | * Assignments types should implement this method if needed |
1776 | * @return boolen |
0b5a80a1 |
1777 | */ |
dc6cb74e |
1778 | function description_is_hidden() { |
1779 | return false; |
1780 | } |
1781 | |
7af1e882 |
1782 | /** |
1783 | * Return an outline of the user's interaction with the assignment |
1784 | * |
1785 | * The default method prints the grade and timemodified |
1786 | * @param $user object |
1787 | * @return object with properties ->info and ->time |
1788 | */ |
73097f07 |
1789 | function user_outline($user) { |
1790 | if ($submission = $this->get_submission($user->id)) { |
39e11905 |
1791 | |
98be6ed8 |
1792 | $result = new object(); |
39e11905 |
1793 | $result->info = get_string('grade').': '.$this->display_grade($submission->grade); |
73097f07 |
1794 | $result->time = $submission->timemodified; |
1795 | return $result; |
1796 | } |
1797 | return NULL; |
1798 | } |
7af1e882 |
1799 | |
1800 | /** |
1801 | * Print complete information about the user's interaction with the assignment |
1802 | * |
1803 | * @param $user object |
1804 | */ |
73097f07 |
1805 | function user_complete($user) { |
1806 | if ($submission = $this->get_submission($user->id)) { |
172dd12c |
1807 | |
1808 | $fs = get_file_storage(); |
1809 | $browser = get_file_browser(); |
26a9dc72 |
1810 | |
172dd12c |
1811 | if ($files = $fs->get_area_files($this->context->id, 'assignment_submission', $user->id, "timemodified", false)) { |
1812 | $countfiles = count($files)." ".get_string("uploadedfiles", "assignment"); |
1813 | foreach ($files as $file) { |
1814 | $countfiles .= "; ".$file->get_filename(); |
73097f07 |
1815 | } |
1816 | } |
45fa3412 |
1817 | |
73097f07 |
1818 | print_simple_box_start(); |
1819 | echo get_string("lastmodified").": "; |
9bf660b3 |
1820 | echo userdate($submission->timemodified); |
1821 | echo $this->display_lateness($submission->timemodified); |
45fa3412 |
1822 | |
70b2c772 |
1823 | $this->print_user_files($user->id); |
45fa3412 |
1824 | |
73097f07 |
1825 | echo '<br />'; |
45fa3412 |
1826 | |
73097f07 |
1827 | if (empty($submission->timemarked)) { |
1828 | print_string("notgradedyet", "assignment"); |
1829 | } else { |
1830 | $this->view_feedback($submission); |
1831 | } |
45fa3412 |
1832 | |
73097f07 |
1833 | print_simple_box_end(); |
45fa3412 |
1834 | |
73097f07 |
1835 | } else { |
1836 | print_string("notsubmittedyet", "assignment"); |
1837 | } |
1838 | } |
1839 | |
7af1e882 |
1840 | /** |
1841 | * Return a string indicating how late a submission is |
1842 | * |
45fa3412 |
1843 | * @param $timesubmitted int |
7af1e882 |
1844 | * @return string |
1845 | */ |
70b2c772 |
1846 | function display_lateness($timesubmitted) { |
76a60031 |
1847 | return assignment_display_lateness($timesubmitted, $this->assignment->timedue); |
73097f07 |
1848 | } |
1849 | |
55b4d096 |
1850 | /** |
1851 | * Empty method stub for all delete actions. |
1852 | */ |
1853 | function delete() { |
1854 | //nothing by default |
1855 | redirect('view.php?id='.$this->cm->id); |
1856 | } |
1857 | |
1858 | /** |
1859 | * Empty custom feedback grading form. |
1860 | */ |
1861 | function custom_feedbackform($submission, $return=false) { |
1862 | //nothing by default |
1863 | return ''; |
1864 | } |
73097f07 |
1865 | |
09ba8e56 |
1866 | /** |
1867 | * Add a get_coursemodule_info function in case any assignment type wants to add 'extra' information |
1868 | * for the course (see resource). |
1869 | * |
206ab184 |
1870 | * Given a course_module object, this function returns any "extra" information that may be needed |
09ba8e56 |
1871 | * when printing this activity in a course listing. See get_array_of_activities() in course/lib.php. |
206ab184 |
1872 | * |
09ba8e56 |
1873 | * @param $coursemodule object The coursemodule object (record). |
1874 | * @return object An object on information that the coures will know about (most noticeably, an icon). |
206ab184 |
1875 | * |
09ba8e56 |
1876 | */ |
1877 | function get_coursemodule_info($coursemodule) { |
1878 | return false; |
1879 | } |
1880 | |
d014b69b |
1881 | /** |
1882 | * Plugin cron method - do not use $this here, create new assignment instances if needed. |
1883 | * @return void |
1884 | */ |
1885 | function cron() { |
1886 | //no plugin cron by default - override if needed |
1887 | } |
1888 | |
0b5a80a1 |
1889 | /** |
1890 | * Reset all submissions |
1891 | */ |
1892 | function reset_userdata($data) { |
5053f00f |
1893 | global $CFG, $DB; |
0b5a80a1 |
1894 | |
74d7d735 |
1895 | if (!$DB->count_records('assignment', array('course'=>$data->courseid, 'assignmenttype'=>$this->type))) { |
0b5a80a1 |
1896 | return array(); // no assignments of this type present |
1897 | } |
1898 | |
1899 | $componentstr = get_string('modulenameplural', 'assignment'); |
1900 | $status = array(); |
1901 | |
1902 | $typestr = get_string('type'.$this->type, 'assignment'); |
1903 | |
1904 | if (!empty($data->reset_assignment_submissions)) { |
1905 | $assignmentssql = "SELECT a.id |
5053f00f |
1906 | FROM {assignment} a |
1907 | WHERE a.course=? AND a.assignmenttype=?"; |
1908 | $params = array($data->courseid, $this->type); |
0b5a80a1 |
1909 | |
75dfe830 |
1910 | // now get rid of all submissions and responses |
4e866d5e |
1911 | $fs = get_file_storage(); |
5053f00f |
1912 | if ($assignments = $DB->get_records_sql($assignmentssql, $params)) { |
0b5a80a1 |
1913 | foreach ($assignments as $assignmentid=>$unused) { |
4e866d5e |
1914 | if (!$cm = get_coursemodule_from_instance('assignment', $assignmentid)) { |
1915 | continue; |
1916 | } |
1917 | $context = get_context_instance(CONTEXT_MODULE, $cm->id); |
1918 | $fs->delete_area_files($context->id, 'assignment_submission'); |
1919 | $fs->delete_area_files($context->id, 'assignment_response'); |
0b5a80a1 |
1920 | } |
1921 | } |
1922 | |
75dfe830 |
1923 | $DB->delete_records_select('assignment_submissions', "assignment IN ($assignmentssql)", $params); |
1924 | |
0b5a80a1 |
1925 | $status[] = array('component'=>$componentstr, 'item'=>get_string('deleteallsubmissions','assignment').': '.$typestr, 'error'=>false); |
dd97c328 |
1926 | |
0b5a80a1 |
1927 | if (empty($data->reset_gradebook_grades)) { |
1928 | // remove all grades from gradebook |
1929 | assignment_reset_gradebook($data->courseid, $this->type); |
1930 | } |
1931 | } |
1932 | |
1933 | /// updating dates - shift may be negative too |
1934 | if ($data->timeshift) { |
1935 | shift_course_mod_dates('assignment', array('timedue', 'timeavailable'), $data->timeshift, $data->courseid); |
1936 | $status[] = array('component'=>$componentstr, 'item'=>get_string('datechanged').': '.$typestr, 'error'=>false); |
1937 | } |
1938 | |
1939 | return $status; |
1940 | } |
67a87e7d |
1941 | |
1942 | |
1943 | function portfolio_exportable() { |
1944 | return false; |
1945 | } |
b0f2597e |
1946 | } ////// End of the assignment_base class |
d699cd1e |
1947 | |
172dd12c |
1948 | class mod_assignment_upload_file_form extends moodleform { |
1949 | function definition() { |
1950 | $mform = $this->_form; |
1951 | $instance = $this->_customdata; |
1952 | |
1953 | //TODO: improve upload size checking |
1954 | $mform->setMaxFileSize($instance->assignment->maxbytes); |
1955 | |
1956 | // visible elements |
1957 | $mform->addElement('file', 'newfile', get_string('uploadafile')); |
1958 | |
1959 | // hidden params |
1960 | $mform->addElement('hidden', 'id', $instance->cm->id); |
1961 | $mform->setType('id', PARAM_INT); |
1962 | $mform->addElement('hidden', 'action', 'uploadfile'); |
1963 | $mform->setType('action', PARAM_ALPHA); |
1964 | |
1965 | // buttons |
1966 | $this->add_action_buttons(false, get_string('uploadthisfile')); |
1967 | } |
1968 | } |
18b8fbfa |
1969 | |
04eba58f |
1970 | |
b0f2597e |
1971 | /// OTHER STANDARD FUNCTIONS //////////////////////////////////////////////////////// |
1972 | |
26a9dc72 |
1973 | /** |
3b120e46 |
1974 | * Code to be executed when a module is installed |
26a9dc72 |
1975 | */ |
3b120e46 |
1976 | function assignment_install() { |
26a9dc72 |
1977 | return true; |
3b120e46 |
1978 | } |
1979 | |
7af1e882 |
1980 | /** |
1981 | * Deletes an assignment instance |
1982 | * |
1983 | * This is done by calling the delete_instance() method of the assignment type class |
1984 | */ |
b0f2597e |
1985 | function assignment_delete_instance($id){ |
c18269c7 |
1986 | global $CFG, $DB; |
26b90e70 |
1987 | |
c18269c7 |
1988 | if (! $assignment = $DB->get_record('assignment', array('id'=>$id))) { |
b0f2597e |
1989 | return false; |
26b90e70 |
1990 | } |
1991 | |
1fc87774 |
1992 | // fall back to base class if plugin missing |
1993 | $classfile = "$CFG->dirroot/mod/assignment/type/$assignment->assignmenttype/assignment.class.php"; |
1994 | if (file_exists($classfile)) { |
1995 | require_once($classfile); |
1996 | $assignmentclass = "assignment_$assignment->assignmenttype"; |
1997 | |
1998 | } else { |
1999 | debugging("Missing assignment plug-in: {$assignment->assignmenttype}. Using base class for deleting instead."); |
2000 | $assignmentclass = "assignment_base"; |
2001 | } |
2002 | |
b0f2597e |
2003 | $ass = new $assignmentclass(); |
2004 | return $ass->delete_instance($assignment); |
2005 | } |
f466c9ed |
2006 | |
ac21ad39 |
2007 | |
7af1e882 |
2008 | /** |
2009 | * Updates an assignment instance |
2010 | * |
2011 | * This is done by calling the update_instance() method of the assignment type class |
2012 | */ |
b0f2597e |
2013 | function assignment_update_instance($assignment){ |
2014 | global $CFG; |
26b90e70 |
2015 | |
200c19fb |
2016 | $assignment->assignmenttype = clean_param($assignment->assignmenttype, PARAM_SAFEDIR); |
2017 | |
b0f2597e |
2018 | require_once("$CFG->dirroot/mod/assignment/type/$assignment->assignmenttype/assignment.class.php"); |
2019 | $assignmentclass = "assignment_$assignment->assignmenttype"; |
2020 | $ass = new $assignmentclass(); |
2021 | return $ass->update_instance($assignment); |
45fa3412 |
2022 | } |
26b90e70 |
2023 | |
26b90e70 |
2024 | |
7af1e882 |
2025 | /** |
2026 | * Adds an assignment instance |
2027 | * |
2028 | * This is done by calling the add_instance() method of the assignment type class |
2029 | */ |
b0f2597e |
2030 | function assignment_add_instance($assignment) { |
2031 | global $CFG; |
f466c9ed |
2032 | |
200c19fb |
2033 | $assignment->assignmenttype = clean_param($assignment->assignmenttype, PARAM_SAFEDIR); |
2034 | |
b0f2597e |
2035 | require_once("$CFG->dirroot/mod/assignment/type/$assignment->assignmenttype/assignment.class.php"); |
2036 | $assignmentclass = "assignment_$assignment->assignmenttype"; |
2037 | $ass = new $assignmentclass(); |
2038 | return $ass->add_instance($assignment); |
2039 | } |
f466c9ed |
2040 | |
73097f07 |
2041 | |
7af1e882 |
2042 | /** |
2043 | * Returns an outline of a user interaction with an assignment |
2044 | * |
2045 | * This is done by calling the user_outline() method of the assignment type class |
2046 | */ |
73097f07 |
2047 | function assignment_user_outline($course, $user, $mod, $assignment) { |
2048 | global $CFG; |
2049 | |
2050 | require_once("$CFG->dirroot/mod/assignment/type/$assignment->assignmenttype/assignment.class.php"); |
2051 | $assignmentclass = "assignment_$assignment->assignmenttype"; |
2052 | $ass = new $assignmentclass($mod->id, $assignment, $mod, $course); |
2053 | return $ass->user_outline($user); |
2054 | } |
2055 | |
7af1e882 |
2056 | /** |
2057 | * Prints the complete info about a user's interaction with an assignment |
2058 | * |
2059 | * This is done by calling the user_complete() method of the assignment type class |
2060 | */ |
73097f07 |
2061 | function assignment_user_complete($course, $user, $mod, $assignment) { |
2062 | global $CFG; |
2063 | |
2064 | require_once("$CFG->dirroot/mod/assignment/type/$assignment->assignmenttype/assignment.class.php"); |
2065 | $assignmentclass = "assignment_$assignment->assignmenttype"; |
2066 | $ass = new $assignmentclass($mod->id, $assignment, $mod, $course); |
2067 | return $ass->user_complete($user); |
2068 | } |
2069 | |
7af1e882 |
2070 | /** |
2071 | * Function to be run periodically according to the moodle cron |
2072 | * |
2073 | * Finds all assignment notifications that have yet to be mailed out, and mails them |
2074 | */ |
73097f07 |
2075 | function assignment_cron () { |
5053f00f |
2076 | global $CFG, $USER, $DB; |
73097f07 |
2077 | |
d014b69b |
2078 | /// first execute all crons in plugins |
2079 | if ($plugins = get_list_of_plugins('mod/assignment/type')) { |
2080 | foreach ($plugins as $plugin) { |
2081 | require_once("$CFG->dirroot/mod/assignment/type/$plugin/assignment.class.php"); |
2082 | $assignmentclass = "assignment_$plugin"; |
2083 | $ass = new $assignmentclass(); |
2084 | $ass->cron(); |
2085 | } |
2086 | } |
2087 | |
73097f07 |
2088 | /// Notices older than 1 day will not be mailed. This is to avoid the problem where |
2089 | /// cron has not been running for a long time, and then suddenly people are flooded |
2090 | /// with mail from the past few weeks or months |
2091 | |
2092 | $timenow = time(); |
2093 | $endtime = $timenow - $CFG->maxeditingtime; |
2094 | $starttime = $endtime - 24 * 3600; /// One day earlier |
2095 | |
2096 | if ($submissions = assignment_get_unmailed_submissions($starttime, $endtime)) { |
2097 | |
98be6ed8 |
2098 | $realuser = clone($USER); |
2099 | |
73097f07 |
2100 | foreach ($submissions as $key => $submission) { |
5053f00f |
2101 | if (! $DB->set_field("assignment_submissions", "mailed", "1", array("id"=>$submission->id))) { |
73097f07 |
2102 | echo "Could not update the mailed field for id $submission->id. Not mailed.\n"; |
2103 | unset($submissions[$key]); |
2104 | } |
2105 | } |
2106 | |
2107 | $timenow = time(); |
2108 | |
2109 | foreach ($submissions as $submission) { |
2110 | |
2111 | echo "Processing assignment submission $submission->id\n"; |
2112 | |
5053f00f |
2113 | if (! $user = $DB->get_record("user", array("id"=>$submission->userid))) { |
73097f07 |
2114 | echo "Could not find user $post->userid\n"; |
2115 | continue; |
2116 | } |
2117 | |
5053f00f |
2118 | if (! $course = $DB->get_record("course", array("id"=>$submission->course))) { |
73097f07 |
2119 | echo "Could not find course $submission->course\n"; |
2120 | continue; |
2121 | } |
98be6ed8 |
2122 | |
2123 | /// Override the language and timezone of the "current" user, so that |
2124 | /// mail is customised for the receiver. |
2125 | $USER = $user; |
2126 | course_setup($course); |
2127 | |
dbbb712e |
2128 | if (!has_capability('moodle/course:view', get_context_instance(CONTEXT_COURSE, $submission->course), $user->id)) { |
6ba65fa0 |
2129 | echo fullname($user)." not an active participant in " . format_string($course->shortname) . "\n"; |
73097f07 |
2130 | continue; |
2131 | } |
2132 | |
5053f00f |
2133 | if (! $teacher = $DB->get_record("user", array("id"=>$submission->teacher))) { |
73097f07 |
2134 | echo "Could not find teacher $submission->teacher\n"; |
2135 | continue; |
2136 | } |
2137 | |
2138 | if (! $mod = get_coursemodule_from_instance("assignment", $submission->assignment, $course->id)) { |
2139 | echo "Could not find course module for assignment id $submission->assignment\n"; |
2140 | continue; |
2141 | } |
2142 | |
2143 | if (! $mod->visible) { /// Hold mail notification for hidden assignments until later |
2144 | continue; |
2145 | } |
2146 | |
2147 | $strassignments = get_string("modulenameplural", "assignment"); |
2148 | $strassignment = get_string("modulename", "assignment"); |
2149 | |
98be6ed8 |
2150 | $assignmentinfo = new object(); |
73097f07 |
2151 | $assignmentinfo->teacher = fullname($teacher); |
2152 | $assignmentinfo->assignment = format_string($submission->name,true); |
2153 | $assignmentinfo->url = "$CFG->wwwroot/mod/assignment/view.php?id=$mod->id"; |
2154 | |
2155 | $postsubject = "$course->shortname: $strassignments: ".format_string($submission->name,true); |
2156 | $posttext = "$course->shortname -> $strassignments -> ".format_string($submission->name,true)."\n"; |
2157 | $posttext .= "---------------------------------------------------------------------\n"; |
3f19bff3 |
2158 | $posttext .= get_string("assignmentmail", "assignment", $assignmentinfo)."\n"; |
73097f07 |
2159 | $posttext .= "---------------------------------------------------------------------\n"; |
2160 | |
2161 | if ($user->mailformat == 1) { // HTML |
2162 | $posthtml = "<p><font face=\"sans-serif\">". |
2163 | "<a href=\"$CFG->wwwroot/course/view.php?id=$course->id\">$course->shortname</a> ->". |
2164 | "<a href=\"$CFG->wwwroot/mod/assignment/index.php?id=$course->id\">$strassignments</a> ->". |
2165 | "<a href=\"$CFG->wwwroot/mod/assignment/view.php?id=$mod->id\">".format_string($submission->name,true)."</a></font></p>"; |
2166 | $posthtml .= "<hr /><font face=\"sans-serif\">"; |
2167 | $posthtml .= "<p>".get_string("assignmentmailhtml", "assignment", $assignmentinfo)."</p>"; |
2168 | $posthtml .= "</font><hr />"; |
2169 | } else { |
2170 | $posthtml = ""; |
2171 | } |
2172 | |
3b120e46 |
2173 | $eventdata = new object(); |
2174 | $eventdata->modulename = 'assignment'; |
2175 | $eventdata->userfrom = $teacher; |
2176 | $eventdata->userto = $user; |
2177 | $eventdata->subject = $postsubject; |
2178 | $eventdata->fullmessage = $posttext; |
2179 | $eventdata->fullmessageformat = FORMAT_PLAIN; |
2180 | $eventdata->fullmessagehtml = $posthtml; |
2181 | $eventdata->smallmessage = ''; |
2182 | if ( events_trigger('message_send', $eventdata) > 0 ){ |
2183 | echo "Error: assignment cron: Could not send out mail for id $submission->id to user $user->id ($user->email)\n"; |
2184 | } |
73097f07 |
2185 | } |
98be6ed8 |
2186 | |
2187 | $USER = $realuser; |
2188 | course_setup(SITEID); // reset cron user language, theme and timezone settings |
2189 | |
73097f07 |
2190 | } |
2191 | |
2192 | return true; |
2193 | } |
2194 | |
45fa3412 |
2195 | /** |
2196 | * Return grade for given user or all users. |
2197 | * |
2198 | * @param int $assignmentid id of assignment |
2199 | * @param int $userid optional user id, 0 means all users |
2200 | * @return array array of grades, false if none |
2201 | */ |
612607bd |
2202 | function assignment_get_user_grades($assignment, $userid=0) { |
5053f00f |
2203 | global $CFG, $DB; |
45fa3412 |
2204 | |
5053f00f |
2205 | if ($userid) { |
2206 | $user = "AND u.id = :userid"; |
2207 | $params = array('userid'=>$userid); |
2208 | } else { |
2209 | $user = ""; |
2210 | } |
2211 | $params['aid'] = $assignment->id; |
45fa3412 |
2212 | |
ced5ee59 |
2213 | $sql = "SELECT u.id, u.id AS userid, s.grade AS rawgrade, s.submissioncomment AS feedback, s.format AS feedbackformat, |
2214 | s.teacher AS usermodified, s.timemarked AS dategraded, s.timemodified AS datesubmitted |
5053f00f |
2215 | FROM {user} u, {assignment_submissions} s |
2216 | WHERE u.id = s.userid AND s.assignment = :aid |
4a1be95c |
2217 | $user"; |
45fa3412 |
2218 | |
5053f00f |
2219 | return $DB->get_records_sql($sql, $params); |
45fa3412 |
2220 | } |
2221 | |
2222 | /** |
775f811a |
2223 | * Update activity grades |
45fa3412 |
2224 | * |
775f811a |
2225 | * @param object $assignment |
2226 | * @param int $userid specific user only, 0 means all |
45fa3412 |
2227 | */ |
775f811a |
2228 | function assignment_update_grades($assignment, $userid=0, $nullifnone=true) { |
5053f00f |
2229 | global $CFG, $DB; |
2230 | require_once($CFG->libdir.'/gradelib.php'); |
45fa3412 |
2231 | |
775f811a |
2232 | if ($assignment->grade == 0) { |
2233 | assignment_grade_item_update($assignment); |
2234 | |
2235 | } else if ($grades = assignment_get_user_grades($assignment, $userid)) { |
2236 | foreach($grades as $k=>$v) { |
2237 | if ($v->rawgrade == -1) { |
2238 | $grades[$k]->rawgrade = null; |
45fa3412 |
2239 | } |
2240 | } |
775f811a |
2241 | assignment_grade_item_update($assignment, $grades); |
45fa3412 |
2242 | |
2243 | } else { |
775f811a |
2244 | assignment_grade_item_update($assignment); |
2245 | } |
2246 | } |
2247 | |
2248 | /** |
2249 | * Update all grades in gradebook. |
2250 | */ |
2251 | function assignment_upgrade_grades() { |
2252 | global $DB; |
2253 | |
2254 | $sql = "SELECT COUNT('x') |
2255 | FROM {assignment} a, {course_modules} cm, {modules} m |
2256 | WHERE m.name='assignment' AND m.id=cm.module AND cm.instance=a.id"; |
2257 | $count = $DB->count_records_sql($sql); |
2258 | |
2259 | $sql = "SELECT a.*, cm.idnumber AS cmidnumber, a.course AS courseid |
2260 | FROM {assignment} a, {course_modules} cm, {modules} m |
2261 | WHERE m.name='assignment' AND m.id=cm.module AND cm.instance=a.id"; |
2262 | if ($rs = $DB->get_recordset_sql($sql)) { |
2263 | // too much debug output |
2264 | $prevdebug = $DB->get_debug(); |
2265 | $DB->set_debug(false); |
2266 | $pbar = new progress_bar('assignmentupgradegrades', 500, true); |
2267 | $i=0; |
2268 | foreach ($rs as $assignment) { |
2269 | $i++; |
2270 | upgrade_set_timeout(60*5); // set up timeout, may also abort execution |
2271 | assignment_update_grades($assignment); |
2272 | $pbar->update($i, $count, "Updating Assignment grades ($i/$count)."); |
2273 | } |
2274 | $DB->set_debug($prevdebug); |
2275 | $rs->close(); |
2276 | upgrade_set_timeout(); // reset to default timeout |
45fa3412 |
2277 | } |
2278 | } |
2279 | |
2280 | /** |
612607bd |
2281 | * Create grade item for given assignment |
45fa3412 |
2282 | * |
8b4fb44e |
2283 | * @param object $assignment object with extra cmidnumber |
0b5a80a1 |
2284 | * @param mixed optional array/object of grade(s); 'reset' means reset grades in gradebook |
612607bd |
2285 | * @return int 0 if ok, error code otherwise |
45fa3412 |
2286 | */ |
ced5ee59 |
2287 | function assignment_grade_item_update($assignment, $grades=NULL) { |
612607bd |
2288 | global $CFG; |
5053f00f |
2289 | require_once($CFG->libdir.'/gradelib.php'); |
45fa3412 |
2290 | |
8b4fb44e |
2291 | if (!isset($assignment->courseid)) { |
2292 | $assignment->courseid = $assignment->course; |
2293 | } |
2294 | |
612607bd |
2295 | $params = array('itemname'=>$assignment->name, 'idnumber'=>$assignment->cmidnumber); |
45fa3412 |
2296 | |
2297 | if ($assignment->grade > 0) { |
2298 | $params['gradetype'] = GRADE_TYPE_VALUE; |
2299 | $params['grademax'] = $assignment->grade; |
2300 | $params['grademin'] = 0; |
2301 | |
2302 | } else if ($assignment->grade < 0) { |
2303 | $params['gradetype'] = GRADE_TYPE_SCALE; |
2304 | $params['scaleid'] = -$assignment->grade; |
2305 | |
2306 | } else { |
5048575d |
2307 | $params['gradetype'] = GRADE_TYPE_TEXT; // allow text comments only |
45fa3412 |
2308 | } |
2309 | |
0b5a80a1 |
2310 | if ($grades === 'reset') { |
2311 | $params['reset'] = true; |
2312 | $grades = NULL; |
2313 | } |
2314 | |
ced5ee59 |
2315 | return grade_update('mod/assignment', $assignment->courseid, 'mod', 'assignment', $assignment->id, 0, $grades, $params); |
45fa3412 |
2316 | } |
2317 | |
2318 | /** |
2319 | * Delete grade item for given assignment |
2320 | * |
8b4fb44e |
2321 | * @param object $assignment object |
612607bd |
2322 | * @return object assignment |
45fa3412 |
2323 | */ |
2324 | function assignment_grade_item_delete($assignment) { |
612607bd |
2325 | global $CFG; |
2326 | require_once($CFG->libdir.'/gradelib.php'); |
2327 | |
8b4fb44e |
2328 | if (!isset($assignment->courseid)) { |
2329 | $assignment->courseid = $assignment->course; |
2330 | } |
2331 | |
b67ec72f |
2332 | return grade_update('mod/assignment', $assignment->courseid, 'mod', 'assignment', $assignment->id, 0, NULL, array('deleted'=>1)); |
45fa3412 |
2333 | } |
2334 | |
7af1e882 |
2335 | /** |
2336 | * Returns the users with data in one assignment (students and teachers) |
2337 | * |
2338 | * @param $assignmentid int |
2339 | * @return array of user objects |
2340 | */ |
73097f07 |
2341 | function assignment_get_participants($assignmentid) { |
5053f00f |
2342 | global $CFG, $DB; |
73097f07 |
2343 | |
2344 | //Get students |
5053f00f |
2345 | $students = $DB->get_records_sql("SELECT DISTINCT u.id, u.id |
2346 | FROM {user} u, |
2347 | {assignment_submissions} a |
2348 | WHERE a.assignment = ? and |
2349 | u.id = a.userid", array($assignmentid)); |
73097f07 |
2350 | //Get teachers |
5053f00f |
2351 | $teachers = $DB->get_records_sql("SELECT DISTINCT u.id, u.id |
2352 | FROM {user} u, |
2353 | {assignment_submissions} a |
2354 | WHERE a.assignment = ? and |
2355 | u.id = a.teacher", array($assignmentid)); |
73097f07 |
2356 | |
2357 | //Add teachers to students |
2358 | if ($teachers) { |
2359 | foreach ($teachers as $teacher) { |
2360 | $students[$teacher->id] = $teacher; |
2361 | } |
2362 | } |
2363 | //Return students array (it contains an array of unique users) |
2364 | return ($students); |
2365 | } |
2366 | |
172dd12c |
2367 | function assignment_pluginfile($course, $cminfo, $context, $filearea, $args) { |
2368 | global $CFG, $DB; |
2369 | |
2370 | if (!$assignment = $DB->get_record('assignment', array('id'=>$cminfo->instance))) { |
2371 | return false; |
2372 | } |
2373 | if (!$cm = get_coursemodule_from_instance('assignment', $assignment->id, $course->id)) { |
2374 | return false; |
2375 | } |
2376 | |
2377 | require_once($CFG->dirroot.'/mod/assignment/type/'.$assignment->assignmenttype.'/assignment.class.php'); |
2378 | $assignmentclass = 'assignment_'.$assignment->assignmenttype; |
2379 | $assignmentinstance = new $assignmentclass($cm->id, $assignment, $cm, $course); |
2380 | |
2381 | return $assignmentinstance->send_file($filearea, $args); |
2382 | } |
7af1e882 |
2383 | /** |
2384 | * Checks if a scale is being used by an assignment |
2385 | * |
2386 | * This is used by the backup code to decide whether to back up a scale |
2387 | * @param $assignmentid int |
2388 | * @param $scaleid int |
2389 | * @return boolean True if the scale is used by the assignment |
2390 | */ |
85c9ebb9 |
2391 | function assignment_scale_used($assignmentid, $scaleid) { |
5053f00f |
2392 | global $DB; |
73097f07 |
2393 | |
2394 | $return = false; |
2395 | |
5053f00f |
2396 | $rec = $DB->get_record('assignment', array('id'=>$assignmentid,'grade'=>-$scaleid)); |
73097f07 |
2397 | |
2398 | if (!empty($rec) && !empty($scaleid)) { |
2399 | $return = true; |
2400 | } |
2401 | |
2402 | return $return; |
2403 | } |
2404 | |
85c9ebb9 |
2405 | /** |
2406 | * Checks if scale is being used by any instance of assignment |
2407 | * |
2408 | * This is used to find out if scale used anywhere |
2409 | * @param $scaleid int |
2410 | * @return boolean True if the scale is used by any assignment |
2411 | */ |
2412 | function assignment_scale_used_anywhere($scaleid) { |
5053f00f |
2413 | global $DB; |
2414 | |
2415 | if ($scaleid and $DB->record_exists('assignment', array('grade'=>-$scaleid))) { |
85c9ebb9 |
2416 | return true; |
2417 | } else { |
2418 | return false; |
2419 | } |
2420 | } |
2421 | |
7af1e882 |
2422 | /** |
2423 | * Make sure up-to-date events are created for all assignment instances |
2424 | * |
2425 | * This standard function will check all instances of this module |
2426 | * and make sure there are up-to-date events created for each of them. |
2427 | * If courseid = 0, then every assignment event in the site is checked, else |
2428 | * only assignment events belonging to the course specified are checked. |
2429 | * This function is used, in its new format, by restore_refresh_events() |
2430 | * |
2431 | * @param $courseid int optional If zero then all assignments for all courses are covered |
2432 | * @return boolean Always returns true |
2433 | */ |
73097f07 |
2434 | function assignment_refresh_events($courseid = 0) { |
5053f00f |
2435 | global $DB; |
73097f07 |
2436 | |
2437 | if ($courseid == 0) { |
5053f00f |
2438 | if (! $assignments = $DB->get_records("assignment")) { |
73097f07 |
2439 | return true; |
2440 | } |
2441 | } else { |
5053f00f |
2442 | if (! $assignments = $DB->get_records("assignment", array("course"=>$courseid))) { |
73097f07 |
2443 | return true; |
2444 | } |
2445 | } |
5053f00f |
2446 | $moduleid = $DB->get_field('modules', 'id', array('name'=>'assignment')); |
73097f07 |
2447 | |
2448 | foreach ($assignments as $assignment) { |
2449 | $event = NULL; |
5053f00f |
2450 | $event->name = $assignment->name; |
2451 | $event->description = $assignment->description; |
73097f07 |
2452 | $event->timestart = $assignment->timedue; |
2453 | |
5053f00f |
2454 | if ($event->id = $DB->get_field('event', 'id', array('modulename'=>'assignment', 'instance'=>$assignment->id))) { |
73097f07 |
2455 | update_event($event); |
2456 | |
2457 | } else { |
2458 | $event->courseid = $assignment->course; |
2459 | $event->groupid = 0; |
2460 | $event->userid = 0; |
2461 | $event->modulename = 'assignment'; |
2462 | $event->instance = $assignment->id; |
2463 | $event->eventtype = 'due'; |
2464 | $event->timeduration = 0; |
5053f00f |
2465 | $event->visible = $DB->get_field('course_modules', 'visible', array('module'=>$moduleid, 'instance'=>$assignment->id)); |
73097f07 |
2466 | add_event($event); |
2467 | } |
2468 | |
2469 | } |
2470 | return true; |
2471 | } |
2472 | |
7af1e882 |
2473 | /** |
2474 | * Print recent activity from all assignments in a given course |
2475 | * |
2476 | * This is used by the recent activity block |
2477 | */ |
dd97c328 |
2478 | function assignment_print_recent_activity($course, $viewfullnames, $timestart) { |
5053f00f |
2479 | global $CFG, $USER, $DB; |
73097f07 |
2480 | |
dd97c328 |
2481 | // do not use log table if possible, it may be huge |
73097f07 |
2482 | |
74d7d735 |
2483 | if (!$submissions = $DB->get_records_sql("SELECT asb.id, asb.timemodified, cm.id AS cmid, asb.userid, |
2484 | u.firstname, u.lastname, u.email, u.picture |
2485 | FROM {assignment_submissions} asb |
2486 | JOIN {assignment} a ON a.id = asb.assignment |
2487 | JOIN {course_modules} cm ON cm.instance = a.id |
2488 | JOIN {modules} md ON md.id = cm.module |
2489 | JOIN {user} u ON u.id = asb.userid |
2490 | WHERE asb.timemodified > ? AND |
2491 | a.course = ? AND |
2492 | md.name = 'assignment' |
2493 | ORDER BY asb.timemodified ASC", array($timestart, $course->id))) { |
dd97c328 |
2494 | return false; |
73097f07 |
2495 | } |
2496 | |
dd97c328 |
2497 | $modinfo =& get_fast_modinfo($course); // reference needed because we might load the groups |
2498 | $show = array(); |
2499 | $grader = array(); |
2500 | |
2501 | foreach($submissions as $submission) { |
2502 | if (!array_key_exists($submission->cmid, $modinfo->cms)) { |
2503 | continue; |
2504 | } |
2505 | $cm = $modinfo->cms[$submission->cmid]; |
2506 | if (!$cm->uservisible) { |
2507 | continue; |
2508 | } |
2509 | if ($submission->userid == $USER->id) { |
2510 | $show[] = $submission; |
2511 | continue; |
2512 | } |
2513 | |
1160eb5a |
2514 | // the act of sumbitting of assignment may be considered private - only graders will see it if specified |
dd97c328 |
2515 | if (empty($CFG->assignment_showrecentsubmissions)) { |
2516 | if (!array_key_exists($cm->id, $grader)) { |
2517 | $grader[$cm->id] = has_capability('moodle/grade:viewall', get_context_instance(CONTEXT_MODULE, $cm->id)); |
2518 | } |
2519 | if (!$grader[$cm->id]) { |
2520 | continue; |
70b5660a |
2521 | } |
73097f07 |
2522 | } |
73097f07 |
2523 | |
dd97c328 |
2524 | $groupmode = groups_get_activity_groupmode($cm, $course); |
2525 | |
2526 | if ($groupmode == SEPARATEGROUPS and !has_capability('moodle/site:accessallgroups', get_context_instance(CONTEXT_MODULE, $cm->id))) { |
2527 | if (isguestuser()) { |
2528 | // shortcut - guest user does not belong into any group |
2529 | continue; |
2530 | } |
2531 | |
2532 | if (is_null($modinfo->groups)) { |
2533 | $modinfo->groups = groups_get_user_groups($course->id); // load all my groups and cache it in modinfo |
2534 | } |
2535 | |
2536 | // this will be slow - show only users that share group with me in this cm |
2537 | if (empty($modinfo->groups[$cm->id])) { |
2538 | continue; |
2539 | } |
2540 | $usersgroups = groups_get_all_groups($course->id, $cm->userid, $cm->groupingid); |
2541 | if (is_array($usersgroups)) { |
2542 | $usersgroups = array_keys($usersgroups); |
2543 | $interset = array_intersect($usersgroups, $modinfo->groups[$cm->id]); |
2544 | if (empty($intersect)) { |
2545 | continue; |
2546 | } |
2547 | } |
73097f07 |
2548 | } |
dd97c328 |
2549 | $show[] = $submission; |
73097f07 |
2550 | } |
2551 | |
dd97c328 |
2552 | if (empty($show)) { |
2553 | return false; |
2554 | } |
2555 | |
2556 | print_headline(get_string('newsubmissions', 'assignment').':'); |
2557 | |
2558 | foreach ($show as $submission) { |
2559 | $cm = $modinfo->cms[$submission->cmid]; |
2560 | $link = $CFG->wwwroot.'/mod/assignment/view.php?id='.$cm->id; |
2561 | print_recent_activity_note($submission->timemodified, $submission, $cm->name, $link, false, $viewfullnames); |
2562 | } |
2563 | |
2564 | return true; |
73097f07 |
2565 | } |
2566 | |
2567 | |
7af1e882 |
2568 | /** |
dd97c328 |
2569 | * Returns all assignments since a given time in specified forum. |
7af1e882 |
2570 | */ |
dd97c328 |
2571 | function assignment_get_recent_mod_activity(&$activities, &$index, $timestart, $courseid, $cmid, $userid=0, $groupid=0) { |
5053f00f |
2572 | global $CFG, $COURSE, $USER, $DB; |
73097f07 |
2573 | |
dd97c328 |
2574 | if ($COURSE->id == $courseid) { |
2575 | $course = $COURSE; |
73097f07 |
2576 | } else { |
5053f00f |
2577 | $course = $DB->get_record('course', array('id'=>$courseid)); |
73097f07 |
2578 | } |
dd97c328 |
2579 | |
2580 | $modinfo =& get_fast_modinfo($course); |
2581 | |
2582 | $cm = $modinfo->cms[$cmid]; |
2583 | |
5053f00f |
2584 | $params = array(); |
dd97c328 |
2585 | if ($userid) { |
5053f00f |
2586 | $userselect = "AND u.id = :userid"; |
2587 | $params['userid'] = $userid; |
73097f07 |
2588 | } else { |
2589 | $userselect = ""; |
2590 | } |
2591 | |
dd97c328 |
2592 | if ($groupid) { |
5053f00f |
2593 | $groupselect = "AND gm.groupid = :groupid"; |
2594 | $groupjoin = "JOIN {groups_members} gm ON gm.userid=u.id"; |
2595 | $params['groupid'] = $groupid; |
dd97c328 |
2596 | } else { |
2597 | $groupselect = ""; |
2598 | $groupjoin = ""; |
2599 | } |
73097f07 |
2600 | |
5053f00f |
2601 | $params['cminstance'] = $cm->instance; |
2602 | $params['timestart'] = $timestart; |
2603 | |
2604 | if (!$submissions = $DB->get_records_sql("SELECT asb.id, asb.timemodified, asb.userid, |
2605 | u.firstname, u.lastname, u.email, u.picture |
2606 | FROM {assignment_submissions} asb |
2607 | JOIN {assignment} a ON a.id = asb.assignment |
2608 | JOIN {user} u ON u.id = asb.userid |
2609 | $groupjoin |
2610 | WHERE asb.timemodified > :timestart AND a.id = :cminstance |
2611 | $userselect $groupselect |
2612 | ORDER BY asb.timemodified ASC", $params)) { |
dd97c328 |
2613 | return; |
2614 | } |
73097f07 |
2615 | |
dd97c328 |
2616 | $groupmode = groups_get_activity_groupmode($cm, $course); |
2617 | $cm_context = get_context_instance(CONTEXT_MODULE, $cm->id); |
2618 | $grader = has_capability('moodle/grade:viewall', $cm_context); |
2619 | $accessallgroups = has_capability('moodle/site:accessallgroups', $cm_context); |
2620 | $viewfullnames = has_capability('moodle/site:viewfullnames', $cm_context); |
2621 | |
2622 | if (is_null($modinfo->groups)) { |
2623 | $modinfo->groups = groups_get_user_groups($course->id); // load all my groups and cache it in modinfo |
2624 | } |
2625 | |
2626 | $show = array(); |
2627 | |
2628 | foreach($submissions as $submission) { |
2629 | if ($submission->userid == $USER->id) { |
2630 | $show[] = $submission; |
2631 | continue; |
2632 | } |
1160eb5a |
2633 | // the act of submitting of assignment may be considered private - only graders will see it if specified |
2634 | if (empty($CFG->assignment_showrecentsubmissions)) { |
dd97c328 |
2635 | if (!$grader) { |
2636 | continue; |
2637 | } |
2638 | } |
73097f07 |
2639 | |
dd97c328 |
2640 | if ($groupmode == SEPARATEGROUPS and !$accessallgroups) { |
2641 | if (isguestuser()) { |
2642 | // shortcut - guest user does not belong into any group |
2643 | continue; |
2644 | } |
2645 | |
2646 | // this will be slow - show only users that share group with me in this cm |
2647 | if (empty($modinfo->groups[$cm->id])) { |
2648 | continue; |
2649 | } |
2650 | $usersgroups = groups_get_all_groups($course->id, $cm->userid, $cm->groupingid); |
2651 | if (is_array($usersgroups)) { |
2652 | $usersgroups = array_keys($usersgroups); |
2653 | $interset = array_intersect($usersgroups, $modinfo->groups[$cm->id]); |
2654 | if (empty($intersect)) { |
2655 | continue; |
2656 | } |
2657 | } |
2658 | } |
2659 | $show[] = $submission; |
2660 | } |
73097f07 |
2661 | |
dd97c328 |
2662 | if (empty($show)) { |
2663 | return; |
2664 | } |
73097f07 |
2665 | |
dd97c328 |
2666 | if ($grader) { |
2667 | require_once($CFG->libdir.'/gradelib.php'); |
2668 | $userids = array(); |
2669 | foreach ($show as $id=>$submission) { |
2670 | $userids[] = $submission->userid; |
73097f07 |
2671 | |
dd97c328 |
2672 | } |
2673 | $grades = grade_get_grades($courseid, 'mod', 'assignment', $cm->instance, $userids); |
2674 | } |
73097f07 |
2675 | |
dd97c328 |
2676 | $aname = format_string($cm->name,true); |
2677 | foreach ($show as $submission) { |
2678 | $tmpactivity = new object(); |
73097f07 |
2679 | |
dd97c328 |
2680 | $tmpactivity->type = 'assignment'; |
2681 | $tmpactivity->cmid = $cm->id; |
2682 | $tmpactivity->name = $aname; |
76cbde41 |
2683 | $tmpactivity->sectionnum = $cm->sectionnum; |
dd97c328 |
2684 | $tmpactivity->timestamp = $submission->timemodified; |
73097f07 |
2685 | |
dd97c328 |
2686 | if ($grader) { |
2687 | $tmpactivity->grade = $grades->items[0]->grades[$submission->userid]->str_long_grade; |
73097f07 |
2688 | } |
dd97c328 |
2689 | |
2690 | $tmpactivity->user->userid = $submission->userid; |
2691 | $tmpactivity->user->fullname = fullname($submission, $viewfullnames); |
2692 | $tmpactivity->user->picture = $submission->picture; |
2693 | |
2694 | $activities[$index++] = $tmpactivity; |
73097f07 |
2695 | } |
2696 | |
2697 | return; |
2698 | } |
2699 | |
7af1e882 |
2700 | /** |
2701 | * Print recent activity from all assignments in a given course |
2702 | * |
2703 | * This is used by course/recent.php |
2704 | */ |
dd97c328 |
2705 | function assignment_print_recent_mod_activity($activity, $courseid, $detail, $modnames) { |
73097f07 |
2706 | global $CFG; |
2707 | |
dd97c328 |
2708 | echo '<table border="0" cellpadding="3" cellspacing="0" class="assignment-recent">'; |
73097f07 |
2709 | |
141a922c |
2710 | echo "<tr><td class=\"userpicture\" valign=\"top\">"; |
dd97c328 |
2711 | print_user_picture($activity->user->userid, $courseid, $activity->user->picture); |
2712 | echo "</td><td>"; |
73097f07 |
2713 | |
2714 | if ($detail) { |
dd97c328 |
2715 | $modname = $modnames[$activity->type]; |
2716 | echo '<div class="title">'; |
2717 | echo "<img src=\"$CFG->modpixpath/assignment/icon.gif\" ". |
2718 | "class=\"icon\" alt=\"$modname\">"; |
2719 | echo "<a href=\"$CFG->wwwroot/mod/assignment/view.php?id={$activity->cmid}\">{$activity->name}</a>"; |
2720 | echo '</div>'; |
73097f07 |
2721 | } |
2722 | |
dd97c328 |
2723 | if (isset($activity->grade)) { |
2724 | echo '<div class="grade">'; |
2725 | echo get_string('grade').': '; |
2726 | echo $activity->grade; |
2727 | echo '</div>'; |
73097f07 |
2728 | } |
73097f07 |
2729 | |
dd97c328 |
2730 | echo '<div class="user">'; |
2731 | echo "<a href=\"$CFG->wwwroot/user/view.php?id={$activity->user->userid}&course=$courseid\">" |
2732 | ."{$activity->user->fullname}</a> - ".userdate($activity->timestamp); |
2733 | echo '</div>'; |
73097f07 |
2734 | |
dd97c328 |
2735 | echo "</td></tr></table>"; |
73097f07 |
2736 | } |
2737 | |
2738 | /// GENERIC SQL FUNCTIONS |
2739 | |
7af1e882 |
2740 | /** |
2741 | * Fetch info from logs |
2742 | * |
2743 | * @param $log object with properties ->info (the assignment id) and ->userid |
2744 | * @return array with assignment name and user firstname and lastname |
2745 | */ |
73097f07 |
2746 | function assignment_log_info($log) { |
5053f00f |
2747 | global $CFG, $DB; |
2748 | |
2749 | return $DB->get_record_sql("SELECT a.name, u.firstname, u.lastname |
2750 | FROM {assignment} a, {user} u |
2751 | WHERE a.id = ? AND u.id = ?", array($log->info, $log->userid)); |
73097f07 |
2752 | } |
2753 | |
7af1e882 |
2754 | /** |
2755 | * Return list of marked submissions that have not been mailed out for currently enrolled students |
2756 | * |
2757 | * @return array |
2758 | */ |
73097f07 |
2759 | function assignment_get_unmailed_submissions($starttime, $endtime) { |
5053f00f |
2760 | global $CFG, $DB; |
7af1e882 |
2761 | |
5053f00f |
2762 | return $DB->get_records_sql("SELECT s.*, a.course, a.name |
2763 | FROM {assignment_submissions} s, |
2764 | {assignment} a |
2765 | WHERE s.mailed = 0 |
2766 | AND s.timemarked <= ? |
2767 | AND s.timemarked >= ? |
2768 | AND s.assignment = a.id", array($endtime, $starttime)); |
73097f07 |
2769 | } |
2770 | |
7af1e882 |
2771 | /** |
2772 | * Counts all real assignment submissions by ENROLLED students (not empty ones) |
2773 | * |
2774 | * There are also assignment type methods count_real_submissions() wich in the default |
2775 | * implementation simply call this function. |
2776 | * @param $groupid int optional If nonzero then count is restricted to this group |
2777 | * @return int The number of submissions |
2778 | */ |
dd97c328 |
2779 | function assignment_count_real_submissions($cm, $groupid=0) { |
74d7d735 |
2780 | global $CFG, $DB; |
73097f07 |
2781 | |
dd97c328 |
2782 | $context = get_context_instance(CONTEXT_MODULE, $cm->id); |
01194b77 |
2783 | |
dd97c328 |
2784 | // this is all the users with this capability set, in this context or higher |
2785 | if ($users = get_users_by_capability($context, 'mod/assignment:submit', 'u.id', '', '', '', $groupid, '', false)) { |
2786 | $users = array_keys($users); |
2787 | } |
01194b77 |
2788 | |
dd97c328 |
2789 | // if groupmembersonly used, remove users who are not in any group |
2790 | if ($users and !empty($CFG->enablegroupings) and $cm->groupmembersonly) { |
2791 | if ($groupingusers = groups_get_grouping_members($cm->groupingid, 'u.id', 'u.id')) { |
2792 | $users = array_intersect($users, array_keys($groupingusers)); |
73097f07 |
2793 | } |
73097f07 |
2794 | } |
dd97c328 |
2795 | |
2796 | if (empty($users)) { |
2797 | return 0; |
2798 | } |
2799 | |
2800 | $userlists = implode(',', $users); |
2801 | |
74d7d735 |
2802 | return $DB->count_records_sql("SELECT COUNT('x') |
2803 | FROM {assignment_submissions} |
2804 | WHERE assignment = ? AND |
2805 | timemodified > 0 AND |
2806 | userid IN ($userlists)", array($cm->instance)); |
73097f07 |
2807 | } |
2808 | |
7af1e882 |
2809 | |
2810 | /** |
2811 | * Return all assignment submissions by ENROLLED students (even empty) |
2812 | * |
2813 | * There are also assignment type methods get_submissions() wich in the default |
2814 | * implementation simply call this function. |
2815 | * @param $sort string optional field names for the ORDER BY in the sql query |
2816 | * @param $dir string optional specifying the sort direction, defaults to DESC |
2817 | * @return array The submission objects indexed by id |
2818 | */ |
73097f07 |
2819 | function assignment_get_all_submissions($assignment, $sort="", $dir="DESC") { |
2820 | /// Return all assignment submissions by ENROLLED students (even empty) |
74d7d735 |
2821 | global $CFG, $DB; |
73097f07 |
2822 | |
2823 | if ($sort == "lastname" or $sort == "firstname") { |
2824 | $sort = "u.$sort $dir"; |
2825 | } else if (empty($sort)) { |
2826 | $sort = "a.timemodified DESC"; |
2827 | } else { |
2828 | $sort = "a.$sort $dir"; |
2829 | } |
2830 | |
ea8158c1 |
2831 | /* not sure this is needed at all since assignmenet already has a course define, so this join? |
73097f07 |
2832 | $select = "s.course = '$assignment->course' AND"; |
2833 | if ($assignment->course == SITEID) { |
2834 | $select = ''; |
ea8158c1 |
2835 | }*/ |
45fa3412 |
2836 | |
74d7d735 |
2837 | return $DB->get_records_sql("SELECT a.* |
2838 | FROM {assignment_submissions} a, {user} u |
2839 | WHERE u.id = a.userid |
2840 | AND a.assignment = ? |
2841 | ORDER BY $sort", array($assignment->id)); |
45fa3412 |
2842 | |
73097f07 |
2843 | } |
2844 | |
09ba8e56 |
2845 | /** |
2846 | * Add a get_coursemodule_info function in case any assignment type wants to add 'extra' information |
2847 | * for the course (see resource). |
2848 | * |
206ab184 |
2849 | * Given a course_module object, this function returns any "extra" information that may be needed |
09ba8e56 |
2850 | * when printing this activity in a course listing. See get_array_of_activities() in course/lib.php. |
206ab184 |
2851 | * |
09ba8e56 |
2852 | * @param $coursemodule object The coursemodule object (record). |
2853 | * @return object An object on information that the coures will know about (most noticeably, an icon). |
206ab184 |
2854 | * |
09ba8e56 |
2855 | */ |
2856 | function assignment_get_coursemodule_info($coursemodule) { |
74d7d735 |
2857 | global $CFG, $DB; |
09ba8e56 |
2858 | |
74d7d735 |
2859 | if (! $assignment = $DB->get_record('assignment', array('id'=>$coursemodule->instance), 'id, assignmenttype, name')) { |
09ba8e56 |
2860 | return false; |
2861 | } |
2862 | |
1ea543df |
2863 | $libfile = "$CFG->dirroot/mod/assignment/type/$assignment->assignmenttype/assignment.class.php"; |
09ba8e56 |
2864 | |
f36cbf1d |
2865 | if (file_exists($libfile)) { |
2866 | require_once($libfile); |
1ea543df |
2867 | $assignmentclass = "assignment_$assignment->assignmenttype"; |
f36cbf1d |
2868 | $ass = new $assignmentclass('staticonly'); |
12dce253 |
2869 | if ($result = $ass->get_coursemodule_info($coursemodule)) { |
1ea543df |
2870 | return $result; |
2871 | } else { |
2872 | $info = new object(); |
2873 | $info->name = $assignment->name; |
2874 | return $info; |
12dce253 |
2875 | } |
f36cbf1d |
2876 | |
2877 | } else { |
1ea543df |
2878 | debugging('Incorrect assignment type: '.$assignment->assignmenttype); |
f36cbf1d |
2879 | return false; |
2880 | } |
09ba8e56 |
2881 | } |
73097f07 |
2882 | |
2883 | |
2884 | |
2885 | /// OTHER GENERAL FUNCTIONS FOR ASSIGNMENTS /////////////////////////////////////// |
2886 | |
7af1e882 |
2887 | /** |
2888 | * Returns an array of installed assignment types indexed and sorted by name |
2889 | * |
2890 | * @return array The index is the name of the assignment type, the value its full name from the language strings |
2891 | */ |
b0f2597e |
2892 | function assignment_types() { |
2893 | $types = array(); |
2894 | $names = get_list_of_plugins('mod/assignment/type'); |
2895 | foreach ($names as $name) { |
2896 | $types[$name] = get_string('type'.$name, 'assignment'); |
ffeca120 |
2897 | } |
b0f2597e |
2898 | asort($types); |
2899 | return $types; |
f466c9ed |
2900 | } |
2901 | |
7af1e882 |
2902 | /** |
2903 | * Executes upgrade scripts for assignment types when necessary |
2904 | */ |
b0f2597e |
2905 | function assignment_upgrade_submodules() { |
e9d46b81 |
2906 | global $CFG; |
59c005b7 |
2907 | |
e9d46b81 |
2908 | /// Install/upgrade assignment types (it uses, simply, the standard plugin architecture) |
2909 | upgrade_plugins('assignment_type', 'mod/assignment/type', "$CFG->wwwroot/$CFG->admin/index.php"); |
59c005b7 |
2910 | |
59c005b7 |
2911 | } |
2912 | |
84fa8f5f |
2913 | function assignment_print_overview($courses, &$htmlarray) { |
74d7d735 |
2914 | global $USER, $CFG, $DB; |
84fa8f5f |
2915 | |
2916 | if (empty($courses) || !is_array($courses) || count($courses) == 0) { |
2917 | return array(); |
2918 | } |
2919 | |
2920 | if (!$assignments = get_all_instances_in_courses('assignment',$courses)) { |
2921 | return; |
2922 | } |
2923 | |
2924 | // Do assignment_base::isopen() here without loading the whole thing for speed |
2925 | foreach ($assignments as $key => $assignment) { |
2926 | $time = time(); |
d6da4a1a |
2927 | if ($assignment->timedue) { |
2928 | if ($assignment->preventlate) { |
2929 | $isopen = ($assignment->timeavailable <= $time && $time <= $assignment->timedue); |
2930 | } else { |
2931 | $isopen = ($assignment->timeavailable <= $time); |
2932 | } |
84fa8f5f |
2933 | } |
d6da4a1a |
2934 | if (empty($isopen) || empty($assignment->timedue)) { |
84fa8f5f |
2935 | unset($assignments[$key]); |
2936 | } |
2937 | } |
2938 | |
2939 | $strduedate = get_string('duedate', 'assignment'); |
8f643c81 |
2940 | $strduedateno = get_string('duedateno', 'assignment'); |
84fa8f5f |
2941 | $strgraded = get_string('graded', 'assignment'); |
2942 | $strnotgradedyet = get_string('notgradedyet', 'assignment'); |
2943 | $strnotsubmittedyet = get_string('notsubmittedyet', 'assignment'); |
2944 | $strsubmitted = get_string('submitted', 'assignment'); |
76a60031 |
2945 | $strassignment = get_string('modulename', 'assignment'); |
c664a036 |
2946 | $strreviewed = get_string('reviewed','assignment'); |
84fa8f5f |
2947 | |
2948 | foreach ($assignments as $assignment) { |
a2a37336 |
2949 | $str = '<div class="assignment overview"><div class="name">'.$strassignment. ': '. |
a7a74d77 |
2950 | '<a '.($assignment->visible ? '':' class="dimmed"'). |
76a60031 |
2951 | 'title="'.$strassignment.'" href="'.$CFG->wwwroot. |
a7a74d77 |
2952 | '/mod/assignment/view.php?id='.$assignment->coursemodule.'">'. |
5d45c04f |
2953 | $assignment->name.'</a></div>'; |
8f643c81 |
2954 | if ($assignment->timedue) { |
2955 | $str .= '<div class="info">'.$strduedate.': '.userdate($assignment->timedue).'</div>'; |
2956 | } else { |
2957 | $str .= '<div class="info">'.$strduedateno.'</div>'; |
2958 | } |
793a8c3a |
2959 | $context = get_context_instance(CONTEXT_MODULE, $assignment->coursemodule); |
0468976c |
2960 | if (has_capability('mod/assignment:grade', $context)) { |
45fa3412 |
2961 | |
ea8158c1 |
2962 | // count how many people can submit |
2963 | $submissions = 0; // init |
7bddd4b7 |
2964 | if ($students = get_users_by_capability($context, 'mod/assignment:submit', '', '', '', '', 0, '', false)) { |
2965 | foreach ($students as $student) { |
74d7d735 |
2966 | if ($DB->record_exists_sql("SELECT id |
2967 | FROM {assignment_submissions} |
2968 | WHERE assignment = ? AND |
2969 | userid = ? AND |
2970 | teacher = 0 AND |
2971 | timemarked = 0", array($assignment->id, $student->id))) { |
45fa3412 |
2972 | $submissions++; |
c2adcc90 |
2973 | } |
ea8158c1 |
2974 | } |
2975 | } |
45fa3412 |
2976 | |
84fa8f5f |
2977 | if ($submissions) { |
2978 | $str .= get_string('submissionsnotgraded', 'assignment', $submissions); |
2979 | } |
2980 | } else { |
2981 | $sql = "SELECT * |
74d7d735 |
2982 | FROM {assignment_submissions} |
2983 | WHERE userid = ? |
2984 | AND assignment = ?"; |
2985 | $params = array($USER->id, $assignment->id); |
2986 | if ($submission = $DB->get_record_sql($sql, $params)) { |
84fa8f5f |
2987 | if ($submission->teacher == 0 && $submission->timemarked == 0) { |
2988 | $str .= $strsubmitted . ', ' . $strnotgradedyet; |
c664a036 |
2989 | } else if ($submission->grade <= 0) { |
2990 | $str .= $strsubmitted . ', ' . $strreviewed; |
84fa8f5f |
2991 | } else { |
2992 | $str .= $strsubmitted . ', ' . $strgraded; |
2993 | } |
2994 | } else { |
76a60031 |
2995 | $str .= $strnotsubmittedyet . ' ' . assignment_display_lateness(time(), $assignment->timedue); |
84fa8f5f |
2996 | } |
2997 | } |
a7a74d77 |
2998 | $str .= '</div>'; |
76a60031 |
2999 | if (empty($htmlarray[$assignment->course]['assignment'])) { |
3000 | $htmlarray[$assignment->course]['assignment'] = $str; |
3001 | } else { |
3002 | $htmlarray[$assignment->course]['assignment'] .= $str; |
3003 | } |
3004 | } |
3005 | } |
3006 | |
3007 | function assignment_display_lateness($timesubmitted, $timedue) { |
3008 | if (!$timedue) { |
3009 | return ''; |
3010 | } |
3011 | $time = $timedue - $timesubmitted; |
3012 | if ($time < 0) { |
3013 | $timetext = get_string('late', 'assignment', format_time($time)); |
3014 | return ' (<span class="late">'.$timetext.'</span>)'; |
3015 | } else { |
3016 | $timetext = get_string('early', 'assignment', format_time($time)); |
3017 | return ' (<span class="early">'.$timetext.'</span>)'; |
84fa8f5f |
3018 | } |
3019 | } |
3020 | |
ac15a2d5 |
3021 | function assignment_get_view_actions() { |
3022 | return array('view'); |
3023 | } |
3024 | |
3025 | function assignment_get_post_actions() { |
3026 | return array('upload'); |
3027 | } |
3028 | |
89bfeee0 |
3029 | function assignment_get_types() { |
0ac1cfc3 |
3030 | global $CFG; |
89bfeee0 |
3031 | $types = array(); |
3032 | |
3033 | $type = new object(); |
3034 | $type->modclass = MOD_CLASS_ACTIVITY; |
3035 | $type->type = "assignment_group_start"; |
3036 | $type->typestr = '--'.get_string('modulenameplural', 'assignment'); |
3037 | $types[] = $type; |
3038 | |
3039 | $standardassignments = array('upload','online','uploadsingle','offline'); |
3040 | foreach ($standardassignments as $assignmenttype) { |
3041 | $type = new object(); |
3042 | $type->modclass = MOD_CLASS_ACTIVITY; |
3043 | $type->type = "assignment&type=$assignmenttype"; |
3044 | $type->typestr = get_string("type$assignmenttype", 'assignment'); |
3045 | $types[] = $type; |
3046 | } |
3047 | |
3048 | /// Drop-in extra assignment types |
3049 | $assignmenttypes = get_list_of_plugins('mod/assignment/type'); |
3050 | foreach ($assignmenttypes as $assignmenttype) { |
3051 | if (!empty($CFG->{'assignment_hide_'.$assignmenttype})) { // Not wanted |
3052 | |