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