b0f2597e |
1 | <?PHP // $Id$ |
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 | |
d699cd1e |
8 | |
4909e176 |
9 | if (!isset($CFG->assignment_maxbytes)) { |
10 | set_config("assignment_maxbytes", 1024000); // Default maximum size for all assignments |
04eba58f |
11 | } |
12 | |
b0f2597e |
13 | /* |
14 | * Standard base class for all assignment submodules (assignment types). |
15 | * |
16 | * |
17 | */ |
18 | class assignment_base { |
19 | |
20 | var $cm; |
21 | var $course; |
22 | var $assignment; |
23 | |
24 | /** |
25 | * Constructor for the base assignment class |
26 | * |
27 | * Constructor for the base assignment class. |
28 | * If cmid is set create the cm, course, assignment objects. |
29 | * |
30 | * @param cmid integer, the current course module id - not set for new assignments |
73097f07 |
31 | * @param assignment object, usually null, but if we have it we pass it to save db access |
b0f2597e |
32 | */ |
73097f07 |
33 | function assignment_base($cmid=0, $assignment=NULL, $cm=NULL, $course=NULL) { |
b0f2597e |
34 | |
35 | global $CFG; |
36 | |
37 | if ($cmid) { |
73097f07 |
38 | if ($cm) { |
39 | $this->cm = $cm; |
40 | } else if (! $this->cm = get_record('course_modules', 'id', $cmid)) { |
41 | error('Course Module ID was incorrect'); |
b0f2597e |
42 | } |
04eba58f |
43 | |
73097f07 |
44 | if ($course) { |
45 | $this->course = $course; |
46 | } else if (! $this->course = get_record('course', 'id', $this->cm->course)) { |
47 | error('Course is misconfigured'); |
b0f2597e |
48 | } |
04eba58f |
49 | |
73097f07 |
50 | if ($assignment) { |
51 | $this->assignment = $assignment; |
52 | } else if (! $this->assignment = get_record('assignment', 'id', $this->cm->instance)) { |
53 | error('assignment ID was incorrect'); |
b0f2597e |
54 | } |
e6a4906b |
55 | |
b0f2597e |
56 | $this->strassignment = get_string('modulename', 'assignment'); |
57 | $this->strassignments = get_string('modulenameplural', 'assignment'); |
58 | $this->strsubmissions = get_string('submissions', 'assignment'); |
59 | $this->strlastmodified = get_string('lastmodified'); |
e6a4906b |
60 | |
b0f2597e |
61 | if ($this->course->category) { |
62 | $this->navigation = "<a target=\"{$CFG->framename}\" href=\"$CFG->wwwroot/course/view.php?id={$this->course->id}\">{$this->course->shortname}</a> -> ". |
63 | "<a target=\"{$CFG->framename}\" href=\"index.php?id={$this->course->id}\">$this->strassignments</a> ->"; |
64 | } else { |
65 | $this->navigation = "<a target=\"{$CFG->framename}\" href=\"index.php?id={$this->course->id}\">$this->strassignments</a> ->"; |
66 | } |
e6a4906b |
67 | |
3898bc33 |
68 | $this->pagetitle = strip_tags($this->course->shortname.': '.$this->strassignment.': '.format_string($this->assignment->name,true)); |
e6a4906b |
69 | |
b0f2597e |
70 | if (!$this->cm->visible and !isteacher($this->course->id)) { |
71 | $pagetitle = strip_tags($this->course->shortname.': '.$this->strassignment); |
72 | print_header($pagetitle, $this->course->fullname, "$this->navigation $this->strassignment", |
73 | "", "", true, '', navmenu($this->course, $this->cm)); |
74 | notice(get_string("activityiscurrentlyhidden"), "$CFG->wwwroot/course/view.php?id={$this->course->id}"); |
75 | } |
b0f2597e |
76 | $this->currentgroup = get_current_group($this->course->id); |
73097f07 |
77 | } |
e6a4906b |
78 | |
73097f07 |
79 | /// Set up things for a HTML editor if it's needed |
80 | if ($this->usehtmleditor = can_use_html_editor()) { |
81 | $this->defaultformat = FORMAT_HTML; |
82 | } else { |
83 | $this->defaultformat = FORMAT_MOODLE; |
e6a4906b |
84 | } |
85 | } |
86 | |
b0f2597e |
87 | /* |
88 | * Display the assignment to students (sub-modules will most likely override this) |
89 | */ |
04eba58f |
90 | |
b0f2597e |
91 | function view() { |
04eba58f |
92 | |
b0f2597e |
93 | add_to_log($this->course->id, "assignment", "view", "view.php?id={$this->cm->id}", |
94 | $this->assignment->id, $this->cm->id); |
04eba58f |
95 | |
73097f07 |
96 | $this->view_header(); |
04eba58f |
97 | |
f77cfb73 |
98 | $this->view_intro(); |
04eba58f |
99 | |
f77cfb73 |
100 | $this->view_dates(); |
04eba58f |
101 | |
b0f2597e |
102 | $this->view_feedback(); |
103 | |
f77cfb73 |
104 | $this->view_footer(); |
36eb856f |
105 | } |
106 | |
73097f07 |
107 | /* |
108 | * Display the top of the view.php page, this doesn't change much for submodules |
109 | */ |
110 | function view_header($subpage='') { |
111 | |
112 | global $CFG; |
113 | |
114 | if ($subpage) { |
115 | $extranav = '<a target="'.$CFG->framename.'" href="view.php?id='.$this->cm->id.'">'. |
3898bc33 |
116 | format_string($this->assignment->name,true).'</a> -> '.$subpage; |
73097f07 |
117 | } else { |
3898bc33 |
118 | $extranav = ' '.format_string($this->assignment->name,true); |
73097f07 |
119 | } |
120 | |
121 | print_header($this->pagetitle, $this->course->fullname, $this->navigation.$extranav, '', '', |
122 | true, update_module_button($this->cm->id, $this->course->id, $this->strassignment), |
123 | navmenu($this->course, $this->cm)); |
124 | |
125 | echo '<div class="reportlink">'.$this->submittedlink().'</div>'; |
126 | } |
127 | |
128 | |
f77cfb73 |
129 | /* |
130 | * Display the assignment intro |
131 | */ |
132 | function view_intro() { |
133 | print_simple_box_start('center', '', '', '', 'generalbox', 'intro'); |
1e4343a0 |
134 | $formatoptions = new stdClass; |
135 | $formatoptions->noclean = true; |
136 | echo format_text($this->assignment->description, $this->assignment->format, $formatoptions); |
f77cfb73 |
137 | print_simple_box_end(); |
138 | } |
139 | |
140 | /* |
141 | * Display the assignment dates |
142 | */ |
143 | function view_dates() { |
144 | if (!$this->assignment->timeavailable && !$this->assignment->timedue) { |
145 | return; |
146 | } |
147 | |
148 | print_simple_box_start('center', '', '', '', 'generalbox', 'dates'); |
149 | echo '<table>'; |
150 | if ($this->assignment->timeavailable) { |
151 | echo '<tr><td class="c0">'.get_string('availabledate','assignment').':</td>'; |
152 | echo ' <td class="c1">'.userdate($this->assignment->timeavailable).'</td></tr>'; |
153 | } |
154 | if ($this->assignment->timedue) { |
155 | echo '<tr><td class="c0">'.get_string('duedate','assignment').':</td>'; |
156 | echo ' <td class="c1">'.userdate($this->assignment->timedue).'</td></tr>'; |
157 | } |
158 | echo '</table>'; |
159 | print_simple_box_end(); |
160 | } |
161 | |
162 | |
73097f07 |
163 | /* |
164 | * Display the bottom of the view.php page, this doesn't change much for submodules |
165 | */ |
166 | function view_footer() { |
167 | print_footer($this->course); |
168 | } |
169 | |
73097f07 |
170 | function view_feedback($submission=NULL) { |
b0f2597e |
171 | global $USER; |
e6a4906b |
172 | |
73097f07 |
173 | if (!$submission) { /// Get submission for this assignment |
174 | $submission = $this->get_submission($USER->id); |
70b2c772 |
175 | } |
176 | |
177 | if (empty($submission->timemarked)) { /// Nothing to show, so print nothing |
178 | return; |
9c48354d |
179 | } |
e6a4906b |
180 | |
b0f2597e |
181 | /// We need the teacher info |
182 | if (! $teacher = get_record('user', 'id', $submission->teacher)) { |
b0f2597e |
183 | error('Could not find the teacher'); |
184 | } |
e6a4906b |
185 | |
b0f2597e |
186 | /// Print the feedback |
6d4ecaec |
187 | print_heading(get_string('feedbackfromteacher', 'assignment', $this->course->teacher)); |
188 | |
b0f2597e |
189 | echo '<table cellspacing="0" class="feedback">'; |
190 | |
191 | echo '<tr>'; |
192 | echo '<td class="left picture">'; |
193 | print_user_picture($teacher->id, $this->course->id, $teacher->picture); |
194 | echo '</td>'; |
6d4ecaec |
195 | echo '<td class="topic">'; |
70b2c772 |
196 | echo '<div class="from">'; |
73097f07 |
197 | echo '<div class="fullname">'.fullname($teacher).'</div>'; |
6d4ecaec |
198 | echo '<div class="time">'.userdate($submission->timemarked).'</div>'; |
70b2c772 |
199 | echo '</div>'; |
200 | $this->print_user_files($submission->userid); |
201 | echo '</td>'; |
b0f2597e |
202 | echo '</td>'; |
203 | echo '</tr>'; |
204 | |
205 | echo '<tr>'; |
206 | echo '<td class="left side"> </td>'; |
6d4ecaec |
207 | echo '<td class="content">'; |
b0f2597e |
208 | if ($this->assignment->grade) { |
6d4ecaec |
209 | echo '<div class="grade">'; |
70b2c772 |
210 | echo get_string("grade").': '.$this->display_grade($submission->grade); |
6d4ecaec |
211 | echo '</div>'; |
52436fe1 |
212 | echo '<div class="clearer"></div>'; |
e6a4906b |
213 | } |
dcd338ff |
214 | |
6d4ecaec |
215 | echo '<div class="comment">'; |
ff8f7015 |
216 | echo format_text($submission->comment, $submission->format); |
6d4ecaec |
217 | echo '</div>'; |
b0f2597e |
218 | echo '</tr>'; |
219 | |
220 | echo '</table>'; |
e6a4906b |
221 | } |
e6a4906b |
222 | |
ba16713f |
223 | /* |
224 | * Returns a link with info about the state of the assignment submissions |
225 | */ |
226 | function submittedlink() { |
227 | global $USER; |
228 | |
229 | $submitted = ''; |
230 | |
231 | if (isteacher($this->course->id)) { |
232 | if (!isteacheredit($this->course->id) and user_group($this->course->id, $USER->id)) { |
233 | $count = $this->count_real_submissions($this->currentgroup); // Only their group |
234 | } else { |
235 | $count = $this->count_real_submissions(); // Everyone |
236 | } |
237 | $submitted = '<a href="submissions.php?id='.$this->cm->id.'">'. |
238 | get_string('viewsubmissions', 'assignment', $count).'</a>'; |
239 | } else { |
240 | if (isset($USER->id)) { |
241 | if ($submission = $this->get_submission($USER->id)) { |
242 | if ($submission->timemodified) { |
1e4343a0 |
243 | if ($submission->timemodified <= $this->assignment->timedue || empty($this->assignment->timedue)) { |
ba16713f |
244 | $submitted = '<span class="early">'.userdate($submission->timemodified).'</span>'; |
245 | } else { |
246 | $submitted = '<span class="late">'.userdate($submission->timemodified).'</span>'; |
247 | } |
248 | } |
249 | } |
250 | } |
251 | } |
252 | |
253 | return $submitted; |
254 | } |
255 | |
256 | |
b0f2597e |
257 | /* |
258 | * Print the start of the setup form for the current assignment type |
259 | */ |
260 | function setup(&$form, $action='') { |
261 | global $CFG, $THEME; |
262 | |
263 | if (empty($this->course)) { |
264 | if (! $this->course = get_record("course", "id", $form->course)) { |
265 | error("Course is misconfigured"); |
77db7e4c |
266 | } |
267 | } |
b0f2597e |
268 | if (empty($action)) { // Default destination for this form |
269 | $action = $CFG->wwwroot.'/course/mod.php'; |
270 | } |
77db7e4c |
271 | |
b0f2597e |
272 | if (empty($form->name)) { |
273 | $form->name = ""; |
274 | } |
275 | if (empty($form->assignmenttype)) { |
276 | $form->assignmenttype = ""; |
1e4343a0 |
277 | } else { |
278 | $form->assignmenttype = clean_param($form->assignmenttype, PARAM_SAFEDIR); |
b0f2597e |
279 | } |
280 | if (empty($form->description)) { |
281 | $form->description = ""; |
282 | } |
77db7e4c |
283 | |
b0f2597e |
284 | $strname = get_string('name'); |
285 | $strassignments = get_string('modulenameplural', 'assignment'); |
3898bc33 |
286 | $strheading = empty($form->name) ? get_string("type$form->assignmenttype",'assignment') : s(format_string(stripslashes($form->name),true)); |
77db7e4c |
287 | |
b0f2597e |
288 | print_header($this->course->shortname.': '.$strheading, "$strheading", |
289 | "<a href=\"$CFG->wwwroot/course/view.php?id={$this->course->id}\">{$this->course->shortname} </a> -> ". |
290 | "<a href=\"$CFG->wwwroot/mod/assignment/index.php?id={$this->course->id}\">$strassignments</a> -> $strheading"); |
77db7e4c |
291 | |
f77cfb73 |
292 | print_simple_box_start('center', '70%'); |
293 | print_heading(get_string('type'.$form->assignmenttype,'assignment')); |
294 | print_simple_box(get_string('help'.$form->assignmenttype, 'assignment'), 'center'); |
b0f2597e |
295 | include("$CFG->dirroot/mod/assignment/type/common.html"); |
f77cfb73 |
296 | |
297 | include("$CFG->dirroot/mod/assignment/type/".$form->assignmenttype."/mod.html"); |
298 | $this->setup_end(); |
b0f2597e |
299 | } |
300 | |
301 | /* |
302 | * Print the end of the setup form for the current assignment type |
303 | */ |
304 | function setup_end() { |
73097f07 |
305 | global $CFG; |
b0f2597e |
306 | |
307 | include($CFG->dirroot.'/mod/assignment/type/common_end.html'); |
77db7e4c |
308 | |
309 | print_simple_box_end(); |
310 | |
73097f07 |
311 | if ($this->usehtmleditor) { |
b0f2597e |
312 | use_html_editor(); |
313 | } |
314 | |
315 | print_footer($this->course); |
77db7e4c |
316 | } |
77db7e4c |
317 | |
318 | |
b0f2597e |
319 | function add_instance($assignment) { |
320 | // Given an object containing all the necessary data, |
321 | // (defined by the form in mod.html) this function |
322 | // will create a new instance and return the id number |
323 | // of the new instance. |
324 | |
325 | $assignment->timemodified = time(); |
38147229 |
326 | if (empty($assignment->dueenable)) { |
327 | $assignment->timedue = 0; |
328 | } else { |
329 | $assignment->timedue = make_timestamp($assignment->dueyear, $assignment->duemonth, |
330 | $assignment->dueday, $assignment->duehour, |
331 | $assignment->dueminute); |
332 | } |
333 | if (empty($assignment->availableenable)) { |
334 | $assignment->timeavailable = 0; |
335 | $assignment->preventlate = 0; |
336 | } else { |
337 | $assignment->timeavailable = make_timestamp($assignment->availableyear, $assignment->availablemonth, |
338 | $assignment->availableday, $assignment->availablehour, |
339 | $assignment->availableminute); |
340 | } |
341 | |
736f191c |
342 | if ($returnid = insert_record("assignment", $assignment)) { |
343 | |
1e4343a0 |
344 | if ($assignment->timedue) { |
345 | $event = NULL; |
346 | $event->name = $assignment->name; |
347 | $event->description = $assignment->description; |
348 | $event->courseid = $assignment->course; |
349 | $event->groupid = 0; |
350 | $event->userid = 0; |
351 | $event->modulename = 'assignment'; |
352 | $event->instance = $returnid; |
353 | $event->eventtype = 'due'; |
354 | $event->timestart = $assignment->timedue; |
355 | $event->timeduration = 0; |
736f191c |
356 | |
1e4343a0 |
357 | add_event($event); |
358 | } |
736f191c |
359 | } |
360 | |
361 | return $returnid; |
b0f2597e |
362 | } |
d699cd1e |
363 | |
b0f2597e |
364 | function delete_instance($assignment) { |
736f191c |
365 | $result = true; |
366 | |
367 | if (! delete_records('assignment_submissions', 'assignment', $assignment->id)) { |
368 | $result = false; |
369 | } |
370 | |
371 | if (! delete_records('assignment', 'id', $assignment->id)) { |
372 | $result = false; |
373 | } |
374 | |
375 | if (! delete_records('event', 'modulename', 'assignment', 'instance', $assignment->id)) { |
376 | $result = false; |
377 | } |
378 | |
379 | return $result; |
b0f2597e |
380 | } |
d699cd1e |
381 | |
b0f2597e |
382 | function update_instance($assignment) { |
383 | // Given an object containing all the necessary data, |
384 | // (defined by the form in mod.html) this function |
385 | // will create a new instance and return the id number |
386 | // of the new instance. |
387 | |
388 | $assignment->timemodified = time(); |
38147229 |
389 | $assignment->timemodified = time(); |
390 | if (empty($assignment->dueenable)) { |
391 | $assignment->timedue = 0; |
392 | } else { |
393 | $assignment->timedue = make_timestamp($assignment->dueyear, $assignment->duemonth, |
394 | $assignment->dueday, $assignment->duehour, |
395 | $assignment->dueminute); |
396 | } |
397 | if (empty($assignment->availableenable)) { |
398 | $assignment->timeavailable = 0; |
399 | $assignment->preventlate = 0; |
400 | } else { |
401 | $assignment->timeavailable = make_timestamp($assignment->availableyear, $assignment->availablemonth, |
402 | $assignment->availableday, $assignment->availablehour, |
403 | $assignment->availableminute); |
404 | } |
405 | |
b0f2597e |
406 | $assignment->id = $assignment->instance; |
736f191c |
407 | |
408 | if ($returnid = update_record('assignment', $assignment)) { |
409 | |
1e4343a0 |
410 | if ($assignment->timedue) { |
411 | $event = NULL; |
736f191c |
412 | |
1e4343a0 |
413 | if ($event->id = get_field('event', 'id', 'modulename', 'assignment', 'instance', $assignment->id)) { |
736f191c |
414 | |
1e4343a0 |
415 | $event->name = $assignment->name; |
416 | $event->description = $assignment->description; |
417 | $event->timestart = $assignment->timedue; |
736f191c |
418 | |
1e4343a0 |
419 | update_event($event); |
47263937 |
420 | } else { |
421 | $event = NULL; |
422 | $event->name = $assignment->name; |
423 | $event->description = $assignment->description; |
424 | $event->courseid = $assignment->course; |
425 | $event->groupid = 0; |
426 | $event->userid = 0; |
427 | $event->modulename = 'assignment'; |
428 | $event->instance = $assignment->id; |
429 | $event->eventtype = 'due'; |
430 | $event->timestart = $assignment->timedue; |
431 | $event->timeduration = 0; |
432 | |
433 | add_event($event); |
1e4343a0 |
434 | } |
47263937 |
435 | } else { |
436 | delete_records('event', 'modulename', 'assignment', 'instance', $assignment->id); |
736f191c |
437 | } |
438 | } |
439 | |
440 | return $returnid; |
b0f2597e |
441 | } |
442 | |
b0f2597e |
443 | /* |
444 | * Top-level function for handling of submissions called by submissions.php |
445 | * |
446 | */ |
447 | function submissions($mode) { |
9bf660b3 |
448 | ///The main switch is changed to facilitate |
449 | ///1) Batch fast grading |
450 | ///2) Skip to the next one on the popup |
451 | ///3) Save and Skip to the next one on the popup |
452 | |
453 | //make user global so we can use the id |
454 | global $USER; |
455 | |
b0f2597e |
456 | switch ($mode) { |
457 | case 'grade': // We are in a popup window grading |
458 | if ($submission = $this->process_feedback()) { |
5a36be8c |
459 | //IE needs proper header with encoding |
460 | print_header(get_string('feedback', 'assignment').':'.format_string($this->assignment->name)); |
b0f2597e |
461 | print_heading(get_string('changessaved')); |
be86672d |
462 | $this->update_main_listing($submission); |
b0f2597e |
463 | } |
464 | close_window(); |
465 | break; |
9cc9b7c1 |
466 | |
b0f2597e |
467 | case 'single': // We are in a popup window displaying submission |
468 | $this->display_submission(); |
469 | break; |
a56d79cd |
470 | |
b0f2597e |
471 | case 'all': // Main window, display everything |
472 | $this->display_submissions(); |
473 | break; |
082215e6 |
474 | |
9bf660b3 |
475 | case 'fastgrade': |
082215e6 |
476 | ///do the fast grading stuff - this process should work for all 3 subclasses |
16907e53 |
477 | $grading = false; |
478 | $commenting = false; |
479 | if (isset($_POST['comment'])) { |
480 | $arr = 'comment'; |
481 | $commenting = true; |
482 | } |
483 | if (isset($_POST['menu'])) { |
484 | $arr = 'menu'; |
485 | $grading = true; |
486 | } |
487 | if (!$grading && !$commenting) { |
488 | //both comment and grade hidden.. |
489 | $this->display_submissions(); |
490 | break; |
491 | } |
492 | foreach ($_POST[$arr] as $id => $unusedvalue){ |
77f4b17b |
493 | |
494 | $id = (int)$id; //clean parameter name |
9bf660b3 |
495 | $newsubmission = $this->get_submission($id, true); // Get or make one |
16907e53 |
496 | unset($newsubmission->data1); // Don't need to update this. |
497 | unset($newsubmission->data2); // Don't need to update this. |
498 | |
9bf660b3 |
499 | //for fast grade, we need to check if any changes take place |
16907e53 |
500 | $updatedb = false; |
501 | |
502 | if ($grading) { |
503 | $grade = $_POST['menu'][$id]; |
504 | $updatedb = $updatedb || ($newsubmission->grade != $grade); |
505 | $newsubmission->grade = $grade; |
506 | } else { |
507 | unset($newsubmission->grade); // Don't need to update this. |
508 | } |
509 | if ($commenting) { |
510 | $commentvalue = $_POST['comment'][$id]; |
511 | $updatedb = $updatedb || ($newsubmission->comment != stripslashes($commentvalue)); |
512 | $newsubmission->comment = $commentvalue; |
513 | } else { |
514 | unset($newsubmission->comment); // Don't need to update this. |
515 | } |
516 | |
9bf660b3 |
517 | $newsubmission->teacher = $USER->id; |
16907e53 |
518 | $newsubmission->mailed = !$updatedb?$newsubmission->mailed:0;//only change if it's a duplicate |
9bf660b3 |
519 | $newsubmission->timemarked = time(); |
9bf660b3 |
520 | |
082215e6 |
521 | if (empty($newsubmission->timemodified)) { // eg for offline assignments |
522 | $newsubmission->timemodified = time(); |
9bf660b3 |
523 | } |
524 | |
525 | //if it is a duplicate, we don't change the last modified time etc. |
526 | //this will also not write into database if no comment and grade is entered. |
527 | |
16907e53 |
528 | if ($updatedb){ |
9bf660b3 |
529 | if (!update_record('assignment_submissions', $newsubmission)) { |
082215e6 |
530 | return false; |
9bf660b3 |
531 | } |
532 | //add to log only if not a duplicate |
533 | add_to_log($this->course->id, 'assignment', 'update grades', |
082215e6 |
534 | 'submissions.php?id='.$this->assignment->id.'&user='.$newsubmission->userid, |
535 | $newsubmission->userid, $this->cm->id); |
9bf660b3 |
536 | } |
537 | |
538 | } |
539 | $this->display_submissions(); |
540 | break; |
541 | |
542 | |
543 | case 'next': |
544 | /// We are currently in pop up, but we want to skip to next one without saving. |
545 | /// This turns out to be similar to a single case |
546 | /// The URL used is for the next submission. |
547 | |
548 | $this->display_submission(); |
549 | break; |
550 | |
551 | case 'saveandnext': |
552 | ///We are in pop up. save the current one and go to the next one. |
553 | //first we save the current changes |
554 | if ($submission = $this->process_feedback()) { |
555 | //print_heading(get_string('changessaved')); |
556 | $this->update_main_listing($submission); |
557 | } |
558 | |
559 | //then we display the next submission |
560 | $this->display_submission(); |
561 | break; |
562 | |
563 | default: |
564 | echo "something seriously is wrong!!"; |
565 | break; |
a56d79cd |
566 | } |
b0f2597e |
567 | } |
9bf660b3 |
568 | |
569 | //function that updates the listing on the main script from popup using javascript |
be86672d |
570 | function update_main_listing($submission) { |
571 | global $SESSION; |
9bf660b3 |
572 | |
573 | $perpage = get_user_preferences('assignment_perpage', 10); |
be86672d |
574 | |
9bf660b3 |
575 | $quickgrade = get_user_preferences('assignment_quickgrade', 0); |
576 | |
be86672d |
577 | /// Run some Javascript to try and update the parent page |
578 | echo '<script type="text/javascript">'."\n<!--\n"; |
be86672d |
579 | if (empty($SESSION->flextable['mod-assignment-submissions']->collapse['comment'])) { |
9bf660b3 |
580 | if ($quickgrade){ |
581 | echo 'opener.document.getElementById("comment['.$submission->userid.']").value="' |
582 | .trim($submission->comment).'";'."\n"; |
583 | } else { |
584 | echo 'opener.document.getElementById("com'.$submission->userid. |
585 | '").innerHTML="'.shorten_text(trim(strip_tags($submission->comment)), 15)."\";\n"; |
586 | } |
be86672d |
587 | } |
9bf660b3 |
588 | |
589 | if (empty($SESSION->flextable['mod-assignment-submissions']->collapse['grade'])) { |
590 | //echo optional_param('menuindex'); |
591 | if ($quickgrade){ |
592 | echo 'opener.document.getElementById("menumenu['.$submission->userid. |
16907e53 |
593 | ']").selectedIndex="'.optional_param('menuindex', 0, PARAM_INT).'";'."\n"; |
9bf660b3 |
594 | } else { |
595 | echo 'opener.document.getElementById("g'.$submission->userid.'").innerHTML="'. |
596 | $this->display_grade($submission->grade)."\";\n"; |
597 | } |
598 | } |
599 | //need to add student's assignments in there too. |
73097f07 |
600 | if (empty($SESSION->flextable['mod-assignment-submissions']->collapse['timemodified']) && |
601 | $submission->timemodified) { |
be86672d |
602 | echo 'opener.document.getElementById("ts'.$submission->userid. |
9bf660b3 |
603 | '").innerHTML="'.addslashes($this->print_student_answer($submission->userid)).userdate($submission->timemodified)."\";\n"; |
be86672d |
604 | } |
9bf660b3 |
605 | |
73097f07 |
606 | if (empty($SESSION->flextable['mod-assignment-submissions']->collapse['timemarked']) && |
607 | $submission->timemarked) { |
be86672d |
608 | echo 'opener.document.getElementById("tt'.$submission->userid. |
609 | '").innerHTML="'.userdate($submission->timemarked)."\";\n"; |
610 | } |
9bf660b3 |
611 | |
be86672d |
612 | if (empty($SESSION->flextable['mod-assignment-submissions']->collapse['status'])) { |
9bf660b3 |
613 | echo 'opener.document.getElementById("up'.$submission->userid.'").className="s1";'; |
614 | $buttontext = get_string('update'); |
16907e53 |
615 | $button = link_to_popup_window ('/mod/assignment/submissions.php?id='.$this->cm->id.'&userid='.$submission->userid.'&mode=single'.'&offset='.optional_param('offset', '', PARAM_INT), |
9bf660b3 |
616 | 'grade'.$submission->userid, $buttontext, 450, 700, $buttontext, 'none', true, 'button'.$submission->userid); |
617 | echo 'opener.document.getElementById("up'.$submission->userid.'").innerHTML="'.addslashes($button).'";'; |
618 | } |
be86672d |
619 | echo "\n-->\n</script>"; |
3262ee10 |
620 | flush(); |
be86672d |
621 | } |
d699cd1e |
622 | |
d59269cf |
623 | /* |
624 | * Display a grade in user-friendly form, whether it's a scale or not |
625 | * |
626 | */ |
627 | function display_grade($grade) { |
628 | |
c86aa2a4 |
629 | static $scalegrades = array(); // Cache scales for each assignment - they might have different scales!! |
d59269cf |
630 | |
631 | if ($this->assignment->grade >= 0) { // Normal number |
082215e6 |
632 | if ($grade == -1) { |
633 | return '-'; |
634 | } else { |
635 | return $grade.' / '.$this->assignment->grade; |
636 | } |
d59269cf |
637 | |
638 | } else { // Scale |
c86aa2a4 |
639 | if (empty($scalegrades[$this->assignment->id])) { |
d59269cf |
640 | if ($scale = get_record('scale', 'id', -($this->assignment->grade))) { |
c86aa2a4 |
641 | $scalegrades[$this->assignment->id] = make_menu_from_list($scale->scale); |
d59269cf |
642 | } else { |
643 | return '-'; |
644 | } |
645 | } |
c86aa2a4 |
646 | if (isset($scalegrades[$this->assignment->id][$grade])) { |
647 | return $scalegrades[$this->assignment->id][$grade]; |
0f7d4e5e |
648 | } |
649 | return ''; |
d59269cf |
650 | } |
651 | } |
652 | |
b0f2597e |
653 | /* |
654 | * Display a single submission, ready for grading on a popup window |
655 | * |
656 | */ |
657 | function display_submission() { |
9bf660b3 |
658 | |
082215e6 |
659 | global $CFG; |
b0f2597e |
660 | |
4fdabdc3 |
661 | $userid = required_param('userid', PARAM_INT); |
662 | $offset = required_param('offset', PARAM_INT);//offset for where to start looking for student. |
d699cd1e |
663 | |
b0f2597e |
664 | if (!$user = get_record('user', 'id', $userid)) { |
665 | error('No such user!'); |
666 | } |
d699cd1e |
667 | |
0f7d4e5e |
668 | if (!$submission = $this->get_submission($user->id, true)) { // Get one or make one |
b0f2597e |
669 | error('Could not find submission!'); |
670 | } |
a5a4cd60 |
671 | |
b0f2597e |
672 | if ($submission->timemodified > $submission->timemarked) { |
673 | $subtype = 'assignmentnew'; |
674 | } else { |
675 | $subtype = 'assignmentold'; |
676 | } |
d699cd1e |
677 | |
9bf660b3 |
678 | ///construct SQL, using current offset to find the data of the next student |
679 | $course = $this->course; |
680 | $assignment = $this->assignment; |
681 | $cm = $this->cm; |
682 | |
683 | if ($groupmode = groupmode($course, $cm)) { // Groups are being used |
684 | $currentgroup = setup_and_print_groups($course, $groupmode, 'submissions.php?id='.$this->cm->id); |
685 | } else { |
686 | $currentgroup = false; |
687 | } |
d699cd1e |
688 | |
9bf660b3 |
689 | /// Get all teachers and students |
690 | if ($currentgroup) { |
691 | $users = get_group_users($currentgroup); |
692 | } else { |
693 | $users = get_course_users($course->id); |
694 | } |
5b48244f |
695 | |
082215e6 |
696 | $select = 'SELECT u.id, u.id, u.firstname, u.lastname, u.picture,'. |
697 | 's.id AS submissionid, s.grade, s.comment, s.timemodified, s.timemarked, ((s.timemarked > 0) AND (s.timemarked >= s.timemodified)) AS status '; |
9bf660b3 |
698 | $sql = 'FROM '.$CFG->prefix.'user u '. |
699 | 'LEFT JOIN '.$CFG->prefix.'assignment_submissions s ON u.id = s.userid AND s.assignment = '.$this->assignment->id.' '. |
082215e6 |
700 | 'WHERE u.id IN ('.implode(',', array_keys($users)).') '; |
02828119 |
701 | |
702 | require_once($CFG->libdir.'/tablelib.php'); |
703 | if($sort = flexible_table::get_sql_sort('mod-assignment-submissions')) { |
704 | $sort = 'ORDER BY '.$sort.' '; |
705 | } |
706 | |
707 | $limit = sql_paging_limit($offset+1, 1); |
708 | |
082215e6 |
709 | $nextid = 0; |
5b48244f |
710 | if (($auser = get_record_sql($select.$sql.$sort.$limit)) !== false) { |
711 | $nextid = $auser->id; |
9bf660b3 |
712 | } |
713 | print_header(get_string('feedback', 'assignment').':'.fullname($user, true).':'.format_string($this->assignment->name)); |
d699cd1e |
714 | |
9bf660b3 |
715 | ///SOme javascript to help with setting up >.> |
716 | |
c9977d05 |
717 | echo '<script type="text/javascript">'."\n"; |
9bf660b3 |
718 | echo 'function setNext(){'."\n"; |
719 | echo 'document.submitform.mode.value=\'next\';'."\n"; |
720 | echo 'document.submitform.userid.value="'.$nextid.'";'."\n"; |
721 | echo '}'."\n"; |
722 | |
723 | echo 'function saveNext(){'."\n"; |
724 | echo 'document.submitform.mode.value=\'saveandnext\';'."\n"; |
725 | echo 'document.submitform.userid.value="'.$nextid.'";'."\n"; |
726 | echo 'document.submitform.saveuserid.value="'.$userid.'";'."\n"; |
727 | echo 'document.submitform.menuindex.value = document.submitform.grade.selectedIndex;'."\n"; |
728 | echo '}'."\n"; |
729 | |
730 | echo '</script>'."\n"; |
52436fe1 |
731 | echo '<table cellspacing="0" class="feedback '.$subtype.'" >'; |
d699cd1e |
732 | |
9bf660b3 |
733 | ///Start of teacher info row |
c69cb506 |
734 | |
b0f2597e |
735 | echo '<tr>'; |
736 | echo '<td width="35" valign="top" class="picture teacher">'; |
737 | if ($submission->teacher) { |
738 | $teacher = get_record('user', 'id', $submission->teacher); |
739 | } else { |
740 | global $USER; |
741 | $teacher = $USER; |
742 | } |
743 | print_user_picture($teacher->id, $this->course->id, $teacher->picture); |
744 | echo '</td>'; |
745 | echo '<td class="content">'; |
9894b824 |
746 | echo '<form name="submitform" action="submissions.php" method="post">'; |
747 | echo '<input type="hidden" name="offset" value="'.++$offset.'">'; |
c9977d05 |
748 | echo '<input type="hidden" name="userid" value="'.$userid.'" />'; |
749 | echo '<input type="hidden" name="id" value="'.$this->cm->id.'" />'; |
750 | echo '<input type="hidden" name="mode" value="grade" />'; |
751 | echo '<input type="hidden" name="menuindex" value="0" />';//selected menu index |
9bf660b3 |
752 | |
753 | //new hidden field, initialized to -1. |
c9977d05 |
754 | echo '<input type="hidden" name="saveuserid" value="-1" />'; |
b0f2597e |
755 | if (!$submission->grade and !$submission->timemarked) { |
756 | $submission->grade = -1; /// Hack to stop zero being selected on the menu below (so it shows 'no grade') |
757 | } |
52436fe1 |
758 | if ($submission->timemarked) { |
759 | echo '<div class="from">'; |
760 | echo '<div class="fullname">'.fullname($teacher, true).'</div>'; |
761 | echo '<div class="time">'.userdate($submission->timemarked).'</div>'; |
762 | echo '</div>'; |
763 | } |
764 | echo '<div class="grade">'.get_string('grade').':'; |
082215e6 |
765 | choose_from_menu(make_grades_menu($this->assignment->grade), 'grade', $submission->grade, get_string('nograde'), '', -1); |
52436fe1 |
766 | echo '</div>'; |
767 | echo '<div class="clearer"></div>'; |
b0f2597e |
768 | |
01e2fdfe |
769 | $this->preprocess_submission($submission); |
770 | |
b0f2597e |
771 | echo '<br />'; |
a8166227 |
772 | print_textarea($this->usehtmleditor, 14, 58, 0, 0, 'comment', $submission->comment, $this->course->id); |
ff8f7015 |
773 | |
ff8f7015 |
774 | if ($this->usehtmleditor) { |
ff8f7015 |
775 | echo '<input type="hidden" name="format" value="'.FORMAT_HTML.'" />'; |
776 | } else { |
f77cfb73 |
777 | echo '<div align="right" class="format">'; |
ff8f7015 |
778 | choose_from_menu(format_text_menu(), "format", $submission->format, ""); |
f77cfb73 |
779 | helpbutton("textformat", get_string("helpformatting")); |
780 | echo '</div>'; |
ff8f7015 |
781 | } |
b0f2597e |
782 | |
9bf660b3 |
783 | ///Print Buttons in Single View |
73097f07 |
784 | echo '<div class="buttons" align="center">'; |
c9977d05 |
785 | echo '<input type="submit" name="submit" value="'.get_string('savechanges').'" onclick = "document.submitform.menuindex.value = document.submitform.grade.selectedIndex" />'; |
b0f2597e |
786 | echo '<input type="submit" name="cancel" value="'.get_string('cancel').'" />'; |
9bf660b3 |
787 | //if there are more to be graded. |
082215e6 |
788 | if ($nextid) { |
5b48244f |
789 | echo '<input type="submit" name="saveandnext" value="'.get_string('saveandnext').'" onclick="saveNext()" />'; |
790 | echo '<input type="submit" name="next" value="'.get_string('next').'" onclick="setNext();" />'; |
9bf660b3 |
791 | } |
73097f07 |
792 | echo '</div>'; |
b0f2597e |
793 | echo '</form>'; |
73097f07 |
794 | echo '</td></tr>'; |
9bf660b3 |
795 | |
796 | ///End of teacher info row, Start of student info row |
797 | echo '<tr>'; |
798 | echo '<td width="35" valign="top" class="picture user">'; |
799 | print_user_picture($user->id, $this->course->id, $user->picture); |
800 | echo '</td>'; |
801 | echo '<td class="topic">'; |
802 | echo '<div class="from">'; |
803 | echo '<div class="fullname">'.fullname($user, true).'</div>'; |
804 | if ($submission->timemodified) { |
805 | echo '<div class="time">'.userdate($submission->timemodified). |
806 | $this->display_lateness($submission->timemodified).'</div>'; |
807 | } |
808 | echo '</div>'; |
809 | $this->print_user_files($user->id); |
810 | echo '</td>'; |
811 | echo '</tr>'; |
812 | |
813 | ///End of student info row |
814 | |
73097f07 |
815 | echo '</table>'; |
816 | |
73097f07 |
817 | if ($this->usehtmleditor) { |
818 | use_html_editor(); |
819 | } |
820 | |
b0f2597e |
821 | print_footer('none'); |
d699cd1e |
822 | } |
823 | |
01e2fdfe |
824 | /* |
825 | * Preprocess submission before grading |
826 | */ |
827 | function preprocess_submission(&$submission) { |
828 | } |
d699cd1e |
829 | |
b0f2597e |
830 | /* |
831 | * Display all the submissions ready for grading |
832 | */ |
833 | function display_submissions() { |
3446205d |
834 | |
9bf660b3 |
835 | global $CFG, $db, $USER; |
3446205d |
836 | |
9bf660b3 |
837 | /* first we check to see if the form has just been submitted |
838 | * to request user_preference updates |
839 | */ |
840 | |
841 | if (isset($_POST['updatepref'])){ |
16907e53 |
842 | $perpage = optional_param('perpage', 10, PARAM_INT); |
9bf660b3 |
843 | $perpage = ($perpage <= 0) ? 10 : $perpage ; |
844 | set_user_preference('assignment_perpage', $perpage); |
16907e53 |
845 | set_user_preference('assignment_quickgrade', optional_param('quickgrade',0, PARAM_BOOL)); |
9bf660b3 |
846 | } |
1b5910c4 |
847 | |
9bf660b3 |
848 | /* next we get perpage and quickgrade (allow quick grade) params |
849 | * from database |
850 | */ |
851 | $perpage = get_user_preferences('assignment_perpage', 10); |
852 | $quickgrade = get_user_preferences('assignment_quickgrade', 0); |
853 | |
854 | $teacherattempts = true; /// Temporary measure |
16907e53 |
855 | $page = optional_param('page', 0, PARAM_INT); |
b0f2597e |
856 | $strsaveallfeedback = get_string('saveallfeedback', 'assignment'); |
d0ac6bc2 |
857 | |
b0f2597e |
858 | /// Some shortcuts to make the code read better |
859 | |
860 | $course = $this->course; |
861 | $assignment = $this->assignment; |
862 | $cm = $this->cm; |
9bf660b3 |
863 | |
864 | $tabindex = 1; //tabindex for quick grading tabbing; Not working for dropdowns yet |
91719320 |
865 | |
b0f2597e |
866 | add_to_log($course->id, 'assignment', 'view submission', 'submissions.php?id='.$this->assignment->id, $this->assignment->id, $this->cm->id); |
867 | |
3898bc33 |
868 | print_header_simple(format_string($this->assignment->name,true), "", '<a href="index.php?id='.$course->id.'">'.$this->strassignments.'</a> -> <a href="view.php?a='.$this->assignment->id.'">'.format_string($this->assignment->name,true).'</a> -> '. $this->strsubmissions, '', '', true, update_module_button($cm->id, $course->id, $this->strassignment), navmenu($course, $cm)); |
fa22fd5f |
869 | |
870 | ///Position swapped |
871 | if ($groupmode = groupmode($course, $cm)) { // Groups are being used |
872 | $currentgroup = setup_and_print_groups($course, $groupmode, 'submissions.php?id='.$this->cm->id); |
873 | } else { |
874 | $currentgroup = false; |
875 | } |
876 | |
877 | /// Get all teachers and students |
878 | if ($currentgroup) { |
879 | $users = get_group_users($currentgroup); |
880 | } else { |
881 | $users = get_course_users($course->id); |
882 | } |
91719320 |
883 | |
9437c854 |
884 | $tablecolumns = array('picture', 'fullname', 'grade', 'comment', 'timemodified', 'timemarked', 'status'); |
885 | $tableheaders = array('', get_string('fullname'), get_string('grade'), get_string('comment', 'assignment'), get_string('lastmodified').' ('.$course->student.')', get_string('lastmodified').' ('.$course->teacher.')', get_string('status')); |
91719320 |
886 | |
b0f2597e |
887 | require_once($CFG->libdir.'/tablelib.php'); |
888 | $table = new flexible_table('mod-assignment-submissions'); |
889 | |
890 | $table->define_columns($tablecolumns); |
891 | $table->define_headers($tableheaders); |
fa22fd5f |
892 | $table->define_baseurl($CFG->wwwroot.'/mod/assignment/submissions.php?id='.$this->cm->id.'&currentgroup='.$currentgroup); |
b0f2597e |
893 | |
894 | $table->sortable(true); |
895 | $table->collapsible(true); |
896 | $table->initialbars(true); |
897 | |
898 | $table->column_suppress('picture'); |
899 | $table->column_suppress('fullname'); |
900 | |
901 | $table->column_class('picture', 'picture'); |
9437c854 |
902 | $table->column_class('fullname', 'fullname'); |
903 | $table->column_class('grade', 'grade'); |
904 | $table->column_class('comment', 'comment'); |
905 | $table->column_class('timemodified', 'timemodified'); |
906 | $table->column_class('timemarked', 'timemarked'); |
907 | $table->column_class('status', 'status'); |
b0f2597e |
908 | |
909 | $table->set_attribute('cellspacing', '0'); |
910 | $table->set_attribute('id', 'attempts'); |
9437c854 |
911 | $table->set_attribute('class', 'submissions'); |
b0f2597e |
912 | $table->set_attribute('width', '90%'); |
913 | $table->set_attribute('align', 'center'); |
914 | |
915 | // Start working -- this is necessary as soon as the niceties are over |
916 | $table->setup(); |
917 | |
b0f2597e |
918 | /// Check to see if groups are being used in this assignment |
05855091 |
919 | |
b0f2597e |
920 | if (!$teacherattempts) { |
921 | $teachers = get_course_teachers($course->id); |
922 | if (!empty($teachers)) { |
923 | $keys = array_keys($teachers); |
924 | } |
925 | foreach ($keys as $key) { |
926 | unset($users[$key]); |
927 | } |
928 | } |
929 | |
930 | if (empty($users)) { |
c8dbfa5c |
931 | print_heading(get_string('noattempts','assignment')); |
b0f2597e |
932 | return true; |
933 | } |
0f1a97c2 |
934 | |
b0f2597e |
935 | /// Construct the SQL |
0f1a97c2 |
936 | |
b0f2597e |
937 | if ($where = $table->get_sql_where()) { |
b0f2597e |
938 | $where .= ' AND '; |
939 | } |
0f1a97c2 |
940 | |
b0f2597e |
941 | if ($sort = $table->get_sql_sort()) { |
86f65395 |
942 | $sort = ' ORDER BY '.$sort; |
b0f2597e |
943 | } |
9fa49e22 |
944 | |
042311a9 |
945 | $select = 'SELECT u.id, u.id, u.firstname, u.lastname, u.picture, s.id AS submissionid, s.grade, s.comment, s.timemodified, s.timemarked, ((s.timemarked > 0) AND (s.timemarked >= s.timemodified)) AS status '; |
b0f2597e |
946 | $sql = 'FROM '.$CFG->prefix.'user u '. |
306dc7e5 |
947 | 'LEFT JOIN '.$CFG->prefix.'assignment_submissions s ON u.id = s.userid AND s.assignment = '.$this->assignment->id.' '. |
948 | 'WHERE '.$where.'u.id IN ('.implode(',', array_keys($users)).') '; |
9bf660b3 |
949 | |
c5d36203 |
950 | $table->pagesize($perpage, count($users)); |
b0f2597e |
951 | |
952 | if($table->get_page_start() !== '' && $table->get_page_size() !== '') { |
953 | $limit = ' '.sql_paging_limit($table->get_page_start(), $table->get_page_size()); |
954 | } |
955 | else { |
956 | $limit = ''; |
957 | } |
9bf660b3 |
958 | |
9bf660b3 |
959 | ///offset used to calculate index of student in that particular query, needed for the pop up to know who's next |
960 | $offset = $page * $perpage; |
961 | |
b0f2597e |
962 | $strupdate = get_string('update'); |
9437c854 |
963 | $strgrade = get_string('grade'); |
b0f2597e |
964 | $grademenu = make_grades_menu($this->assignment->grade); |
965 | |
c5d36203 |
966 | if (($ausers = get_records_sql($select.$sql.$sort.$limit)) !== false) { |
d59269cf |
967 | |
d59269cf |
968 | foreach ($ausers as $auser) { |
969 | $picture = print_user_picture($auser->id, $course->id, $auser->picture, false, true); |
9bf660b3 |
970 | |
971 | if (!$auser->grade and !$auser->timemarked and $quickgrade) { |
972 | $auser->grade = -1;//Martin's hack to prevent 0 showing up and select no grade instead. |
973 | } |
974 | |
d59269cf |
975 | if (!empty($auser->submissionid)) { |
9bf660b3 |
976 | ///Prints student answer and student modified date |
977 | ///attach file or print link to student answer, depending on the type of the assignment. |
978 | ///Refer to print_student_answer in inherited classes. |
979 | if ($auser->timemodified > 0) { |
980 | $studentmodified = '<div id="ts'.$auser->id.'">'.$this->print_student_answer($auser->id).userdate($auser->timemodified).'</div>'; |
d59269cf |
981 | } else { |
9437c854 |
982 | $studentmodified = '<div id="ts'.$auser->id.'"> </div>'; |
d59269cf |
983 | } |
9bf660b3 |
984 | ///Print grade, dropdown or text |
d59269cf |
985 | if ($auser->timemarked > 0) { |
986 | $teachermodified = '<div id="tt'.$auser->id.'">'.userdate($auser->timemarked).'</div>'; |
9bf660b3 |
987 | |
988 | if ($quickgrade) { |
989 | $grade = '<div id="g'.$auser->id.'">'.choose_from_menu(make_grades_menu($this->assignment->grade), |
082215e6 |
990 | 'menu['.$auser->id.']', $auser->grade, get_string('nograde'),'',-1,true,false,$tabindex++).'</div>'; |
9bf660b3 |
991 | } else { |
992 | $grade = '<div id="g'.$auser->id.'">'.$this->display_grade($auser->grade).'</div>'; |
993 | } |
994 | |
b0f2597e |
995 | } else { |
9437c854 |
996 | $teachermodified = '<div id="tt'.$auser->id.'"> </div>'; |
9bf660b3 |
997 | if ($quickgrade){ |
998 | $grade = '<div id="g'.$auser->id.'">'.choose_from_menu(make_grades_menu($this->assignment->grade), |
082215e6 |
999 | 'menu['.$auser->id.']', $auser->grade, get_string('nograde'),'',-1,true,false,$tabindex++).'</div>'; |
9bf660b3 |
1000 | } else { |
1001 | $grade = '<div id="g'.$auser->id.'">'.$this->display_grade($auser->grade).'</div>'; |
1002 | } |
1003 | } |
1004 | ///Print Comment |
1005 | if ($quickgrade){ |
1006 | $comment = '<div id="com'.$auser->id.'"><textarea tabindex="'.$tabindex++.'" name="comment['.$auser->id.']" id="comment['.$auser->id.']">'.($auser->comment).'</textarea></div>'; |
1007 | } else { |
1008 | $comment = '<div id="com'.$auser->id.'">'.shorten_text(strip_tags($auser->comment),15).'</div>'; |
b0f2597e |
1009 | } |
1010 | } else { |
9437c854 |
1011 | $studentmodified = '<div id="ts'.$auser->id.'"> </div>'; |
1012 | $teachermodified = '<div id="tt'.$auser->id.'"> </div>'; |
9bf660b3 |
1013 | $status = '<div id="st'.$auser->id.'"> </div>'; |
1014 | if ($quickgrade){ // allow editing |
1015 | $grade = '<div id="g'.$auser->id.'">'.choose_from_menu(make_grades_menu($this->assignment->grade), |
082215e6 |
1016 | 'menu['.$auser->id.']', $auser->grade, get_string('nograde'),'',-1,true,false,$tabindex++).'</div>'; |
9bf660b3 |
1017 | } else { |
1018 | $grade = '<div id="g'.$auser->id.'"> </div>'; |
1019 | } |
1020 | if ($quickgrade){ |
1021 | $comment = '<div id="com'.$auser->id.'"><textarea tabindex="'.$tabindex++.'" name="comment['.$auser->id.']" id="comment['.$auser->id.']">'.($auser->comment).'</textarea></div>'; |
1022 | } else { |
1023 | $comment = '<div id="com'.$auser->id.'"> </div>'; |
1024 | } |
b0f2597e |
1025 | } |
9fa49e22 |
1026 | |
0f7d4e5e |
1027 | if ($auser->status === NULL) { |
1028 | $auser->status = 0; |
1029 | } |
1030 | |
9437c854 |
1031 | $buttontext = ($auser->status == 1) ? $strupdate : $strgrade; |
9bf660b3 |
1032 | |
1033 | ///No more buttons, we use popups ;-). |
9894b824 |
1034 | $button = link_to_popup_window ('/mod/assignment/submissions.php?id='.$this->cm->id.'&userid='.$auser->id.'&mode=single'.'&offset='.$offset++, |
a8166227 |
1035 | 'grade'.$auser->id, $buttontext, 500, 780, $buttontext, 'none', true, 'button'.$auser->id); |
0f7d4e5e |
1036 | |
9437c854 |
1037 | $status = '<div id="up'.$auser->id.'" class="s'.$auser->status.'">'.$button.'</div>'; |
9bf660b3 |
1038 | |
9437c854 |
1039 | $row = array($picture, fullname($auser), $grade, $comment, $studentmodified, $teachermodified, $status); |
d59269cf |
1040 | $table->add_data($row); |
1041 | } |
b0f2597e |
1042 | } |
9bf660b3 |
1043 | |
082215e6 |
1044 | /// Print quickgrade form around the table |
1045 | if ($quickgrade){ |
1046 | echo '<form action="submissions.php" name="fastg" method="post">'; |
1047 | echo '<input type="hidden" name="id" value="'.$this->cm->id.'">'; |
1048 | echo '<input type="hidden" name="mode" value="fastgrade">'; |
16907e53 |
1049 | echo '<input type="hidden" name="page" value="'.$page.'">'; |
082215e6 |
1050 | } |
1051 | |
1052 | $table->print_html(); /// Print the whole table |
1053 | |
9bf660b3 |
1054 | if ($quickgrade){ |
1055 | echo '<p align="center"><input type="submit" name="fastg" value="'.get_string('saveallfeedback', 'assignment').'" /></p>'; |
082215e6 |
1056 | echo '</form>'; |
9bf660b3 |
1057 | } |
082215e6 |
1058 | /// End of fast grading form |
9bf660b3 |
1059 | |
082215e6 |
1060 | /// Mini form for setting user preference |
9bf660b3 |
1061 | echo '<br />'; |
1062 | echo '<form name="options" action="submissions.php?id='.$this->cm->id.'" method="post">'; |
c9977d05 |
1063 | echo '<input type="hidden" id="updatepref" name="updatepref" value="1" />'; |
9bf660b3 |
1064 | echo '<table id="optiontable" align="center">'; |
1065 | echo '<tr align="right"><td>'; |
1066 | echo '<label for="perpage">'.get_string('pagesize','assignment').'</label>'; |
1067 | echo ':</td>'; |
9bf660b3 |
1068 | echo '<td align="left">'; |
1069 | echo '<input type="text" id="perpage" name="perpage" size="1" value="'.$perpage.'" />'; |
1070 | helpbutton('pagesize', get_string('pagesize','assignment'), 'assignment'); |
1071 | echo '</td></tr>'; |
1072 | echo '<tr align="right">'; |
1073 | echo '<td>'; |
1074 | print_string('quickgrade','assignment'); |
1075 | echo ':</td>'; |
1076 | echo '<td align="left">'; |
1077 | if ($quickgrade){ |
1078 | echo '<input type="checkbox" name="quickgrade" value="1" checked="checked" />'; |
1079 | } else { |
1080 | echo '<input type="checkbox" name="quickgrade" value="1" />'; |
1081 | } |
1082 | helpbutton('quickgrade', get_string('quickgrade', 'assignment'), 'assignment').'</p></div>'; |
1083 | echo '</td></tr>'; |
1084 | echo '<tr>'; |
1085 | echo '<td colspan="2" align="right">'; |
1086 | echo '<input type="submit" value="'.get_string('savepreferences').'" />'; |
1087 | echo '</td></tr></table>'; |
1088 | echo '</form>'; |
1089 | ///End of mini form |
b0f2597e |
1090 | print_footer($this->course); |
8e340cb0 |
1091 | } |
d699cd1e |
1092 | |
b0f2597e |
1093 | /* |
1094 | * Display and process the submissions |
1095 | */ |
1096 | function process_feedback() { |
d699cd1e |
1097 | |
b0f2597e |
1098 | global $USER; |
d699cd1e |
1099 | |
9894b824 |
1100 | if (!$feedback = data_submitted()) { // No incoming data? |
b0f2597e |
1101 | return false; |
d699cd1e |
1102 | } |
b7b42874 |
1103 | |
9bf660b3 |
1104 | ///For save and next, we need to know the userid to save, and the userid to go |
1105 | ///We use a new hidden field in the form, and set it to -1. If it's set, we use this |
1106 | ///as the userid to store |
1107 | if ((int)$feedback->saveuserid !== -1){ |
1108 | $feedback->userid = $feedback->saveuserid; |
1109 | } |
1110 | |
b0f2597e |
1111 | if (!empty($feedback->cancel)) { // User hit cancel button |
1112 | return false; |
1113 | } |
d699cd1e |
1114 | |
0f7d4e5e |
1115 | $newsubmission = $this->get_submission($feedback->userid, true); // Get or make one |
d699cd1e |
1116 | |
b0f2597e |
1117 | $newsubmission->grade = $feedback->grade; |
1118 | $newsubmission->comment = $feedback->comment; |
ff8f7015 |
1119 | $newsubmission->format = $feedback->format; |
b0f2597e |
1120 | $newsubmission->teacher = $USER->id; |
1121 | $newsubmission->mailed = 0; // Make sure mail goes out (again, even) |
1122 | $newsubmission->timemarked = time(); |
d699cd1e |
1123 | |
d4156e80 |
1124 | unset($newsubmission->data1); // Don't need to update this. |
1125 | unset($newsubmission->data2); // Don't need to update this. |
1126 | |
b0f2597e |
1127 | if (empty($submission->timemodified)) { // eg for offline assignments |
1128 | $newsubmission->timemodified = time(); |
1129 | } |
d699cd1e |
1130 | |
b0f2597e |
1131 | if (! update_record('assignment_submissions', $newsubmission)) { |
1132 | return false; |
1133 | } |
d699cd1e |
1134 | |
b0f2597e |
1135 | add_to_log($this->course->id, 'assignment', 'update grades', |
1136 | 'submissions.php?id='.$this->assignment->id.'&user='.$feedback->userid, $feedback->userid, $this->cm->id); |
1137 | |
1138 | return $newsubmission; |
d699cd1e |
1139 | |
d699cd1e |
1140 | } |
d699cd1e |
1141 | |
f77cfb73 |
1142 | function get_submission($userid=0, $createnew=false) { |
1143 | global $USER; |
1144 | |
1145 | if (empty($userid)) { |
1146 | $userid = $USER->id; |
1147 | } |
1148 | |
b0f2597e |
1149 | $submission = get_record('assignment_submissions', 'assignment', $this->assignment->id, 'userid', $userid); |
d699cd1e |
1150 | |
b0f2597e |
1151 | if ($submission || !$createnew) { |
1152 | return $submission; |
1153 | } |
d699cd1e |
1154 | |
b0f2597e |
1155 | $newsubmission = new Object; |
1156 | $newsubmission->assignment = $this->assignment->id; |
1157 | $newsubmission->userid = $userid; |
1158 | $newsubmission->timecreated = time(); |
16907e53 |
1159 | $newsubmission->grade = -1; |
b0f2597e |
1160 | if (!insert_record("assignment_submissions", $newsubmission)) { |
1161 | error("Could not insert a new empty submission"); |
1162 | } |
d699cd1e |
1163 | |
b0f2597e |
1164 | return get_record('assignment_submissions', 'assignment', $this->assignment->id, 'userid', $userid); |
1165 | } |
d699cd1e |
1166 | |
3f8247c2 |
1167 | |
b0f2597e |
1168 | function get_submissions($sort='', $dir='DESC') { |
1169 | /// Return all assignment submissions by ENROLLED students (even empty) |
1170 | global $CFG; |
1171 | |
1172 | if ($sort == "lastname" or $sort == "firstname") { |
1173 | $sort = "u.$sort $dir"; |
1174 | } else if (empty($sort)) { |
1175 | $sort = "a.timemodified DESC"; |
1176 | } else { |
1177 | $sort = "a.$sort $dir"; |
d699cd1e |
1178 | } |
d699cd1e |
1179 | |
b0f2597e |
1180 | $select = "s.course = '$this->assignment->course' AND"; |
1181 | $site = get_site(); |
1182 | if ($this->assignment->course == $site->id) { |
1183 | $select = ''; |
1184 | } |
1185 | return get_records_sql("SELECT a.* |
1186 | FROM {$CFG->prefix}assignment_submissions a, |
1187 | {$CFG->prefix}user_students s, |
1188 | {$CFG->prefix}user u |
1189 | WHERE a.userid = s.userid |
1190 | AND u.id = a.userid |
1191 | AND $select a.assignment = '$this->assignment->id' |
1192 | ORDER BY $sort"); |
1193 | } |
1194 | |
1195 | |
1196 | function count_real_submissions($groupid=0) { |
1197 | /// Return all real assignment submissions by ENROLLED students (not empty ones) |
1198 | global $CFG; |
1199 | |
1200 | if ($groupid) { /// How many in a particular group? |
1201 | return count_records_sql("SELECT COUNT(DISTINCT g.userid, g.groupid) |
1202 | FROM {$CFG->prefix}assignment_submissions a, |
1203 | {$CFG->prefix}groups_members g |
1204 | WHERE a.assignment = {$this->assignment->id} |
1205 | AND a.timemodified > 0 |
1206 | AND g.groupid = '$groupid' |
1207 | AND a.userid = g.userid "); |
1208 | } else { |
1209 | $select = "s.course = '{$this->assignment->course}' AND"; |
1210 | if ($this->assignment->course == SITEID) { |
1211 | $select = ''; |
d699cd1e |
1212 | } |
b0f2597e |
1213 | return count_records_sql("SELECT COUNT(*) |
1214 | FROM {$CFG->prefix}assignment_submissions a, |
1215 | {$CFG->prefix}user_students s |
1216 | WHERE a.assignment = '{$this->assignment->id}' |
1217 | AND a.timemodified > 0 |
1218 | AND $select a.userid = s.userid "); |
1219 | } |
d59269cf |
1220 | } |
d699cd1e |
1221 | |
73097f07 |
1222 | function email_teachers($submission) { |
1223 | /// Alerts teachers by email of new or changed assignments that need grading |
1224 | |
1225 | global $CFG; |
1226 | |
d8199f1d |
1227 | if (empty($this->assignment->emailteachers)) { // No need to do anything |
73097f07 |
1228 | return; |
1229 | } |
1230 | |
1231 | $user = get_record('user', 'id', $submission->userid); |
1232 | |
d8199f1d |
1233 | if (groupmode($this->course, $this->cm) == SEPARATEGROUPS) { // Separate groups are being used |
1234 | if (!$group = user_group($this->course->id, $user->id)) { // Try to find a group |
73097f07 |
1235 | $group->id = 0; // Not in a group, never mind |
1236 | } |
d8199f1d |
1237 | $teachers = get_group_teachers($this->course->id, $group->id); // Works even if not in group |
73097f07 |
1238 | } else { |
d8199f1d |
1239 | $teachers = get_course_teachers($this->course->id); |
73097f07 |
1240 | } |
1241 | |
1242 | if ($teachers) { |
1243 | |
1244 | $strassignments = get_string('modulenameplural', 'assignment'); |
1245 | $strassignment = get_string('modulename', 'assignment'); |
1246 | $strsubmitted = get_string('submitted', 'assignment'); |
1247 | |
1248 | foreach ($teachers as $teacher) { |
1249 | unset($info); |
1250 | $info->username = fullname($user); |
d8199f1d |
1251 | $info->assignment = format_string($this->assignment->name,true); |
1252 | $info->url = $CFG->wwwroot.'/mod/assignment/submissions.php?id='.$this->cm->id; |
1253 | |
1254 | $postsubject = $strsubmitted.': '.$info->username.' -> '.$this->assignment->name; |
1255 | $posttext = $this->email_teachers_text($info); |
1256 | $posthtml = ($teacher->mailformat == 1) ? $this->email_teachers_html($info) : ''; |
73097f07 |
1257 | |
1258 | @email_to_user($teacher, $user, $postsubject, $posttext, $posthtml); // If it fails, oh well, too bad. |
1259 | } |
1260 | } |
1261 | } |
1262 | |
d8199f1d |
1263 | function email_teachers_text($info) { |
1264 | $posttext = $this->course->shortname.' -> '.$this->strassignments.' -> '. |
1265 | format_string($this->assignment->name, true)."\n"; |
1266 | $posttext .= '---------------------------------------------------------------------'."\n"; |
1267 | $posttext .= get_string("emailteachermail", "assignment", $info)."\n"; |
1268 | $posttext .= '---------------------------------------------------------------------'."\n"; |
1269 | return $posttext; |
1270 | } |
1271 | |
d8199f1d |
1272 | function email_teachers_html($info) { |
3554b5c2 |
1273 | global $CFG; |
d8199f1d |
1274 | $posthtml = '<p><font face="sans-serif">'. |
3554b5c2 |
1275 | '<a href="'.$CFG->wwwroot.'/course/view.php?id='.$this->course->id.'">'.$this->course->shortname.'</a> ->'. |
d8199f1d |
1276 | '<a href="'.$CFG->wwwroot.'/mod/assignment/index.php?id='.$this->course->id.'">'.$this->strassignments.'</a> ->'. |
3554b5c2 |
1277 | '<a href="'.$CFG->wwwroot.'/mod/assignment/view.php?id='.$this->cm->id.'">'.format_string($this->assignment->name,true).'</a></font></p>'; |
d8199f1d |
1278 | $posthtml .= '<hr /><font face="sans-serif">'; |
1279 | $posthtml .= '<p>'.get_string('emailteachermailhtml', 'assignment', $info).'</p>'; |
1280 | $posthtml .= '</font><hr />'; |
815b5ca6 |
1281 | return $posthtml; |
d8199f1d |
1282 | } |
1283 | |
d8199f1d |
1284 | function print_user_files($userid=0, $return=false) { |
d8199f1d |
1285 | global $CFG, $USER; |
9bf660b3 |
1286 | |
d8199f1d |
1287 | if (!$userid) { |
1288 | if (!isloggedin()) { |
1289 | return ''; |
1290 | } |
1291 | $userid = $USER->id; |
1292 | } |
73097f07 |
1293 | |
70b2c772 |
1294 | $filearea = $this->file_area_name($userid); |
73097f07 |
1295 | |
1296 | $output = ''; |
1297 | |
70b2c772 |
1298 | if ($basedir = $this->file_area($userid)) { |
73097f07 |
1299 | if ($files = get_directory_list($basedir)) { |
9bf660b3 |
1300 | |
73097f07 |
1301 | foreach ($files as $key => $file) { |
1302 | require_once($CFG->libdir.'/filelib.php'); |
9bf660b3 |
1303 | |
73097f07 |
1304 | $icon = mimeinfo('icon', $file); |
9bf660b3 |
1305 | |
73097f07 |
1306 | if ($CFG->slasharguments) { |
d4156e80 |
1307 | $ffurl = "$CFG->wwwroot/file.php/$filearea/$file"; |
73097f07 |
1308 | } else { |
d4156e80 |
1309 | $ffurl = "$CFG->wwwroot/file.php?file=/$filearea/$file"; |
73097f07 |
1310 | } |
9bf660b3 |
1311 | |
73097f07 |
1312 | $output = '<img align="middle" src="'.$CFG->pixpath.'/f/'.$icon.'" height="16" width="16" alt="'.$icon.'" />'. |
9bf660b3 |
1313 | '<a href="'.$ffurl.'" >'.$file.'</a><br />'; |
73097f07 |
1314 | } |
1315 | } |
1316 | } |
1317 | |
1318 | $output = '<div class="files">'.$output.'</div>'; |
1319 | |
1320 | if ($return) { |
1321 | return $output; |
1322 | } |
1323 | echo $output; |
1324 | } |
1325 | |
70b2c772 |
1326 | function count_user_files($userid) { |
1327 | global $CFG; |
1328 | |
1329 | $filearea = $this->file_area_name($userid); |
1330 | |
1331 | if ($basedir = $this->file_area($userid)) { |
1332 | if ($files = get_directory_list($basedir)) { |
1333 | return count($files); |
1334 | } |
1335 | } |
1336 | return 0; |
1337 | } |
73097f07 |
1338 | |
70b2c772 |
1339 | function file_area_name($userid) { |
73097f07 |
1340 | // Creates a directory file name, suitable for make_upload_directory() |
1341 | global $CFG; |
1342 | |
70b2c772 |
1343 | return $this->course->id.'/'.$CFG->moddata.'/assignment/'.$this->assignment->id.'/'.$userid; |
73097f07 |
1344 | } |
1345 | |
70b2c772 |
1346 | function file_area($userid) { |
1347 | return make_upload_directory( $this->file_area_name($userid) ); |
73097f07 |
1348 | } |
1349 | |
f77cfb73 |
1350 | function isopen() { |
1351 | $time = time(); |
1e4343a0 |
1352 | if ($this->assignment->preventlate && $this->assignment->timedue) { |
f77cfb73 |
1353 | return ($this->assignment->timeavailable <= $time && $time <= $this->assignment->timedue); |
1354 | } else { |
1355 | return ($this->assignment->timeavailable <= $time); |
1356 | } |
1357 | } |
1358 | |
73097f07 |
1359 | function user_outline($user) { |
1360 | if ($submission = $this->get_submission($user->id)) { |
1361 | |
1362 | if ($submission->grade) { |
f1893f44 |
1363 | $result->info = get_string('grade').': '.$this->display_grade($submission->grade); |
73097f07 |
1364 | } |
1365 | $result->time = $submission->timemodified; |
1366 | return $result; |
1367 | } |
1368 | return NULL; |
1369 | } |
1370 | |
1371 | function user_complete($user) { |
1372 | if ($submission = $this->get_submission($user->id)) { |
70b2c772 |
1373 | if ($basedir = $this->file_area($user->id)) { |
73097f07 |
1374 | if ($files = get_directory_list($basedir)) { |
1375 | $countfiles = count($files)." ".get_string("uploadedfiles", "assignment"); |
1376 | foreach ($files as $file) { |
1377 | $countfiles .= "; $file"; |
1378 | } |
1379 | } |
1380 | } |
1381 | |
1382 | print_simple_box_start(); |
1383 | echo get_string("lastmodified").": "; |
9bf660b3 |
1384 | echo userdate($submission->timemodified); |
1385 | echo $this->display_lateness($submission->timemodified); |
73097f07 |
1386 | |
70b2c772 |
1387 | $this->print_user_files($user->id); |
73097f07 |
1388 | |
1389 | echo '<br />'; |
1390 | |
1391 | if (empty($submission->timemarked)) { |
1392 | print_string("notgradedyet", "assignment"); |
1393 | } else { |
1394 | $this->view_feedback($submission); |
1395 | } |
1396 | |
1397 | print_simple_box_end(); |
1398 | |
1399 | } else { |
1400 | print_string("notsubmittedyet", "assignment"); |
1401 | } |
1402 | } |
1403 | |
70b2c772 |
1404 | function display_lateness($timesubmitted) { |
1e4343a0 |
1405 | if (!$this->assignment->timedue) { |
1406 | return ''; |
1407 | } |
70b2c772 |
1408 | $time = $this->assignment->timedue - $timesubmitted; |
73097f07 |
1409 | if ($time < 0) { |
1410 | $timetext = get_string('late', 'assignment', format_time($time)); |
70b2c772 |
1411 | return ' (<span class="late">'.$timetext.'</span>)'; |
73097f07 |
1412 | } else { |
1413 | $timetext = get_string('early', 'assignment', format_time($time)); |
70b2c772 |
1414 | return ' (<span class="early">'.$timetext.'</span>)'; |
73097f07 |
1415 | } |
1416 | } |
1417 | |
1418 | |
b0f2597e |
1419 | } ////// End of the assignment_base class |
d699cd1e |
1420 | |
18b8fbfa |
1421 | |
04eba58f |
1422 | |
b0f2597e |
1423 | /// OTHER STANDARD FUNCTIONS //////////////////////////////////////////////////////// |
1424 | |
1425 | |
1426 | function assignment_delete_instance($id){ |
26b90e70 |
1427 | global $CFG; |
1428 | |
b0f2597e |
1429 | if (! $assignment = get_record('assignment', 'id', $id)) { |
1430 | return false; |
26b90e70 |
1431 | } |
1432 | |
b0f2597e |
1433 | require_once("$CFG->dirroot/mod/assignment/type/$assignment->assignmenttype/assignment.class.php"); |
1434 | $assignmentclass = "assignment_$assignment->assignmenttype"; |
1435 | $ass = new $assignmentclass(); |
1436 | return $ass->delete_instance($assignment); |
1437 | } |
f466c9ed |
1438 | |
ac21ad39 |
1439 | |
b0f2597e |
1440 | function assignment_update_instance($assignment){ |
1441 | global $CFG; |
26b90e70 |
1442 | |
200c19fb |
1443 | $assignment->assignmenttype = clean_param($assignment->assignmenttype, PARAM_SAFEDIR); |
1444 | |
b0f2597e |
1445 | require_once("$CFG->dirroot/mod/assignment/type/$assignment->assignmenttype/assignment.class.php"); |
1446 | $assignmentclass = "assignment_$assignment->assignmenttype"; |
1447 | $ass = new $assignmentclass(); |
1448 | return $ass->update_instance($assignment); |
1449 | } |
26b90e70 |
1450 | |
26b90e70 |
1451 | |
b0f2597e |
1452 | function assignment_add_instance($assignment) { |
1453 | global $CFG; |
f466c9ed |
1454 | |
200c19fb |
1455 | $assignment->assignmenttype = clean_param($assignment->assignmenttype, PARAM_SAFEDIR); |
1456 | |
b0f2597e |
1457 | require_once("$CFG->dirroot/mod/assignment/type/$assignment->assignmenttype/assignment.class.php"); |
1458 | $assignmentclass = "assignment_$assignment->assignmenttype"; |
1459 | $ass = new $assignmentclass(); |
1460 | return $ass->add_instance($assignment); |
1461 | } |
f466c9ed |
1462 | |
73097f07 |
1463 | |
1464 | function assignment_user_outline($course, $user, $mod, $assignment) { |
1465 | global $CFG; |
1466 | |
1467 | require_once("$CFG->dirroot/mod/assignment/type/$assignment->assignmenttype/assignment.class.php"); |
1468 | $assignmentclass = "assignment_$assignment->assignmenttype"; |
1469 | $ass = new $assignmentclass($mod->id, $assignment, $mod, $course); |
1470 | return $ass->user_outline($user); |
1471 | } |
1472 | |
1473 | function assignment_user_complete($course, $user, $mod, $assignment) { |
1474 | global $CFG; |
1475 | |
1476 | require_once("$CFG->dirroot/mod/assignment/type/$assignment->assignmenttype/assignment.class.php"); |
1477 | $assignmentclass = "assignment_$assignment->assignmenttype"; |
1478 | $ass = new $assignmentclass($mod->id, $assignment, $mod, $course); |
1479 | return $ass->user_complete($user); |
1480 | } |
1481 | |
1482 | |
1483 | function assignment_cron () { |
1484 | // Function to be run periodically according to the moodle cron |
1485 | // Finds all assignment notifications that have yet to be mailed out, and mails them |
1486 | |
1487 | global $CFG, $USER; |
1488 | |
1489 | /// Notices older than 1 day will not be mailed. This is to avoid the problem where |
1490 | /// cron has not been running for a long time, and then suddenly people are flooded |
1491 | /// with mail from the past few weeks or months |
1492 | |
1493 | $timenow = time(); |
1494 | $endtime = $timenow - $CFG->maxeditingtime; |
1495 | $starttime = $endtime - 24 * 3600; /// One day earlier |
1496 | |
1497 | if ($submissions = assignment_get_unmailed_submissions($starttime, $endtime)) { |
1498 | |
1499 | foreach ($submissions as $key => $submission) { |
1500 | if (! set_field("assignment_submissions", "mailed", "1", "id", "$submission->id")) { |
1501 | echo "Could not update the mailed field for id $submission->id. Not mailed.\n"; |
1502 | unset($submissions[$key]); |
1503 | } |
1504 | } |
1505 | |
1506 | $timenow = time(); |
1507 | |
1508 | foreach ($submissions as $submission) { |
1509 | |
1510 | echo "Processing assignment submission $submission->id\n"; |
1511 | |
1512 | if (! $user = get_record("user", "id", "$submission->userid")) { |
1513 | echo "Could not find user $post->userid\n"; |
1514 | continue; |
1515 | } |
1516 | |
1517 | $USER->lang = $user->lang; |
1518 | |
1519 | if (! $course = get_record("course", "id", "$submission->course")) { |
1520 | echo "Could not find course $submission->course\n"; |
1521 | continue; |
1522 | } |
1523 | |
1524 | if (! isstudent($course->id, $user->id) and !isteacher($course->id, $user->id)) { |
1525 | echo fullname($user)." not an active participant in $course->shortname\n"; |
1526 | continue; |
1527 | } |
1528 | |
1529 | if (! $teacher = get_record("user", "id", "$submission->teacher")) { |
1530 | echo "Could not find teacher $submission->teacher\n"; |
1531 | continue; |
1532 | } |
1533 | |
1534 | if (! $mod = get_coursemodule_from_instance("assignment", $submission->assignment, $course->id)) { |
1535 | echo "Could not find course module for assignment id $submission->assignment\n"; |
1536 | continue; |
1537 | } |
1538 | |
1539 | if (! $mod->visible) { /// Hold mail notification for hidden assignments until later |
1540 | continue; |
1541 | } |
1542 | |
1543 | $strassignments = get_string("modulenameplural", "assignment"); |
1544 | $strassignment = get_string("modulename", "assignment"); |
1545 | |
1546 | unset($assignmentinfo); |
1547 | $assignmentinfo->teacher = fullname($teacher); |
1548 | $assignmentinfo->assignment = format_string($submission->name,true); |
1549 | $assignmentinfo->url = "$CFG->wwwroot/mod/assignment/view.php?id=$mod->id"; |
1550 | |
1551 | $postsubject = "$course->shortname: $strassignments: ".format_string($submission->name,true); |
1552 | $posttext = "$course->shortname -> $strassignments -> ".format_string($submission->name,true)."\n"; |
1553 | $posttext .= "---------------------------------------------------------------------\n"; |
1554 | $posttext .= get_string("assignmentmail", "assignment", $assignmentinfo); |
1555 | $posttext .= "---------------------------------------------------------------------\n"; |
1556 | |
1557 | if ($user->mailformat == 1) { // HTML |
1558 | $posthtml = "<p><font face=\"sans-serif\">". |
1559 | "<a href=\"$CFG->wwwroot/course/view.php?id=$course->id\">$course->shortname</a> ->". |
1560 | "<a href=\"$CFG->wwwroot/mod/assignment/index.php?id=$course->id\">$strassignments</a> ->". |
1561 | "<a href=\"$CFG->wwwroot/mod/assignment/view.php?id=$mod->id\">".format_string($submission->name,true)."</a></font></p>"; |
1562 | $posthtml .= "<hr /><font face=\"sans-serif\">"; |
1563 | $posthtml .= "<p>".get_string("assignmentmailhtml", "assignment", $assignmentinfo)."</p>"; |
1564 | $posthtml .= "</font><hr />"; |
1565 | } else { |
1566 | $posthtml = ""; |
1567 | } |
1568 | |
1569 | if (! email_to_user($user, $teacher, $postsubject, $posttext, $posthtml)) { |
1570 | echo "Error: assignment cron: Could not send out mail for id $submission->id to user $user->id ($user->email)\n"; |
1571 | } |
1572 | } |
1573 | } |
1574 | |
1575 | return true; |
1576 | } |
1577 | |
082215e6 |
1578 | |
73097f07 |
1579 | function assignment_grades($assignmentid) { |
1580 | /// Must return an array of grades, indexed by user, and a max grade. |
1581 | |
082215e6 |
1582 | if (!$assignment = get_record('assignment', 'id', $assignmentid)) { |
73097f07 |
1583 | return NULL; |
1584 | } |
3262ee10 |
1585 | if ($assignment->grade == 0) { // No grading |
1586 | return NULL; |
1587 | } |
73097f07 |
1588 | |
082215e6 |
1589 | $grades = get_records_menu('assignment_submissions', 'assignment', |
1590 | $assignment->id, '', 'userid,grade'); |
73097f07 |
1591 | |
3262ee10 |
1592 | if ($assignment->grade > 0) { |
fa22fd5f |
1593 | if ($grades) { |
1594 | foreach ($grades as $userid => $grade) { |
1595 | if ($grade == -1) { |
1596 | $grades[$userid] = '-'; |
1597 | } |
082215e6 |
1598 | } |
1599 | } |
73097f07 |
1600 | $return->grades = $grades; |
1601 | $return->maxgrade = $assignment->grade; |
1602 | |
1603 | } else { // Scale |
1604 | if ($grades) { |
1605 | $scaleid = - ($assignment->grade); |
1606 | if ($scale = get_record('scale', 'id', $scaleid)) { |
1607 | $scalegrades = make_menu_from_list($scale->scale); |
082215e6 |
1608 | foreach ($grades as $userid => $grade) { |
de4564ee |
1609 | if (empty($scalegrades[$grade])) { |
082215e6 |
1610 | $grades[$userid] = ''; |
0a3f66a2 |
1611 | } else { |
082215e6 |
1612 | $grades[$userid] = $scalegrades[$grade]; |
0a3f66a2 |
1613 | } |
73097f07 |
1614 | } |
1615 | } |
1616 | } |
1617 | $return->grades = $grades; |
1618 | $return->maxgrade = ""; |
1619 | } |
1620 | |
1621 | return $return; |
1622 | } |
1623 | |
1624 | function assignment_get_participants($assignmentid) { |
1625 | //Returns the users with data in one assignment |
1626 | //(users with records in assignment_submissions, students and teachers) |
1627 | |
1628 | global $CFG; |
1629 | |
1630 | //Get students |
1631 | $students = get_records_sql("SELECT DISTINCT u.id, u.id |
1632 | FROM {$CFG->prefix}user u, |
1633 | {$CFG->prefix}assignment_submissions a |
1634 | WHERE a.assignment = '$assignmentid' and |
1635 | u.id = a.userid"); |
1636 | //Get teachers |
1637 | $teachers = get_records_sql("SELECT DISTINCT u.id, u.id |
1638 | FROM {$CFG->prefix}user u, |
1639 | {$CFG->prefix}assignment_submissions a |
1640 | WHERE a.assignment = '$assignmentid' and |
1641 | u.id = a.teacher"); |
1642 | |
1643 | //Add teachers to students |
1644 | if ($teachers) { |
1645 | foreach ($teachers as $teacher) { |
1646 | $students[$teacher->id] = $teacher; |
1647 | } |
1648 | } |
1649 | //Return students array (it contains an array of unique users) |
1650 | return ($students); |
1651 | } |
1652 | |
73097f07 |
1653 | function assignment_scale_used ($assignmentid,$scaleid) { |
1654 | //This function returns if a scale is being used by one assignment |
1655 | |
1656 | $return = false; |
1657 | |
1658 | $rec = get_record('assignment','id',$assignmentid,'grade',-$scaleid); |
1659 | |
1660 | if (!empty($rec) && !empty($scaleid)) { |
1661 | $return = true; |
1662 | } |
1663 | |
1664 | return $return; |
1665 | } |
1666 | |
1667 | |
1668 | function assignment_refresh_events($courseid = 0) { |
1669 | // This standard function will check all instances of this module |
1670 | // and make sure there are up-to-date events created for each of them. |
1671 | // If courseid = 0, then every assignment event in the site is checked, else |
1672 | // only assignment events belonging to the course specified are checked. |
1673 | // This function is used, in its new format, by restore_refresh_events() |
1674 | |
1675 | if ($courseid == 0) { |
1676 | if (! $assignments = get_records("assignment")) { |
1677 | return true; |
1678 | } |
1679 | } else { |
1680 | if (! $assignments = get_records("assignment", "course", $courseid)) { |
1681 | return true; |
1682 | } |
1683 | } |
1684 | $moduleid = get_field('modules', 'id', 'name', 'assignment'); |
1685 | |
1686 | foreach ($assignments as $assignment) { |
1687 | $event = NULL; |
1688 | $event->name = addslashes($assignment->name); |
1689 | $event->description = addslashes($assignment->description); |
1690 | $event->timestart = $assignment->timedue; |
1691 | |
1692 | if ($event->id = get_field('event', 'id', 'modulename', 'assignment', 'instance', $assignment->id)) { |
1693 | update_event($event); |
1694 | |
1695 | } else { |
1696 | $event->courseid = $assignment->course; |
1697 | $event->groupid = 0; |
1698 | $event->userid = 0; |
1699 | $event->modulename = 'assignment'; |
1700 | $event->instance = $assignment->id; |
1701 | $event->eventtype = 'due'; |
1702 | $event->timeduration = 0; |
1703 | $event->visible = get_field('course_modules', 'visible', 'module', $moduleid, 'instance', $assignment->id); |
1704 | add_event($event); |
1705 | } |
1706 | |
1707 | } |
1708 | return true; |
1709 | } |
1710 | |
1711 | |
1712 | function assignment_print_recent_activity($course, $isteacher, $timestart) { |
1713 | global $CFG; |
1714 | |
1715 | $content = false; |
1716 | $assignments = NULL; |
1717 | |
1718 | if (!$logs = get_records_select('log', 'time > \''.$timestart.'\' AND '. |
1719 | 'course = \''.$course->id.'\' AND '. |
1720 | 'module = \'assignment\' AND '. |
1721 | 'action = \'upload\' ', 'time ASC')) { |
1722 | return false; |
1723 | } |
1724 | |
1725 | foreach ($logs as $log) { |
1726 | //Create a temp valid module structure (course,id) |
1727 | $tempmod->course = $log->course; |
1728 | $tempmod->id = $log->info; |
1729 | //Obtain the visible property from the instance |
1730 | $modvisible = instance_is_visible($log->module,$tempmod); |
1731 | |
1732 | //Only if the mod is visible |
1733 | if ($modvisible) { |
1734 | $assignments[$log->info] = assignment_log_info($log); |
1735 | $assignments[$log->info]->time = $log->time; |
1736 | $assignments[$log->info]->url = str_replace('&', '&', $log->url); |
1737 | } |
1738 | } |
1739 | |
1740 | if ($assignments) { |
1741 | print_headline(get_string('newsubmissions', 'assignment').':'); |
1742 | foreach ($assignments as $assignment) { |
1743 | print_recent_activity_note($assignment->time, $assignment, $isteacher, $assignment->name, |
1744 | $CFG->wwwroot.'/mod/assignment/'.$assignment->url); |
1745 | } |
1746 | $content = true; |
1747 | } |
1748 | |
1749 | return $content; |
1750 | } |
1751 | |
1752 | |
1753 | |
1754 | function assignment_get_recent_mod_activity(&$activities, &$index, $sincetime, $courseid, $assignment="0", $user="", $groupid="") { |
1755 | // Returns all assignments since a given time. If assignment is specified then |
1756 | // this restricts the results |
1757 | |
1758 | global $CFG; |
1759 | |
1760 | if ($assignment) { |
1761 | $assignmentselect = " AND cm.id = '$assignment'"; |
1762 | } else { |
1763 | $assignmentselect = ""; |
1764 | } |
1765 | if ($user) { |
1766 | $userselect = " AND u.id = '$user'"; |
1767 | } else { |
1768 | $userselect = ""; |
1769 | } |
1770 | |
1771 | $assignments = get_records_sql("SELECT asub.*, u.firstname, u.lastname, u.picture, u.id as userid, |
1772 | a.grade as maxgrade, name, cm.instance, cm.section, a.assignmenttype |
1773 | FROM {$CFG->prefix}assignment_submissions asub, |
1774 | {$CFG->prefix}user u, |
1775 | {$CFG->prefix}assignment a, |
1776 | {$CFG->prefix}course_modules cm |
1777 | WHERE asub.timemodified > '$sincetime' |
1778 | AND asub.userid = u.id $userselect |
1779 | AND a.id = asub.assignment $assignmentselect |
1780 | AND cm.course = '$courseid' |
1781 | AND cm.instance = a.id |
1782 | ORDER BY asub.timemodified ASC"); |
1783 | |
1784 | if (empty($assignments)) |
1785 | return; |
1786 | |
1787 | foreach ($assignments as $assignment) { |
1788 | if (empty($groupid) || ismember($groupid, $assignment->userid)) { |
1789 | |
1790 | $tmpactivity = new Object; |
1791 | |
1792 | $tmpactivity->type = "assignment"; |
1793 | $tmpactivity->defaultindex = $index; |
1794 | $tmpactivity->instance = $assignment->instance; |
1795 | $tmpactivity->name = $assignment->name; |
1796 | $tmpactivity->section = $assignment->section; |
1797 | |
1798 | $tmpactivity->content->grade = $assignment->grade; |
1799 | $tmpactivity->content->maxgrade = $assignment->maxgrade; |
1800 | $tmpactivity->content->type = $assignment->assignmenttype; |
1801 | |
1802 | $tmpactivity->user->userid = $assignment->userid; |
1803 | $tmpactivity->user->fullname = fullname($assignment); |
1804 | $tmpactivity->user->picture = $assignment->picture; |
1805 | |
1806 | $tmpactivity->timestamp = $assignment->timemodified; |
1807 | |
1808 | $activities[] = $tmpactivity; |
1809 | |
1810 | $index++; |
1811 | } |
1812 | } |
1813 | |
1814 | return; |
1815 | } |
1816 | |
1817 | |
1818 | function assignment_print_recent_mod_activity($activity, $course, $detail=false) { |
1819 | global $CFG; |
1820 | |
1821 | echo '<table border="0" cellpadding="3" cellspacing="0">'; |
1822 | |
1823 | echo "<tr><td class=\"userpicture\" width=\"35\" valign=\"top\">"; |
1824 | print_user_picture($activity->user->userid, $course, $activity->user->picture); |
1825 | echo "</td><td width=\"100%\"><font size=2>"; |
1826 | |
1827 | if ($detail) { |
1828 | echo "<img src=\"$CFG->modpixpath/$activity->type/icon.gif\" ". |
1829 | "height=16 width=16 alt=\"$activity->type\"> "; |
1830 | echo "<a href=\"$CFG->wwwroot/mod/assignment/view.php?id=" . $activity->instance . "\">" |
1831 | . format_string($activity->name,true) . "</a> - "; |
1832 | |
1833 | } |
1834 | |
1835 | if (isteacher($course)) { |
1836 | $grades = "(" . $activity->content->grade . " / " . $activity->content->maxgrade . ") "; |
1837 | |
1838 | $assignment->id = $activity->instance; |
1839 | $assignment->course = $course; |
1840 | $user->id = $activity->user->userid; |
1841 | |
1842 | echo $grades; |
1843 | echo "<br />"; |
1844 | } |
1845 | echo "<a href=\"$CFG->wwwroot/user/view.php?id=" |
1846 | . $activity->user->userid . "&course=$course\">" |
1847 | . $activity->user->fullname . "</a> "; |
1848 | |
1849 | echo " - " . userdate($activity->timestamp); |
1850 | |
1851 | echo "</font></td></tr>"; |
1852 | echo "</table>"; |
1853 | |
1854 | return; |
1855 | } |
1856 | |
1857 | /// GENERIC SQL FUNCTIONS |
1858 | |
1859 | function assignment_log_info($log) { |
1860 | global $CFG; |
1861 | return get_record_sql("SELECT a.name, u.firstname, u.lastname |
1862 | FROM {$CFG->prefix}assignment a, |
1863 | {$CFG->prefix}user u |
1864 | WHERE a.id = '$log->info' |
1865 | AND u.id = '$log->userid'"); |
1866 | } |
1867 | |
1868 | function assignment_get_unmailed_submissions($starttime, $endtime) { |
1869 | /// Return list of marked submissions that have not been mailed out for currently enrolled students |
1870 | global $CFG; |
1871 | return get_records_sql("SELECT s.*, a.course, a.name |
1872 | FROM {$CFG->prefix}assignment_submissions s, |
1873 | {$CFG->prefix}assignment a, |
1874 | {$CFG->prefix}user_students us |
1875 | WHERE s.mailed = 0 |
1876 | AND s.timemarked <= $endtime |
1877 | AND s.timemarked >= $starttime |
1878 | AND s.assignment = a.id |
1879 | AND s.userid = us.userid |
1880 | AND a.course = us.course"); |
1881 | } |
1882 | |
1883 | function assignment_count_real_submissions($assignment, $groupid=0) { |
1884 | /// Return all real assignment submissions by ENROLLED students (not empty ones) |
1885 | global $CFG; |
1886 | |
1887 | if ($groupid) { /// How many in a particular group? |
1888 | return count_records_sql("SELECT COUNT(DISTINCT g.userid, g.groupid) |
1889 | FROM {$CFG->prefix}assignment_submissions a, |
1890 | {$CFG->prefix}groups_members g |
1891 | WHERE a.assignment = $assignment->id |
1892 | AND a.timemodified > 0 |
1893 | AND g.groupid = '$groupid' |
1894 | AND a.userid = g.userid "); |
1895 | } else { |
1896 | $select = "s.course = '$assignment->course' AND"; |
1897 | if ($assignment->course == SITEID) { |
1898 | $select = ''; |
1899 | } |
1900 | return count_records_sql("SELECT COUNT(*) |
1901 | FROM {$CFG->prefix}assignment_submissions a, |
1902 | {$CFG->prefix}user_students s |
1903 | WHERE a.assignment = '$assignment->id' |
1904 | AND a.timemodified > 0 |
1905 | AND $select a.userid = s.userid "); |
1906 | } |
1907 | } |
1908 | |
1909 | function assignment_get_all_submissions($assignment, $sort="", $dir="DESC") { |
1910 | /// Return all assignment submissions by ENROLLED students (even empty) |
1911 | global $CFG; |
1912 | |
1913 | if ($sort == "lastname" or $sort == "firstname") { |
1914 | $sort = "u.$sort $dir"; |
1915 | } else if (empty($sort)) { |
1916 | $sort = "a.timemodified DESC"; |
1917 | } else { |
1918 | $sort = "a.$sort $dir"; |
1919 | } |
1920 | |
1921 | $select = "s.course = '$assignment->course' AND"; |
1922 | if ($assignment->course == SITEID) { |
1923 | $select = ''; |
1924 | } |
1925 | return get_records_sql("SELECT a.* |
1926 | FROM {$CFG->prefix}assignment_submissions a, |
1927 | {$CFG->prefix}user_students s, |
1928 | {$CFG->prefix}user u |
1929 | WHERE a.userid = s.userid |
1930 | AND u.id = a.userid |
1931 | AND $select a.assignment = '$assignment->id' |
1932 | ORDER BY $sort"); |
1933 | } |
1934 | |
1935 | |
1936 | |
1937 | |
1938 | /// OTHER GENERAL FUNCTIONS FOR ASSIGNMENTS /////////////////////////////////////// |
1939 | |
1940 | |
b0f2597e |
1941 | function assignment_types() { |
1942 | $types = array(); |
1943 | $names = get_list_of_plugins('mod/assignment/type'); |
1944 | foreach ($names as $name) { |
1945 | $types[$name] = get_string('type'.$name, 'assignment'); |
ffeca120 |
1946 | } |
b0f2597e |
1947 | asort($types); |
1948 | return $types; |
f466c9ed |
1949 | } |
1950 | |
b0f2597e |
1951 | function assignment_upgrade_submodules() { |
f1c1d2f1 |
1952 | global $CFG; |
26b90e70 |
1953 | |
b0f2597e |
1954 | $types = assignment_types(); |
26b90e70 |
1955 | |
d175966b |
1956 | include($CFG->dirroot.'/mod/assignment/version.php'); // defines $module with version etc |
26b90e70 |
1957 | |
d175966b |
1958 | foreach ($types as $type => $typename) { |
26b90e70 |
1959 | |
b0f2597e |
1960 | $fullpath = $CFG->dirroot.'/mod/assignment/type/'.$type; |
26b90e70 |
1961 | |
b0f2597e |
1962 | /// Check for an external version file (defines $submodule) |
26b90e70 |
1963 | |
b0f2597e |
1964 | if (!is_readable($fullpath .'/version.php')) { |
1965 | continue; |
ffeca120 |
1966 | } |
b0f2597e |
1967 | include_once($fullpath .'/version.php'); |
26b90e70 |
1968 | |
b0f2597e |
1969 | /// Check whether we need to upgrade |
26b90e70 |
1970 | |
b0f2597e |
1971 | if (!isset($submodule->version)) { |
1972 | continue; |
1973 | } |
26b90e70 |
1974 | |
b0f2597e |
1975 | /// Make sure this submodule will work with this assignment version |
26b90e70 |
1976 | |
d175966b |
1977 | if (isset($submodule->requires) and ($submodule->requires > $module->version)) { |
b0f2597e |
1978 | notify("Assignment submodule '$type' is too new for your assignment"); |
1979 | continue; |
1980 | } |
f466c9ed |
1981 | |
a86a538f |
1982 | /// If the submodule is new, then let's install it! |
f466c9ed |
1983 | |
b0f2597e |
1984 | $currentversion = 'assignment_'.$type.'_version'; |
f466c9ed |
1985 | |
a86a538f |
1986 | if (!isset($CFG->$currentversion)) { // First install! |
1987 | set_config($currentversion, $submodule->version); // Must keep track of version |
1988 | |
1989 | if (!is_readable($fullpath .'/db/'.$CFG->dbtype.'.sql')) { |
1990 | continue; |
1991 | } |
1992 | |
1993 | $db->debug=true; |
1994 | if (!modify_database($fullpath .'/db/'.$CFG->dbtype.'.sql')) { |
1995 | notify("Error installing tables for submodule '$type'!"); |
1996 | } |
1997 | $db->debug=false; |
1998 | continue; |
f466c9ed |
1999 | } |
f466c9ed |
2000 | |
b0f2597e |
2001 | /// See if we need to upgrade |
2002 | |
2003 | if ($submodule->version <= $CFG->$currentversion) { |
2004 | continue; |
59c005b7 |
2005 | } |
59c005b7 |
2006 | |
b0f2597e |
2007 | /// Look for the upgrade file |
59c005b7 |
2008 | |
b0f2597e |
2009 | if (!is_readable($fullpath .'/db/'.$CFG->dbtype.'.php')) { |
2010 | continue; |
2011 | } |
59c005b7 |
2012 | |
b0f2597e |
2013 | include_once($fullpath .'/db/'. $CFG->dbtype .'.php'); // defines assignment_xxx_upgrade |
59c005b7 |
2014 | |
b0f2597e |
2015 | /// Perform the upgrade |
59c005b7 |
2016 | |
b0f2597e |
2017 | $upgrade_function = 'assignment_'.$type.'_upgrade'; |
2018 | if (function_exists($upgrade_function)) { |
2019 | $db->debug=true; |
2020 | if ($upgrade_function($CFG->$currentversion)) { |
2021 | $db->debug=false; |
2022 | set_config($currentversion, $submodule->version); |
59c005b7 |
2023 | } |
b0f2597e |
2024 | $db->debug=false; |
59c005b7 |
2025 | } |
2026 | } |
2027 | } |
2028 | |
f3221af9 |
2029 | function assignment_get_view_actions() { |
2030 | return array('view','view all','view submission'); |
2031 | } |
2032 | |
2033 | function assignment_get_post_actions() { |
2034 | return array('upload','update grades'); |
2035 | } |
2036 | |
04eba58f |
2037 | ?> |