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 | |
13 | |
b0f2597e |
14 | /* |
15 | * Standard base class for all assignment submodules (assignment types). |
16 | * |
17 | * |
18 | */ |
19 | class assignment_base { |
20 | |
21 | var $cm; |
22 | var $course; |
23 | var $assignment; |
24 | |
25 | /** |
26 | * Constructor for the base assignment class |
27 | * |
28 | * Constructor for the base assignment class. |
29 | * If cmid is set create the cm, course, assignment objects. |
30 | * |
31 | * @param cmid integer, the current course module id - not set for new assignments |
73097f07 |
32 | * @param assignment object, usually null, but if we have it we pass it to save db access |
b0f2597e |
33 | */ |
73097f07 |
34 | function assignment_base($cmid=0, $assignment=NULL, $cm=NULL, $course=NULL) { |
b0f2597e |
35 | |
36 | global $CFG; |
37 | |
38 | if ($cmid) { |
73097f07 |
39 | if ($cm) { |
40 | $this->cm = $cm; |
41 | } else if (! $this->cm = get_record('course_modules', 'id', $cmid)) { |
42 | error('Course Module ID was incorrect'); |
b0f2597e |
43 | } |
04eba58f |
44 | |
73097f07 |
45 | if ($course) { |
46 | $this->course = $course; |
47 | } else if (! $this->course = get_record('course', 'id', $this->cm->course)) { |
48 | error('Course is misconfigured'); |
b0f2597e |
49 | } |
04eba58f |
50 | |
73097f07 |
51 | if ($assignment) { |
52 | $this->assignment = $assignment; |
53 | } else if (! $this->assignment = get_record('assignment', 'id', $this->cm->instance)) { |
54 | error('assignment ID was incorrect'); |
b0f2597e |
55 | } |
e6a4906b |
56 | |
b0f2597e |
57 | $this->strassignment = get_string('modulename', 'assignment'); |
58 | $this->strassignments = get_string('modulenameplural', 'assignment'); |
59 | $this->strsubmissions = get_string('submissions', 'assignment'); |
60 | $this->strlastmodified = get_string('lastmodified'); |
e6a4906b |
61 | |
b0f2597e |
62 | if ($this->course->category) { |
63 | $this->navigation = "<a target=\"{$CFG->framename}\" href=\"$CFG->wwwroot/course/view.php?id={$this->course->id}\">{$this->course->shortname}</a> -> ". |
64 | "<a target=\"{$CFG->framename}\" href=\"index.php?id={$this->course->id}\">$this->strassignments</a> ->"; |
65 | } else { |
66 | $this->navigation = "<a target=\"{$CFG->framename}\" href=\"index.php?id={$this->course->id}\">$this->strassignments</a> ->"; |
67 | } |
e6a4906b |
68 | |
3898bc33 |
69 | $this->pagetitle = strip_tags($this->course->shortname.': '.$this->strassignment.': '.format_string($this->assignment->name,true)); |
e6a4906b |
70 | |
b0f2597e |
71 | if (!$this->cm->visible and !isteacher($this->course->id)) { |
72 | $pagetitle = strip_tags($this->course->shortname.': '.$this->strassignment); |
73 | print_header($pagetitle, $this->course->fullname, "$this->navigation $this->strassignment", |
74 | "", "", true, '', navmenu($this->course, $this->cm)); |
75 | notice(get_string("activityiscurrentlyhidden"), "$CFG->wwwroot/course/view.php?id={$this->course->id}"); |
76 | } |
77 | |
78 | $this->currentgroup = get_current_group($this->course->id); |
73097f07 |
79 | } |
e6a4906b |
80 | |
73097f07 |
81 | /// Set up things for a HTML editor if it's needed |
82 | if ($this->usehtmleditor = can_use_html_editor()) { |
83 | $this->defaultformat = FORMAT_HTML; |
84 | } else { |
85 | $this->defaultformat = FORMAT_MOODLE; |
e6a4906b |
86 | } |
73097f07 |
87 | |
e6a4906b |
88 | } |
89 | |
b0f2597e |
90 | /* |
91 | * Display the assignment to students (sub-modules will most likely override this) |
92 | */ |
04eba58f |
93 | |
b0f2597e |
94 | function view() { |
04eba58f |
95 | |
b0f2597e |
96 | add_to_log($this->course->id, "assignment", "view", "view.php?id={$this->cm->id}", |
97 | $this->assignment->id, $this->cm->id); |
04eba58f |
98 | |
73097f07 |
99 | $this->view_header(); |
04eba58f |
100 | |
b0f2597e |
101 | print_simple_box_start('center'); |
102 | echo format_text($this->assignment->description, $this->assignment->format); |
103 | print_simple_box_end(); |
04eba58f |
104 | |
b0f2597e |
105 | print_simple_box_start('center', '', '', '', 'time'); |
106 | echo '<table>'; |
107 | echo '<tr><td class="c0">'.get_string('availabledate','assignment').':</td>'; |
108 | echo ' <td class="c1">'.userdate($this->assignment->timeavailable).'</td></tr>'; |
109 | echo '<tr><td class="c0">'.get_string('duedate','assignment').':</td>'; |
110 | echo ' <td class="c1">'.userdate($this->assignment->timedue).'</td></tr>'; |
111 | echo '</table>'; |
b0f2597e |
112 | print_simple_box_end(); |
04eba58f |
113 | |
b0f2597e |
114 | $this->view_feedback(); |
115 | |
116 | print_footer($this->course); |
36eb856f |
117 | } |
118 | |
73097f07 |
119 | /* |
120 | * Display the top of the view.php page, this doesn't change much for submodules |
121 | */ |
122 | function view_header($subpage='') { |
123 | |
124 | global $CFG; |
125 | |
126 | if ($subpage) { |
127 | $extranav = '<a target="'.$CFG->framename.'" href="view.php?id='.$this->cm->id.'">'. |
3898bc33 |
128 | format_string($this->assignment->name,true).'</a> -> '.$subpage; |
73097f07 |
129 | } else { |
3898bc33 |
130 | $extranav = ' '.format_string($this->assignment->name,true); |
73097f07 |
131 | } |
132 | |
133 | print_header($this->pagetitle, $this->course->fullname, $this->navigation.$extranav, '', '', |
134 | true, update_module_button($this->cm->id, $this->course->id, $this->strassignment), |
135 | navmenu($this->course, $this->cm)); |
136 | |
137 | echo '<div class="reportlink">'.$this->submittedlink().'</div>'; |
138 | } |
139 | |
140 | |
141 | /* |
142 | * Display the bottom of the view.php page, this doesn't change much for submodules |
143 | */ |
144 | function view_footer() { |
145 | print_footer($this->course); |
146 | } |
147 | |
04eba58f |
148 | |
73097f07 |
149 | function view_feedback($submission=NULL) { |
b0f2597e |
150 | global $USER; |
e6a4906b |
151 | |
73097f07 |
152 | if (!$submission) { /// Get submission for this assignment |
153 | $submission = $this->get_submission($USER->id); |
70b2c772 |
154 | } |
155 | |
156 | if (empty($submission->timemarked)) { /// Nothing to show, so print nothing |
157 | return; |
9c48354d |
158 | } |
e6a4906b |
159 | |
b0f2597e |
160 | /// We need the teacher info |
161 | if (! $teacher = get_record('user', 'id', $submission->teacher)) { |
162 | print_object($submission); |
163 | error('Could not find the teacher'); |
164 | } |
e6a4906b |
165 | |
b0f2597e |
166 | /// Print the feedback |
6d4ecaec |
167 | print_heading(get_string('feedbackfromteacher', 'assignment', $this->course->teacher)); |
168 | |
b0f2597e |
169 | echo '<table cellspacing="0" class="feedback">'; |
170 | |
171 | echo '<tr>'; |
172 | echo '<td class="left picture">'; |
173 | print_user_picture($teacher->id, $this->course->id, $teacher->picture); |
174 | echo '</td>'; |
6d4ecaec |
175 | echo '<td class="topic">'; |
70b2c772 |
176 | echo '<div class="from">'; |
73097f07 |
177 | echo '<div class="fullname">'.fullname($teacher).'</div>'; |
6d4ecaec |
178 | echo '<div class="time">'.userdate($submission->timemarked).'</div>'; |
70b2c772 |
179 | echo '</div>'; |
180 | $this->print_user_files($submission->userid); |
181 | echo '</td>'; |
b0f2597e |
182 | echo '</td>'; |
183 | echo '</tr>'; |
184 | |
185 | echo '<tr>'; |
186 | echo '<td class="left side"> </td>'; |
6d4ecaec |
187 | echo '<td class="content">'; |
b0f2597e |
188 | if ($this->assignment->grade) { |
6d4ecaec |
189 | echo '<div class="grade">'; |
70b2c772 |
190 | echo get_string("grade").': '.$this->display_grade($submission->grade); |
6d4ecaec |
191 | echo '</div>'; |
52436fe1 |
192 | echo '<div class="clearer"></div>'; |
e6a4906b |
193 | } |
dcd338ff |
194 | |
6d4ecaec |
195 | echo '<div class="comment">'; |
ff8f7015 |
196 | echo format_text($submission->comment, $submission->format); |
6d4ecaec |
197 | echo '</div>'; |
b0f2597e |
198 | echo '</tr>'; |
199 | |
200 | echo '</table>'; |
e6a4906b |
201 | } |
e6a4906b |
202 | |
203 | |
77db7e4c |
204 | |
b0f2597e |
205 | /* |
206 | * Print the start of the setup form for the current assignment type |
207 | */ |
208 | function setup(&$form, $action='') { |
209 | global $CFG, $THEME; |
210 | |
211 | if (empty($this->course)) { |
212 | if (! $this->course = get_record("course", "id", $form->course)) { |
213 | error("Course is misconfigured"); |
77db7e4c |
214 | } |
215 | } |
b0f2597e |
216 | if (empty($action)) { // Default destination for this form |
217 | $action = $CFG->wwwroot.'/course/mod.php'; |
218 | } |
77db7e4c |
219 | |
b0f2597e |
220 | if (empty($form->name)) { |
221 | $form->name = ""; |
222 | } |
223 | if (empty($form->assignmenttype)) { |
224 | $form->assignmenttype = ""; |
225 | } |
226 | if (empty($form->description)) { |
227 | $form->description = ""; |
228 | } |
77db7e4c |
229 | |
b0f2597e |
230 | $strname = get_string('name'); |
231 | $strassignments = get_string('modulenameplural', 'assignment'); |
3898bc33 |
232 | $strheading = empty($form->name) ? get_string("type$form->assignmenttype",'assignment') : s(format_string(stripslashes($form->name),true)); |
77db7e4c |
233 | |
b0f2597e |
234 | print_header($this->course->shortname.': '.$strheading, "$strheading", |
235 | "<a href=\"$CFG->wwwroot/course/view.php?id={$this->course->id}\">{$this->course->shortname} </a> -> ". |
236 | "<a href=\"$CFG->wwwroot/mod/assignment/index.php?id={$this->course->id}\">$strassignments</a> -> $strheading"); |
77db7e4c |
237 | |
b0f2597e |
238 | print_simple_box_start("center"); |
239 | print_heading(get_string("type$form->assignmenttype",'assignment')); |
240 | include("$CFG->dirroot/mod/assignment/type/common.html"); |
241 | } |
242 | |
243 | /* |
244 | * Print the end of the setup form for the current assignment type |
245 | */ |
246 | function setup_end() { |
73097f07 |
247 | global $CFG; |
b0f2597e |
248 | |
249 | include($CFG->dirroot.'/mod/assignment/type/common_end.html'); |
77db7e4c |
250 | |
251 | print_simple_box_end(); |
252 | |
73097f07 |
253 | if ($this->usehtmleditor) { |
b0f2597e |
254 | use_html_editor(); |
255 | } |
256 | |
257 | print_footer($this->course); |
77db7e4c |
258 | } |
77db7e4c |
259 | |
260 | |
b0f2597e |
261 | function add_instance($assignment) { |
262 | // Given an object containing all the necessary data, |
263 | // (defined by the form in mod.html) this function |
264 | // will create a new instance and return the id number |
265 | // of the new instance. |
266 | |
267 | $assignment->timemodified = time(); |
268 | $assignment->timedue = make_timestamp($assignment->dueyear, $assignment->duemonth, |
269 | $assignment->dueday, $assignment->duehour, |
270 | $assignment->dueminute); |
271 | $assignment->timeavailable = make_timestamp($assignment->availableyear, $assignment->availablemonth, |
272 | $assignment->availableday, $assignment->availablehour, |
273 | $assignment->availableminute); |
d699cd1e |
274 | |
b0f2597e |
275 | return insert_record("assignment", $assignment); |
276 | } |
d699cd1e |
277 | |
b0f2597e |
278 | function delete_instance($assignment) { |
279 | if (! delete_records("assignment", "id", "$assignment->id")) { |
280 | $result = false; |
281 | } |
282 | return $result; |
283 | } |
d699cd1e |
284 | |
b0f2597e |
285 | function update_instance($assignment) { |
286 | // Given an object containing all the necessary data, |
287 | // (defined by the form in mod.html) this function |
288 | // will create a new instance and return the id number |
289 | // of the new instance. |
290 | |
291 | $assignment->timemodified = time(); |
292 | $assignment->timedue = make_timestamp($assignment->dueyear, $assignment->duemonth, |
293 | $assignment->dueday, $assignment->duehour, |
294 | $assignment->dueminute); |
295 | $assignment->timeavailable = make_timestamp($assignment->availableyear, $assignment->availablemonth, |
296 | $assignment->availableday, $assignment->availablehour, |
297 | $assignment->availableminute); |
298 | $assignment->id = $assignment->instance; |
299 | return update_record("assignment", $assignment); |
300 | } |
301 | |
302 | |
303 | |
304 | /* |
305 | * Top-level function for handling of submissions called by submissions.php |
306 | * |
307 | */ |
308 | function submissions($mode) { |
309 | switch ($mode) { |
310 | case 'grade': // We are in a popup window grading |
311 | if ($submission = $this->process_feedback()) { |
312 | print_heading(get_string('changessaved')); |
be86672d |
313 | $this->update_main_listing($submission); |
b0f2597e |
314 | } |
315 | close_window(); |
316 | break; |
9cc9b7c1 |
317 | |
b0f2597e |
318 | case 'single': // We are in a popup window displaying submission |
319 | $this->display_submission(); |
320 | break; |
a56d79cd |
321 | |
b0f2597e |
322 | case 'all': // Main window, display everything |
323 | $this->display_submissions(); |
324 | break; |
a56d79cd |
325 | } |
b0f2597e |
326 | } |
a56d79cd |
327 | |
be86672d |
328 | function update_main_listing($submission) { |
329 | global $SESSION; |
330 | |
331 | /// Run some Javascript to try and update the parent page |
332 | echo '<script type="text/javascript">'."\n<!--\n"; |
333 | if (empty($SESSION->flextable['mod-assignment-submissions']->collapse['grade'])) { |
334 | echo 'opener.document.getElementById("g'.$submission->userid. |
335 | '").innerHTML="'.$this->display_grade($submission->grade)."\";\n"; |
336 | } |
337 | if (empty($SESSION->flextable['mod-assignment-submissions']->collapse['comment'])) { |
338 | echo 'opener.document.getElementById("com'.$submission->userid. |
339 | '").innerHTML="'.shorten_text($submission->comment, 15)."\";\n"; |
340 | } |
73097f07 |
341 | if (empty($SESSION->flextable['mod-assignment-submissions']->collapse['timemodified']) && |
342 | $submission->timemodified) { |
be86672d |
343 | echo 'opener.document.getElementById("ts'.$submission->userid. |
344 | '").innerHTML="'.userdate($submission->timemodified)."\";\n"; |
345 | } |
73097f07 |
346 | if (empty($SESSION->flextable['mod-assignment-submissions']->collapse['timemarked']) && |
347 | $submission->timemarked) { |
be86672d |
348 | echo 'opener.document.getElementById("tt'.$submission->userid. |
349 | '").innerHTML="'.userdate($submission->timemarked)."\";\n"; |
350 | } |
351 | if (empty($SESSION->flextable['mod-assignment-submissions']->collapse['status'])) { |
352 | echo 'opener.document.getElementById("up'.$submission->userid.'").className="s1";'; |
6d4ecaec |
353 | echo 'opener.document.getElementById("button'.$submission->userid.'").value="'.get_string('update').' ...";'; |
be86672d |
354 | } |
355 | echo "\n-->\n</script>"; |
356 | fflush(); |
357 | } |
d699cd1e |
358 | |
d59269cf |
359 | /* |
360 | * Display a grade in user-friendly form, whether it's a scale or not |
361 | * |
362 | */ |
363 | function display_grade($grade) { |
364 | |
365 | static $scalegrades; // Cached because we only have one per assignment |
366 | |
367 | if ($this->assignment->grade >= 0) { // Normal number |
3a3643df |
368 | return $grade.' / '.$this->assignment->grade; |
d59269cf |
369 | |
370 | } else { // Scale |
371 | if (empty($scalegrades)) { |
372 | if ($scale = get_record('scale', 'id', -($this->assignment->grade))) { |
373 | $scalegrades = make_menu_from_list($scale->scale); |
374 | } else { |
375 | return '-'; |
376 | } |
377 | } |
0f7d4e5e |
378 | if (isset($scalegrades[$grade])) { |
379 | return $scalegrades[$grade]; |
380 | } |
381 | return ''; |
d59269cf |
382 | } |
383 | } |
384 | |
b0f2597e |
385 | /* |
386 | * Display a single submission, ready for grading on a popup window |
387 | * |
388 | */ |
389 | function display_submission() { |
b0f2597e |
390 | |
391 | $userid = required_param('userid'); |
d699cd1e |
392 | |
b0f2597e |
393 | if (!$user = get_record('user', 'id', $userid)) { |
394 | error('No such user!'); |
395 | } |
d699cd1e |
396 | |
0f7d4e5e |
397 | if (!$submission = $this->get_submission($user->id, true)) { // Get one or make one |
b0f2597e |
398 | error('Could not find submission!'); |
399 | } |
a5a4cd60 |
400 | |
b0f2597e |
401 | if ($submission->timemodified > $submission->timemarked) { |
402 | $subtype = 'assignmentnew'; |
403 | } else { |
404 | $subtype = 'assignmentold'; |
405 | } |
d699cd1e |
406 | |
3898bc33 |
407 | print_header(get_string('feedback', 'assignment').':'.fullname($user, true).':'.format_string($this->assignment->name)); |
d699cd1e |
408 | |
d699cd1e |
409 | |
52436fe1 |
410 | echo '<table cellspacing="0" class="feedback '.$subtype.'" >'; |
d699cd1e |
411 | |
b0f2597e |
412 | echo '<tr>'; |
413 | echo '<td width="35" valign="top" class="picture user">'; |
414 | print_user_picture($user->id, $this->course->id, $user->picture); |
415 | echo '</td>'; |
70b2c772 |
416 | echo '<td class="topic">'; |
417 | echo '<div class="from">'; |
73097f07 |
418 | echo '<div class="fullname">'.fullname($user, true).'</div>'; |
70b2c772 |
419 | if ($submission->timemodified) { |
420 | echo '<div class="time">'.userdate($submission->timemodified). |
421 | $this->display_lateness($submission->timemodified).'</div>'; |
422 | } |
423 | echo '</div>'; |
424 | $this->print_user_files($user->id); |
73097f07 |
425 | echo '</td>'; |
b0f2597e |
426 | echo '</tr>'; |
c69cb506 |
427 | |
b0f2597e |
428 | echo '<tr>'; |
429 | echo '<td width="35" valign="top" class="picture teacher">'; |
430 | if ($submission->teacher) { |
431 | $teacher = get_record('user', 'id', $submission->teacher); |
432 | } else { |
433 | global $USER; |
434 | $teacher = $USER; |
435 | } |
436 | print_user_picture($teacher->id, $this->course->id, $teacher->picture); |
437 | echo '</td>'; |
438 | echo '<td class="content">'; |
d699cd1e |
439 | |
73097f07 |
440 | echo '<form action="submissions.php" method="post">'; |
441 | echo '<input type="hidden" name="userid" value="'.$userid.'">'; |
442 | echo '<input type="hidden" name="id" value="'.$this->cm->id.'">'; |
443 | echo '<input type="hidden" name="mode" value="grade">'; |
b0f2597e |
444 | if (!$submission->grade and !$submission->timemarked) { |
445 | $submission->grade = -1; /// Hack to stop zero being selected on the menu below (so it shows 'no grade') |
446 | } |
52436fe1 |
447 | if ($submission->timemarked) { |
448 | echo '<div class="from">'; |
449 | echo '<div class="fullname">'.fullname($teacher, true).'</div>'; |
450 | echo '<div class="time">'.userdate($submission->timemarked).'</div>'; |
451 | echo '</div>'; |
452 | } |
453 | echo '<div class="grade">'.get_string('grade').':'; |
b0f2597e |
454 | choose_from_menu(make_grades_menu($this->assignment->grade), 'grade', |
455 | $submission->grade, get_string('nograde')); |
52436fe1 |
456 | echo '</div>'; |
457 | echo '<div class="clearer"></div>'; |
b0f2597e |
458 | |
b0f2597e |
459 | echo '<br />'; |
ff8f7015 |
460 | print_textarea($this->usehtmleditor, 12, 58, 0, 0, 'comment', $submission->comment, $this->course->id); |
461 | |
462 | echo '<div align="right" class="format">'; |
463 | if ($this->usehtmleditor) { |
464 | print_string('formathtml'); |
465 | echo '<input type="hidden" name="format" value="'.FORMAT_HTML.'" />'; |
466 | } else { |
467 | choose_from_menu(format_text_menu(), "format", $submission->format, ""); |
468 | } |
469 | helpbutton("textformat", get_string("helpformatting")); |
470 | echo '</div>'; |
b0f2597e |
471 | |
73097f07 |
472 | echo '<div class="buttons" align="center">'; |
b0f2597e |
473 | echo '<input type="submit" name="submit" value="'.get_string('savechanges').'" />'; |
474 | echo '<input type="submit" name="cancel" value="'.get_string('cancel').'" />'; |
73097f07 |
475 | echo '</div>'; |
476 | |
b0f2597e |
477 | echo '</form>'; |
73097f07 |
478 | |
479 | echo '</td></tr>'; |
480 | echo '</table>'; |
481 | |
482 | |
483 | if ($this->usehtmleditor) { |
484 | use_html_editor(); |
485 | } |
486 | |
b0f2597e |
487 | print_footer('none'); |
d699cd1e |
488 | } |
489 | |
d699cd1e |
490 | |
b0f2597e |
491 | /* |
492 | * Display all the submissions ready for grading |
493 | */ |
494 | function display_submissions() { |
3446205d |
495 | |
b0f2597e |
496 | global $CFG, $db; |
3446205d |
497 | |
b0f2597e |
498 | $teacherattempts = true; /// Temporary measure |
1b5910c4 |
499 | |
b0f2597e |
500 | $page = optional_param('page', 0); |
501 | $perpage = optional_param('perpage', 10); |
d699cd1e |
502 | |
b0f2597e |
503 | $strsaveallfeedback = get_string('saveallfeedback', 'assignment'); |
d0ac6bc2 |
504 | |
b0f2597e |
505 | /// Some shortcuts to make the code read better |
506 | |
507 | $course = $this->course; |
508 | $assignment = $this->assignment; |
509 | $cm = $this->cm; |
91719320 |
510 | |
91719320 |
511 | |
b0f2597e |
512 | add_to_log($course->id, 'assignment', 'view submission', 'submissions.php?id='.$this->assignment->id, $this->assignment->id, $this->cm->id); |
513 | |
3898bc33 |
514 | 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)); |
91719320 |
515 | |
91719320 |
516 | |
9437c854 |
517 | $tablecolumns = array('picture', 'fullname', 'grade', 'comment', 'timemodified', 'timemarked', 'status'); |
518 | $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 |
519 | |
d0ac6bc2 |
520 | |
b0f2597e |
521 | require_once($CFG->libdir.'/tablelib.php'); |
522 | $table = new flexible_table('mod-assignment-submissions'); |
523 | |
524 | $table->define_columns($tablecolumns); |
525 | $table->define_headers($tableheaders); |
526 | $table->define_baseurl($CFG->wwwroot.'/mod/assignment/submissions.php?id='.$this->cm->id); |
527 | |
528 | $table->sortable(true); |
529 | $table->collapsible(true); |
530 | $table->initialbars(true); |
531 | |
532 | $table->column_suppress('picture'); |
533 | $table->column_suppress('fullname'); |
534 | |
535 | $table->column_class('picture', 'picture'); |
9437c854 |
536 | $table->column_class('fullname', 'fullname'); |
537 | $table->column_class('grade', 'grade'); |
538 | $table->column_class('comment', 'comment'); |
539 | $table->column_class('timemodified', 'timemodified'); |
540 | $table->column_class('timemarked', 'timemarked'); |
541 | $table->column_class('status', 'status'); |
b0f2597e |
542 | |
543 | $table->set_attribute('cellspacing', '0'); |
544 | $table->set_attribute('id', 'attempts'); |
9437c854 |
545 | $table->set_attribute('class', 'submissions'); |
b0f2597e |
546 | $table->set_attribute('width', '90%'); |
547 | $table->set_attribute('align', 'center'); |
548 | |
549 | // Start working -- this is necessary as soon as the niceties are over |
550 | $table->setup(); |
551 | |
05855091 |
552 | |
05855091 |
553 | |
b0f2597e |
554 | /// Check to see if groups are being used in this assignment |
555 | if ($groupmode = groupmode($course, $cm)) { // Groups are being used |
306dc7e5 |
556 | $currentgroup = setup_and_print_groups($course, $groupmode, 'submissions.php?id='.$this->cm->id); |
b0f2597e |
557 | } else { |
558 | $currentgroup = false; |
05855091 |
559 | } |
05855091 |
560 | |
0f1a97c2 |
561 | |
b0f2597e |
562 | /// Get all teachers and students |
563 | if ($currentgroup) { |
564 | $users = get_group_users($currentgroup); |
565 | } else { |
566 | $users = get_course_users($course->id); |
567 | } |
568 | |
569 | if (!$teacherattempts) { |
570 | $teachers = get_course_teachers($course->id); |
571 | if (!empty($teachers)) { |
572 | $keys = array_keys($teachers); |
573 | } |
574 | foreach ($keys as $key) { |
575 | unset($users[$key]); |
576 | } |
577 | } |
578 | |
579 | if (empty($users)) { |
580 | print_heading($strnoattempts); |
581 | return true; |
582 | } |
0f1a97c2 |
583 | |
0f1a97c2 |
584 | |
b0f2597e |
585 | /// Construct the SQL |
0f1a97c2 |
586 | |
b0f2597e |
587 | if ($where = $table->get_sql_where()) { |
588 | $where = str_replace('firstname', 'u.firstname', $where); |
589 | $where = str_replace('lastname', 'u.lastname', $where); |
590 | $where .= ' AND '; |
591 | } |
0f1a97c2 |
592 | |
b0f2597e |
593 | if ($sort = $table->get_sql_sort()) { |
594 | $sortparts = explode(',', $sort); |
595 | $newsort = array(); |
596 | foreach ($sortparts as $sortpart) { |
597 | $sortpart = trim($sortpart); |
598 | $newsort[] = $sortpart; |
599 | } |
600 | $sort = ' ORDER BY '.implode(', ', $newsort); |
601 | } |
9fa49e22 |
602 | |
9fa49e22 |
603 | |
9437c854 |
604 | $select = 'SELECT '.$db->Concat('u.id', '\'#\'', $db->IfNull('s.userid', '0')).' AS uvs, u.id, u.firstname, u.lastname, u.picture, s.id AS submissionid, s.grade, s.comment, s.timemodified, s.timemarked, ((s.timemarked > 0) && (s.timemarked >= s.timemodified)) AS status '; |
d59269cf |
605 | $group = 'GROUP BY uvs '; |
b0f2597e |
606 | $sql = 'FROM '.$CFG->prefix.'user u '. |
306dc7e5 |
607 | 'LEFT JOIN '.$CFG->prefix.'assignment_submissions s ON u.id = s.userid AND s.assignment = '.$this->assignment->id.' '. |
608 | 'WHERE '.$where.'u.id IN ('.implode(',', array_keys($users)).') '; |
8ff79e8c |
609 | |
8ff79e8c |
610 | |
d59269cf |
611 | $total = count_records_sql('SELECT COUNT(DISTINCT('.$db->Concat('u.id', '\'#\'', $db->IfNull('s.userid', '0')).')) '.$sql); |
000cc405 |
612 | |
b0f2597e |
613 | $table->pagesize($perpage, $total); |
614 | |
615 | if($table->get_page_start() !== '' && $table->get_page_size() !== '') { |
616 | $limit = ' '.sql_paging_limit($table->get_page_start(), $table->get_page_size()); |
617 | } |
618 | else { |
619 | $limit = ''; |
620 | } |
9fa49e22 |
621 | |
b0f2597e |
622 | $strupdate = get_string('update'); |
9437c854 |
623 | $strgrade = get_string('grade'); |
b0f2597e |
624 | $grademenu = make_grades_menu($this->assignment->grade); |
625 | |
9437c854 |
626 | if (($ausers = get_records_sql($select.$sql.$group.$sort.$limit)) !== false) { |
d59269cf |
627 | |
d59269cf |
628 | foreach ($ausers as $auser) { |
629 | $picture = print_user_picture($auser->id, $course->id, $auser->picture, false, true); |
630 | if (!empty($auser->submissionid)) { |
631 | if ($auser->timemodified > 0) { |
632 | $studentmodified = '<div id="ts'.$auser->id.'">'.userdate($auser->timemodified).'</div>'; |
d59269cf |
633 | } else { |
9437c854 |
634 | $studentmodified = '<div id="ts'.$auser->id.'"> </div>'; |
d59269cf |
635 | } |
636 | if ($auser->timemarked > 0) { |
637 | $teachermodified = '<div id="tt'.$auser->id.'">'.userdate($auser->timemarked).'</div>'; |
b0f2597e |
638 | } else { |
9437c854 |
639 | $teachermodified = '<div id="tt'.$auser->id.'"> </div>'; |
b0f2597e |
640 | } |
9437c854 |
641 | |
d59269cf |
642 | $grade = '<div id="g'.$auser->id.'">'.$this->display_grade($auser->grade).'</div>'; |
9437c854 |
643 | $comment = '<div id="com'.$auser->id.'">'.shorten_text($auser->comment, 15).'</div>'; |
d59269cf |
644 | |
b0f2597e |
645 | } else { |
9437c854 |
646 | $studentmodified = '<div id="ts'.$auser->id.'"> </div>'; |
647 | $teachermodified = '<div id="tt'.$auser->id.'"> </div>'; |
d59269cf |
648 | $status = '<div id="st'.$auser->id.'"></div>'; |
9437c854 |
649 | $grade = '<div id="g'.$auser->id.'"> </div>'; |
650 | $comment = '<div id="com'.$auser->id.'"> </div>'; |
b0f2597e |
651 | } |
9fa49e22 |
652 | |
0f7d4e5e |
653 | if ($auser->status === NULL) { |
654 | $auser->status = 0; |
655 | } |
656 | |
9437c854 |
657 | $buttontext = ($auser->status == 1) ? $strupdate : $strgrade; |
9fa49e22 |
658 | |
9437c854 |
659 | $button = button_to_popup_window ('/mod/assignment/submissions.php?id='.$this->cm->id.'&userid='.$auser->id.'&mode=single', |
52436fe1 |
660 | 'grade'.$auser->id, $buttontext, 450, 700, $buttontext, 'none', true, 'button'.$auser->id); |
0f7d4e5e |
661 | |
9437c854 |
662 | $status = '<div id="up'.$auser->id.'" class="s'.$auser->status.'">'.$button.'</div>'; |
306dc7e5 |
663 | |
9437c854 |
664 | $row = array($picture, fullname($auser), $grade, $comment, $studentmodified, $teachermodified, $status); |
d59269cf |
665 | $table->add_data($row); |
666 | } |
b0f2597e |
667 | } |
d699cd1e |
668 | |
b0f2597e |
669 | $table->print_html(); |
d699cd1e |
670 | |
b0f2597e |
671 | print_footer($this->course); |
d699cd1e |
672 | |
8e340cb0 |
673 | } |
d699cd1e |
674 | |
d699cd1e |
675 | |
d699cd1e |
676 | |
b0f2597e |
677 | /* |
678 | * Display and process the submissions |
679 | */ |
680 | function process_feedback() { |
d699cd1e |
681 | |
b0f2597e |
682 | global $USER; |
d699cd1e |
683 | |
b0f2597e |
684 | if (!$feedback = data_submitted()) { // No incoming data? |
685 | return false; |
d699cd1e |
686 | } |
b7b42874 |
687 | |
b0f2597e |
688 | if (!empty($feedback->cancel)) { // User hit cancel button |
689 | return false; |
690 | } |
d699cd1e |
691 | |
0f7d4e5e |
692 | $newsubmission = $this->get_submission($feedback->userid, true); // Get or make one |
d699cd1e |
693 | |
b0f2597e |
694 | $newsubmission->grade = $feedback->grade; |
695 | $newsubmission->comment = $feedback->comment; |
ff8f7015 |
696 | $newsubmission->format = $feedback->format; |
b0f2597e |
697 | $newsubmission->teacher = $USER->id; |
698 | $newsubmission->mailed = 0; // Make sure mail goes out (again, even) |
699 | $newsubmission->timemarked = time(); |
d699cd1e |
700 | |
b0f2597e |
701 | if (empty($submission->timemodified)) { // eg for offline assignments |
702 | $newsubmission->timemodified = time(); |
703 | } |
d699cd1e |
704 | |
b0f2597e |
705 | if (! update_record('assignment_submissions', $newsubmission)) { |
706 | return false; |
707 | } |
d699cd1e |
708 | |
b0f2597e |
709 | add_to_log($this->course->id, 'assignment', 'update grades', |
710 | 'submissions.php?id='.$this->assignment->id.'&user='.$feedback->userid, $feedback->userid, $this->cm->id); |
711 | |
712 | return $newsubmission; |
d699cd1e |
713 | |
d699cd1e |
714 | } |
d699cd1e |
715 | |
d699cd1e |
716 | |
0f7d4e5e |
717 | function get_submission($userid, $createnew=false) { |
b0f2597e |
718 | $submission = get_record('assignment_submissions', 'assignment', $this->assignment->id, 'userid', $userid); |
d699cd1e |
719 | |
b0f2597e |
720 | if ($submission || !$createnew) { |
721 | return $submission; |
722 | } |
d699cd1e |
723 | |
b0f2597e |
724 | $newsubmission = new Object; |
725 | $newsubmission->assignment = $this->assignment->id; |
726 | $newsubmission->userid = $userid; |
727 | $newsubmission->timecreated = time(); |
728 | if (!insert_record("assignment_submissions", $newsubmission)) { |
729 | error("Could not insert a new empty submission"); |
730 | } |
d699cd1e |
731 | |
b0f2597e |
732 | return get_record('assignment_submissions', 'assignment', $this->assignment->id, 'userid', $userid); |
733 | } |
d699cd1e |
734 | |
3f8247c2 |
735 | |
b0f2597e |
736 | function get_submissions($sort='', $dir='DESC') { |
737 | /// Return all assignment submissions by ENROLLED students (even empty) |
738 | global $CFG; |
739 | |
740 | if ($sort == "lastname" or $sort == "firstname") { |
741 | $sort = "u.$sort $dir"; |
742 | } else if (empty($sort)) { |
743 | $sort = "a.timemodified DESC"; |
744 | } else { |
745 | $sort = "a.$sort $dir"; |
d699cd1e |
746 | } |
d699cd1e |
747 | |
b0f2597e |
748 | $select = "s.course = '$this->assignment->course' AND"; |
749 | $site = get_site(); |
750 | if ($this->assignment->course == $site->id) { |
751 | $select = ''; |
752 | } |
753 | return get_records_sql("SELECT a.* |
754 | FROM {$CFG->prefix}assignment_submissions a, |
755 | {$CFG->prefix}user_students s, |
756 | {$CFG->prefix}user u |
757 | WHERE a.userid = s.userid |
758 | AND u.id = a.userid |
759 | AND $select a.assignment = '$this->assignment->id' |
760 | ORDER BY $sort"); |
761 | } |
762 | |
763 | |
764 | function count_real_submissions($groupid=0) { |
765 | /// Return all real assignment submissions by ENROLLED students (not empty ones) |
766 | global $CFG; |
767 | |
768 | if ($groupid) { /// How many in a particular group? |
769 | return count_records_sql("SELECT COUNT(DISTINCT g.userid, g.groupid) |
770 | FROM {$CFG->prefix}assignment_submissions a, |
771 | {$CFG->prefix}groups_members g |
772 | WHERE a.assignment = {$this->assignment->id} |
773 | AND a.timemodified > 0 |
774 | AND g.groupid = '$groupid' |
775 | AND a.userid = g.userid "); |
776 | } else { |
777 | $select = "s.course = '{$this->assignment->course}' AND"; |
778 | if ($this->assignment->course == SITEID) { |
779 | $select = ''; |
d699cd1e |
780 | } |
b0f2597e |
781 | return count_records_sql("SELECT COUNT(*) |
782 | FROM {$CFG->prefix}assignment_submissions a, |
783 | {$CFG->prefix}user_students s |
784 | WHERE a.assignment = '{$this->assignment->id}' |
785 | AND a.timemodified > 0 |
786 | AND $select a.userid = s.userid "); |
787 | } |
d59269cf |
788 | } |
d699cd1e |
789 | |
73097f07 |
790 | function email_teachers($submission) { |
791 | /// Alerts teachers by email of new or changed assignments that need grading |
792 | |
793 | global $CFG; |
794 | |
795 | if (empty($assignment->emailteachers)) { // No need to do anything |
796 | return; |
797 | } |
798 | |
799 | $user = get_record('user', 'id', $submission->userid); |
800 | |
801 | $course = $this->course; // Shortcuts |
802 | $assignment = $this->assignment; |
803 | $cm = $this->cm; |
804 | |
805 | if (groupmode($course, $cm) == SEPARATEGROUPS) { // Separate groups are being used |
806 | if (!$group = user_group($course->id, $user->id)) { // Try to find a group |
807 | $group->id = 0; // Not in a group, never mind |
808 | } |
809 | $teachers = get_group_teachers($course->id, $group->id); // Works even if not in group |
810 | } else { |
811 | $teachers = get_course_teachers($course->id); |
812 | } |
813 | |
814 | if ($teachers) { |
815 | |
816 | $strassignments = get_string('modulenameplural', 'assignment'); |
817 | $strassignment = get_string('modulename', 'assignment'); |
818 | $strsubmitted = get_string('submitted', 'assignment'); |
819 | |
820 | foreach ($teachers as $teacher) { |
821 | unset($info); |
822 | $info->username = fullname($user); |
823 | $info->assignment = format_string($assignment->name,true); |
824 | $info->url = "$CFG->wwwroot/mod/assignment/submissions.php?id=$assignment->id"; |
825 | |
826 | $postsubject = "$strsubmitted: $info->username -> $assignment->name"; |
827 | $posttext = "$course->shortname -> $strassignments -> ".format_string($assignment->name,true)."\n"; |
828 | $posttext .= "---------------------------------------------------------------------\n"; |
829 | $posttext .= get_string("emailteachermail", "assignment", $info); |
830 | $posttext .= "\n---------------------------------------------------------------------\n"; |
831 | |
832 | if ($user->mailformat == 1) { // HTML |
833 | $posthtml = "<p><font face=\"sans-serif\">". |
834 | "<a href=\"$CFG->wwwroot/course/view.php?id=$course->id\">$course->shortname</a> ->". |
835 | "<a href=\"$CFG->wwwroot/mod/assignment/index.php?id=$course->id\">$strassignments</a> ->". |
836 | "<a href=\"$CFG->wwwroot/mod/assignment/view.php?id=$cm->id\">".format_string($assignment->name,true)."</a></font></p>"; |
837 | $posthtml .= "<hr /><font face=\"sans-serif\">"; |
838 | $posthtml .= "<p>".get_string("emailteachermailhtml", "assignment", $info)."</p>"; |
839 | $posthtml .= "</font><hr />"; |
840 | } else { |
841 | $posthtml = ""; |
842 | } |
843 | |
844 | @email_to_user($teacher, $user, $postsubject, $posttext, $posthtml); // If it fails, oh well, too bad. |
845 | } |
846 | } |
847 | } |
848 | |
70b2c772 |
849 | function print_user_files($userid, $return=false) { |
73097f07 |
850 | |
851 | global $CFG; |
852 | |
70b2c772 |
853 | $filearea = $this->file_area_name($userid); |
73097f07 |
854 | |
855 | $output = ''; |
856 | |
70b2c772 |
857 | if ($basedir = $this->file_area($userid)) { |
73097f07 |
858 | if ($files = get_directory_list($basedir)) { |
859 | foreach ($files as $key => $file) { |
860 | require_once($CFG->libdir.'/filelib.php'); |
861 | $icon = mimeinfo('icon', $file); |
862 | if ($CFG->slasharguments) { |
863 | $ffurl = "file.php/$filearea/$file"; |
864 | } else { |
865 | $ffurl = "file.php?file=/$filearea/$file"; |
866 | } |
867 | |
868 | $output = '<img align="middle" src="'.$CFG->pixpath.'/f/'.$icon.'" height="16" width="16" alt="'.$icon.'" />'. |
869 | link_to_popup_window ('/'.$ffurl, 'file'.$key, $file, 450, 580, $file, 'none', true). |
870 | '<br />'; |
871 | } |
872 | } |
873 | } |
874 | |
875 | $output = '<div class="files">'.$output.'</div>'; |
876 | |
877 | if ($return) { |
878 | return $output; |
879 | } |
880 | echo $output; |
881 | } |
882 | |
70b2c772 |
883 | function count_user_files($userid) { |
884 | global $CFG; |
885 | |
886 | $filearea = $this->file_area_name($userid); |
887 | |
888 | if ($basedir = $this->file_area($userid)) { |
889 | if ($files = get_directory_list($basedir)) { |
890 | return count($files); |
891 | } |
892 | } |
893 | return 0; |
894 | } |
73097f07 |
895 | |
70b2c772 |
896 | function file_area_name($userid) { |
73097f07 |
897 | // Creates a directory file name, suitable for make_upload_directory() |
898 | global $CFG; |
899 | |
70b2c772 |
900 | return $this->course->id.'/'.$CFG->moddata.'/assignment/'.$this->assignment->id.'/'.$userid; |
73097f07 |
901 | } |
902 | |
70b2c772 |
903 | function file_area($userid) { |
904 | return make_upload_directory( $this->file_area_name($userid) ); |
73097f07 |
905 | } |
906 | |
907 | function user_outline($user) { |
908 | if ($submission = $this->get_submission($user->id)) { |
909 | |
910 | if ($submission->grade) { |
f1893f44 |
911 | $result->info = get_string('grade').': '.$this->display_grade($submission->grade); |
73097f07 |
912 | } |
913 | $result->time = $submission->timemodified; |
914 | return $result; |
915 | } |
916 | return NULL; |
917 | } |
918 | |
919 | function user_complete($user) { |
920 | if ($submission = $this->get_submission($user->id)) { |
70b2c772 |
921 | if ($basedir = $this->file_area($user->id)) { |
73097f07 |
922 | if ($files = get_directory_list($basedir)) { |
923 | $countfiles = count($files)." ".get_string("uploadedfiles", "assignment"); |
924 | foreach ($files as $file) { |
925 | $countfiles .= "; $file"; |
926 | } |
927 | } |
928 | } |
929 | |
930 | print_simple_box_start(); |
931 | echo get_string("lastmodified").": "; |
932 | echo userdate($submission->timemodified); |
70b2c772 |
933 | echo $this->display_lateness($submission->timemodified); |
73097f07 |
934 | |
70b2c772 |
935 | $this->print_user_files($user->id); |
73097f07 |
936 | |
937 | echo '<br />'; |
938 | |
939 | if (empty($submission->timemarked)) { |
940 | print_string("notgradedyet", "assignment"); |
941 | } else { |
942 | $this->view_feedback($submission); |
943 | } |
944 | |
945 | print_simple_box_end(); |
946 | |
947 | } else { |
948 | print_string("notsubmittedyet", "assignment"); |
949 | } |
950 | } |
951 | |
70b2c772 |
952 | function display_lateness($timesubmitted) { |
953 | $time = $this->assignment->timedue - $timesubmitted; |
73097f07 |
954 | if ($time < 0) { |
955 | $timetext = get_string('late', 'assignment', format_time($time)); |
70b2c772 |
956 | return ' (<span class="late">'.$timetext.'</span>)'; |
73097f07 |
957 | } else { |
958 | $timetext = get_string('early', 'assignment', format_time($time)); |
70b2c772 |
959 | return ' (<span class="early">'.$timetext.'</span>)'; |
73097f07 |
960 | } |
961 | } |
962 | |
963 | |
964 | |
965 | |
966 | |
b0f2597e |
967 | } ////// End of the assignment_base class |
d699cd1e |
968 | |
18b8fbfa |
969 | |
04eba58f |
970 | |
b0f2597e |
971 | /// OTHER STANDARD FUNCTIONS //////////////////////////////////////////////////////// |
972 | |
973 | |
974 | function assignment_delete_instance($id){ |
26b90e70 |
975 | global $CFG; |
976 | |
b0f2597e |
977 | if (! $assignment = get_record('assignment', 'id', $id)) { |
978 | return false; |
26b90e70 |
979 | } |
980 | |
b0f2597e |
981 | require_once("$CFG->dirroot/mod/assignment/type/$assignment->assignmenttype/assignment.class.php"); |
982 | $assignmentclass = "assignment_$assignment->assignmenttype"; |
983 | $ass = new $assignmentclass(); |
984 | return $ass->delete_instance($assignment); |
985 | } |
f466c9ed |
986 | |
ac21ad39 |
987 | |
b0f2597e |
988 | function assignment_update_instance($assignment){ |
989 | global $CFG; |
26b90e70 |
990 | |
b0f2597e |
991 | require_once("$CFG->dirroot/mod/assignment/type/$assignment->assignmenttype/assignment.class.php"); |
992 | $assignmentclass = "assignment_$assignment->assignmenttype"; |
993 | $ass = new $assignmentclass(); |
994 | return $ass->update_instance($assignment); |
995 | } |
26b90e70 |
996 | |
26b90e70 |
997 | |
b0f2597e |
998 | function assignment_add_instance($assignment) { |
999 | global $CFG; |
f466c9ed |
1000 | |
b0f2597e |
1001 | require_once("$CFG->dirroot/mod/assignment/type/$assignment->assignmenttype/assignment.class.php"); |
1002 | $assignmentclass = "assignment_$assignment->assignmenttype"; |
1003 | $ass = new $assignmentclass(); |
1004 | return $ass->add_instance($assignment); |
1005 | } |
f466c9ed |
1006 | |
73097f07 |
1007 | |
1008 | function assignment_user_outline($course, $user, $mod, $assignment) { |
1009 | global $CFG; |
1010 | |
1011 | require_once("$CFG->dirroot/mod/assignment/type/$assignment->assignmenttype/assignment.class.php"); |
1012 | $assignmentclass = "assignment_$assignment->assignmenttype"; |
1013 | $ass = new $assignmentclass($mod->id, $assignment, $mod, $course); |
1014 | return $ass->user_outline($user); |
1015 | } |
1016 | |
1017 | function assignment_user_complete($course, $user, $mod, $assignment) { |
1018 | global $CFG; |
1019 | |
1020 | require_once("$CFG->dirroot/mod/assignment/type/$assignment->assignmenttype/assignment.class.php"); |
1021 | $assignmentclass = "assignment_$assignment->assignmenttype"; |
1022 | $ass = new $assignmentclass($mod->id, $assignment, $mod, $course); |
1023 | return $ass->user_complete($user); |
1024 | } |
1025 | |
1026 | |
1027 | function assignment_cron () { |
1028 | // Function to be run periodically according to the moodle cron |
1029 | // Finds all assignment notifications that have yet to be mailed out, and mails them |
1030 | |
1031 | global $CFG, $USER; |
1032 | |
1033 | /// Notices older than 1 day will not be mailed. This is to avoid the problem where |
1034 | /// cron has not been running for a long time, and then suddenly people are flooded |
1035 | /// with mail from the past few weeks or months |
1036 | |
1037 | $timenow = time(); |
1038 | $endtime = $timenow - $CFG->maxeditingtime; |
1039 | $starttime = $endtime - 24 * 3600; /// One day earlier |
1040 | |
1041 | if ($submissions = assignment_get_unmailed_submissions($starttime, $endtime)) { |
1042 | |
1043 | foreach ($submissions as $key => $submission) { |
1044 | if (! set_field("assignment_submissions", "mailed", "1", "id", "$submission->id")) { |
1045 | echo "Could not update the mailed field for id $submission->id. Not mailed.\n"; |
1046 | unset($submissions[$key]); |
1047 | } |
1048 | } |
1049 | |
1050 | $timenow = time(); |
1051 | |
1052 | foreach ($submissions as $submission) { |
1053 | |
1054 | echo "Processing assignment submission $submission->id\n"; |
1055 | |
1056 | if (! $user = get_record("user", "id", "$submission->userid")) { |
1057 | echo "Could not find user $post->userid\n"; |
1058 | continue; |
1059 | } |
1060 | |
1061 | $USER->lang = $user->lang; |
1062 | |
1063 | if (! $course = get_record("course", "id", "$submission->course")) { |
1064 | echo "Could not find course $submission->course\n"; |
1065 | continue; |
1066 | } |
1067 | |
1068 | if (! isstudent($course->id, $user->id) and !isteacher($course->id, $user->id)) { |
1069 | echo fullname($user)." not an active participant in $course->shortname\n"; |
1070 | continue; |
1071 | } |
1072 | |
1073 | if (! $teacher = get_record("user", "id", "$submission->teacher")) { |
1074 | echo "Could not find teacher $submission->teacher\n"; |
1075 | continue; |
1076 | } |
1077 | |
1078 | if (! $mod = get_coursemodule_from_instance("assignment", $submission->assignment, $course->id)) { |
1079 | echo "Could not find course module for assignment id $submission->assignment\n"; |
1080 | continue; |
1081 | } |
1082 | |
1083 | if (! $mod->visible) { /// Hold mail notification for hidden assignments until later |
1084 | continue; |
1085 | } |
1086 | |
1087 | $strassignments = get_string("modulenameplural", "assignment"); |
1088 | $strassignment = get_string("modulename", "assignment"); |
1089 | |
1090 | unset($assignmentinfo); |
1091 | $assignmentinfo->teacher = fullname($teacher); |
1092 | $assignmentinfo->assignment = format_string($submission->name,true); |
1093 | $assignmentinfo->url = "$CFG->wwwroot/mod/assignment/view.php?id=$mod->id"; |
1094 | |
1095 | $postsubject = "$course->shortname: $strassignments: ".format_string($submission->name,true); |
1096 | $posttext = "$course->shortname -> $strassignments -> ".format_string($submission->name,true)."\n"; |
1097 | $posttext .= "---------------------------------------------------------------------\n"; |
1098 | $posttext .= get_string("assignmentmail", "assignment", $assignmentinfo); |
1099 | $posttext .= "---------------------------------------------------------------------\n"; |
1100 | |
1101 | if ($user->mailformat == 1) { // HTML |
1102 | $posthtml = "<p><font face=\"sans-serif\">". |
1103 | "<a href=\"$CFG->wwwroot/course/view.php?id=$course->id\">$course->shortname</a> ->". |
1104 | "<a href=\"$CFG->wwwroot/mod/assignment/index.php?id=$course->id\">$strassignments</a> ->". |
1105 | "<a href=\"$CFG->wwwroot/mod/assignment/view.php?id=$mod->id\">".format_string($submission->name,true)."</a></font></p>"; |
1106 | $posthtml .= "<hr /><font face=\"sans-serif\">"; |
1107 | $posthtml .= "<p>".get_string("assignmentmailhtml", "assignment", $assignmentinfo)."</p>"; |
1108 | $posthtml .= "</font><hr />"; |
1109 | } else { |
1110 | $posthtml = ""; |
1111 | } |
1112 | |
1113 | if (! email_to_user($user, $teacher, $postsubject, $posttext, $posthtml)) { |
1114 | echo "Error: assignment cron: Could not send out mail for id $submission->id to user $user->id ($user->email)\n"; |
1115 | } |
1116 | } |
1117 | } |
1118 | |
1119 | return true; |
1120 | } |
1121 | |
1122 | function assignment_grades($assignmentid) { |
1123 | /// Must return an array of grades, indexed by user, and a max grade. |
1124 | |
1125 | |
1126 | if (!$assignment = get_record("assignment", "id", $assignmentid)) { |
1127 | return NULL; |
1128 | } |
1129 | |
1130 | $grades = get_records_menu("assignment_submissions", "assignment", |
1131 | $assignment->id, "", "userid,grade"); |
1132 | |
1133 | if ($assignment->grade >= 0) { |
1134 | $return->grades = $grades; |
1135 | $return->maxgrade = $assignment->grade; |
1136 | |
1137 | } else { // Scale |
1138 | if ($grades) { |
1139 | $scaleid = - ($assignment->grade); |
1140 | if ($scale = get_record('scale', 'id', $scaleid)) { |
1141 | $scalegrades = make_menu_from_list($scale->scale); |
1142 | foreach ($grades as $key => $grade) { |
1143 | $grades[$key] = $scalegrades[$grade]; |
1144 | } |
1145 | } |
1146 | } |
1147 | $return->grades = $grades; |
1148 | $return->maxgrade = ""; |
1149 | } |
1150 | |
1151 | return $return; |
1152 | } |
1153 | |
1154 | function assignment_get_participants($assignmentid) { |
1155 | //Returns the users with data in one assignment |
1156 | //(users with records in assignment_submissions, students and teachers) |
1157 | |
1158 | global $CFG; |
1159 | |
1160 | //Get students |
1161 | $students = get_records_sql("SELECT DISTINCT u.id, u.id |
1162 | FROM {$CFG->prefix}user u, |
1163 | {$CFG->prefix}assignment_submissions a |
1164 | WHERE a.assignment = '$assignmentid' and |
1165 | u.id = a.userid"); |
1166 | //Get teachers |
1167 | $teachers = get_records_sql("SELECT DISTINCT u.id, u.id |
1168 | FROM {$CFG->prefix}user u, |
1169 | {$CFG->prefix}assignment_submissions a |
1170 | WHERE a.assignment = '$assignmentid' and |
1171 | u.id = a.teacher"); |
1172 | |
1173 | //Add teachers to students |
1174 | if ($teachers) { |
1175 | foreach ($teachers as $teacher) { |
1176 | $students[$teacher->id] = $teacher; |
1177 | } |
1178 | } |
1179 | //Return students array (it contains an array of unique users) |
1180 | return ($students); |
1181 | } |
1182 | |
1183 | |
1184 | function assignment_scale_used ($assignmentid,$scaleid) { |
1185 | //This function returns if a scale is being used by one assignment |
1186 | |
1187 | $return = false; |
1188 | |
1189 | $rec = get_record('assignment','id',$assignmentid,'grade',-$scaleid); |
1190 | |
1191 | if (!empty($rec) && !empty($scaleid)) { |
1192 | $return = true; |
1193 | } |
1194 | |
1195 | return $return; |
1196 | } |
1197 | |
1198 | |
1199 | function assignment_refresh_events($courseid = 0) { |
1200 | // This standard function will check all instances of this module |
1201 | // and make sure there are up-to-date events created for each of them. |
1202 | // If courseid = 0, then every assignment event in the site is checked, else |
1203 | // only assignment events belonging to the course specified are checked. |
1204 | // This function is used, in its new format, by restore_refresh_events() |
1205 | |
1206 | if ($courseid == 0) { |
1207 | if (! $assignments = get_records("assignment")) { |
1208 | return true; |
1209 | } |
1210 | } else { |
1211 | if (! $assignments = get_records("assignment", "course", $courseid)) { |
1212 | return true; |
1213 | } |
1214 | } |
1215 | $moduleid = get_field('modules', 'id', 'name', 'assignment'); |
1216 | |
1217 | foreach ($assignments as $assignment) { |
1218 | $event = NULL; |
1219 | $event->name = addslashes($assignment->name); |
1220 | $event->description = addslashes($assignment->description); |
1221 | $event->timestart = $assignment->timedue; |
1222 | |
1223 | if ($event->id = get_field('event', 'id', 'modulename', 'assignment', 'instance', $assignment->id)) { |
1224 | update_event($event); |
1225 | |
1226 | } else { |
1227 | $event->courseid = $assignment->course; |
1228 | $event->groupid = 0; |
1229 | $event->userid = 0; |
1230 | $event->modulename = 'assignment'; |
1231 | $event->instance = $assignment->id; |
1232 | $event->eventtype = 'due'; |
1233 | $event->timeduration = 0; |
1234 | $event->visible = get_field('course_modules', 'visible', 'module', $moduleid, 'instance', $assignment->id); |
1235 | add_event($event); |
1236 | } |
1237 | |
1238 | } |
1239 | return true; |
1240 | } |
1241 | |
1242 | |
1243 | function assignment_print_recent_activity($course, $isteacher, $timestart) { |
1244 | global $CFG; |
1245 | |
1246 | $content = false; |
1247 | $assignments = NULL; |
1248 | |
1249 | if (!$logs = get_records_select('log', 'time > \''.$timestart.'\' AND '. |
1250 | 'course = \''.$course->id.'\' AND '. |
1251 | 'module = \'assignment\' AND '. |
1252 | 'action = \'upload\' ', 'time ASC')) { |
1253 | return false; |
1254 | } |
1255 | |
1256 | foreach ($logs as $log) { |
1257 | //Create a temp valid module structure (course,id) |
1258 | $tempmod->course = $log->course; |
1259 | $tempmod->id = $log->info; |
1260 | //Obtain the visible property from the instance |
1261 | $modvisible = instance_is_visible($log->module,$tempmod); |
1262 | |
1263 | //Only if the mod is visible |
1264 | if ($modvisible) { |
1265 | $assignments[$log->info] = assignment_log_info($log); |
1266 | $assignments[$log->info]->time = $log->time; |
1267 | $assignments[$log->info]->url = str_replace('&', '&', $log->url); |
1268 | } |
1269 | } |
1270 | |
1271 | if ($assignments) { |
1272 | print_headline(get_string('newsubmissions', 'assignment').':'); |
1273 | foreach ($assignments as $assignment) { |
1274 | print_recent_activity_note($assignment->time, $assignment, $isteacher, $assignment->name, |
1275 | $CFG->wwwroot.'/mod/assignment/'.$assignment->url); |
1276 | } |
1277 | $content = true; |
1278 | } |
1279 | |
1280 | return $content; |
1281 | } |
1282 | |
1283 | |
1284 | |
1285 | function assignment_get_recent_mod_activity(&$activities, &$index, $sincetime, $courseid, $assignment="0", $user="", $groupid="") { |
1286 | // Returns all assignments since a given time. If assignment is specified then |
1287 | // this restricts the results |
1288 | |
1289 | global $CFG; |
1290 | |
1291 | if ($assignment) { |
1292 | $assignmentselect = " AND cm.id = '$assignment'"; |
1293 | } else { |
1294 | $assignmentselect = ""; |
1295 | } |
1296 | if ($user) { |
1297 | $userselect = " AND u.id = '$user'"; |
1298 | } else { |
1299 | $userselect = ""; |
1300 | } |
1301 | |
1302 | $assignments = get_records_sql("SELECT asub.*, u.firstname, u.lastname, u.picture, u.id as userid, |
1303 | a.grade as maxgrade, name, cm.instance, cm.section, a.assignmenttype |
1304 | FROM {$CFG->prefix}assignment_submissions asub, |
1305 | {$CFG->prefix}user u, |
1306 | {$CFG->prefix}assignment a, |
1307 | {$CFG->prefix}course_modules cm |
1308 | WHERE asub.timemodified > '$sincetime' |
1309 | AND asub.userid = u.id $userselect |
1310 | AND a.id = asub.assignment $assignmentselect |
1311 | AND cm.course = '$courseid' |
1312 | AND cm.instance = a.id |
1313 | ORDER BY asub.timemodified ASC"); |
1314 | |
1315 | if (empty($assignments)) |
1316 | return; |
1317 | |
1318 | foreach ($assignments as $assignment) { |
1319 | if (empty($groupid) || ismember($groupid, $assignment->userid)) { |
1320 | |
1321 | $tmpactivity = new Object; |
1322 | |
1323 | $tmpactivity->type = "assignment"; |
1324 | $tmpactivity->defaultindex = $index; |
1325 | $tmpactivity->instance = $assignment->instance; |
1326 | $tmpactivity->name = $assignment->name; |
1327 | $tmpactivity->section = $assignment->section; |
1328 | |
1329 | $tmpactivity->content->grade = $assignment->grade; |
1330 | $tmpactivity->content->maxgrade = $assignment->maxgrade; |
1331 | $tmpactivity->content->type = $assignment->assignmenttype; |
1332 | |
1333 | $tmpactivity->user->userid = $assignment->userid; |
1334 | $tmpactivity->user->fullname = fullname($assignment); |
1335 | $tmpactivity->user->picture = $assignment->picture; |
1336 | |
1337 | $tmpactivity->timestamp = $assignment->timemodified; |
1338 | |
1339 | $activities[] = $tmpactivity; |
1340 | |
1341 | $index++; |
1342 | } |
1343 | } |
1344 | |
1345 | return; |
1346 | } |
1347 | |
1348 | |
1349 | function assignment_print_recent_mod_activity($activity, $course, $detail=false) { |
1350 | global $CFG; |
1351 | |
1352 | echo '<table border="0" cellpadding="3" cellspacing="0">'; |
1353 | |
1354 | echo "<tr><td class=\"userpicture\" width=\"35\" valign=\"top\">"; |
1355 | print_user_picture($activity->user->userid, $course, $activity->user->picture); |
1356 | echo "</td><td width=\"100%\"><font size=2>"; |
1357 | |
1358 | if ($detail) { |
1359 | echo "<img src=\"$CFG->modpixpath/$activity->type/icon.gif\" ". |
1360 | "height=16 width=16 alt=\"$activity->type\"> "; |
1361 | echo "<a href=\"$CFG->wwwroot/mod/assignment/view.php?id=" . $activity->instance . "\">" |
1362 | . format_string($activity->name,true) . "</a> - "; |
1363 | |
1364 | } |
1365 | |
1366 | if (isteacher($course)) { |
1367 | $grades = "(" . $activity->content->grade . " / " . $activity->content->maxgrade . ") "; |
1368 | |
1369 | $assignment->id = $activity->instance; |
1370 | $assignment->course = $course; |
1371 | $user->id = $activity->user->userid; |
1372 | |
1373 | echo $grades; |
1374 | echo "<br />"; |
1375 | } |
1376 | echo "<a href=\"$CFG->wwwroot/user/view.php?id=" |
1377 | . $activity->user->userid . "&course=$course\">" |
1378 | . $activity->user->fullname . "</a> "; |
1379 | |
1380 | echo " - " . userdate($activity->timestamp); |
1381 | |
1382 | echo "</font></td></tr>"; |
1383 | echo "</table>"; |
1384 | |
1385 | return; |
1386 | } |
1387 | |
1388 | /// GENERIC SQL FUNCTIONS |
1389 | |
1390 | function assignment_log_info($log) { |
1391 | global $CFG; |
1392 | return get_record_sql("SELECT a.name, u.firstname, u.lastname |
1393 | FROM {$CFG->prefix}assignment a, |
1394 | {$CFG->prefix}user u |
1395 | WHERE a.id = '$log->info' |
1396 | AND u.id = '$log->userid'"); |
1397 | } |
1398 | |
1399 | function assignment_get_unmailed_submissions($starttime, $endtime) { |
1400 | /// Return list of marked submissions that have not been mailed out for currently enrolled students |
1401 | global $CFG; |
1402 | return get_records_sql("SELECT s.*, a.course, a.name |
1403 | FROM {$CFG->prefix}assignment_submissions s, |
1404 | {$CFG->prefix}assignment a, |
1405 | {$CFG->prefix}user_students us |
1406 | WHERE s.mailed = 0 |
1407 | AND s.timemarked <= $endtime |
1408 | AND s.timemarked >= $starttime |
1409 | AND s.assignment = a.id |
1410 | AND s.userid = us.userid |
1411 | AND a.course = us.course"); |
1412 | } |
1413 | |
1414 | function assignment_count_real_submissions($assignment, $groupid=0) { |
1415 | /// Return all real assignment submissions by ENROLLED students (not empty ones) |
1416 | global $CFG; |
1417 | |
1418 | if ($groupid) { /// How many in a particular group? |
1419 | return count_records_sql("SELECT COUNT(DISTINCT g.userid, g.groupid) |
1420 | FROM {$CFG->prefix}assignment_submissions a, |
1421 | {$CFG->prefix}groups_members g |
1422 | WHERE a.assignment = $assignment->id |
1423 | AND a.timemodified > 0 |
1424 | AND g.groupid = '$groupid' |
1425 | AND a.userid = g.userid "); |
1426 | } else { |
1427 | $select = "s.course = '$assignment->course' AND"; |
1428 | if ($assignment->course == SITEID) { |
1429 | $select = ''; |
1430 | } |
1431 | return count_records_sql("SELECT COUNT(*) |
1432 | FROM {$CFG->prefix}assignment_submissions a, |
1433 | {$CFG->prefix}user_students s |
1434 | WHERE a.assignment = '$assignment->id' |
1435 | AND a.timemodified > 0 |
1436 | AND $select a.userid = s.userid "); |
1437 | } |
1438 | } |
1439 | |
1440 | function assignment_get_all_submissions($assignment, $sort="", $dir="DESC") { |
1441 | /// Return all assignment submissions by ENROLLED students (even empty) |
1442 | global $CFG; |
1443 | |
1444 | if ($sort == "lastname" or $sort == "firstname") { |
1445 | $sort = "u.$sort $dir"; |
1446 | } else if (empty($sort)) { |
1447 | $sort = "a.timemodified DESC"; |
1448 | } else { |
1449 | $sort = "a.$sort $dir"; |
1450 | } |
1451 | |
1452 | $select = "s.course = '$assignment->course' AND"; |
1453 | if ($assignment->course == SITEID) { |
1454 | $select = ''; |
1455 | } |
1456 | return get_records_sql("SELECT a.* |
1457 | FROM {$CFG->prefix}assignment_submissions a, |
1458 | {$CFG->prefix}user_students s, |
1459 | {$CFG->prefix}user u |
1460 | WHERE a.userid = s.userid |
1461 | AND u.id = a.userid |
1462 | AND $select a.assignment = '$assignment->id' |
1463 | ORDER BY $sort"); |
1464 | } |
1465 | |
1466 | |
1467 | |
1468 | |
1469 | /// OTHER GENERAL FUNCTIONS FOR ASSIGNMENTS /////////////////////////////////////// |
1470 | |
1471 | |
b0f2597e |
1472 | function assignment_types() { |
1473 | $types = array(); |
1474 | $names = get_list_of_plugins('mod/assignment/type'); |
1475 | foreach ($names as $name) { |
1476 | $types[$name] = get_string('type'.$name, 'assignment'); |
ffeca120 |
1477 | } |
b0f2597e |
1478 | asort($types); |
1479 | return $types; |
f466c9ed |
1480 | } |
1481 | |
b0f2597e |
1482 | function assignment_upgrade_submodules() { |
f1c1d2f1 |
1483 | global $CFG; |
26b90e70 |
1484 | |
b0f2597e |
1485 | $types = assignment_types(); |
26b90e70 |
1486 | |
b0f2597e |
1487 | include_once($CFG->dirroot.'/mod/assignment/version.php'); // defines $module with version etc |
26b90e70 |
1488 | |
b0f2597e |
1489 | foreach ($types as $type) { |
26b90e70 |
1490 | |
b0f2597e |
1491 | $fullpath = $CFG->dirroot.'/mod/assignment/type/'.$type; |
26b90e70 |
1492 | |
b0f2597e |
1493 | /// Check for an external version file (defines $submodule) |
26b90e70 |
1494 | |
b0f2597e |
1495 | if (!is_readable($fullpath .'/version.php')) { |
1496 | continue; |
ffeca120 |
1497 | } |
b0f2597e |
1498 | unset($module); |
1499 | include_once($fullpath .'/version.php'); |
26b90e70 |
1500 | |
b0f2597e |
1501 | /// Check whether we need to upgrade |
26b90e70 |
1502 | |
b0f2597e |
1503 | if (!isset($submodule->version)) { |
1504 | continue; |
1505 | } |
26b90e70 |
1506 | |
b0f2597e |
1507 | /// Make sure this submodule will work with this assignment version |
26b90e70 |
1508 | |
b0f2597e |
1509 | if (isset($submodule->requires) and ($submodules->requires > $module->version)) { |
1510 | notify("Assignment submodule '$type' is too new for your assignment"); |
1511 | continue; |
1512 | } |
f466c9ed |
1513 | |
b0f2597e |
1514 | /// If we use versions, make sure an internal record exists |
f466c9ed |
1515 | |
b0f2597e |
1516 | $currentversion = 'assignment_'.$type.'_version'; |
f466c9ed |
1517 | |
b0f2597e |
1518 | if (!isset($CFG->$currentversion)) { |
1519 | set_config($currentversion, 0); |
f466c9ed |
1520 | } |
f466c9ed |
1521 | |
b0f2597e |
1522 | /// See if we need to upgrade |
1523 | |
1524 | if ($submodule->version <= $CFG->$currentversion) { |
1525 | continue; |
59c005b7 |
1526 | } |
59c005b7 |
1527 | |
b0f2597e |
1528 | /// Look for the upgrade file |
59c005b7 |
1529 | |
b0f2597e |
1530 | if (!is_readable($fullpath .'/db/'.$CFG->dbtype.'.php')) { |
1531 | continue; |
1532 | } |
59c005b7 |
1533 | |
b0f2597e |
1534 | include_once($fullpath .'/db/'. $CFG->dbtype .'.php'); // defines assignment_xxx_upgrade |
59c005b7 |
1535 | |
b0f2597e |
1536 | /// Perform the upgrade |
59c005b7 |
1537 | |
b0f2597e |
1538 | $upgrade_function = 'assignment_'.$type.'_upgrade'; |
1539 | if (function_exists($upgrade_function)) { |
1540 | $db->debug=true; |
1541 | if ($upgrade_function($CFG->$currentversion)) { |
1542 | $db->debug=false; |
1543 | set_config($currentversion, $submodule->version); |
59c005b7 |
1544 | } |
b0f2597e |
1545 | $db->debug=false; |
59c005b7 |
1546 | } |
1547 | } |
9437c854 |
1548 | |
1549 | |
59c005b7 |
1550 | } |
1551 | |
04eba58f |
1552 | ?> |