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