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