New function field_exists() to detect if one field exists
[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,
ea6432fe 212 * grade and teacher submissioncomment.
7af1e882 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">';
ea6432fe 260 echo format_text($submission->submissioncomment, $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;
ea6432fe 585 if (isset($_POST['submissioncomment'])) {
586 $col = 'submissioncomment';
16907e53 587 $commenting = true;
588 }
589 if (isset($_POST['menu'])) {
39e11905 590 $col = 'menu';
16907e53 591 $grading = true;
592 }
39e11905 593 if (!$col) {
ea6432fe 594 //both submissioncomment and grade columns collapsed..
39e11905 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) {
ea6432fe 623 $commentvalue = trim($_POST['submissioncomment'][$id]);
624 $updatedb = $updatedb || ($submission->submissioncomment != stripslashes($commentvalue));
625 $submission->submissioncomment = $commentvalue;
16907e53 626 } else {
ea6432fe 627 unset($submission->submissioncomment); // 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.
ea6432fe 635 //this will also not write into database if no submissioncomment 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";
ea6432fe 701 if (empty($SESSION->flextable['mod-assignment-submissions']->collapse['submissioncomment'])) {
9bf660b3 702 if ($quickgrade){
ea6432fe 703 $output.= 'opener.document.getElementById("submissioncomment['.$submission->userid.']").value="'
704 .trim($submission->submissioncomment).'";'."\n";
9bf660b3 705 } else {
73963212 706 $output.= 'opener.document.getElementById("com'.$submission->userid.
ea6432fe 707 '").innerHTML="'.shorten_text(trim(strip_tags($submission->submissioncomment)), 15)."\";\n";
9bf660b3 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 *
ea6432fe 780 * This default method prints the teacher info and submissioncomment box at the top and
7af1e882 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
0cfafdc7 809 /// construct SQL, using current offset to find the data of the next student
9bf660b3 810 $course = $this->course;
811 $assignment = $this->assignment;
812 $cm = $this->cm;
813
d699cd1e 814
9bf660b3 815 /// Get all teachers and students
0cfafdc7 816
817 $currentgroup = get_current_group($course->id);
818
9bf660b3 819 if ($currentgroup) {
820 $users = get_group_users($currentgroup);
821 } else {
822 $users = get_course_users($course->id);
823 }
5b48244f 824
082215e6 825 $select = 'SELECT u.id, u.id, u.firstname, u.lastname, u.picture,'.
ea6432fe 826 's.id AS submissionid, s.grade, s.submissioncomment, s.timemodified, s.timemarked, ((s.timemarked > 0) AND (s.timemarked >= s.timemodified)) AS status ';
9bf660b3 827 $sql = 'FROM '.$CFG->prefix.'user u '.
828 'LEFT JOIN '.$CFG->prefix.'assignment_submissions s ON u.id = s.userid AND s.assignment = '.$this->assignment->id.' '.
082215e6 829 'WHERE u.id IN ('.implode(',', array_keys($users)).') ';
02828119 830
831 require_once($CFG->libdir.'/tablelib.php');
0cfafdc7 832
833 if ($sort = flexible_table::get_sql_sort('mod-assignment-submissions')) {
02828119 834 $sort = 'ORDER BY '.$sort.' ';
835 }
836
837 $limit = sql_paging_limit($offset+1, 1);
838
082215e6 839 $nextid = 0;
81532b92 840 if (($auser = get_record_sql($select.$sql.$sort.$limit, false, true)) !== false) {
5b48244f 841 $nextid = $auser->id;
9bf660b3 842 }
81532b92 843
9bf660b3 844 print_header(get_string('feedback', 'assignment').':'.fullname($user, true).':'.format_string($this->assignment->name));
d699cd1e 845
73963212 846 /// Print any extra javascript needed for saveandnext
847 echo $extra_javascript;
848
9bf660b3 849 ///SOme javascript to help with setting up >.>
850
c9977d05 851 echo '<script type="text/javascript">'."\n";
9bf660b3 852 echo 'function setNext(){'."\n";
853 echo 'document.submitform.mode.value=\'next\';'."\n";
854 echo 'document.submitform.userid.value="'.$nextid.'";'."\n";
855 echo '}'."\n";
856
857 echo 'function saveNext(){'."\n";
858 echo 'document.submitform.mode.value=\'saveandnext\';'."\n";
859 echo 'document.submitform.userid.value="'.$nextid.'";'."\n";
860 echo 'document.submitform.saveuserid.value="'.$userid.'";'."\n";
861 echo 'document.submitform.menuindex.value = document.submitform.grade.selectedIndex;'."\n";
862 echo '}'."\n";
863
864 echo '</script>'."\n";
52436fe1 865 echo '<table cellspacing="0" class="feedback '.$subtype.'" >';
d699cd1e 866
9bf660b3 867 ///Start of teacher info row
c69cb506 868
b0f2597e 869 echo '<tr>';
870 echo '<td width="35" valign="top" class="picture teacher">';
871 if ($submission->teacher) {
872 $teacher = get_record('user', 'id', $submission->teacher);
873 } else {
874 global $USER;
875 $teacher = $USER;
876 }
877 print_user_picture($teacher->id, $this->course->id, $teacher->picture);
878 echo '</td>';
879 echo '<td class="content">';
9894b824 880 echo '<form name="submitform" action="submissions.php" method="post">';
881 echo '<input type="hidden" name="offset" value="'.++$offset.'">';
c9977d05 882 echo '<input type="hidden" name="userid" value="'.$userid.'" />';
883 echo '<input type="hidden" name="id" value="'.$this->cm->id.'" />';
884 echo '<input type="hidden" name="mode" value="grade" />';
885 echo '<input type="hidden" name="menuindex" value="0" />';//selected menu index
9bf660b3 886
887 //new hidden field, initialized to -1.
c9977d05 888 echo '<input type="hidden" name="saveuserid" value="-1" />';
52436fe1 889 if ($submission->timemarked) {
890 echo '<div class="from">';
891 echo '<div class="fullname">'.fullname($teacher, true).'</div>';
892 echo '<div class="time">'.userdate($submission->timemarked).'</div>';
893 echo '</div>';
894 }
895 echo '<div class="grade">'.get_string('grade').':';
082215e6 896 choose_from_menu(make_grades_menu($this->assignment->grade), 'grade', $submission->grade, get_string('nograde'), '', -1);
52436fe1 897 echo '</div>';
898 echo '<div class="clearer"></div>';
b0f2597e 899
01e2fdfe 900 $this->preprocess_submission($submission);
901
b0f2597e 902 echo '<br />';
ea6432fe 903 print_textarea($this->usehtmleditor, 14, 58, 0, 0, 'submissioncomment', $submission->submissioncomment, $this->course->id);
ff8f7015 904
ff8f7015 905 if ($this->usehtmleditor) {
ff8f7015 906 echo '<input type="hidden" name="format" value="'.FORMAT_HTML.'" />';
907 } else {
f77cfb73 908 echo '<div align="right" class="format">';
ff8f7015 909 choose_from_menu(format_text_menu(), "format", $submission->format, "");
f77cfb73 910 helpbutton("textformat", get_string("helpformatting"));
911 echo '</div>';
ff8f7015 912 }
b0f2597e 913
9bf660b3 914 ///Print Buttons in Single View
73097f07 915 echo '<div class="buttons" align="center">';
c9977d05 916 echo '<input type="submit" name="submit" value="'.get_string('savechanges').'" onclick = "document.submitform.menuindex.value = document.submitform.grade.selectedIndex" />';
b0f2597e 917 echo '<input type="submit" name="cancel" value="'.get_string('cancel').'" />';
9bf660b3 918 //if there are more to be graded.
082215e6 919 if ($nextid) {
5b48244f 920 echo '<input type="submit" name="saveandnext" value="'.get_string('saveandnext').'" onclick="saveNext()" />';
921 echo '<input type="submit" name="next" value="'.get_string('next').'" onclick="setNext();" />';
9bf660b3 922 }
73097f07 923 echo '</div>';
b0f2597e 924 echo '</form>';
73097f07 925 echo '</td></tr>';
9bf660b3 926
927 ///End of teacher info row, Start of student info row
928 echo '<tr>';
929 echo '<td width="35" valign="top" class="picture user">';
930 print_user_picture($user->id, $this->course->id, $user->picture);
931 echo '</td>';
932 echo '<td class="topic">';
933 echo '<div class="from">';
934 echo '<div class="fullname">'.fullname($user, true).'</div>';
935 if ($submission->timemodified) {
936 echo '<div class="time">'.userdate($submission->timemodified).
937 $this->display_lateness($submission->timemodified).'</div>';
938 }
939 echo '</div>';
940 $this->print_user_files($user->id);
941 echo '</td>';
942 echo '</tr>';
943
944 ///End of student info row
945
73097f07 946 echo '</table>';
947
73097f07 948 if ($this->usehtmleditor) {
949 use_html_editor();
950 }
951
b0f2597e 952 print_footer('none');
d699cd1e 953 }
954
7af1e882 955 /**
01e2fdfe 956 * Preprocess submission before grading
7af1e882 957 *
958 * Called by display_submission()
959 * The default type does nothing here.
960 * @param $submission object The submission object
01e2fdfe 961 */
962 function preprocess_submission(&$submission) {
963 }
d699cd1e 964
7af1e882 965 /**
b0f2597e 966 * Display all the submissions ready for grading
967 */
968 function display_submissions() {
3446205d 969
9bf660b3 970 global $CFG, $db, $USER;
3446205d 971
9bf660b3 972 /* first we check to see if the form has just been submitted
973 * to request user_preference updates
974 */
975
976 if (isset($_POST['updatepref'])){
16907e53 977 $perpage = optional_param('perpage', 10, PARAM_INT);
9bf660b3 978 $perpage = ($perpage <= 0) ? 10 : $perpage ;
979 set_user_preference('assignment_perpage', $perpage);
16907e53 980 set_user_preference('assignment_quickgrade', optional_param('quickgrade',0, PARAM_BOOL));
9bf660b3 981 }
1b5910c4 982
9bf660b3 983 /* next we get perpage and quickgrade (allow quick grade) params
984 * from database
985 */
986 $perpage = get_user_preferences('assignment_perpage', 10);
987 $quickgrade = get_user_preferences('assignment_quickgrade', 0);
988
989 $teacherattempts = true; /// Temporary measure
16907e53 990 $page = optional_param('page', 0, PARAM_INT);
b0f2597e 991 $strsaveallfeedback = get_string('saveallfeedback', 'assignment');
d0ac6bc2 992
b0f2597e 993 /// Some shortcuts to make the code read better
994
995 $course = $this->course;
996 $assignment = $this->assignment;
997 $cm = $this->cm;
9bf660b3 998
999 $tabindex = 1; //tabindex for quick grading tabbing; Not working for dropdowns yet
91719320 1000
b0f2597e 1001 add_to_log($course->id, 'assignment', 'view submission', 'submissions.php?id='.$this->assignment->id, $this->assignment->id, $this->cm->id);
1002
3898bc33 1003 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 1004
1005 ///Position swapped
1006 if ($groupmode = groupmode($course, $cm)) { // Groups are being used
1007 $currentgroup = setup_and_print_groups($course, $groupmode, 'submissions.php?id='.$this->cm->id);
1008 } else {
1009 $currentgroup = false;
1010 }
1011
1012 /// Get all teachers and students
1013 if ($currentgroup) {
1014 $users = get_group_users($currentgroup);
1015 } else {
1648afb2 1016 $context = get_context_instance(CONTEXT_MODULE, $cm->id);
1017 $users = get_users_by_capability($context, 'mod/assignment:submit'); // everyone with this capability set to non-prohibit
fa22fd5f 1018 }
91719320 1019
ea6432fe 1020 $tablecolumns = array('picture', 'fullname', 'grade', 'submissioncomment', 'timemodified', 'timemarked', 'status');
9437c854 1021 $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 1022
b0f2597e 1023 require_once($CFG->libdir.'/tablelib.php');
1024 $table = new flexible_table('mod-assignment-submissions');
1025
1026 $table->define_columns($tablecolumns);
1027 $table->define_headers($tableheaders);
fa22fd5f 1028 $table->define_baseurl($CFG->wwwroot.'/mod/assignment/submissions.php?id='.$this->cm->id.'&amp;currentgroup='.$currentgroup);
b0f2597e 1029
246444b9 1030 $table->sortable(true, 'lastname');//sorted by lastname by default
b0f2597e 1031 $table->collapsible(true);
1032 $table->initialbars(true);
1033
1034 $table->column_suppress('picture');
1035 $table->column_suppress('fullname');
1036
1037 $table->column_class('picture', 'picture');
9437c854 1038 $table->column_class('fullname', 'fullname');
1039 $table->column_class('grade', 'grade');
ea6432fe 1040 $table->column_class('submissioncomment', 'comment');
9437c854 1041 $table->column_class('timemodified', 'timemodified');
1042 $table->column_class('timemarked', 'timemarked');
1043 $table->column_class('status', 'status');
b0f2597e 1044
1045 $table->set_attribute('cellspacing', '0');
1046 $table->set_attribute('id', 'attempts');
9437c854 1047 $table->set_attribute('class', 'submissions');
b0f2597e 1048 $table->set_attribute('width', '90%');
1049 $table->set_attribute('align', 'center');
1050
1051 // Start working -- this is necessary as soon as the niceties are over
1052 $table->setup();
1053
b0f2597e 1054 /// Check to see if groups are being used in this assignment
05855091 1055
b0f2597e 1056 if (!$teacherattempts) {
1057 $teachers = get_course_teachers($course->id);
1058 if (!empty($teachers)) {
1059 $keys = array_keys($teachers);
1060 }
1061 foreach ($keys as $key) {
1062 unset($users[$key]);
1063 }
1064 }
1065
1066 if (empty($users)) {
c8dbfa5c 1067 print_heading(get_string('noattempts','assignment'));
b0f2597e 1068 return true;
1069 }
0f1a97c2 1070
b0f2597e 1071 /// Construct the SQL
0f1a97c2 1072
b0f2597e 1073 if ($where = $table->get_sql_where()) {
b0f2597e 1074 $where .= ' AND ';
1075 }
0f1a97c2 1076
b0f2597e 1077 if ($sort = $table->get_sql_sort()) {
86f65395 1078 $sort = ' ORDER BY '.$sort;
b0f2597e 1079 }
9fa49e22 1080
ea6432fe 1081 $select = 'SELECT u.id, u.id, u.firstname, u.lastname, u.picture, s.id AS submissionid, s.grade, s.submissioncomment, s.timemodified, s.timemarked, ((s.timemarked > 0) AND (s.timemarked >= s.timemodified)) AS status ';
b0f2597e 1082 $sql = 'FROM '.$CFG->prefix.'user u '.
306dc7e5 1083 'LEFT JOIN '.$CFG->prefix.'assignment_submissions s ON u.id = s.userid AND s.assignment = '.$this->assignment->id.' '.
1084 'WHERE '.$where.'u.id IN ('.implode(',', array_keys($users)).') ';
9bf660b3 1085
c5d36203 1086 $table->pagesize($perpage, count($users));
b0f2597e 1087
1088 if($table->get_page_start() !== '' && $table->get_page_size() !== '') {
1089 $limit = ' '.sql_paging_limit($table->get_page_start(), $table->get_page_size());
1090 }
1091 else {
1092 $limit = '';
1093 }
9bf660b3 1094
9bf660b3 1095 ///offset used to calculate index of student in that particular query, needed for the pop up to know who's next
1096 $offset = $page * $perpage;
1097
b0f2597e 1098 $strupdate = get_string('update');
9437c854 1099 $strgrade = get_string('grade');
b0f2597e 1100 $grademenu = make_grades_menu($this->assignment->grade);
1101
c5d36203 1102 if (($ausers = get_records_sql($select.$sql.$sort.$limit)) !== false) {
d59269cf 1103
d59269cf 1104 foreach ($ausers as $auser) {
1105 $picture = print_user_picture($auser->id, $course->id, $auser->picture, false, true);
9bf660b3 1106
39e11905 1107 if (empty($auser->submissionid)) {
1108 $auser->grade = -1; //no submission yet
9bf660b3 1109 }
1110
d59269cf 1111 if (!empty($auser->submissionid)) {
9bf660b3 1112 ///Prints student answer and student modified date
1113 ///attach file or print link to student answer, depending on the type of the assignment.
1114 ///Refer to print_student_answer in inherited classes.
1115 if ($auser->timemodified > 0) {
1116 $studentmodified = '<div id="ts'.$auser->id.'">'.$this->print_student_answer($auser->id).userdate($auser->timemodified).'</div>';
d59269cf 1117 } else {
9437c854 1118 $studentmodified = '<div id="ts'.$auser->id.'">&nbsp;</div>';
d59269cf 1119 }
9bf660b3 1120 ///Print grade, dropdown or text
d59269cf 1121 if ($auser->timemarked > 0) {
1122 $teachermodified = '<div id="tt'.$auser->id.'">'.userdate($auser->timemarked).'</div>';
9bf660b3 1123
1124 if ($quickgrade) {
1125 $grade = '<div id="g'.$auser->id.'">'.choose_from_menu(make_grades_menu($this->assignment->grade),
082215e6 1126 'menu['.$auser->id.']', $auser->grade, get_string('nograde'),'',-1,true,false,$tabindex++).'</div>';
9bf660b3 1127 } else {
1128 $grade = '<div id="g'.$auser->id.'">'.$this->display_grade($auser->grade).'</div>';
1129 }
1130
b0f2597e 1131 } else {
9437c854 1132 $teachermodified = '<div id="tt'.$auser->id.'">&nbsp;</div>';
9bf660b3 1133 if ($quickgrade){
1134 $grade = '<div id="g'.$auser->id.'">'.choose_from_menu(make_grades_menu($this->assignment->grade),
082215e6 1135 'menu['.$auser->id.']', $auser->grade, get_string('nograde'),'',-1,true,false,$tabindex++).'</div>';
9bf660b3 1136 } else {
1137 $grade = '<div id="g'.$auser->id.'">'.$this->display_grade($auser->grade).'</div>';
1138 }
1139 }
1140 ///Print Comment
1141 if ($quickgrade){
ea6432fe 1142 $comment = '<div id="com'.$auser->id.'"><textarea tabindex="'.$tabindex++.'" name="submissioncomment['.$auser->id.']" id="submissioncomment['.$auser->id.']">'.($auser->submissioncomment).'</textarea></div>';
9bf660b3 1143 } else {
ea6432fe 1144 $comment = '<div id="com'.$auser->id.'">'.shorten_text(strip_tags($auser->submissioncomment),15).'</div>';
b0f2597e 1145 }
1146 } else {
9437c854 1147 $studentmodified = '<div id="ts'.$auser->id.'">&nbsp;</div>';
1148 $teachermodified = '<div id="tt'.$auser->id.'">&nbsp;</div>';
9bf660b3 1149 $status = '<div id="st'.$auser->id.'">&nbsp;</div>';
1150 if ($quickgrade){ // allow editing
1151 $grade = '<div id="g'.$auser->id.'">'.choose_from_menu(make_grades_menu($this->assignment->grade),
082215e6 1152 'menu['.$auser->id.']', $auser->grade, get_string('nograde'),'',-1,true,false,$tabindex++).'</div>';
9bf660b3 1153 } else {
39e11905 1154 $grade = '<div id="g'.$auser->id.'">-</div>';
9bf660b3 1155 }
1156 if ($quickgrade){
ea6432fe 1157 $comment = '<div id="com'.$auser->id.'"><textarea tabindex="'.$tabindex++.'" name="submissioncomment['.$auser->id.']" id="submissioncomment['.$auser->id.']">'.($auser->submissioncomment).'</textarea></div>';
9bf660b3 1158 } else {
1159 $comment = '<div id="com'.$auser->id.'">&nbsp;</div>';
1160 }
b0f2597e 1161 }
9fa49e22 1162
0f7d4e5e 1163 if ($auser->status === NULL) {
1164 $auser->status = 0;
1165 }
1166
9437c854 1167 $buttontext = ($auser->status == 1) ? $strupdate : $strgrade;
9bf660b3 1168
1169 ///No more buttons, we use popups ;-).
9894b824 1170 $button = link_to_popup_window ('/mod/assignment/submissions.php?id='.$this->cm->id.'&amp;userid='.$auser->id.'&amp;mode=single'.'&amp;offset='.$offset++,
a8166227 1171 'grade'.$auser->id, $buttontext, 500, 780, $buttontext, 'none', true, 'button'.$auser->id);
0f7d4e5e 1172
9437c854 1173 $status = '<div id="up'.$auser->id.'" class="s'.$auser->status.'">'.$button.'</div>';
9bf660b3 1174
9437c854 1175 $row = array($picture, fullname($auser), $grade, $comment, $studentmodified, $teachermodified, $status);
d59269cf 1176 $table->add_data($row);
1177 }
b0f2597e 1178 }
9bf660b3 1179
082215e6 1180 /// Print quickgrade form around the table
1181 if ($quickgrade){
1182 echo '<form action="submissions.php" name="fastg" method="post">';
1183 echo '<input type="hidden" name="id" value="'.$this->cm->id.'">';
1184 echo '<input type="hidden" name="mode" value="fastgrade">';
16907e53 1185 echo '<input type="hidden" name="page" value="'.$page.'">';
9e0f5d2a 1186 echo '<p align="center"><input type="submit" name="fastg" value="'.get_string('saveallfeedback', 'assignment').'" /></p>';
082215e6 1187 }
1188
1189 $table->print_html(); /// Print the whole table
1190
9bf660b3 1191 if ($quickgrade){
1192 echo '<p align="center"><input type="submit" name="fastg" value="'.get_string('saveallfeedback', 'assignment').'" /></p>';
082215e6 1193 echo '</form>';
9bf660b3 1194 }
082215e6 1195 /// End of fast grading form
9bf660b3 1196
082215e6 1197 /// Mini form for setting user preference
9bf660b3 1198 echo '<br />';
1199 echo '<form name="options" action="submissions.php?id='.$this->cm->id.'" method="post">';
c9977d05 1200 echo '<input type="hidden" id="updatepref" name="updatepref" value="1" />';
9bf660b3 1201 echo '<table id="optiontable" align="center">';
1202 echo '<tr align="right"><td>';
1203 echo '<label for="perpage">'.get_string('pagesize','assignment').'</label>';
1204 echo ':</td>';
9bf660b3 1205 echo '<td align="left">';
1206 echo '<input type="text" id="perpage" name="perpage" size="1" value="'.$perpage.'" />';
1207 helpbutton('pagesize', get_string('pagesize','assignment'), 'assignment');
1208 echo '</td></tr>';
1209 echo '<tr align="right">';
1210 echo '<td>';
1211 print_string('quickgrade','assignment');
1212 echo ':</td>';
1213 echo '<td align="left">';
1214 if ($quickgrade){
1215 echo '<input type="checkbox" name="quickgrade" value="1" checked="checked" />';
1216 } else {
1217 echo '<input type="checkbox" name="quickgrade" value="1" />';
1218 }
1219 helpbutton('quickgrade', get_string('quickgrade', 'assignment'), 'assignment').'</p></div>';
1220 echo '</td></tr>';
1221 echo '<tr>';
1222 echo '<td colspan="2" align="right">';
1223 echo '<input type="submit" value="'.get_string('savepreferences').'" />';
1224 echo '</td></tr></table>';
1225 echo '</form>';
1226 ///End of mini form
b0f2597e 1227 print_footer($this->course);
8e340cb0 1228 }
d699cd1e 1229
7af1e882 1230 /**
1231 * Process teacher feedback submission
1232 *
1233 * This is called by submissions() when a grading even has taken place.
1234 * It gets its data from the submitted form.
1235 * @return object The updated submission object
b0f2597e 1236 */
1237 function process_feedback() {
d699cd1e 1238
b0f2597e 1239 global $USER;
d699cd1e 1240
9894b824 1241 if (!$feedback = data_submitted()) { // No incoming data?
b0f2597e 1242 return false;
d699cd1e 1243 }
b7b42874 1244
9bf660b3 1245 ///For save and next, we need to know the userid to save, and the userid to go
1246 ///We use a new hidden field in the form, and set it to -1. If it's set, we use this
1247 ///as the userid to store
1248 if ((int)$feedback->saveuserid !== -1){
1249 $feedback->userid = $feedback->saveuserid;
1250 }
1251
b0f2597e 1252 if (!empty($feedback->cancel)) { // User hit cancel button
1253 return false;
1254 }
d699cd1e 1255
7af1e882 1256 $submission = $this->get_submission($feedback->userid, true); // Get or make one
d699cd1e 1257
7af1e882 1258 $submission->grade = $feedback->grade;
ea6432fe 1259 $submission->submissioncomment = $feedback->submissioncomment;
7af1e882 1260 $submission->format = $feedback->format;
1261 $submission->teacher = $USER->id;
1262 $submission->mailed = 0; // Make sure mail goes out (again, even)
1263 $submission->timemarked = time();
d699cd1e 1264
7af1e882 1265 unset($submission->data1); // Don't need to update this.
1266 unset($submission->data2); // Don't need to update this.
d4156e80 1267
b0f2597e 1268 if (empty($submission->timemodified)) { // eg for offline assignments
7af1e882 1269 $submission->timemodified = time();
b0f2597e 1270 }
d699cd1e 1271
7af1e882 1272 if (! update_record('assignment_submissions', $submission)) {
b0f2597e 1273 return false;
1274 }
d699cd1e 1275
b0f2597e 1276 add_to_log($this->course->id, 'assignment', 'update grades',
1277 'submissions.php?id='.$this->assignment->id.'&user='.$feedback->userid, $feedback->userid, $this->cm->id);
1278
7af1e882 1279 return $submission;
d699cd1e 1280
d699cd1e 1281 }
d699cd1e 1282
7af1e882 1283 /**
1284 * Load the submission object for a particular user
1285 *
1286 * @param $userid int The id of the user whose submission we want or 0 in which case USER->id is used
1287 * @param $createnew boolean optional Defaults to false. If set to true a new submission object will be created in the database
1288 * @return object The submission
1289 */
f77cfb73 1290 function get_submission($userid=0, $createnew=false) {
1291 global $USER;
1292
1293 if (empty($userid)) {
1294 $userid = $USER->id;
1295 }
1296
b0f2597e 1297 $submission = get_record('assignment_submissions', 'assignment', $this->assignment->id, 'userid', $userid);
d699cd1e 1298
b0f2597e 1299 if ($submission || !$createnew) {
1300 return $submission;
1301 }
39e11905 1302 $newsubmission = $this->prepare_new_submission($userid);
b0f2597e 1303 if (!insert_record("assignment_submissions", $newsubmission)) {
1304 error("Could not insert a new empty submission");
1305 }
d699cd1e 1306
b0f2597e 1307 return get_record('assignment_submissions', 'assignment', $this->assignment->id, 'userid', $userid);
1308 }
d699cd1e 1309
7af1e882 1310 /**
1311 * Instantiates a new submission object for a given user
1312 *
1313 * Sets the assignment, userid and times, everything else is set to default values.
1314 * @param $userid int The userid for which we want a submission object
1315 * @return object The submission
1316 */
39e11905 1317 function prepare_new_submission($userid) {
1318 $submission = new Object;
1319 $submission->assignment = $this->assignment->id;
1320 $submission->userid = $userid;
1321 $submission->timecreated = time();
1322 $submission->timemodified = $submission->timecreated;
1323 $submission->numfiles = 0;
1324 $submission->data1 = '';
1325 $submission->data2 = '';
1326 $submission->grade = -1;
ea6432fe 1327 $submission->submissioncomment = '';
39e11905 1328 $submission->format = 0;
1329 $submission->teacher = 0;
1330 $submission->timemarked = 0;
1331 $submission->mailed = 0;
1332 return $submission;
1333 }
1334
7af1e882 1335 /**
1336 * Return all assignment submissions by ENROLLED students (even empty)
1337 *
1338 * @param $sort string optional field names for the ORDER BY in the sql query
1339 * @param $dir string optional specifying the sort direction, defaults to DESC
1340 * @return array The submission objects indexed by id
1341 */
b0f2597e 1342 function get_submissions($sort='', $dir='DESC') {
7af1e882 1343 return assignment_get_all_submissions($this->assignment, $sort, $dir);
b0f2597e 1344 }
1345
7af1e882 1346 /**
1347 * Counts all real assignment submissions by ENROLLED students (not empty ones)
1348 *
1349 * @param $groupid int optional If nonzero then count is restricted to this group
1350 * @return int The number of submissions
1351 */
b0f2597e 1352 function count_real_submissions($groupid=0) {
7af1e882 1353 return assignment_count_real_submissions($this->assignment, $groupid);
d59269cf 1354 }
d699cd1e 1355
7af1e882 1356 /**
1357 * Alerts teachers by email of new or changed assignments that need grading
1358 *
1359 * First checks whether the option to email teachers is set for this assignment.
1360 * Sends an email to ALL teachers in the course (or in the group if using separate groups).
1361 * Uses the methods email_teachers_text() and email_teachers_html() to construct the content.
1362 * @param $submission object The submission that has changed
1363 */
73097f07 1364 function email_teachers($submission) {
73097f07 1365 global $CFG;
1366
d8199f1d 1367 if (empty($this->assignment->emailteachers)) { // No need to do anything
73097f07 1368 return;
1369 }
1370
1371 $user = get_record('user', 'id', $submission->userid);
1372
d8199f1d 1373 if (groupmode($this->course, $this->cm) == SEPARATEGROUPS) { // Separate groups are being used
f262874b 1374 if ($groups = user_group($this->course->id, $user->id)) { // Try to find groups
1375 $teachers = array();
1376 foreach ($groups as $group) {
1377 $teachers = array_merge($teachers, get_group_teachers($this->course->id, $group->id));
1378 }
1379 } else {
1380 $teachers = get_group_teachers($this->course->id, 0); // Works even if not in group
73097f07 1381 }
73097f07 1382 } else {
d8199f1d 1383 $teachers = get_course_teachers($this->course->id);
73097f07 1384 }
1385
1386 if ($teachers) {
1387
1388 $strassignments = get_string('modulenameplural', 'assignment');
1389 $strassignment = get_string('modulename', 'assignment');
1390 $strsubmitted = get_string('submitted', 'assignment');
1391
1392 foreach ($teachers as $teacher) {
1393 unset($info);
1394 $info->username = fullname($user);
d8199f1d 1395 $info->assignment = format_string($this->assignment->name,true);
1396 $info->url = $CFG->wwwroot.'/mod/assignment/submissions.php?id='.$this->cm->id;
1397
1398 $postsubject = $strsubmitted.': '.$info->username.' -> '.$this->assignment->name;
1399 $posttext = $this->email_teachers_text($info);
1400 $posthtml = ($teacher->mailformat == 1) ? $this->email_teachers_html($info) : '';
73097f07 1401
1402 @email_to_user($teacher, $user, $postsubject, $posttext, $posthtml); // If it fails, oh well, too bad.
1403 }
1404 }
1405 }
1406
7af1e882 1407 /**
1408 * Creates the text content for emails to teachers
1409 *
1410 * @param $info object The info used by the 'emailteachermail' language string
1411 * @return string
1412 */
d8199f1d 1413 function email_teachers_text($info) {
1414 $posttext = $this->course->shortname.' -> '.$this->strassignments.' -> '.
1415 format_string($this->assignment->name, true)."\n";
1416 $posttext .= '---------------------------------------------------------------------'."\n";
1417 $posttext .= get_string("emailteachermail", "assignment", $info)."\n";
73963212 1418 $posttext .= "\n---------------------------------------------------------------------\n";
d8199f1d 1419 return $posttext;
1420 }
1421
7af1e882 1422 /**
1423 * Creates the html content for emails to teachers
1424 *
1425 * @param $info object The info used by the 'emailteachermailhtml' language string
1426 * @return string
1427 */
d8199f1d 1428 function email_teachers_html($info) {
3554b5c2 1429 global $CFG;
d8199f1d 1430 $posthtml = '<p><font face="sans-serif">'.
3554b5c2 1431 '<a href="'.$CFG->wwwroot.'/course/view.php?id='.$this->course->id.'">'.$this->course->shortname.'</a> ->'.
d8199f1d 1432 '<a href="'.$CFG->wwwroot.'/mod/assignment/index.php?id='.$this->course->id.'">'.$this->strassignments.'</a> ->'.
3554b5c2 1433 '<a href="'.$CFG->wwwroot.'/mod/assignment/view.php?id='.$this->cm->id.'">'.format_string($this->assignment->name,true).'</a></font></p>';
d8199f1d 1434 $posthtml .= '<hr /><font face="sans-serif">';
1435 $posthtml .= '<p>'.get_string('emailteachermailhtml', 'assignment', $info).'</p>';
1436 $posthtml .= '</font><hr />';
815b5ca6 1437 return $posthtml;
d8199f1d 1438 }
1439
7af1e882 1440 /**
1441 * Produces a list of links to the files uploaded by a user
1442 *
1443 * @param $userid int optional id of the user. If 0 then $USER->id is used.
1444 * @param $return boolean optional defaults to false. If true the list is returned rather than printed
1445 * @return string optional
1446 */
d8199f1d 1447 function print_user_files($userid=0, $return=false) {
d8199f1d 1448 global $CFG, $USER;
9bf660b3 1449
d8199f1d 1450 if (!$userid) {
1451 if (!isloggedin()) {
1452 return '';
1453 }
1454 $userid = $USER->id;
1455 }
73097f07 1456
70b2c772 1457 $filearea = $this->file_area_name($userid);
73097f07 1458
1459 $output = '';
1460
70b2c772 1461 if ($basedir = $this->file_area($userid)) {
73097f07 1462 if ($files = get_directory_list($basedir)) {
1ef048ae 1463 require_once($CFG->libdir.'/filelib.php');
73097f07 1464 foreach ($files as $key => $file) {
9bf660b3 1465
73097f07 1466 $icon = mimeinfo('icon', $file);
9bf660b3 1467
73097f07 1468 if ($CFG->slasharguments) {
d4156e80 1469 $ffurl = "$CFG->wwwroot/file.php/$filearea/$file";
73097f07 1470 } else {
d4156e80 1471 $ffurl = "$CFG->wwwroot/file.php?file=/$filearea/$file";
73097f07 1472 }
9bf660b3 1473
1ef048ae 1474 $output .= '<img align="middle" src="'.$CFG->pixpath.'/f/'.$icon.'" height="16" width="16" alt="'.$icon.'" />'.
9bf660b3 1475 '<a href="'.$ffurl.'" >'.$file.'</a><br />';
73097f07 1476 }
1477 }
1478 }
1479
1480 $output = '<div class="files">'.$output.'</div>';
1481
1482 if ($return) {
1483 return $output;
1484 }
1485 echo $output;
1486 }
1487
7af1e882 1488 /**
1489 * Count the files uploaded by a given user
1490 *
1491 * @param $userid int The user id
1492 * @return int
1493 */
70b2c772 1494 function count_user_files($userid) {
1495 global $CFG;
1496
1497 $filearea = $this->file_area_name($userid);
1498
c853b39f 1499 if ( is_dir($CFG->dataroot.'/'.$filearea) && $basedir = $this->file_area($userid)) {
70b2c772 1500 if ($files = get_directory_list($basedir)) {
1501 return count($files);
1502 }
1503 }
1504 return 0;
1505 }
73097f07 1506
7af1e882 1507 /**
1508 * Creates a directory file name, suitable for make_upload_directory()
1509 *
1510 * @param $userid int The user id
1511 * @return string path to file area
1512 */
70b2c772 1513 function file_area_name($userid) {
73097f07 1514 global $CFG;
1515
70b2c772 1516 return $this->course->id.'/'.$CFG->moddata.'/assignment/'.$this->assignment->id.'/'.$userid;
73097f07 1517 }
7af1e882 1518
1519 /**
1520 * Makes an upload directory
1521 *
1522 * @param $userid int The user id
1523 * @return string path to file area.
1524 */
70b2c772 1525 function file_area($userid) {
1526 return make_upload_directory( $this->file_area_name($userid) );
73097f07 1527 }
1528
7af1e882 1529 /**
1530 * Returns true if the student is allowed to submit
1531 *
1532 * Checks that the assignment has started and, if the option to prevent late
1533 * submissions is set, also checks that the assignment has not yet closed.
1534 * @return boolean
1535 */
f77cfb73 1536 function isopen() {
1537 $time = time();
1e4343a0 1538 if ($this->assignment->preventlate && $this->assignment->timedue) {
f77cfb73 1539 return ($this->assignment->timeavailable <= $time && $time <= $this->assignment->timedue);
1540 } else {
1541 return ($this->assignment->timeavailable <= $time);
1542 }
1543 }
1544
7af1e882 1545 /**
1546 * Return an outline of the user's interaction with the assignment
1547 *
1548 * The default method prints the grade and timemodified
1549 * @param $user object
1550 * @return object with properties ->info and ->time
1551 */
73097f07 1552 function user_outline($user) {
1553 if ($submission = $this->get_submission($user->id)) {
39e11905 1554
1555 $result->info = get_string('grade').': '.$this->display_grade($submission->grade);
73097f07 1556 $result->time = $submission->timemodified;
1557 return $result;
1558 }
1559 return NULL;
1560 }
7af1e882 1561
1562 /**
1563 * Print complete information about the user's interaction with the assignment
1564 *
1565 * @param $user object
1566 */
73097f07 1567 function user_complete($user) {
1568 if ($submission = $this->get_submission($user->id)) {
70b2c772 1569 if ($basedir = $this->file_area($user->id)) {
73097f07 1570 if ($files = get_directory_list($basedir)) {
1571 $countfiles = count($files)." ".get_string("uploadedfiles", "assignment");
1572 foreach ($files as $file) {
1573 $countfiles .= "; $file";
1574 }
1575 }
1576 }
1577
1578 print_simple_box_start();
1579 echo get_string("lastmodified").": ";
9bf660b3 1580 echo userdate($submission->timemodified);
1581 echo $this->display_lateness($submission->timemodified);
73097f07 1582
70b2c772 1583 $this->print_user_files($user->id);
73097f07 1584
1585 echo '<br />';
1586
1587 if (empty($submission->timemarked)) {
1588 print_string("notgradedyet", "assignment");
1589 } else {
1590 $this->view_feedback($submission);
1591 }
1592
1593 print_simple_box_end();
1594
1595 } else {
1596 print_string("notsubmittedyet", "assignment");
1597 }
1598 }
1599
7af1e882 1600 /**
1601 * Return a string indicating how late a submission is
1602 *
1603 * @param $timesubmitted int
1604 * @return string
1605 */
70b2c772 1606 function display_lateness($timesubmitted) {
76a60031 1607 return assignment_display_lateness($timesubmitted, $this->assignment->timedue);
73097f07 1608 }
1609
1610
b0f2597e 1611} ////// End of the assignment_base class
d699cd1e 1612
18b8fbfa 1613
04eba58f 1614
b0f2597e 1615/// OTHER STANDARD FUNCTIONS ////////////////////////////////////////////////////////
1616
7af1e882 1617/**
1618 * Deletes an assignment instance
1619 *
1620 * This is done by calling the delete_instance() method of the assignment type class
1621 */
b0f2597e 1622function assignment_delete_instance($id){
26b90e70 1623 global $CFG;
1624
b0f2597e 1625 if (! $assignment = get_record('assignment', 'id', $id)) {
1626 return false;
26b90e70 1627 }
1628
b0f2597e 1629 require_once("$CFG->dirroot/mod/assignment/type/$assignment->assignmenttype/assignment.class.php");
1630 $assignmentclass = "assignment_$assignment->assignmenttype";
1631 $ass = new $assignmentclass();
1632 return $ass->delete_instance($assignment);
1633}
f466c9ed 1634
ac21ad39 1635
7af1e882 1636/**
1637 * Updates an assignment instance
1638 *
1639 * This is done by calling the update_instance() method of the assignment type class
1640 */
b0f2597e 1641function assignment_update_instance($assignment){
1642 global $CFG;
26b90e70 1643
200c19fb 1644 $assignment->assignmenttype = clean_param($assignment->assignmenttype, PARAM_SAFEDIR);
1645
b0f2597e 1646 require_once("$CFG->dirroot/mod/assignment/type/$assignment->assignmenttype/assignment.class.php");
1647 $assignmentclass = "assignment_$assignment->assignmenttype";
1648 $ass = new $assignmentclass();
1649 return $ass->update_instance($assignment);
1650}
26b90e70 1651
26b90e70 1652
7af1e882 1653/**
1654 * Adds an assignment instance
1655 *
1656 * This is done by calling the add_instance() method of the assignment type class
1657 */
b0f2597e 1658function assignment_add_instance($assignment) {
1659 global $CFG;
f466c9ed 1660
200c19fb 1661 $assignment->assignmenttype = clean_param($assignment->assignmenttype, PARAM_SAFEDIR);
1662
b0f2597e 1663 require_once("$CFG->dirroot/mod/assignment/type/$assignment->assignmenttype/assignment.class.php");
1664 $assignmentclass = "assignment_$assignment->assignmenttype";
1665 $ass = new $assignmentclass();
1666 return $ass->add_instance($assignment);
1667}
f466c9ed 1668
73097f07 1669
7af1e882 1670/**
1671 * Returns an outline of a user interaction with an assignment
1672 *
1673 * This is done by calling the user_outline() method of the assignment type class
1674 */
73097f07 1675function assignment_user_outline($course, $user, $mod, $assignment) {
1676 global $CFG;
1677
1678 require_once("$CFG->dirroot/mod/assignment/type/$assignment->assignmenttype/assignment.class.php");
1679 $assignmentclass = "assignment_$assignment->assignmenttype";
1680 $ass = new $assignmentclass($mod->id, $assignment, $mod, $course);
1681 return $ass->user_outline($user);
1682}
1683
7af1e882 1684/**
1685 * Prints the complete info about a user's interaction with an assignment
1686 *
1687 * This is done by calling the user_complete() method of the assignment type class
1688 */
73097f07 1689function assignment_user_complete($course, $user, $mod, $assignment) {
1690 global $CFG;
1691
1692 require_once("$CFG->dirroot/mod/assignment/type/$assignment->assignmenttype/assignment.class.php");
1693 $assignmentclass = "assignment_$assignment->assignmenttype";
1694 $ass = new $assignmentclass($mod->id, $assignment, $mod, $course);
1695 return $ass->user_complete($user);
1696}
1697
7af1e882 1698/**
1699 * Function to be run periodically according to the moodle cron
1700 *
1701 * Finds all assignment notifications that have yet to be mailed out, and mails them
1702 */
73097f07 1703function assignment_cron () {
73097f07 1704
1705 global $CFG, $USER;
1706
1707 /// Notices older than 1 day will not be mailed. This is to avoid the problem where
1708 /// cron has not been running for a long time, and then suddenly people are flooded
1709 /// with mail from the past few weeks or months
1710
1711 $timenow = time();
1712 $endtime = $timenow - $CFG->maxeditingtime;
1713 $starttime = $endtime - 24 * 3600; /// One day earlier
1714
1715 if ($submissions = assignment_get_unmailed_submissions($starttime, $endtime)) {
1716
1717 foreach ($submissions as $key => $submission) {
1718 if (! set_field("assignment_submissions", "mailed", "1", "id", "$submission->id")) {
1719 echo "Could not update the mailed field for id $submission->id. Not mailed.\n";
1720 unset($submissions[$key]);
1721 }
1722 }
1723
1724 $timenow = time();
1725
1726 foreach ($submissions as $submission) {
1727
1728 echo "Processing assignment submission $submission->id\n";
1729
1730 if (! $user = get_record("user", "id", "$submission->userid")) {
1731 echo "Could not find user $post->userid\n";
1732 continue;
1733 }
1734
1735 $USER->lang = $user->lang;
1736
1737 if (! $course = get_record("course", "id", "$submission->course")) {
1738 echo "Could not find course $submission->course\n";
1739 continue;
1740 }
0bde6300 1741
1742 if (!has_capability('moodle/course:view', get_context_instance(CONTEXT_COURSE, $$submission->course))) {
73097f07 1743 echo fullname($user)." not an active participant in $course->shortname\n";
1744 continue;
1745 }
1746
1747 if (! $teacher = get_record("user", "id", "$submission->teacher")) {
1748 echo "Could not find teacher $submission->teacher\n";
1749 continue;
1750 }
1751
1752 if (! $mod = get_coursemodule_from_instance("assignment", $submission->assignment, $course->id)) {
1753 echo "Could not find course module for assignment id $submission->assignment\n";
1754 continue;
1755 }
1756
1757 if (! $mod->visible) { /// Hold mail notification for hidden assignments until later
1758 continue;
1759 }
1760
1761 $strassignments = get_string("modulenameplural", "assignment");
1762 $strassignment = get_string("modulename", "assignment");
1763
1764 unset($assignmentinfo);
1765 $assignmentinfo->teacher = fullname($teacher);
1766 $assignmentinfo->assignment = format_string($submission->name,true);
1767 $assignmentinfo->url = "$CFG->wwwroot/mod/assignment/view.php?id=$mod->id";
1768
1769 $postsubject = "$course->shortname: $strassignments: ".format_string($submission->name,true);
1770 $posttext = "$course->shortname -> $strassignments -> ".format_string($submission->name,true)."\n";
1771 $posttext .= "---------------------------------------------------------------------\n";
3f19bff3 1772 $posttext .= get_string("assignmentmail", "assignment", $assignmentinfo)."\n";
73097f07 1773 $posttext .= "---------------------------------------------------------------------\n";
1774
1775 if ($user->mailformat == 1) { // HTML
1776 $posthtml = "<p><font face=\"sans-serif\">".
1777 "<a href=\"$CFG->wwwroot/course/view.php?id=$course->id\">$course->shortname</a> ->".
1778 "<a href=\"$CFG->wwwroot/mod/assignment/index.php?id=$course->id\">$strassignments</a> ->".
1779 "<a href=\"$CFG->wwwroot/mod/assignment/view.php?id=$mod->id\">".format_string($submission->name,true)."</a></font></p>";
1780 $posthtml .= "<hr /><font face=\"sans-serif\">";
1781 $posthtml .= "<p>".get_string("assignmentmailhtml", "assignment", $assignmentinfo)."</p>";
1782 $posthtml .= "</font><hr />";
1783 } else {
1784 $posthtml = "";
1785 }
1786
1787 if (! email_to_user($user, $teacher, $postsubject, $posttext, $posthtml)) {
1788 echo "Error: assignment cron: Could not send out mail for id $submission->id to user $user->id ($user->email)\n";
1789 }
1790 }
1791 }
1792
1793 return true;
1794}
1795
7af1e882 1796/**
1797 * Return an array of grades, indexed by user, and a max grade.
1798 *
1799 * @param $assignmentid int
1800 * @return object with properties ->grades (an array of grades) and ->maxgrade.
1801 */
73097f07 1802function assignment_grades($assignmentid) {
73097f07 1803
082215e6 1804 if (!$assignment = get_record('assignment', 'id', $assignmentid)) {
73097f07 1805 return NULL;
1806 }
3262ee10 1807 if ($assignment->grade == 0) { // No grading
1808 return NULL;
1809 }
73097f07 1810
082215e6 1811 $grades = get_records_menu('assignment_submissions', 'assignment',
1812 $assignment->id, '', 'userid,grade');
73097f07 1813
3262ee10 1814 if ($assignment->grade > 0) {
fa22fd5f 1815 if ($grades) {
1816 foreach ($grades as $userid => $grade) {
1817 if ($grade == -1) {
1818 $grades[$userid] = '-';
1819 }
082215e6 1820 }
1821 }
73097f07 1822 $return->grades = $grades;
1823 $return->maxgrade = $assignment->grade;
1824
1825 } else { // Scale
1826 if ($grades) {
1827 $scaleid = - ($assignment->grade);
bed24ce7 1828 $maxgrade = "";
73097f07 1829 if ($scale = get_record('scale', 'id', $scaleid)) {
1830 $scalegrades = make_menu_from_list($scale->scale);
082215e6 1831 foreach ($grades as $userid => $grade) {
de4564ee 1832 if (empty($scalegrades[$grade])) {
39e11905 1833 $grades[$userid] = '-';
0a3f66a2 1834 } else {
082215e6 1835 $grades[$userid] = $scalegrades[$grade];
0a3f66a2 1836 }
73097f07 1837 }
bed24ce7 1838 $maxgrade = $scale->name;
73097f07 1839 }
1840 }
1841 $return->grades = $grades;
bed24ce7 1842 $return->maxgrade = $maxgrade;
73097f07 1843 }
1844
1845 return $return;
1846}
1847
7af1e882 1848/**
1849 * Returns the users with data in one assignment (students and teachers)
1850 *
1851 * @param $assignmentid int
1852 * @return array of user objects
1853 */
73097f07 1854function assignment_get_participants($assignmentid) {
73097f07 1855
1856 global $CFG;
1857
1858 //Get students
1859 $students = get_records_sql("SELECT DISTINCT u.id, u.id
1860 FROM {$CFG->prefix}user u,
1861 {$CFG->prefix}assignment_submissions a
1862 WHERE a.assignment = '$assignmentid' and
1863 u.id = a.userid");
1864 //Get teachers
1865 $teachers = get_records_sql("SELECT DISTINCT u.id, u.id
1866 FROM {$CFG->prefix}user u,
1867 {$CFG->prefix}assignment_submissions a
1868 WHERE a.assignment = '$assignmentid' and
1869 u.id = a.teacher");
1870
1871 //Add teachers to students
1872 if ($teachers) {
1873 foreach ($teachers as $teacher) {
1874 $students[$teacher->id] = $teacher;
1875 }
1876 }
1877 //Return students array (it contains an array of unique users)
1878 return ($students);
1879}
1880
7af1e882 1881/**
1882 * Checks if a scale is being used by an assignment
1883 *
1884 * This is used by the backup code to decide whether to back up a scale
1885 * @param $assignmentid int
1886 * @param $scaleid int
1887 * @return boolean True if the scale is used by the assignment
1888 */
1889function assignment_scale_used ($assignmentid, $scaleid) {
73097f07 1890
1891 $return = false;
1892
1893 $rec = get_record('assignment','id',$assignmentid,'grade',-$scaleid);
1894
1895 if (!empty($rec) && !empty($scaleid)) {
1896 $return = true;
1897 }
1898
1899 return $return;
1900}
1901
7af1e882 1902/**
1903 * Make sure up-to-date events are created for all assignment instances
1904 *
1905 * This standard function will check all instances of this module
1906 * and make sure there are up-to-date events created for each of them.
1907 * If courseid = 0, then every assignment event in the site is checked, else
1908 * only assignment events belonging to the course specified are checked.
1909 * This function is used, in its new format, by restore_refresh_events()
1910 *
1911 * @param $courseid int optional If zero then all assignments for all courses are covered
1912 * @return boolean Always returns true
1913 */
73097f07 1914function assignment_refresh_events($courseid = 0) {
73097f07 1915
1916 if ($courseid == 0) {
1917 if (! $assignments = get_records("assignment")) {
1918 return true;
1919 }
1920 } else {
1921 if (! $assignments = get_records("assignment", "course", $courseid)) {
1922 return true;
1923 }
1924 }
1925 $moduleid = get_field('modules', 'id', 'name', 'assignment');
1926
1927 foreach ($assignments as $assignment) {
1928 $event = NULL;
1929 $event->name = addslashes($assignment->name);
1930 $event->description = addslashes($assignment->description);
1931 $event->timestart = $assignment->timedue;
1932
1933 if ($event->id = get_field('event', 'id', 'modulename', 'assignment', 'instance', $assignment->id)) {
1934 update_event($event);
1935
1936 } else {
1937 $event->courseid = $assignment->course;
1938 $event->groupid = 0;
1939 $event->userid = 0;
1940 $event->modulename = 'assignment';
1941 $event->instance = $assignment->id;
1942 $event->eventtype = 'due';
1943 $event->timeduration = 0;
1944 $event->visible = get_field('course_modules', 'visible', 'module', $moduleid, 'instance', $assignment->id);
1945 add_event($event);
1946 }
1947
1948 }
1949 return true;
1950}
1951
7af1e882 1952/**
1953 * Print recent activity from all assignments in a given course
1954 *
1955 * This is used by the recent activity block
1956 */
73097f07 1957function assignment_print_recent_activity($course, $isteacher, $timestart) {
1958 global $CFG;
1959
1960 $content = false;
1961 $assignments = NULL;
1962
1963 if (!$logs = get_records_select('log', 'time > \''.$timestart.'\' AND '.
1964 'course = \''.$course->id.'\' AND '.
1965 'module = \'assignment\' AND '.
1966 'action = \'upload\' ', 'time ASC')) {
1967 return false;
1968 }
1969
1970 foreach ($logs as $log) {
1971 //Create a temp valid module structure (course,id)
1972 $tempmod->course = $log->course;
1973 $tempmod->id = $log->info;
1974 //Obtain the visible property from the instance
1975 $modvisible = instance_is_visible($log->module,$tempmod);
1976
1977 //Only if the mod is visible
1978 if ($modvisible) {
1979 $assignments[$log->info] = assignment_log_info($log);
1980 $assignments[$log->info]->time = $log->time;
1981 $assignments[$log->info]->url = str_replace('&', '&amp;', $log->url);
1982 }
1983 }
1984
1985 if ($assignments) {
1986 print_headline(get_string('newsubmissions', 'assignment').':');
1987 foreach ($assignments as $assignment) {
583b57b4 1988 print_recent_activity_note($assignment->time, $assignment, $assignment->name,
73097f07 1989 $CFG->wwwroot.'/mod/assignment/'.$assignment->url);
1990 }
1991 $content = true;
1992 }
1993
1994 return $content;
1995}
1996
1997
7af1e882 1998/**
1999 * Returns all assignments since a given time.
2000 *
2001 * If assignment is specified then this restricts the results
2002 */
73097f07 2003function assignment_get_recent_mod_activity(&$activities, &$index, $sincetime, $courseid, $assignment="0", $user="", $groupid="") {
73097f07 2004
2005 global $CFG;
2006
2007 if ($assignment) {
2008 $assignmentselect = " AND cm.id = '$assignment'";
2009 } else {
2010 $assignmentselect = "";
2011 }
2012 if ($user) {
2013 $userselect = " AND u.id = '$user'";
2014 } else {
2015 $userselect = "";
2016 }
2017
2018 $assignments = get_records_sql("SELECT asub.*, u.firstname, u.lastname, u.picture, u.id as userid,
2019 a.grade as maxgrade, name, cm.instance, cm.section, a.assignmenttype
2020 FROM {$CFG->prefix}assignment_submissions asub,
2021 {$CFG->prefix}user u,
2022 {$CFG->prefix}assignment a,
2023 {$CFG->prefix}course_modules cm
2024 WHERE asub.timemodified > '$sincetime'
2025 AND asub.userid = u.id $userselect
2026 AND a.id = asub.assignment $assignmentselect
2027 AND cm.course = '$courseid'
2028 AND cm.instance = a.id
2029 ORDER BY asub.timemodified ASC");
2030
2031 if (empty($assignments))
2032 return;
2033
2034 foreach ($assignments as $assignment) {
2035 if (empty($groupid) || ismember($groupid, $assignment->userid)) {
2036
2037 $tmpactivity = new Object;
2038
2039 $tmpactivity->type = "assignment";
2040 $tmpactivity->defaultindex = $index;
2041 $tmpactivity->instance = $assignment->instance;
2042 $tmpactivity->name = $assignment->name;
2043 $tmpactivity->section = $assignment->section;
2044
2045 $tmpactivity->content->grade = $assignment->grade;
2046 $tmpactivity->content->maxgrade = $assignment->maxgrade;
2047 $tmpactivity->content->type = $assignment->assignmenttype;
2048
2049 $tmpactivity->user->userid = $assignment->userid;
2050 $tmpactivity->user->fullname = fullname($assignment);
2051 $tmpactivity->user->picture = $assignment->picture;
2052
2053 $tmpactivity->timestamp = $assignment->timemodified;
2054
2055 $activities[] = $tmpactivity;
2056
2057 $index++;
2058 }
2059 }
2060
2061 return;
2062}
2063
7af1e882 2064/**
2065 * Print recent activity from all assignments in a given course
2066 *
2067 * This is used by course/recent.php
2068 */
73097f07 2069function assignment_print_recent_mod_activity($activity, $course, $detail=false) {
2070 global $CFG;
2071
2072 echo '<table border="0" cellpadding="3" cellspacing="0">';
2073
2074 echo "<tr><td class=\"userpicture\" width=\"35\" valign=\"top\">";
2075 print_user_picture($activity->user->userid, $course, $activity->user->picture);
2076 echo "</td><td width=\"100%\"><font size=2>";
2077
2078 if ($detail) {
2079 echo "<img src=\"$CFG->modpixpath/$activity->type/icon.gif\" ".
2080 "height=16 width=16 alt=\"$activity->type\"> ";
2081 echo "<a href=\"$CFG->wwwroot/mod/assignment/view.php?id=" . $activity->instance . "\">"
2082 . format_string($activity->name,true) . "</a> - ";
2083
2084 }
2085
0bde6300 2086 if (has_capability('moodle/course:viewrecent', get_context_instance(CONTEXT_COURSE, $course))) {
73097f07 2087 $grades = "(" . $activity->content->grade . " / " . $activity->content->maxgrade . ") ";
2088
2089 $assignment->id = $activity->instance;
2090 $assignment->course = $course;
2091 $user->id = $activity->user->userid;
2092
2093 echo $grades;
2094 echo "<br />";
2095 }
2096 echo "<a href=\"$CFG->wwwroot/user/view.php?id="
2097 . $activity->user->userid . "&amp;course=$course\">"
2098 . $activity->user->fullname . "</a> ";
2099
2100 echo " - " . userdate($activity->timestamp);
2101
2102 echo "</font></td></tr>";
2103 echo "</table>";
73097f07 2104}
2105
2106/// GENERIC SQL FUNCTIONS
2107
7af1e882 2108/**
2109 * Fetch info from logs
2110 *
2111 * @param $log object with properties ->info (the assignment id) and ->userid
2112 * @return array with assignment name and user firstname and lastname
2113 */
73097f07 2114function assignment_log_info($log) {
2115 global $CFG;
2116 return get_record_sql("SELECT a.name, u.firstname, u.lastname
2117 FROM {$CFG->prefix}assignment a,
2118 {$CFG->prefix}user u
2119 WHERE a.id = '$log->info'
2120 AND u.id = '$log->userid'");
2121}
2122
7af1e882 2123/**
2124 * Return list of marked submissions that have not been mailed out for currently enrolled students
2125 *
2126 * @return array
2127 */
73097f07 2128function assignment_get_unmailed_submissions($starttime, $endtime) {
7af1e882 2129
73097f07 2130 global $CFG;
ea8158c1 2131
73097f07 2132 return get_records_sql("SELECT s.*, a.course, a.name
ea8158c1 2133 FROM {$CFG->prefix}assignment_submissions s,
4be6bced 2134 {$CFG->prefix}assignment a
ea8158c1 2135 WHERE s.mailed = 0
2136 AND s.timemarked <= $endtime
2137 AND s.timemarked >= $starttime
4be6bced 2138 AND s.assignment = a.id");
ea8158c1 2139
2140 /* return get_records_sql("SELECT s.*, a.course, a.name
73097f07 2141 FROM {$CFG->prefix}assignment_submissions s,
2142 {$CFG->prefix}assignment a,
2143 {$CFG->prefix}user_students us
2144 WHERE s.mailed = 0
2145 AND s.timemarked <= $endtime
2146 AND s.timemarked >= $starttime
2147 AND s.assignment = a.id
2148 AND s.userid = us.userid
2149 AND a.course = us.course");
ea8158c1 2150 */
73097f07 2151}
2152
7af1e882 2153/**
2154 * Counts all real assignment submissions by ENROLLED students (not empty ones)
2155 *
2156 * There are also assignment type methods count_real_submissions() wich in the default
2157 * implementation simply call this function.
2158 * @param $groupid int optional If nonzero then count is restricted to this group
2159 * @return int The number of submissions
2160 */
73097f07 2161function assignment_count_real_submissions($assignment, $groupid=0) {
73097f07 2162 global $CFG;
2163
2164 if ($groupid) { /// How many in a particular group?
2165 return count_records_sql("SELECT COUNT(DISTINCT g.userid, g.groupid)
2166 FROM {$CFG->prefix}assignment_submissions a,
2167 {$CFG->prefix}groups_members g
2168 WHERE a.assignment = $assignment->id
2169 AND a.timemodified > 0
2170 AND g.groupid = '$groupid'
2171 AND a.userid = g.userid ");
2172 } else {
1648afb2 2173 $cm = get_coursemodule_from_instance('assignment', $assignment->id);
2174 $context = get_context_instance(CONTEXT_MODULE, $cm->id);
2175
2176 // this is all the users with this capability set, in this context or higher
2177 $users = get_users_by_capability($context, 'mod/assignment:submit');
2178 foreach ($users as $user) {
2179 $array[] = $user->id;
73097f07 2180 }
1648afb2 2181
2182 $userlists = '('.implode(',',$array).')';
2183
73097f07 2184 return count_records_sql("SELECT COUNT(*)
1648afb2 2185 FROM {$CFG->prefix}assignment_submissions
2186 WHERE assignment = '$assignment->id'
2187 AND timemodified > 0
2188 AND userid IN $userlists ");
73097f07 2189 }
2190}
2191
7af1e882 2192
2193/**
2194 * Return all assignment submissions by ENROLLED students (even empty)
2195 *
2196 * There are also assignment type methods get_submissions() wich in the default
2197 * implementation simply call this function.
2198 * @param $sort string optional field names for the ORDER BY in the sql query
2199 * @param $dir string optional specifying the sort direction, defaults to DESC
2200 * @return array The submission objects indexed by id
2201 */
73097f07 2202function assignment_get_all_submissions($assignment, $sort="", $dir="DESC") {
2203/// Return all assignment submissions by ENROLLED students (even empty)
2204 global $CFG;
2205
2206 if ($sort == "lastname" or $sort == "firstname") {
2207 $sort = "u.$sort $dir";
2208 } else if (empty($sort)) {
2209 $sort = "a.timemodified DESC";
2210 } else {
2211 $sort = "a.$sort $dir";
2212 }
2213
ea8158c1 2214 /* not sure this is needed at all since assignmenet already has a course define, so this join?
73097f07 2215 $select = "s.course = '$assignment->course' AND";
2216 if ($assignment->course == SITEID) {
2217 $select = '';
ea8158c1 2218 }*/
2219
73097f07 2220 return get_records_sql("SELECT a.*
ea8158c1 2221 FROM {$CFG->prefix}assignment_submissions a,
2222 {$CFG->prefix}user u
2223 WHERE u.id = a.userid
2224 AND a.assignment = '$assignment->id'
2225 ORDER BY $sort");
2226
2227 /* return get_records_sql("SELECT a.*
73097f07 2228 FROM {$CFG->prefix}assignment_submissions a,
2229 {$CFG->prefix}user_students s,
2230 {$CFG->prefix}user u
2231 WHERE a.userid = s.userid
2232 AND u.id = a.userid
2233 AND $select a.assignment = '$assignment->id'
2234 ORDER BY $sort");
ea8158c1 2235 */
73097f07 2236}
2237
2238
2239
2240
2241/// OTHER GENERAL FUNCTIONS FOR ASSIGNMENTS ///////////////////////////////////////
2242
7af1e882 2243/**
2244 * Returns an array of installed assignment types indexed and sorted by name
2245 *
2246 * @return array The index is the name of the assignment type, the value its full name from the language strings
2247 */
b0f2597e 2248function assignment_types() {
2249 $types = array();
2250 $names = get_list_of_plugins('mod/assignment/type');
2251 foreach ($names as $name) {
2252 $types[$name] = get_string('type'.$name, 'assignment');
ffeca120 2253 }
b0f2597e 2254 asort($types);
2255 return $types;
f466c9ed 2256}
2257
7af1e882 2258/**
2259 * Executes upgrade scripts for assignment types when necessary
2260 */
b0f2597e 2261function assignment_upgrade_submodules() {
f1c1d2f1 2262 global $CFG;
26b90e70 2263
b0f2597e 2264 $types = assignment_types();
26b90e70 2265
d175966b 2266 include($CFG->dirroot.'/mod/assignment/version.php'); // defines $module with version etc
26b90e70 2267
d175966b 2268 foreach ($types as $type => $typename) {
26b90e70 2269
b0f2597e 2270 $fullpath = $CFG->dirroot.'/mod/assignment/type/'.$type;
26b90e70 2271
b0f2597e 2272 /// Check for an external version file (defines $submodule)
26b90e70 2273
b0f2597e 2274 if (!is_readable($fullpath .'/version.php')) {
2275 continue;
ffeca120 2276 }
b0f2597e 2277 include_once($fullpath .'/version.php');
26b90e70 2278
b0f2597e 2279 /// Check whether we need to upgrade
26b90e70 2280
b0f2597e 2281 if (!isset($submodule->version)) {
2282 continue;
2283 }
26b90e70 2284
b0f2597e 2285 /// Make sure this submodule will work with this assignment version
26b90e70 2286
d175966b 2287 if (isset($submodule->requires) and ($submodule->requires > $module->version)) {
b0f2597e 2288 notify("Assignment submodule '$type' is too new for your assignment");
2289 continue;
2290 }
f466c9ed 2291
a86a538f 2292 /// If the submodule is new, then let's install it!
f466c9ed 2293
b0f2597e 2294 $currentversion = 'assignment_'.$type.'_version';
f466c9ed 2295
a86a538f 2296 if (!isset($CFG->$currentversion)) { // First install!
2297 set_config($currentversion, $submodule->version); // Must keep track of version
2298
2299 if (!is_readable($fullpath .'/db/'.$CFG->dbtype.'.sql')) {
2300 continue;
2301 }
2302
583fad99 2303 upgrade_log_start();
a86a538f 2304 $db->debug=true;
2305 if (!modify_database($fullpath .'/db/'.$CFG->dbtype.'.sql')) {
2306 notify("Error installing tables for submodule '$type'!");
2307 }
2308 $db->debug=false;
2309 continue;
f466c9ed 2310 }
f466c9ed 2311
b0f2597e 2312 /// See if we need to upgrade
2313
2314 if ($submodule->version <= $CFG->$currentversion) {
2315 continue;
59c005b7 2316 }
59c005b7 2317
b0f2597e 2318 /// Look for the upgrade file
59c005b7 2319
b0f2597e 2320 if (!is_readable($fullpath .'/db/'.$CFG->dbtype.'.php')) {
2321 continue;
2322 }
59c005b7 2323
b0f2597e 2324 include_once($fullpath .'/db/'. $CFG->dbtype .'.php'); // defines assignment_xxx_upgrade
59c005b7 2325
b0f2597e 2326 /// Perform the upgrade
59c005b7 2327
b0f2597e 2328 $upgrade_function = 'assignment_'.$type.'_upgrade';
2329 if (function_exists($upgrade_function)) {
583fad99 2330 upgrade_log_start();
b0f2597e 2331 $db->debug=true;
2332 if ($upgrade_function($CFG->$currentversion)) {
2333 $db->debug=false;
2334 set_config($currentversion, $submodule->version);
59c005b7 2335 }
b0f2597e 2336 $db->debug=false;
59c005b7 2337 }
2338 }
2339}
2340
84fa8f5f 2341function assignment_print_overview($courses, &$htmlarray) {
2342 global $USER, $CFG;
2343
2344 if (empty($courses) || !is_array($courses) || count($courses) == 0) {
2345 return array();
2346 }
2347
2348 if (!$assignments = get_all_instances_in_courses('assignment',$courses)) {
2349 return;
2350 }
2351
2352 // Do assignment_base::isopen() here without loading the whole thing for speed
2353 foreach ($assignments as $key => $assignment) {
2354 $time = time();
d6da4a1a 2355 if ($assignment->timedue) {
2356 if ($assignment->preventlate) {
2357 $isopen = ($assignment->timeavailable <= $time && $time <= $assignment->timedue);
2358 } else {
2359 $isopen = ($assignment->timeavailable <= $time);
2360 }
84fa8f5f 2361 }
d6da4a1a 2362 if (empty($isopen) || empty($assignment->timedue)) {
84fa8f5f 2363 unset($assignments[$key]);
2364 }
2365 }
2366
2367 $strduedate = get_string('duedate', 'assignment');
8f643c81 2368 $strduedateno = get_string('duedateno', 'assignment');
84fa8f5f 2369 $strgraded = get_string('graded', 'assignment');
2370 $strnotgradedyet = get_string('notgradedyet', 'assignment');
2371 $strnotsubmittedyet = get_string('notsubmittedyet', 'assignment');
2372 $strsubmitted = get_string('submitted', 'assignment');
76a60031 2373 $strassignment = get_string('modulename', 'assignment');
84fa8f5f 2374
2375 foreach ($assignments as $assignment) {
a2a37336 2376 $str = '<div class="assignment overview"><div class="name">'.$strassignment. ': '.
a7a74d77 2377 '<a '.($assignment->visible ? '':' class="dimmed"').
76a60031 2378 'title="'.$strassignment.'" href="'.$CFG->wwwroot.
a7a74d77 2379 '/mod/assignment/view.php?id='.$assignment->coursemodule.'">'.
5d45c04f 2380 $assignment->name.'</a></div>';
8f643c81 2381 if ($assignment->timedue) {
2382 $str .= '<div class="info">'.$strduedate.': '.userdate($assignment->timedue).'</div>';
2383 } else {
2384 $str .= '<div class="info">'.$strduedateno.'</div>';
2385 }
76a60031 2386
bbbf2d40 2387 $context = get_context_instance(CONTEXT_MODULE,$this->cm->id);
0468976c 2388 if (has_capability('mod/assignment:grade', $context)) {
ea8158c1 2389
2390 // count how many people can submit
2391 $submissions = 0; // init
2392 $students = get_users_by_capability($context, 'mod/assignment:submit');
2393 foreach ($student as $student) {
2394 if (get_record('assignment_submissions', 'assignment', $assignment->id, 'userid', $student->id)) {
2395 $submissions++;
2396 }
2397 }
2398
84fa8f5f 2399 if ($submissions) {
2400 $str .= get_string('submissionsnotgraded', 'assignment', $submissions);
2401 }
2402 } else {
2403 $sql = "SELECT *
2404 FROM {$CFG->prefix}assignment_submissions
b3d4840d 2405 WHERE userid = '$USER->id'
2406 AND assignment = '{$assignment->id}'";
84fa8f5f 2407 if ($submission = get_record_sql($sql)) {
2408 if ($submission->teacher == 0 && $submission->timemarked == 0) {
2409 $str .= $strsubmitted . ', ' . $strnotgradedyet;
2410 } else {
2411 $str .= $strsubmitted . ', ' . $strgraded;
2412 }
2413 } else {
76a60031 2414 $str .= $strnotsubmittedyet . ' ' . assignment_display_lateness(time(), $assignment->timedue);
84fa8f5f 2415 }
2416 }
a7a74d77 2417 $str .= '</div>';
76a60031 2418 if (empty($htmlarray[$assignment->course]['assignment'])) {
2419 $htmlarray[$assignment->course]['assignment'] = $str;
2420 } else {
2421 $htmlarray[$assignment->course]['assignment'] .= $str;
2422 }
2423 }
2424}
2425
2426function assignment_display_lateness($timesubmitted, $timedue) {
2427 if (!$timedue) {
2428 return '';
2429 }
2430 $time = $timedue - $timesubmitted;
2431 if ($time < 0) {
2432 $timetext = get_string('late', 'assignment', format_time($time));
2433 return ' (<span class="late">'.$timetext.'</span>)';
2434 } else {
2435 $timetext = get_string('early', 'assignment', format_time($time));
2436 return ' (<span class="early">'.$timetext.'</span>)';
84fa8f5f 2437 }
2438}
2439
76a60031 2440?>