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