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