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