5c6b657a |
1 | <?PHP // $Id$ |
b0f2597e |
2 | /** |
3 | * assignment_base is the base class for assignment types |
4 | * |
5 | * This class provides all the functionality for an assignment |
6 | */ |
04eba58f |
7 | |
1884f2a6 |
8 | DEFINE ('ASSIGNMENT_COUNT_WORDS', 1); |
9 | DEFINE ('ASSIGNMENT_COUNT_LETTERS', 2); |
d699cd1e |
10 | |
4909e176 |
11 | if (!isset($CFG->assignment_maxbytes)) { |
12 | set_config("assignment_maxbytes", 1024000); // Default maximum size for all assignments |
04eba58f |
13 | } |
1884f2a6 |
14 | if (!isset($CFG->assignment_itemstocount)) { |
15 | set_config("assignment_itemstocount", ASSIGNMENT_COUNT_WORDS); // Default item to count |
16 | } |
04eba58f |
17 | |
7af1e882 |
18 | /** |
b0f2597e |
19 | * Standard base class for all assignment submodules (assignment types). |
b0f2597e |
20 | */ |
21 | class assignment_base { |
22 | |
23 | var $cm; |
24 | var $course; |
25 | var $assignment; |
7af1e882 |
26 | var $strassignment; |
27 | var $strassignments; |
28 | var $strsubmissions; |
29 | var $strlastmodified; |
30 | var $navigation; |
31 | var $pagetitle; |
32 | var $currentgroup; |
33 | var $usehtmleditor; |
34 | var $defaultformat; |
55b4d096 |
35 | var $context; |
b0f2597e |
36 | |
37 | /** |
38 | * Constructor for the base assignment class |
39 | * |
40 | * Constructor for the base assignment class. |
41 | * If cmid is set create the cm, course, assignment objects. |
7af1e882 |
42 | * If the assignment is hidden and the user is not a teacher then |
43 | * this prints a page header and notice. |
b0f2597e |
44 | * |
45 | * @param cmid integer, the current course module id - not set for new assignments |
73097f07 |
46 | * @param assignment object, usually null, but if we have it we pass it to save db access |
7af1e882 |
47 | * @param cm object, usually null, but if we have it we pass it to save db access |
48 | * @param course object, usually null, but if we have it we pass it to save db access |
b0f2597e |
49 | */ |
73097f07 |
50 | function assignment_base($cmid=0, $assignment=NULL, $cm=NULL, $course=NULL) { |
b0f2597e |
51 | |
52 | global $CFG; |
53 | |
54 | if ($cmid) { |
73097f07 |
55 | if ($cm) { |
56 | $this->cm = $cm; |
f9d5371b |
57 | } else if (! $this->cm = get_coursemodule_from_id('assignment', $cmid)) { |
73097f07 |
58 | error('Course Module ID was incorrect'); |
b0f2597e |
59 | } |
04eba58f |
60 | |
55b4d096 |
61 | $this->context = get_context_instance(CONTEXT_MODULE,$this->cm->id); |
62 | |
73097f07 |
63 | if ($course) { |
64 | $this->course = $course; |
65 | } else if (! $this->course = get_record('course', 'id', $this->cm->course)) { |
66 | error('Course is misconfigured'); |
b0f2597e |
67 | } |
04eba58f |
68 | |
73097f07 |
69 | if ($assignment) { |
70 | $this->assignment = $assignment; |
71 | } else if (! $this->assignment = get_record('assignment', 'id', $this->cm->instance)) { |
72 | error('assignment ID was incorrect'); |
b0f2597e |
73 | } |
e6a4906b |
74 | |
b0f2597e |
75 | $this->strassignment = get_string('modulename', 'assignment'); |
76 | $this->strassignments = get_string('modulenameplural', 'assignment'); |
77 | $this->strsubmissions = get_string('submissions', 'assignment'); |
78 | $this->strlastmodified = get_string('lastmodified'); |
b9dc2734 |
79 | |
80 | $this->navigation[] = array('name' => $this->strassignments, 'link' => "index.php?id={$this->course->id}", 'type' => 'activity'); |
81 | |
3898bc33 |
82 | $this->pagetitle = strip_tags($this->course->shortname.': '.$this->strassignment.': '.format_string($this->assignment->name,true)); |
e6a4906b |
83 | |
0bde6300 |
84 | // visibility |
85 | $context = get_context_instance(CONTEXT_MODULE, $cmid); |
86 | if (!$this->cm->visible and !has_capability('moodle/course:viewhiddenactivities', $context)) { |
b0f2597e |
87 | $pagetitle = strip_tags($this->course->shortname.': '.$this->strassignment); |
b9dc2734 |
88 | $this->navigation[] = array('name' => $this->strassignment, 'link' => '', 'type' => 'activityinstance'); |
70c6c0ad |
89 | $navigation = build_navigation($this->navigation); |
b9dc2734 |
90 | |
b0f2597e |
91 | print_header($pagetitle, $this->course->fullname, "$this->navigation $this->strassignment", |
92 | "", "", true, '', navmenu($this->course, $this->cm)); |
93 | notice(get_string("activityiscurrentlyhidden"), "$CFG->wwwroot/course/view.php?id={$this->course->id}"); |
94 | } |
b0f2597e |
95 | $this->currentgroup = get_current_group($this->course->id); |
73097f07 |
96 | } |
e6a4906b |
97 | |
73097f07 |
98 | /// Set up things for a HTML editor if it's needed |
99 | if ($this->usehtmleditor = can_use_html_editor()) { |
100 | $this->defaultformat = FORMAT_HTML; |
101 | } else { |
102 | $this->defaultformat = FORMAT_MOODLE; |
e6a4906b |
103 | } |
104 | } |
105 | |
7af1e882 |
106 | /** |
107 | * Display the assignment, used by view.php |
108 | * |
109 | * This in turn calls the methods producing individual parts of the page |
b0f2597e |
110 | */ |
b0f2597e |
111 | function view() { |
bbbf2d40 |
112 | |
dabfd0ed |
113 | $context = get_context_instance(CONTEXT_MODULE,$this->cm->id); |
0468976c |
114 | require_capability('mod/assignment:view', $context); |
bbbf2d40 |
115 | |
dabfd0ed |
116 | add_to_log($this->course->id, "assignment", "view", "view.php?id={$this->cm->id}", |
b0f2597e |
117 | $this->assignment->id, $this->cm->id); |
04eba58f |
118 | |
73097f07 |
119 | $this->view_header(); |
04eba58f |
120 | |
f77cfb73 |
121 | $this->view_intro(); |
04eba58f |
122 | |
f77cfb73 |
123 | $this->view_dates(); |
04eba58f |
124 | |
b0f2597e |
125 | $this->view_feedback(); |
126 | |
f77cfb73 |
127 | $this->view_footer(); |
36eb856f |
128 | } |
129 | |
7af1e882 |
130 | /** |
131 | * Display the header and top of a page |
132 | * |
133 | * (this doesn't change much for assignment types) |
134 | * This is used by the view() method to print the header of view.php but |
135 | * it can be used on other pages in which case the string to denote the |
136 | * page in the navigation trail should be passed as an argument |
137 | * |
138 | * @param $subpage string Description of subpage to be used in navigation trail |
73097f07 |
139 | */ |
140 | function view_header($subpage='') { |
141 | |
142 | global $CFG; |
143 | |
b9dc2734 |
144 | |
73097f07 |
145 | if ($subpage) { |
b9dc2734 |
146 | $this->navigation[] = array('name' => format_string($this->assignment->name,true), 'link' => "view.php?id={$this->cm->id}", 'type' => 'activityinstance'); |
147 | $this->navigation[] = array('name' => $subpage, 'link' => '', 'type' => 'title'); |
73097f07 |
148 | } else { |
b9dc2734 |
149 | $this->navigation[] = array('name' => format_string($this->assignment->name,true), 'link' => '', 'type' => 'activityinstance'); |
73097f07 |
150 | } |
b9dc2734 |
151 | |
70c6c0ad |
152 | $navigation = build_navigation($this->navigation); |
73097f07 |
153 | |
b9dc2734 |
154 | print_header($this->pagetitle, $this->course->fullname, $navigation, '', '', |
73097f07 |
155 | true, update_module_button($this->cm->id, $this->course->id, $this->strassignment), |
156 | navmenu($this->course, $this->cm)); |
157 | |
158 | echo '<div class="reportlink">'.$this->submittedlink().'</div>'; |
159 | } |
160 | |
161 | |
7af1e882 |
162 | /** |
f77cfb73 |
163 | * Display the assignment intro |
7af1e882 |
164 | * |
165 | * This will most likely be extended by assignment type plug-ins |
166 | * The default implementation prints the assignment description in a box |
f77cfb73 |
167 | */ |
168 | function view_intro() { |
32776fef |
169 | print_simple_box_start('center', '', '', 0, 'generalbox', 'intro'); |
1e4343a0 |
170 | $formatoptions = new stdClass; |
171 | $formatoptions->noclean = true; |
172 | echo format_text($this->assignment->description, $this->assignment->format, $formatoptions); |
f77cfb73 |
173 | print_simple_box_end(); |
174 | } |
175 | |
7af1e882 |
176 | /** |
f77cfb73 |
177 | * Display the assignment dates |
7af1e882 |
178 | * |
179 | * Prints the assignment start and end dates in a box. |
180 | * This will be suitable for most assignment types |
f77cfb73 |
181 | */ |
182 | function view_dates() { |
183 | if (!$this->assignment->timeavailable && !$this->assignment->timedue) { |
184 | return; |
185 | } |
186 | |
32776fef |
187 | print_simple_box_start('center', '', '', 0, 'generalbox', 'dates'); |
f77cfb73 |
188 | echo '<table>'; |
189 | if ($this->assignment->timeavailable) { |
190 | echo '<tr><td class="c0">'.get_string('availabledate','assignment').':</td>'; |
191 | echo ' <td class="c1">'.userdate($this->assignment->timeavailable).'</td></tr>'; |
192 | } |
193 | if ($this->assignment->timedue) { |
194 | echo '<tr><td class="c0">'.get_string('duedate','assignment').':</td>'; |
195 | echo ' <td class="c1">'.userdate($this->assignment->timedue).'</td></tr>'; |
196 | } |
197 | echo '</table>'; |
198 | print_simple_box_end(); |
199 | } |
200 | |
201 | |
7af1e882 |
202 | /** |
203 | * Display the bottom and footer of a page |
204 | * |
205 | * This default method just prints the footer. |
206 | * This will be suitable for most assignment types |
73097f07 |
207 | */ |
208 | function view_footer() { |
209 | print_footer($this->course); |
210 | } |
211 | |
7af1e882 |
212 | /** |
213 | * Display the feedback to the student |
214 | * |
215 | * This default method prints the teacher picture and name, date when marked, |
ea6432fe |
216 | * grade and teacher submissioncomment. |
7af1e882 |
217 | * |
218 | * @param $submission object The submission object or NULL in which case it will be loaded |
219 | */ |
73097f07 |
220 | function view_feedback($submission=NULL) { |
b0f2597e |
221 | global $USER; |
e6a4906b |
222 | |
73097f07 |
223 | if (!$submission) { /// Get submission for this assignment |
224 | $submission = $this->get_submission($USER->id); |
70b2c772 |
225 | } |
226 | |
227 | if (empty($submission->timemarked)) { /// Nothing to show, so print nothing |
228 | return; |
9c48354d |
229 | } |
e6a4906b |
230 | |
b0f2597e |
231 | /// We need the teacher info |
232 | if (! $teacher = get_record('user', 'id', $submission->teacher)) { |
b0f2597e |
233 | error('Could not find the teacher'); |
234 | } |
e6a4906b |
235 | |
b0f2597e |
236 | /// Print the feedback |
6d4ecaec |
237 | print_heading(get_string('feedbackfromteacher', 'assignment', $this->course->teacher)); |
238 | |
b0f2597e |
239 | echo '<table cellspacing="0" class="feedback">'; |
240 | |
241 | echo '<tr>'; |
242 | echo '<td class="left picture">'; |
243 | print_user_picture($teacher->id, $this->course->id, $teacher->picture); |
244 | echo '</td>'; |
6d4ecaec |
245 | echo '<td class="topic">'; |
70b2c772 |
246 | echo '<div class="from">'; |
73097f07 |
247 | echo '<div class="fullname">'.fullname($teacher).'</div>'; |
6d4ecaec |
248 | echo '<div class="time">'.userdate($submission->timemarked).'</div>'; |
70b2c772 |
249 | echo '</div>'; |
b0f2597e |
250 | echo '</td>'; |
251 | echo '</tr>'; |
252 | |
253 | echo '<tr>'; |
254 | echo '<td class="left side"> </td>'; |
6d4ecaec |
255 | echo '<td class="content">'; |
b0f2597e |
256 | if ($this->assignment->grade) { |
6d4ecaec |
257 | echo '<div class="grade">'; |
70b2c772 |
258 | echo get_string("grade").': '.$this->display_grade($submission->grade); |
6d4ecaec |
259 | echo '</div>'; |
52436fe1 |
260 | echo '<div class="clearer"></div>'; |
e6a4906b |
261 | } |
dcd338ff |
262 | |
6d4ecaec |
263 | echo '<div class="comment">'; |
ea6432fe |
264 | echo format_text($submission->submissioncomment, $submission->format); |
6d4ecaec |
265 | echo '</div>'; |
b0f2597e |
266 | echo '</tr>'; |
267 | |
268 | echo '</table>'; |
e6a4906b |
269 | } |
e6a4906b |
270 | |
7af1e882 |
271 | /** |
ba16713f |
272 | * Returns a link with info about the state of the assignment submissions |
7af1e882 |
273 | * |
274 | * This is used by view_header to put this link at the top right of the page. |
275 | * For teachers it gives the number of submitted assignments with a link |
276 | * For students it gives the time of their submission. |
277 | * This will be suitable for most assignment types. |
278 | * @return string |
ba16713f |
279 | */ |
280 | function submittedlink() { |
281 | global $USER; |
282 | |
283 | $submitted = ''; |
284 | |
bbbf2d40 |
285 | $context = get_context_instance(CONTEXT_MODULE,$this->cm->id); |
1648afb2 |
286 | if (has_capability('mod/assignment:grade', $context)) { |
bbbf2d40 |
287 | |
288 | // if this user can mark and is put in a group |
289 | // then he can only see/mark submission in his own groups |
1648afb2 |
290 | if (!has_capability('moodle/course:managegroups', $context) and (groupmode($this->course, $this->cm) == SEPARATEGROUPS)) { |
bbbf2d40 |
291 | $count = $this->count_real_submissions($this->currentgroup); // Only their groups |
ba16713f |
292 | } else { |
293 | $count = $this->count_real_submissions(); // Everyone |
294 | } |
295 | $submitted = '<a href="submissions.php?id='.$this->cm->id.'">'. |
296 | get_string('viewsubmissions', 'assignment', $count).'</a>'; |
297 | } else { |
86a1ba04 |
298 | if (!empty($USER->id)) { |
ba16713f |
299 | if ($submission = $this->get_submission($USER->id)) { |
300 | if ($submission->timemodified) { |
1e4343a0 |
301 | if ($submission->timemodified <= $this->assignment->timedue || empty($this->assignment->timedue)) { |
ba16713f |
302 | $submitted = '<span class="early">'.userdate($submission->timemodified).'</span>'; |
303 | } else { |
304 | $submitted = '<span class="late">'.userdate($submission->timemodified).'</span>'; |
305 | } |
306 | } |
307 | } |
308 | } |
309 | } |
310 | |
311 | return $submitted; |
312 | } |
313 | |
314 | |
436cfa9f |
315 | function setup_elements(&$mform) { |
316 | |
317 | } |
318 | |
7af1e882 |
319 | /** |
320 | * Print the setup form for the current assignment type |
321 | * |
322 | * Includes common.html and the assignment type's mod.html |
323 | * This will be suitable for all assignment types |
324 | * |
325 | * @param $form object The object used to fill the form |
326 | * @param $action url Default destination for this form |
b0f2597e |
327 | */ |
328 | function setup(&$form, $action='') { |
329 | global $CFG, $THEME; |
330 | |
331 | if (empty($this->course)) { |
332 | if (! $this->course = get_record("course", "id", $form->course)) { |
333 | error("Course is misconfigured"); |
77db7e4c |
334 | } |
335 | } |
f619f8c8 |
336 | |
b0f2597e |
337 | if (empty($action)) { // Default destination for this form |
338 | $action = $CFG->wwwroot.'/course/mod.php'; |
339 | } |
77db7e4c |
340 | |
b0f2597e |
341 | if (empty($form->assignmenttype)) { |
f619f8c8 |
342 | $form->assignmenttype = ''; |
1e4343a0 |
343 | } else { |
344 | $form->assignmenttype = clean_param($form->assignmenttype, PARAM_SAFEDIR); |
b0f2597e |
345 | } |
f619f8c8 |
346 | |
347 | if (empty($form->name)) { |
348 | $form->name = ''; |
349 | } else { |
350 | $form->name = stripslashes($form->name); |
351 | } |
352 | |
b0f2597e |
353 | if (empty($form->description)) { |
f619f8c8 |
354 | $form->description = ''; |
355 | } else { |
356 | $form->description = stripslashes($form->description); |
b0f2597e |
357 | } |
77db7e4c |
358 | |
b0f2597e |
359 | $strname = get_string('name'); |
360 | $strassignments = get_string('modulenameplural', 'assignment'); |
3898bc33 |
361 | $strheading = empty($form->name) ? get_string("type$form->assignmenttype",'assignment') : s(format_string(stripslashes($form->name),true)); |
b9dc2734 |
362 | |
f619f8c8 |
363 | print_header($this->course->shortname.': '.$strheading, $this->course->fullname, |
b0f2597e |
364 | "<a href=\"$CFG->wwwroot/course/view.php?id={$this->course->id}\">{$this->course->shortname} </a> -> ". |
365 | "<a href=\"$CFG->wwwroot/mod/assignment/index.php?id={$this->course->id}\">$strassignments</a> -> $strheading"); |
77db7e4c |
366 | |
f77cfb73 |
367 | print_simple_box_start('center', '70%'); |
368 | print_heading(get_string('type'.$form->assignmenttype,'assignment')); |
369 | print_simple_box(get_string('help'.$form->assignmenttype, 'assignment'), 'center'); |
b0f2597e |
370 | include("$CFG->dirroot/mod/assignment/type/common.html"); |
f77cfb73 |
371 | |
372 | include("$CFG->dirroot/mod/assignment/type/".$form->assignmenttype."/mod.html"); |
373 | $this->setup_end(); |
b0f2597e |
374 | } |
375 | |
7af1e882 |
376 | /** |
b0f2597e |
377 | * Print the end of the setup form for the current assignment type |
7af1e882 |
378 | * |
379 | * Includes common_end.html |
b0f2597e |
380 | */ |
381 | function setup_end() { |
73097f07 |
382 | global $CFG; |
b0f2597e |
383 | |
384 | include($CFG->dirroot.'/mod/assignment/type/common_end.html'); |
77db7e4c |
385 | |
386 | print_simple_box_end(); |
387 | |
73097f07 |
388 | if ($this->usehtmleditor) { |
b0f2597e |
389 | use_html_editor(); |
390 | } |
391 | |
392 | print_footer($this->course); |
77db7e4c |
393 | } |
77db7e4c |
394 | |
7af1e882 |
395 | /** |
396 | * Create a new assignment activity |
397 | * |
398 | * Given an object containing all the necessary data, |
399 | * (defined by the form in mod.html) this function |
400 | * will create a new instance and return the id number |
401 | * of the new instance. |
402 | * The due data is added to the calendar |
403 | * This is common to all assignment types. |
404 | * |
405 | * @param $assignment object The data from the form on mod.html |
406 | * @return int The id of the assignment |
407 | */ |
b0f2597e |
408 | function add_instance($assignment) { |
b0f2597e |
409 | |
410 | $assignment->timemodified = time(); |
38147229 |
411 | |
736f191c |
412 | if ($returnid = insert_record("assignment", $assignment)) { |
413 | |
1e4343a0 |
414 | if ($assignment->timedue) { |
415 | $event = NULL; |
416 | $event->name = $assignment->name; |
417 | $event->description = $assignment->description; |
418 | $event->courseid = $assignment->course; |
419 | $event->groupid = 0; |
420 | $event->userid = 0; |
421 | $event->modulename = 'assignment'; |
422 | $event->instance = $returnid; |
423 | $event->eventtype = 'due'; |
424 | $event->timestart = $assignment->timedue; |
425 | $event->timeduration = 0; |
736f191c |
426 | |
1e4343a0 |
427 | add_event($event); |
428 | } |
736f191c |
429 | } |
430 | |
431 | return $returnid; |
b0f2597e |
432 | } |
d699cd1e |
433 | |
7af1e882 |
434 | /** |
435 | * Deletes an assignment activity |
436 | * |
1f8c6549 |
437 | * Deletes all database records, files and calendar events for this assignment. |
7af1e882 |
438 | * @param $assignment object The assignment to be deleted |
439 | * @return boolean False indicates error |
440 | */ |
b0f2597e |
441 | function delete_instance($assignment) { |
1f8c6549 |
442 | global $CFG; |
443 | |
736f191c |
444 | $result = true; |
445 | |
446 | if (! delete_records('assignment_submissions', 'assignment', $assignment->id)) { |
447 | $result = false; |
448 | } |
449 | |
450 | if (! delete_records('assignment', 'id', $assignment->id)) { |
451 | $result = false; |
452 | } |
453 | |
454 | if (! delete_records('event', 'modulename', 'assignment', 'instance', $assignment->id)) { |
455 | $result = false; |
456 | } |
73963212 |
457 | |
458 | // Get the cm id to properly clean up the grade_items for this assignment |
459 | // bug 4976 |
460 | if (! $cm = get_record('modules', 'name', 'assignment')) { |
461 | $result = false; |
462 | } else { |
463 | if (! delete_records('grade_item', 'modid', $cm->id, 'cminstance', $assignment->id)) { |
464 | $result = false; |
465 | } |
466 | } |
736f191c |
467 | |
1f8c6549 |
468 | // delete file area with all attachments - ignore errors |
469 | require_once($CFG->libdir.'/filelib.php'); |
470 | fulldelete($CFG->dataroot.'/'.$assignment->course.'/'.$CFG->moddata.'/assignment/'.$assignment->id); |
471 | |
736f191c |
472 | return $result; |
b0f2597e |
473 | } |
d699cd1e |
474 | |
7af1e882 |
475 | /** |
476 | * Updates a new assignment activity |
477 | * |
478 | * Given an object containing all the necessary data, |
479 | * (defined by the form in mod.html) this function |
480 | * will update the assignment instance and return the id number |
481 | * The due date is updated in the calendar |
482 | * This is common to all assignment types. |
483 | * |
484 | * @param $assignment object The data from the form on mod.html |
485 | * @return int The assignment id |
486 | */ |
b0f2597e |
487 | function update_instance($assignment) { |
b0f2597e |
488 | |
38147229 |
489 | $assignment->timemodified = time(); |
38147229 |
490 | |
b0f2597e |
491 | $assignment->id = $assignment->instance; |
736f191c |
492 | |
493 | if ($returnid = update_record('assignment', $assignment)) { |
494 | |
1e4343a0 |
495 | if ($assignment->timedue) { |
496 | $event = NULL; |
736f191c |
497 | |
1e4343a0 |
498 | if ($event->id = get_field('event', 'id', 'modulename', 'assignment', 'instance', $assignment->id)) { |
736f191c |
499 | |
1e4343a0 |
500 | $event->name = $assignment->name; |
501 | $event->description = $assignment->description; |
502 | $event->timestart = $assignment->timedue; |
736f191c |
503 | |
1e4343a0 |
504 | update_event($event); |
47263937 |
505 | } else { |
506 | $event = NULL; |
507 | $event->name = $assignment->name; |
508 | $event->description = $assignment->description; |
509 | $event->courseid = $assignment->course; |
510 | $event->groupid = 0; |
511 | $event->userid = 0; |
512 | $event->modulename = 'assignment'; |
513 | $event->instance = $assignment->id; |
514 | $event->eventtype = 'due'; |
515 | $event->timestart = $assignment->timedue; |
516 | $event->timeduration = 0; |
517 | |
518 | add_event($event); |
1e4343a0 |
519 | } |
47263937 |
520 | } else { |
521 | delete_records('event', 'modulename', 'assignment', 'instance', $assignment->id); |
736f191c |
522 | } |
523 | } |
524 | |
525 | return $returnid; |
b0f2597e |
526 | } |
527 | |
7af1e882 |
528 | /** |
b0f2597e |
529 | * Top-level function for handling of submissions called by submissions.php |
7af1e882 |
530 | * |
531 | * This is for handling the teacher interaction with the grading interface |
532 | * This should be suitable for most assignment types. |
533 | * |
534 | * @param $mode string Specifies the kind of teacher interaction taking place |
b0f2597e |
535 | */ |
536 | function submissions($mode) { |
9bf660b3 |
537 | ///The main switch is changed to facilitate |
538 | ///1) Batch fast grading |
539 | ///2) Skip to the next one on the popup |
540 | ///3) Save and Skip to the next one on the popup |
541 | |
542 | //make user global so we can use the id |
543 | global $USER; |
544 | |
b0f2597e |
545 | switch ($mode) { |
546 | case 'grade': // We are in a popup window grading |
547 | if ($submission = $this->process_feedback()) { |
5a36be8c |
548 | //IE needs proper header with encoding |
549 | print_header(get_string('feedback', 'assignment').':'.format_string($this->assignment->name)); |
b0f2597e |
550 | print_heading(get_string('changessaved')); |
73963212 |
551 | print $this->update_main_listing($submission); |
b0f2597e |
552 | } |
989a0a52 |
553 | close_window(); |
b0f2597e |
554 | break; |
9cc9b7c1 |
555 | |
b0f2597e |
556 | case 'single': // We are in a popup window displaying submission |
557 | $this->display_submission(); |
558 | break; |
a56d79cd |
559 | |
1648afb2 |
560 | case 'all': // Main window, display everything |
b0f2597e |
561 | $this->display_submissions(); |
562 | break; |
082215e6 |
563 | |
9bf660b3 |
564 | case 'fastgrade': |
082215e6 |
565 | ///do the fast grading stuff - this process should work for all 3 subclasses |
39e11905 |
566 | $grading = false; |
16907e53 |
567 | $commenting = false; |
39e11905 |
568 | $col = false; |
ea6432fe |
569 | if (isset($_POST['submissioncomment'])) { |
570 | $col = 'submissioncomment'; |
16907e53 |
571 | $commenting = true; |
572 | } |
573 | if (isset($_POST['menu'])) { |
39e11905 |
574 | $col = 'menu'; |
16907e53 |
575 | $grading = true; |
576 | } |
39e11905 |
577 | if (!$col) { |
ea6432fe |
578 | //both submissioncomment and grade columns collapsed.. |
39e11905 |
579 | $this->display_submissions(); |
16907e53 |
580 | break; |
581 | } |
39e11905 |
582 | foreach ($_POST[$col] as $id => $unusedvalue){ |
77f4b17b |
583 | |
584 | $id = (int)$id; //clean parameter name |
39e11905 |
585 | if (!$submission = $this->get_submission($id)) { |
586 | $submission = $this->prepare_new_submission($id); |
587 | $newsubmission = true; |
588 | } else { |
589 | $newsubmission = false; |
590 | } |
591 | unset($submission->data1); // Don't need to update this. |
592 | unset($submission->data2); // Don't need to update this. |
16907e53 |
593 | |
9bf660b3 |
594 | //for fast grade, we need to check if any changes take place |
16907e53 |
595 | $updatedb = false; |
596 | |
597 | if ($grading) { |
598 | $grade = $_POST['menu'][$id]; |
39e11905 |
599 | $updatedb = $updatedb || ($submission->grade != $grade); |
600 | $submission->grade = $grade; |
16907e53 |
601 | } else { |
39e11905 |
602 | if (!$newsubmission) { |
603 | unset($submission->grade); // Don't need to update this. |
604 | } |
16907e53 |
605 | } |
606 | if ($commenting) { |
ea6432fe |
607 | $commentvalue = trim($_POST['submissioncomment'][$id]); |
608 | $updatedb = $updatedb || ($submission->submissioncomment != stripslashes($commentvalue)); |
609 | $submission->submissioncomment = $commentvalue; |
16907e53 |
610 | } else { |
ea6432fe |
611 | unset($submission->submissioncomment); // Don't need to update this. |
9bf660b3 |
612 | } |
613 | |
39e11905 |
614 | $submission->teacher = $USER->id; |
615 | $submission->mailed = $updatedb?0:$submission->mailed;//only change if it's an update |
616 | $submission->timemarked = time(); |
617 | |
618 | //if it is not an update, we don't change the last modified time etc. |
ea6432fe |
619 | //this will also not write into database if no submissioncomment and grade is entered. |
39e11905 |
620 | |
16907e53 |
621 | if ($updatedb){ |
39e11905 |
622 | if ($newsubmission) { |
623 | if (!insert_record('assignment_submissions', $submission)) { |
624 | return false; |
625 | } |
626 | } else { |
627 | if (!update_record('assignment_submissions', $submission)) { |
628 | return false; |
629 | } |
9bf660b3 |
630 | } |
39e11905 |
631 | //add to log only if updating |
9bf660b3 |
632 | add_to_log($this->course->id, 'assignment', 'update grades', |
39e11905 |
633 | 'submissions.php?id='.$this->assignment->id.'&user='.$submission->userid, |
634 | $submission->userid, $this->cm->id); |
9bf660b3 |
635 | } |
636 | |
e11dd872 |
637 | } |
638 | print_heading(get_string('changessaved')); |
9bf660b3 |
639 | $this->display_submissions(); |
640 | break; |
39e11905 |
641 | |
642 | |
9bf660b3 |
643 | case 'next': |
644 | /// We are currently in pop up, but we want to skip to next one without saving. |
645 | /// This turns out to be similar to a single case |
646 | /// The URL used is for the next submission. |
647 | |
648 | $this->display_submission(); |
649 | break; |
650 | |
651 | case 'saveandnext': |
652 | ///We are in pop up. save the current one and go to the next one. |
653 | //first we save the current changes |
654 | if ($submission = $this->process_feedback()) { |
655 | //print_heading(get_string('changessaved')); |
73963212 |
656 | $extra_javascript = $this->update_main_listing($submission); |
9bf660b3 |
657 | } |
658 | |
659 | //then we display the next submission |
73963212 |
660 | $this->display_submission($extra_javascript); |
9bf660b3 |
661 | break; |
662 | |
663 | default: |
664 | echo "something seriously is wrong!!"; |
665 | break; |
a56d79cd |
666 | } |
b0f2597e |
667 | } |
9bf660b3 |
668 | |
7af1e882 |
669 | /** |
670 | * Helper method updating the listing on the main script from popup using javascript |
671 | * |
672 | * @param $submission object The submission whose data is to be updated on the main page |
673 | */ |
be86672d |
674 | function update_main_listing($submission) { |
675 | global $SESSION; |
9bf660b3 |
676 | |
73963212 |
677 | $output = ''; |
678 | |
9bf660b3 |
679 | $perpage = get_user_preferences('assignment_perpage', 10); |
be86672d |
680 | |
9bf660b3 |
681 | $quickgrade = get_user_preferences('assignment_quickgrade', 0); |
682 | |
be86672d |
683 | /// Run some Javascript to try and update the parent page |
73963212 |
684 | $output .= '<script type="text/javascript">'."\n<!--\n"; |
ea6432fe |
685 | if (empty($SESSION->flextable['mod-assignment-submissions']->collapse['submissioncomment'])) { |
9bf660b3 |
686 | if ($quickgrade){ |
16fc2088 |
687 | $output.= 'opener.document.getElementById("submissioncomment'.$submission->userid.'").value="' |
ea6432fe |
688 | .trim($submission->submissioncomment).'";'."\n"; |
9bf660b3 |
689 | } else { |
73963212 |
690 | $output.= 'opener.document.getElementById("com'.$submission->userid. |
ea6432fe |
691 | '").innerHTML="'.shorten_text(trim(strip_tags($submission->submissioncomment)), 15)."\";\n"; |
9bf660b3 |
692 | } |
be86672d |
693 | } |
9bf660b3 |
694 | |
695 | if (empty($SESSION->flextable['mod-assignment-submissions']->collapse['grade'])) { |
696 | //echo optional_param('menuindex'); |
697 | if ($quickgrade){ |
16fc2088 |
698 | $output.= 'opener.document.getElementById("menumenu'.$submission->userid. |
699 | '").selectedIndex="'.optional_param('menuindex', 0, PARAM_INT).'";'."\n"; |
9bf660b3 |
700 | } else { |
73963212 |
701 | $output.= 'opener.document.getElementById("g'.$submission->userid.'").innerHTML="'. |
9bf660b3 |
702 | $this->display_grade($submission->grade)."\";\n"; |
703 | } |
704 | } |
705 | //need to add student's assignments in there too. |
73097f07 |
706 | if (empty($SESSION->flextable['mod-assignment-submissions']->collapse['timemodified']) && |
707 | $submission->timemodified) { |
73963212 |
708 | $output.= 'opener.document.getElementById("ts'.$submission->userid. |
9bf660b3 |
709 | '").innerHTML="'.addslashes($this->print_student_answer($submission->userid)).userdate($submission->timemodified)."\";\n"; |
be86672d |
710 | } |
9bf660b3 |
711 | |
73097f07 |
712 | if (empty($SESSION->flextable['mod-assignment-submissions']->collapse['timemarked']) && |
713 | $submission->timemarked) { |
73963212 |
714 | $output.= 'opener.document.getElementById("tt'.$submission->userid. |
be86672d |
715 | '").innerHTML="'.userdate($submission->timemarked)."\";\n"; |
716 | } |
9bf660b3 |
717 | |
be86672d |
718 | if (empty($SESSION->flextable['mod-assignment-submissions']->collapse['status'])) { |
73963212 |
719 | $output.= 'opener.document.getElementById("up'.$submission->userid.'").className="s1";'; |
9bf660b3 |
720 | $buttontext = get_string('update'); |
16fc2088 |
721 | $button = link_to_popup_window ('/mod/assignment/submissions.php?id='.$this->cm->id.'&userid='.$submission->userid.'&mode=single'.'&offset='.(optional_param('offset', '', PARAM_INT)-1), |
9bf660b3 |
722 | 'grade'.$submission->userid, $buttontext, 450, 700, $buttontext, 'none', true, 'button'.$submission->userid); |
73963212 |
723 | $output.= 'opener.document.getElementById("up'.$submission->userid.'").innerHTML="'.addslashes($button).'";'; |
9bf660b3 |
724 | } |
73963212 |
725 | $output .= "\n-->\n</script>"; |
726 | return $output; |
be86672d |
727 | } |
d699cd1e |
728 | |
7af1e882 |
729 | /** |
730 | * Return a grade in user-friendly form, whether it's a scale or not |
d59269cf |
731 | * |
7af1e882 |
732 | * @param $grade |
733 | * @return string User-friendly representation of grade |
d59269cf |
734 | */ |
735 | function display_grade($grade) { |
736 | |
c86aa2a4 |
737 | static $scalegrades = array(); // Cache scales for each assignment - they might have different scales!! |
d59269cf |
738 | |
739 | if ($this->assignment->grade >= 0) { // Normal number |
082215e6 |
740 | if ($grade == -1) { |
741 | return '-'; |
742 | } else { |
743 | return $grade.' / '.$this->assignment->grade; |
744 | } |
d59269cf |
745 | |
746 | } else { // Scale |
c86aa2a4 |
747 | if (empty($scalegrades[$this->assignment->id])) { |
d59269cf |
748 | if ($scale = get_record('scale', 'id', -($this->assignment->grade))) { |
c86aa2a4 |
749 | $scalegrades[$this->assignment->id] = make_menu_from_list($scale->scale); |
d59269cf |
750 | } else { |
751 | return '-'; |
752 | } |
753 | } |
c86aa2a4 |
754 | if (isset($scalegrades[$this->assignment->id][$grade])) { |
755 | return $scalegrades[$this->assignment->id][$grade]; |
0f7d4e5e |
756 | } |
39e11905 |
757 | return '-'; |
d59269cf |
758 | } |
759 | } |
760 | |
7af1e882 |
761 | /** |
b0f2597e |
762 | * Display a single submission, ready for grading on a popup window |
7af1e882 |
763 | * |
ea6432fe |
764 | * This default method prints the teacher info and submissioncomment box at the top and |
7af1e882 |
765 | * the student info and submission at the bottom. |
766 | * This method also fetches the necessary data in order to be able to |
767 | * provide a "Next submission" button. |
768 | * Calls preprocess_submission() to give assignment type plug-ins a chance |
769 | * to process submissions before they are graded |
770 | * This method gets its arguments from the page parameters userid and offset |
b0f2597e |
771 | */ |
73963212 |
772 | function display_submission($extra_javascript = '') { |
9bf660b3 |
773 | |
082215e6 |
774 | global $CFG; |
b0f2597e |
775 | |
4fdabdc3 |
776 | $userid = required_param('userid', PARAM_INT); |
777 | $offset = required_param('offset', PARAM_INT);//offset for where to start looking for student. |
d699cd1e |
778 | |
b0f2597e |
779 | if (!$user = get_record('user', 'id', $userid)) { |
780 | error('No such user!'); |
781 | } |
d699cd1e |
782 | |
39e11905 |
783 | if (!$submission = $this->get_submission($user->id)) { |
784 | $submission = $this->prepare_new_submission($userid); |
b0f2597e |
785 | } |
b0f2597e |
786 | if ($submission->timemodified > $submission->timemarked) { |
787 | $subtype = 'assignmentnew'; |
788 | } else { |
789 | $subtype = 'assignmentold'; |
790 | } |
d699cd1e |
791 | |
0cfafdc7 |
792 | /// construct SQL, using current offset to find the data of the next student |
9bf660b3 |
793 | $course = $this->course; |
794 | $assignment = $this->assignment; |
795 | $cm = $this->cm; |
16fc2088 |
796 | $context = get_context_instance(CONTEXT_MODULE, $cm->id); |
d699cd1e |
797 | |
9bf660b3 |
798 | /// Get all teachers and students |
0cfafdc7 |
799 | |
800 | $currentgroup = get_current_group($course->id); |
801 | |
9bf660b3 |
802 | if ($currentgroup) { |
803 | $users = get_group_users($currentgroup); |
804 | } else { |
16fc2088 |
805 | $users = get_users_by_capability($context, 'mod/assignment:submit', 'u.id, u.id', '', |
806 | '', '', '', '', false); |
9bf660b3 |
807 | } |
5b48244f |
808 | |
f5ae7c49 |
809 | $select = 'SELECT u.id, u.firstname, u.lastname, u.picture, |
9ad5c91f |
810 | s.id AS submissionid, s.grade, s.submissioncomment, |
811 | s.timemodified, s.timemarked '; |
9bf660b3 |
812 | $sql = 'FROM '.$CFG->prefix.'user u '. |
9ad5c91f |
813 | 'LEFT JOIN '.$CFG->prefix.'assignment_submissions s ON u.id = s.userid |
814 | AND s.assignment = '.$this->assignment->id.' '. |
082215e6 |
815 | 'WHERE u.id IN ('.implode(',', array_keys($users)).') '; |
02828119 |
816 | |
817 | require_once($CFG->libdir.'/tablelib.php'); |
0cfafdc7 |
818 | |
819 | if ($sort = flexible_table::get_sql_sort('mod-assignment-submissions')) { |
02828119 |
820 | $sort = 'ORDER BY '.$sort.' '; |
821 | } |
822 | |
082215e6 |
823 | $nextid = 0; |
422770d8 |
824 | if (($auser = get_records_sql($select.$sql.$sort, $offset+1, 1)) !== false) { |
70ad6fdb |
825 | $nextuser = array_shift($auser); |
9ad5c91f |
826 | /// Calculate user status |
16fc2088 |
827 | $nextuser->status = ($nextuser->timemarked > 0) && ($nextuser->timemarked >= $nextuser->timemodified); |
70ad6fdb |
828 | $nextid = $nextuser->id; |
9bf660b3 |
829 | } |
81532b92 |
830 | |
9bf660b3 |
831 | print_header(get_string('feedback', 'assignment').':'.fullname($user, true).':'.format_string($this->assignment->name)); |
d699cd1e |
832 | |
73963212 |
833 | /// Print any extra javascript needed for saveandnext |
834 | echo $extra_javascript; |
835 | |
9bf660b3 |
836 | ///SOme javascript to help with setting up >.> |
837 | |
c9977d05 |
838 | echo '<script type="text/javascript">'."\n"; |
9bf660b3 |
839 | echo 'function setNext(){'."\n"; |
16fc2088 |
840 | echo 'document.getElementById(\'submitform\').mode.value=\'next\';'."\n"; |
841 | echo 'document.getElementById(\'submitform\').userid.value="'.$nextid.'";'."\n"; |
9bf660b3 |
842 | echo '}'."\n"; |
843 | |
844 | echo 'function saveNext(){'."\n"; |
16fc2088 |
845 | echo 'document.getElementById(\'submitform\').mode.value=\'saveandnext\';'."\n"; |
846 | echo 'document.getElementById(\'submitform\').userid.value="'.$nextid.'";'."\n"; |
847 | echo 'document.getElementById(\'submitform\').saveuserid.value="'.$userid.'";'."\n"; |
848 | echo 'document.getElementById(\'submitform\').menuindex.value = document.getElementById(\'submitform\').grade.selectedIndex;'."\n"; |
9bf660b3 |
849 | echo '}'."\n"; |
850 | |
851 | echo '</script>'."\n"; |
52436fe1 |
852 | echo '<table cellspacing="0" class="feedback '.$subtype.'" >'; |
d699cd1e |
853 | |
9bf660b3 |
854 | ///Start of teacher info row |
c69cb506 |
855 | |
b0f2597e |
856 | echo '<tr>'; |
141a922c |
857 | echo '<td class="picture teacher">'; |
b0f2597e |
858 | if ($submission->teacher) { |
859 | $teacher = get_record('user', 'id', $submission->teacher); |
860 | } else { |
861 | global $USER; |
862 | $teacher = $USER; |
863 | } |
864 | print_user_picture($teacher->id, $this->course->id, $teacher->picture); |
865 | echo '</td>'; |
866 | echo '<td class="content">'; |
b7dc2256 |
867 | echo '<form id="submitform" action="submissions.php" method="post">'; |
d9cb14b8 |
868 | echo '<fieldset class="invisiblefieldset">'; |
16fc2088 |
869 | echo '<input type="hidden" name="offset" value="'.($offset+1).'" />'; |
c9977d05 |
870 | echo '<input type="hidden" name="userid" value="'.$userid.'" />'; |
871 | echo '<input type="hidden" name="id" value="'.$this->cm->id.'" />'; |
872 | echo '<input type="hidden" name="mode" value="grade" />'; |
873 | echo '<input type="hidden" name="menuindex" value="0" />';//selected menu index |
9bf660b3 |
874 | |
875 | //new hidden field, initialized to -1. |
c9977d05 |
876 | echo '<input type="hidden" name="saveuserid" value="-1" />'; |
52436fe1 |
877 | if ($submission->timemarked) { |
878 | echo '<div class="from">'; |
879 | echo '<div class="fullname">'.fullname($teacher, true).'</div>'; |
880 | echo '<div class="time">'.userdate($submission->timemarked).'</div>'; |
881 | echo '</div>'; |
882 | } |
883 | echo '<div class="grade">'.get_string('grade').':'; |
082215e6 |
884 | choose_from_menu(make_grades_menu($this->assignment->grade), 'grade', $submission->grade, get_string('nograde'), '', -1); |
52436fe1 |
885 | echo '</div>'; |
886 | echo '<div class="clearer"></div>'; |
b0f2597e |
887 | |
01e2fdfe |
888 | $this->preprocess_submission($submission); |
889 | |
b0f2597e |
890 | echo '<br />'; |
ea6432fe |
891 | print_textarea($this->usehtmleditor, 14, 58, 0, 0, 'submissioncomment', $submission->submissioncomment, $this->course->id); |
ff8f7015 |
892 | |
ff8f7015 |
893 | if ($this->usehtmleditor) { |
ff8f7015 |
894 | echo '<input type="hidden" name="format" value="'.FORMAT_HTML.'" />'; |
895 | } else { |
2bf7e0b1 |
896 | echo '<div class="format">'; |
ff8f7015 |
897 | choose_from_menu(format_text_menu(), "format", $submission->format, ""); |
f77cfb73 |
898 | helpbutton("textformat", get_string("helpformatting")); |
899 | echo '</div>'; |
ff8f7015 |
900 | } |
b0f2597e |
901 | |
9bf660b3 |
902 | ///Print Buttons in Single View |
141a922c |
903 | echo '<div class="buttons">'; |
16fc2088 |
904 | echo '<input type="submit" name="submit" value="'.get_string('savechanges').'" onclick = "document.getElementById(\'submitform\').menuindex.value = document.getElementById(\'submitform\').grade.selectedIndex" />'; |
b0f2597e |
905 | echo '<input type="submit" name="cancel" value="'.get_string('cancel').'" />'; |
9bf660b3 |
906 | //if there are more to be graded. |
082215e6 |
907 | if ($nextid) { |
5b48244f |
908 | echo '<input type="submit" name="saveandnext" value="'.get_string('saveandnext').'" onclick="saveNext()" />'; |
909 | echo '<input type="submit" name="next" value="'.get_string('next').'" onclick="setNext();" />'; |
9bf660b3 |
910 | } |
73097f07 |
911 | echo '</div>'; |
d9cb14b8 |
912 | echo '</fieldset>'; |
b0f2597e |
913 | echo '</form>'; |
55b4d096 |
914 | |
915 | $customfeedback = $this->custom_feedbackform($submission, true); |
916 | if (!empty($customfeedback)) { |
917 | echo $customfeedback; |
918 | } |
919 | |
73097f07 |
920 | echo '</td></tr>'; |
9bf660b3 |
921 | |
922 | ///End of teacher info row, Start of student info row |
923 | echo '<tr>'; |
141a922c |
924 | echo '<td class="picture user">'; |
9bf660b3 |
925 | print_user_picture($user->id, $this->course->id, $user->picture); |
926 | echo '</td>'; |
927 | echo '<td class="topic">'; |
928 | echo '<div class="from">'; |
929 | echo '<div class="fullname">'.fullname($user, true).'</div>'; |
930 | if ($submission->timemodified) { |
931 | echo '<div class="time">'.userdate($submission->timemodified). |
932 | $this->display_lateness($submission->timemodified).'</div>'; |
933 | } |
934 | echo '</div>'; |
935 | $this->print_user_files($user->id); |
936 | echo '</td>'; |
937 | echo '</tr>'; |
938 | |
939 | ///End of student info row |
940 | |
73097f07 |
941 | echo '</table>'; |
942 | |
73097f07 |
943 | if ($this->usehtmleditor) { |
944 | use_html_editor(); |
945 | } |
946 | |
b0f2597e |
947 | print_footer('none'); |
d699cd1e |
948 | } |
949 | |
7af1e882 |
950 | /** |
01e2fdfe |
951 | * Preprocess submission before grading |
7af1e882 |
952 | * |
953 | * Called by display_submission() |
954 | * The default type does nothing here. |
955 | * @param $submission object The submission object |
01e2fdfe |
956 | */ |
957 | function preprocess_submission(&$submission) { |
958 | } |
d699cd1e |
959 | |
7af1e882 |
960 | /** |
b0f2597e |
961 | * Display all the submissions ready for grading |
962 | */ |
963 | function display_submissions() { |
3446205d |
964 | |
9bf660b3 |
965 | global $CFG, $db, $USER; |
3446205d |
966 | |
9bf660b3 |
967 | /* first we check to see if the form has just been submitted |
968 | * to request user_preference updates |
969 | */ |
970 | |
971 | if (isset($_POST['updatepref'])){ |
16907e53 |
972 | $perpage = optional_param('perpage', 10, PARAM_INT); |
9bf660b3 |
973 | $perpage = ($perpage <= 0) ? 10 : $perpage ; |
974 | set_user_preference('assignment_perpage', $perpage); |
16907e53 |
975 | set_user_preference('assignment_quickgrade', optional_param('quickgrade',0, PARAM_BOOL)); |
9bf660b3 |
976 | } |
1b5910c4 |
977 | |
9bf660b3 |
978 | /* next we get perpage and quickgrade (allow quick grade) params |
979 | * from database |
980 | */ |
981 | $perpage = get_user_preferences('assignment_perpage', 10); |
982 | $quickgrade = get_user_preferences('assignment_quickgrade', 0); |
983 | |
984 | $teacherattempts = true; /// Temporary measure |
16907e53 |
985 | $page = optional_param('page', 0, PARAM_INT); |
b0f2597e |
986 | $strsaveallfeedback = get_string('saveallfeedback', 'assignment'); |
d0ac6bc2 |
987 | |
b0f2597e |
988 | /// Some shortcuts to make the code read better |
989 | |
990 | $course = $this->course; |
991 | $assignment = $this->assignment; |
992 | $cm = $this->cm; |
9bf660b3 |
993 | |
994 | $tabindex = 1; //tabindex for quick grading tabbing; Not working for dropdowns yet |
91719320 |
995 | |
b0f2597e |
996 | add_to_log($course->id, 'assignment', 'view submission', 'submissions.php?id='.$this->assignment->id, $this->assignment->id, $this->cm->id); |
997 | |
b9dc2734 |
998 | $crumbs[] = array('name' => $this->strassignments, 'link' => "index.php?id=$course->id", 'type' => 'activity'); |
999 | $crumbs[] = array('name' => format_string($this->assignment->name,true), 'link' => "view.php?a={$this->assignment->id}", 'type' => 'activityinstance'); |
1000 | $crumbs[] = array('name' => $this->strsubmissions, 'link' => '', 'type' => 'title'); |
70c6c0ad |
1001 | $navigation = build_navigation($crumbs); |
b9dc2734 |
1002 | |
1003 | print_header_simple(format_string($this->assignment->name,true), "", $navigation, '', '', true, update_module_button($cm->id, $course->id, $this->strassignment), navmenu($course, $cm)); |
1004 | |
fa22fd5f |
1005 | ///Position swapped |
2d7617c6 |
1006 | /* |
fa22fd5f |
1007 | if ($groupmode = groupmode($course, $cm)) { // Groups are being used |
1008 | $currentgroup = setup_and_print_groups($course, $groupmode, 'submissions.php?id='.$this->cm->id); |
1009 | } else { |
1010 | $currentgroup = false; |
1011 | } |
2d7617c6 |
1012 | */ |
1013 | |
1014 | /// copied code from assignment module, if this is not the way to do this please change it |
1015 | /// the above code does not work |
1016 | /// set_and_print_groups() is not fully implemented as function groups_instance_print_grouping_selector() |
1017 | /// and function groups_instance_print_group_selector() are missing. |
1018 | |
1019 | $context = get_context_instance(CONTEXT_MODULE, $cm->id); |
1020 | $changegroup = optional_param('group', -1, PARAM_INT); // choose the current group |
1021 | $groupmode = groupmode($course, $cm); |
1022 | $currentgroup = get_and_set_current_group($course, $groupmode, $changegroup); |
1023 | |
1024 | /// Now we need a menu for separategroups as well! |
1025 | if ($groupmode == VISIBLEGROUPS || ($groupmode |
1026 | && has_capability('moodle/site:accessallgroups', $context))) { |
1027 | |
1028 | //the following query really needs to change |
1029 | if ($groups = groups_get_groups_names($course->id)) { //TODO: |
1030 | print_box_start('groupmenu'); |
1031 | print_group_menu($groups, $groupmode, $currentgroup, 'submissions.php?id='.$this->cm->id); |
1032 | print_box_end(); // groupmenu |
1033 | } |
1034 | } |
1035 | |
fa22fd5f |
1036 | /// Get all teachers and students |
1037 | if ($currentgroup) { |
1038 | $users = get_group_users($currentgroup); |
1039 | } else { |
1648afb2 |
1040 | $context = get_context_instance(CONTEXT_MODULE, $cm->id); |
1041 | $users = get_users_by_capability($context, 'mod/assignment:submit'); // everyone with this capability set to non-prohibit |
fa22fd5f |
1042 | } |
91719320 |
1043 | |
ea6432fe |
1044 | $tablecolumns = array('picture', 'fullname', 'grade', 'submissioncomment', 'timemodified', 'timemarked', 'status'); |
9437c854 |
1045 | $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 |
1046 | |
b0f2597e |
1047 | require_once($CFG->libdir.'/tablelib.php'); |
1048 | $table = new flexible_table('mod-assignment-submissions'); |
1049 | |
1050 | $table->define_columns($tablecolumns); |
1051 | $table->define_headers($tableheaders); |
fa22fd5f |
1052 | $table->define_baseurl($CFG->wwwroot.'/mod/assignment/submissions.php?id='.$this->cm->id.'&currentgroup='.$currentgroup); |
b0f2597e |
1053 | |
246444b9 |
1054 | $table->sortable(true, 'lastname');//sorted by lastname by default |
b0f2597e |
1055 | $table->collapsible(true); |
1056 | $table->initialbars(true); |
1057 | |
1058 | $table->column_suppress('picture'); |
1059 | $table->column_suppress('fullname'); |
1060 | |
1061 | $table->column_class('picture', 'picture'); |
9437c854 |
1062 | $table->column_class('fullname', 'fullname'); |
1063 | $table->column_class('grade', 'grade'); |
ea6432fe |
1064 | $table->column_class('submissioncomment', 'comment'); |
9437c854 |
1065 | $table->column_class('timemodified', 'timemodified'); |
1066 | $table->column_class('timemarked', 'timemarked'); |
1067 | $table->column_class('status', 'status'); |
b0f2597e |
1068 | |
1069 | $table->set_attribute('cellspacing', '0'); |
1070 | $table->set_attribute('id', 'attempts'); |
9437c854 |
1071 | $table->set_attribute('class', 'submissions'); |
b0f2597e |
1072 | $table->set_attribute('width', '90%'); |
d9cb14b8 |
1073 | //$table->set_attribute('align', 'center'); |
b0f2597e |
1074 | |
1075 | // Start working -- this is necessary as soon as the niceties are over |
1076 | $table->setup(); |
1077 | |
b0f2597e |
1078 | /// Check to see if groups are being used in this assignment |
05855091 |
1079 | |
b0f2597e |
1080 | if (!$teacherattempts) { |
1081 | $teachers = get_course_teachers($course->id); |
1082 | if (!empty($teachers)) { |
1083 | $keys = array_keys($teachers); |
1084 | } |
1085 | foreach ($keys as $key) { |
1086 | unset($users[$key]); |
1087 | } |
1088 | } |
1089 | |
1090 | if (empty($users)) { |
c8dbfa5c |
1091 | print_heading(get_string('noattempts','assignment')); |
b0f2597e |
1092 | return true; |
1093 | } |
0f1a97c2 |
1094 | |
b0f2597e |
1095 | /// Construct the SQL |
0f1a97c2 |
1096 | |
b0f2597e |
1097 | if ($where = $table->get_sql_where()) { |
b0f2597e |
1098 | $where .= ' AND '; |
1099 | } |
0f1a97c2 |
1100 | |
b0f2597e |
1101 | if ($sort = $table->get_sql_sort()) { |
86f65395 |
1102 | $sort = ' ORDER BY '.$sort; |
b0f2597e |
1103 | } |
9fa49e22 |
1104 | |
f5ae7c49 |
1105 | $select = 'SELECT u.id, u.firstname, u.lastname, u.picture, |
9ad5c91f |
1106 | s.id AS submissionid, s.grade, s.submissioncomment, |
1107 | s.timemodified, s.timemarked '; |
b0f2597e |
1108 | $sql = 'FROM '.$CFG->prefix.'user u '. |
9ad5c91f |
1109 | 'LEFT JOIN '.$CFG->prefix.'assignment_submissions s ON u.id = s.userid |
1110 | AND s.assignment = '.$this->assignment->id.' '. |
306dc7e5 |
1111 | 'WHERE '.$where.'u.id IN ('.implode(',', array_keys($users)).') '; |
9bf660b3 |
1112 | |
c5d36203 |
1113 | $table->pagesize($perpage, count($users)); |
b0f2597e |
1114 | |
9bf660b3 |
1115 | ///offset used to calculate index of student in that particular query, needed for the pop up to know who's next |
1116 | $offset = $page * $perpage; |
1117 | |
b0f2597e |
1118 | $strupdate = get_string('update'); |
9437c854 |
1119 | $strgrade = get_string('grade'); |
b0f2597e |
1120 | $grademenu = make_grades_menu($this->assignment->grade); |
1121 | |
422770d8 |
1122 | if (($ausers = get_records_sql($select.$sql.$sort, $table->get_page_start(), $table->get_page_size())) !== false) { |
d59269cf |
1123 | |
d59269cf |
1124 | foreach ($ausers as $auser) { |
9ad5c91f |
1125 | /// Calculate user status |
1126 | $auser->status = ($auser->timemarked > 0) && ($auser->timemarked >= $auser->timemodified); |
d59269cf |
1127 | $picture = print_user_picture($auser->id, $course->id, $auser->picture, false, true); |
9bf660b3 |
1128 | |
39e11905 |
1129 | if (empty($auser->submissionid)) { |
1130 | $auser->grade = -1; //no submission yet |
9bf660b3 |
1131 | } |
1132 | |
d59269cf |
1133 | if (!empty($auser->submissionid)) { |
9bf660b3 |
1134 | ///Prints student answer and student modified date |
1135 | ///attach file or print link to student answer, depending on the type of the assignment. |
1136 | ///Refer to print_student_answer in inherited classes. |
1137 | if ($auser->timemodified > 0) { |
1138 | $studentmodified = '<div id="ts'.$auser->id.'">'.$this->print_student_answer($auser->id).userdate($auser->timemodified).'</div>'; |
d59269cf |
1139 | } else { |
9437c854 |
1140 | $studentmodified = '<div id="ts'.$auser->id.'"> </div>'; |
d59269cf |
1141 | } |
9bf660b3 |
1142 | ///Print grade, dropdown or text |
d59269cf |
1143 | if ($auser->timemarked > 0) { |
1144 | $teachermodified = '<div id="tt'.$auser->id.'">'.userdate($auser->timemarked).'</div>'; |
9bf660b3 |
1145 | |
1146 | if ($quickgrade) { |
1147 | $grade = '<div id="g'.$auser->id.'">'.choose_from_menu(make_grades_menu($this->assignment->grade), |
082215e6 |
1148 | 'menu['.$auser->id.']', $auser->grade, get_string('nograde'),'',-1,true,false,$tabindex++).'</div>'; |
9bf660b3 |
1149 | } else { |
1150 | $grade = '<div id="g'.$auser->id.'">'.$this->display_grade($auser->grade).'</div>'; |
1151 | } |
1152 | |
b0f2597e |
1153 | } else { |
9437c854 |
1154 | $teachermodified = '<div id="tt'.$auser->id.'"> </div>'; |
9bf660b3 |
1155 | if ($quickgrade){ |
1156 | $grade = '<div id="g'.$auser->id.'">'.choose_from_menu(make_grades_menu($this->assignment->grade), |
082215e6 |
1157 | 'menu['.$auser->id.']', $auser->grade, get_string('nograde'),'',-1,true,false,$tabindex++).'</div>'; |
9bf660b3 |
1158 | } else { |
1159 | $grade = '<div id="g'.$auser->id.'">'.$this->display_grade($auser->grade).'</div>'; |
1160 | } |
1161 | } |
1162 | ///Print Comment |
1163 | if ($quickgrade){ |
a1c91f9a |
1164 | $comment = '<div id="com'.$auser->id.'"><textarea tabindex="'.$tabindex++.'" name="submissioncomment['.$auser->id.']" id="submissioncomment'.$auser->id.'" rows="2" cols="20">'.($auser->submissioncomment).'</textarea></div>'; |
9bf660b3 |
1165 | } else { |
ea6432fe |
1166 | $comment = '<div id="com'.$auser->id.'">'.shorten_text(strip_tags($auser->submissioncomment),15).'</div>'; |
b0f2597e |
1167 | } |
1168 | } else { |
9437c854 |
1169 | $studentmodified = '<div id="ts'.$auser->id.'"> </div>'; |
1170 | $teachermodified = '<div id="tt'.$auser->id.'"> </div>'; |
9bf660b3 |
1171 | $status = '<div id="st'.$auser->id.'"> </div>'; |
1172 | if ($quickgrade){ // allow editing |
1173 | $grade = '<div id="g'.$auser->id.'">'.choose_from_menu(make_grades_menu($this->assignment->grade), |
082215e6 |
1174 | 'menu['.$auser->id.']', $auser->grade, get_string('nograde'),'',-1,true,false,$tabindex++).'</div>'; |
9bf660b3 |
1175 | } else { |
39e11905 |
1176 | $grade = '<div id="g'.$auser->id.'">-</div>'; |
9bf660b3 |
1177 | } |
1178 | if ($quickgrade){ |
a1c91f9a |
1179 | $comment = '<div id="com'.$auser->id.'"><textarea tabindex="'.$tabindex++.'" name="submissioncomment['.$auser->id.']" id="submissioncomment'.$auser->id.'" rows="2" cols="20">'.($auser->submissioncomment).'</textarea></div>'; |
9bf660b3 |
1180 | } else { |
1181 | $comment = '<div id="com'.$auser->id.'"> </div>'; |
1182 | } |
b0f2597e |
1183 | } |
9fa49e22 |
1184 | |
9ad5c91f |
1185 | if (empty($auser->status)) { /// Confirm we have exclusively 0 or 1 |
0f7d4e5e |
1186 | $auser->status = 0; |
9ad5c91f |
1187 | } else { |
1188 | $auser->status = 1; |
0f7d4e5e |
1189 | } |
1190 | |
9437c854 |
1191 | $buttontext = ($auser->status == 1) ? $strupdate : $strgrade; |
9bf660b3 |
1192 | |
1193 | ///No more buttons, we use popups ;-). |
9894b824 |
1194 | $button = link_to_popup_window ('/mod/assignment/submissions.php?id='.$this->cm->id.'&userid='.$auser->id.'&mode=single'.'&offset='.$offset++, |
a8166227 |
1195 | 'grade'.$auser->id, $buttontext, 500, 780, $buttontext, 'none', true, 'button'.$auser->id); |
0f7d4e5e |
1196 | |
9437c854 |
1197 | $status = '<div id="up'.$auser->id.'" class="s'.$auser->status.'">'.$button.'</div>'; |
9bf660b3 |
1198 | |
9437c854 |
1199 | $row = array($picture, fullname($auser), $grade, $comment, $studentmodified, $teachermodified, $status); |
d59269cf |
1200 | $table->add_data($row); |
1201 | } |
b0f2597e |
1202 | } |
9bf660b3 |
1203 | |
082215e6 |
1204 | /// Print quickgrade form around the table |
1205 | if ($quickgrade){ |
b7dc2256 |
1206 | echo '<form action="submissions.php" id="fastg" method="post">'; |
a1b5dd2b |
1207 | echo '<div>'; |
820aff13 |
1208 | echo '<input type="hidden" name="id" value="'.$this->cm->id.'" />'; |
1209 | echo '<input type="hidden" name="mode" value="fastgrade" />'; |
1210 | echo '<input type="hidden" name="page" value="'.$page.'" />'; |
a1b5dd2b |
1211 | echo '</div>'; |
d9cb14b8 |
1212 | echo '<div style="text-align:center"><input type="submit" name="fastg" value="'.get_string('saveallfeedback', 'assignment').'" /></div>'; |
082215e6 |
1213 | } |
1214 | |
1215 | $table->print_html(); /// Print the whole table |
1216 | |
9bf660b3 |
1217 | if ($quickgrade){ |
d9cb14b8 |
1218 | echo '<div style="text-align:center"><input type="submit" name="fastg" value="'.get_string('saveallfeedback', 'assignment').'" /></div>'; |
082215e6 |
1219 | echo '</form>'; |
9bf660b3 |
1220 | } |
082215e6 |
1221 | /// End of fast grading form |
9bf660b3 |
1222 | |
082215e6 |
1223 | /// Mini form for setting user preference |
9bf660b3 |
1224 | echo '<br />'; |
b7dc2256 |
1225 | echo '<form id="options" action="submissions.php?id='.$this->cm->id.'" method="post">'; |
d9cb14b8 |
1226 | echo '<fieldset class="invisiblefieldset">'; |
c9977d05 |
1227 | echo '<input type="hidden" id="updatepref" name="updatepref" value="1" />'; |
d9cb14b8 |
1228 | echo '<table id="optiontable">'; |
9bf660b3 |
1229 | echo '<tr align="right"><td>'; |
1230 | echo '<label for="perpage">'.get_string('pagesize','assignment').'</label>'; |
1231 | echo ':</td>'; |
9bf660b3 |
1232 | echo '<td align="left">'; |
1233 | echo '<input type="text" id="perpage" name="perpage" size="1" value="'.$perpage.'" />'; |
1234 | helpbutton('pagesize', get_string('pagesize','assignment'), 'assignment'); |
1235 | echo '</td></tr>'; |
1236 | echo '<tr align="right">'; |
1237 | echo '<td>'; |
1238 | print_string('quickgrade','assignment'); |
1239 | echo ':</td>'; |
1240 | echo '<td align="left">'; |
1241 | if ($quickgrade){ |
1242 | echo '<input type="checkbox" name="quickgrade" value="1" checked="checked" />'; |
1243 | } else { |
1244 | echo '<input type="checkbox" name="quickgrade" value="1" />'; |
1245 | } |
1246 | helpbutton('quickgrade', get_string('quickgrade', 'assignment'), 'assignment').'</p></div>'; |
1247 | echo '</td></tr>'; |
1248 | echo '<tr>'; |
1249 | echo '<td colspan="2" align="right">'; |
1250 | echo '<input type="submit" value="'.get_string('savepreferences').'" />'; |
1251 | echo '</td></tr></table>'; |
d9cb14b8 |
1252 | echo '</fieldset>'; |
9bf660b3 |
1253 | echo '</form>'; |
1254 | ///End of mini form |
b0f2597e |
1255 | print_footer($this->course); |
8e340cb0 |
1256 | } |
d699cd1e |
1257 | |
7af1e882 |
1258 | /** |
1259 | * Process teacher feedback submission |
1260 | * |
1261 | * This is called by submissions() when a grading even has taken place. |
1262 | * It gets its data from the submitted form. |
1263 | * @return object The updated submission object |
b0f2597e |
1264 | */ |
1265 | function process_feedback() { |
d699cd1e |
1266 | |
b0f2597e |
1267 | global $USER; |
d699cd1e |
1268 | |
9894b824 |
1269 | if (!$feedback = data_submitted()) { // No incoming data? |
b0f2597e |
1270 | return false; |
d699cd1e |
1271 | } |
b7b42874 |
1272 | |
9bf660b3 |
1273 | ///For save and next, we need to know the userid to save, and the userid to go |
1274 | ///We use a new hidden field in the form, and set it to -1. If it's set, we use this |
1275 | ///as the userid to store |
1276 | if ((int)$feedback->saveuserid !== -1){ |
1277 | $feedback->userid = $feedback->saveuserid; |
1278 | } |
1279 | |
b0f2597e |
1280 | if (!empty($feedback->cancel)) { // User hit cancel button |
1281 | return false; |
1282 | } |
d699cd1e |
1283 | |
7af1e882 |
1284 | $submission = $this->get_submission($feedback->userid, true); // Get or make one |
d699cd1e |
1285 | |
7af1e882 |
1286 | $submission->grade = $feedback->grade; |
ea6432fe |
1287 | $submission->submissioncomment = $feedback->submissioncomment; |
7af1e882 |
1288 | $submission->format = $feedback->format; |
1289 | $submission->teacher = $USER->id; |
1290 | $submission->mailed = 0; // Make sure mail goes out (again, even) |
1291 | $submission->timemarked = time(); |
d699cd1e |
1292 | |
7af1e882 |
1293 | unset($submission->data1); // Don't need to update this. |
1294 | unset($submission->data2); // Don't need to update this. |
d4156e80 |
1295 | |
b0f2597e |
1296 | if (empty($submission->timemodified)) { // eg for offline assignments |
16fc2088 |
1297 | // $submission->timemodified = time(); |
b0f2597e |
1298 | } |
d699cd1e |
1299 | |
7af1e882 |
1300 | if (! update_record('assignment_submissions', $submission)) { |
b0f2597e |
1301 | return false; |
1302 | } |
d699cd1e |
1303 | |
b0f2597e |
1304 | add_to_log($this->course->id, 'assignment', 'update grades', |
1305 | 'submissions.php?id='.$this->assignment->id.'&user='.$feedback->userid, $feedback->userid, $this->cm->id); |
1306 | |
7af1e882 |
1307 | return $submission; |
d699cd1e |
1308 | |
d699cd1e |
1309 | } |
d699cd1e |
1310 | |
7af1e882 |
1311 | /** |
1312 | * Load the submission object for a particular user |
1313 | * |
1314 | * @param $userid int The id of the user whose submission we want or 0 in which case USER->id is used |
1315 | * @param $createnew boolean optional Defaults to false. If set to true a new submission object will be created in the database |
1316 | * @return object The submission |
1317 | */ |
f77cfb73 |
1318 | function get_submission($userid=0, $createnew=false) { |
1319 | global $USER; |
1320 | |
1321 | if (empty($userid)) { |
1322 | $userid = $USER->id; |
1323 | } |
1324 | |
b0f2597e |
1325 | $submission = get_record('assignment_submissions', 'assignment', $this->assignment->id, 'userid', $userid); |
d699cd1e |
1326 | |
b0f2597e |
1327 | if ($submission || !$createnew) { |
1328 | return $submission; |
1329 | } |
39e11905 |
1330 | $newsubmission = $this->prepare_new_submission($userid); |
b0f2597e |
1331 | if (!insert_record("assignment_submissions", $newsubmission)) { |
1332 | error("Could not insert a new empty submission"); |
1333 | } |
d699cd1e |
1334 | |
b0f2597e |
1335 | return get_record('assignment_submissions', 'assignment', $this->assignment->id, 'userid', $userid); |
1336 | } |
d699cd1e |
1337 | |
7af1e882 |
1338 | /** |
1339 | * Instantiates a new submission object for a given user |
1340 | * |
1341 | * Sets the assignment, userid and times, everything else is set to default values. |
1342 | * @param $userid int The userid for which we want a submission object |
1343 | * @return object The submission |
1344 | */ |
39e11905 |
1345 | function prepare_new_submission($userid) { |
1346 | $submission = new Object; |
1347 | $submission->assignment = $this->assignment->id; |
1348 | $submission->userid = $userid; |
16fc2088 |
1349 | //$submission->timecreated = time(); |
1350 | $submission->timecreated = ''; |
1351 | // teachers should not be modifying modified date, except offline assignments |
39e11905 |
1352 | $submission->timemodified = $submission->timecreated; |
1353 | $submission->numfiles = 0; |
1354 | $submission->data1 = ''; |
1355 | $submission->data2 = ''; |
1356 | $submission->grade = -1; |
ea6432fe |
1357 | $submission->submissioncomment = ''; |
39e11905 |
1358 | $submission->format = 0; |
1359 | $submission->teacher = 0; |
1360 | $submission->timemarked = 0; |
1361 | $submission->mailed = 0; |
1362 | return $submission; |
1363 | } |
1364 | |
7af1e882 |
1365 | /** |
1366 | * Return all assignment submissions by ENROLLED students (even empty) |
1367 | * |
1368 | * @param $sort string optional field names for the ORDER BY in the sql query |
1369 | * @param $dir string optional specifying the sort direction, defaults to DESC |
1370 | * @return array The submission objects indexed by id |
1371 | */ |
b0f2597e |
1372 | function get_submissions($sort='', $dir='DESC') { |
7af1e882 |
1373 | return assignment_get_all_submissions($this->assignment, $sort, $dir); |
b0f2597e |
1374 | } |
1375 | |
7af1e882 |
1376 | /** |
1377 | * Counts all real assignment submissions by ENROLLED students (not empty ones) |
1378 | * |
1379 | * @param $groupid int optional If nonzero then count is restricted to this group |
1380 | * @return int The number of submissions |
1381 | */ |
b0f2597e |
1382 | function count_real_submissions($groupid=0) { |
7af1e882 |
1383 | return assignment_count_real_submissions($this->assignment, $groupid); |
d59269cf |
1384 | } |
d699cd1e |
1385 | |
7af1e882 |
1386 | /** |
1387 | * Alerts teachers by email of new or changed assignments that need grading |
1388 | * |
1389 | * First checks whether the option to email teachers is set for this assignment. |
1390 | * Sends an email to ALL teachers in the course (or in the group if using separate groups). |
1391 | * Uses the methods email_teachers_text() and email_teachers_html() to construct the content. |
1392 | * @param $submission object The submission that has changed |
1393 | */ |
73097f07 |
1394 | function email_teachers($submission) { |
73097f07 |
1395 | global $CFG; |
1396 | |
d8199f1d |
1397 | if (empty($this->assignment->emailteachers)) { // No need to do anything |
73097f07 |
1398 | return; |
1399 | } |
1400 | |
1401 | $user = get_record('user', 'id', $submission->userid); |
1402 | |
413efd22 |
1403 | if ($teachers = $this->get_graders($user)) { |
73097f07 |
1404 | |
1405 | $strassignments = get_string('modulenameplural', 'assignment'); |
1406 | $strassignment = get_string('modulename', 'assignment'); |
1407 | $strsubmitted = get_string('submitted', 'assignment'); |
1408 | |
1409 | foreach ($teachers as $teacher) { |
98be6ed8 |
1410 | $info = new object(); |
413efd22 |
1411 | $info->username = fullname($user, true); |
d8199f1d |
1412 | $info->assignment = format_string($this->assignment->name,true); |
1413 | $info->url = $CFG->wwwroot.'/mod/assignment/submissions.php?id='.$this->cm->id; |
1414 | |
1415 | $postsubject = $strsubmitted.': '.$info->username.' -> '.$this->assignment->name; |
1416 | $posttext = $this->email_teachers_text($info); |
1417 | $posthtml = ($teacher->mailformat == 1) ? $this->email_teachers_html($info) : ''; |
73097f07 |
1418 | |
1419 | @email_to_user($teacher, $user, $postsubject, $posttext, $posthtml); // If it fails, oh well, too bad. |
1420 | } |
1421 | } |
1422 | } |
1423 | |
413efd22 |
1424 | /** |
1425 | * Returns a list of teachers that should be grading given submission |
1426 | */ |
1427 | function get_graders($user) { |
1428 | //potential graders |
1429 | $potgraders = get_users_by_capability($this->context, 'mod/assignment:grade', $fields='', $sort='', $limitfrom='', |
1430 | $limitnum='', $groups='', $exceptions='', $doanything=false, $view=false); |
1431 | $graders = array(); |
1432 | if (groupmode($this->course, $this->cm) == SEPARATEGROUPS) { // Separate groups are being used |
1433 | if ($groups = user_group($this->course->id, $user->id)) { // Try to find all groups |
1434 | foreach ($groups as $group) { |
1435 | foreach ($potgraders as $t) { |
1436 | if ($t->id == $user->id) { |
1437 | continue; // do not send self |
1438 | } |
1439 | if (groups_is_member($group->id, $t->id)) { |
1440 | $graders[$t->id] = $t; |
1441 | } |
1442 | } |
1443 | } |
1444 | } else { |
1445 | // user not in group, try to find graders without group |
1446 | foreach ($potgraders as $t) { |
1447 | if ($t->id == $user->id) { |
1448 | continue; // do not send self |
1449 | } |
1450 | if (!user_group($this->course->id, $t->id)) { //ugly hack |
1451 | $graders[$t->id] = $t; |
1452 | } |
1453 | } |
1454 | } |
1455 | } else { |
1456 | foreach ($potgraders as $t) { |
1457 | if ($t->id == $user->id) { |
1458 | continue; // do not send self |
1459 | } |
1460 | $graders[$t->id] = $t; |
1461 | } |
1462 | } |
1463 | return $graders; |
1464 | } |
1465 | |
7af1e882 |
1466 | /** |
1467 | * Creates the text content for emails to teachers |
1468 | * |
1469 | * @param $info object The info used by the 'emailteachermail' language string |
1470 | * @return string |
1471 | */ |
d8199f1d |
1472 | function email_teachers_text($info) { |
413efd22 |
1473 | $posttext = format_string($this->course->shortname).' -> '.$this->strassignments.' -> '. |
1474 | format_string($this->assignment->name)."\n"; |
d8199f1d |
1475 | $posttext .= '---------------------------------------------------------------------'."\n"; |
1476 | $posttext .= get_string("emailteachermail", "assignment", $info)."\n"; |
73963212 |
1477 | $posttext .= "\n---------------------------------------------------------------------\n"; |
d8199f1d |
1478 | return $posttext; |
1479 | } |
1480 | |
7af1e882 |
1481 | /** |
1482 | * Creates the html content for emails to teachers |
1483 | * |
1484 | * @param $info object The info used by the 'emailteachermailhtml' language string |
1485 | * @return string |
1486 | */ |
d8199f1d |
1487 | function email_teachers_html($info) { |
3554b5c2 |
1488 | global $CFG; |
d8199f1d |
1489 | $posthtml = '<p><font face="sans-serif">'. |
413efd22 |
1490 | '<a href="'.$CFG->wwwroot.'/course/view.php?id='.$this->course->id.'">'.format_string($this->course->shortname).'</a> ->'. |
d8199f1d |
1491 | '<a href="'.$CFG->wwwroot.'/mod/assignment/index.php?id='.$this->course->id.'">'.$this->strassignments.'</a> ->'. |
413efd22 |
1492 | '<a href="'.$CFG->wwwroot.'/mod/assignment/view.php?id='.$this->cm->id.'">'.format_string($this->assignment->name).'</a></font></p>'; |
d8199f1d |
1493 | $posthtml .= '<hr /><font face="sans-serif">'; |
1494 | $posthtml .= '<p>'.get_string('emailteachermailhtml', 'assignment', $info).'</p>'; |
1495 | $posthtml .= '</font><hr />'; |
815b5ca6 |
1496 | return $posthtml; |
d8199f1d |
1497 | } |
1498 | |
7af1e882 |
1499 | /** |
1500 | * Produces a list of links to the files uploaded by a user |
1501 | * |
1502 | * @param $userid int optional id of the user. If 0 then $USER->id is used. |
1503 | * @param $return boolean optional defaults to false. If true the list is returned rather than printed |
1504 | * @return string optional |
1505 | */ |
d8199f1d |
1506 | function print_user_files($userid=0, $return=false) { |
d8199f1d |
1507 | global $CFG, $USER; |
9bf660b3 |
1508 | |
d8199f1d |
1509 | if (!$userid) { |
1510 | if (!isloggedin()) { |
1511 | return ''; |
1512 | } |
1513 | $userid = $USER->id; |
1514 | } |
73097f07 |
1515 | |
70b2c772 |
1516 | $filearea = $this->file_area_name($userid); |
73097f07 |
1517 | |
1518 | $output = ''; |
1519 | |
70b2c772 |
1520 | if ($basedir = $this->file_area($userid)) { |
73097f07 |
1521 | if ($files = get_directory_list($basedir)) { |
1ef048ae |
1522 | require_once($CFG->libdir.'/filelib.php'); |
73097f07 |
1523 | foreach ($files as $key => $file) { |
9bf660b3 |
1524 | |
73097f07 |
1525 | $icon = mimeinfo('icon', $file); |
9bf660b3 |
1526 | |
73097f07 |
1527 | if ($CFG->slasharguments) { |
d4156e80 |
1528 | $ffurl = "$CFG->wwwroot/file.php/$filearea/$file"; |
73097f07 |
1529 | } else { |
d4156e80 |
1530 | $ffurl = "$CFG->wwwroot/file.php?file=/$filearea/$file"; |
73097f07 |
1531 | } |
9bf660b3 |
1532 | |
0d905d9f |
1533 | $output .= '<img align="middle" src="'.$CFG->pixpath.'/f/'.$icon.'" class="icon" alt="'.$icon.'" />'. |
9bf660b3 |
1534 | '<a href="'.$ffurl.'" >'.$file.'</a><br />'; |
73097f07 |
1535 | } |
1536 | } |
1537 | } |
1538 | |
1539 | $output = '<div class="files">'.$output.'</div>'; |
1540 | |
1541 | if ($return) { |
1542 | return $output; |
1543 | } |
1544 | echo $output; |
1545 | } |
1546 | |
7af1e882 |
1547 | /** |
1548 | * Count the files uploaded by a given user |
1549 | * |
1550 | * @param $userid int The user id |
1551 | * @return int |
1552 | */ |
70b2c772 |
1553 | function count_user_files($userid) { |
1554 | global $CFG; |
1555 | |
1556 | $filearea = $this->file_area_name($userid); |
1557 | |
c853b39f |
1558 | if ( is_dir($CFG->dataroot.'/'.$filearea) && $basedir = $this->file_area($userid)) { |
70b2c772 |
1559 | if ($files = get_directory_list($basedir)) { |
1560 | return count($files); |
1561 | } |
1562 | } |
1563 | return 0; |
1564 | } |
73097f07 |
1565 | |
7af1e882 |
1566 | /** |
1567 | * Creates a directory file name, suitable for make_upload_directory() |
1568 | * |
1569 | * @param $userid int The user id |
1570 | * @return string path to file area |
1571 | */ |
70b2c772 |
1572 | function file_area_name($userid) { |
73097f07 |
1573 | global $CFG; |
1574 | |
70b2c772 |
1575 | return $this->course->id.'/'.$CFG->moddata.'/assignment/'.$this->assignment->id.'/'.$userid; |
73097f07 |
1576 | } |
7af1e882 |
1577 | |
1578 | /** |
1579 | * Makes an upload directory |
1580 | * |
1581 | * @param $userid int The user id |
1582 | * @return string path to file area. |
1583 | */ |
70b2c772 |
1584 | function file_area($userid) { |
1585 | return make_upload_directory( $this->file_area_name($userid) ); |
73097f07 |
1586 | } |
1587 | |
7af1e882 |
1588 | /** |
1589 | * Returns true if the student is allowed to submit |
1590 | * |
1591 | * Checks that the assignment has started and, if the option to prevent late |
1592 | * submissions is set, also checks that the assignment has not yet closed. |
1593 | * @return boolean |
1594 | */ |
f77cfb73 |
1595 | function isopen() { |
1596 | $time = time(); |
1e4343a0 |
1597 | if ($this->assignment->preventlate && $this->assignment->timedue) { |
f77cfb73 |
1598 | return ($this->assignment->timeavailable <= $time && $time <= $this->assignment->timedue); |
1599 | } else { |
1600 | return ($this->assignment->timeavailable <= $time); |
1601 | } |
1602 | } |
1603 | |
7af1e882 |
1604 | /** |
1605 | * Return an outline of the user's interaction with the assignment |
1606 | * |
1607 | * The default method prints the grade and timemodified |
1608 | * @param $user object |
1609 | * @return object with properties ->info and ->time |
1610 | */ |
73097f07 |
1611 | function user_outline($user) { |
1612 | if ($submission = $this->get_submission($user->id)) { |
39e11905 |
1613 | |
98be6ed8 |
1614 | $result = new object(); |
39e11905 |
1615 | $result->info = get_string('grade').': '.$this->display_grade($submission->grade); |
73097f07 |
1616 | $result->time = $submission->timemodified; |
1617 | return $result; |
1618 | } |
1619 | return NULL; |
1620 | } |
7af1e882 |
1621 | |
1622 | /** |
1623 | * Print complete information about the user's interaction with the assignment |
1624 | * |
1625 | * @param $user object |
1626 | */ |
73097f07 |
1627 | function user_complete($user) { |
1628 | if ($submission = $this->get_submission($user->id)) { |
70b2c772 |
1629 | if ($basedir = $this->file_area($user->id)) { |
73097f07 |
1630 | if ($files = get_directory_list($basedir)) { |
1631 | $countfiles = count($files)." ".get_string("uploadedfiles", "assignment"); |
1632 | foreach ($files as $file) { |
1633 | $countfiles .= "; $file"; |
1634 | } |
1635 | } |
1636 | } |
1637 | |
1638 | print_simple_box_start(); |
1639 | echo get_string("lastmodified").": "; |
9bf660b3 |
1640 | echo userdate($submission->timemodified); |
1641 | echo $this->display_lateness($submission->timemodified); |
73097f07 |
1642 | |
70b2c772 |
1643 | $this->print_user_files($user->id); |
73097f07 |
1644 | |
1645 | echo '<br />'; |
1646 | |
1647 | if (empty($submission->timemarked)) { |
1648 | print_string("notgradedyet", "assignment"); |
1649 | } else { |
1650 | $this->view_feedback($submission); |
1651 | } |
1652 | |
1653 | print_simple_box_end(); |
1654 | |
1655 | } else { |
1656 | print_string("notsubmittedyet", "assignment"); |
1657 | } |
1658 | } |
1659 | |
7af1e882 |
1660 | /** |
1661 | * Return a string indicating how late a submission is |
1662 | * |
1663 | * @param $timesubmitted int |
1664 | * @return string |
1665 | */ |
70b2c772 |
1666 | function display_lateness($timesubmitted) { |
76a60031 |
1667 | return assignment_display_lateness($timesubmitted, $this->assignment->timedue); |
73097f07 |
1668 | } |
1669 | |
55b4d096 |
1670 | /** |
1671 | * Empty method stub for all delete actions. |
1672 | */ |
1673 | function delete() { |
1674 | //nothing by default |
1675 | redirect('view.php?id='.$this->cm->id); |
1676 | } |
1677 | |
1678 | /** |
1679 | * Empty custom feedback grading form. |
1680 | */ |
1681 | function custom_feedbackform($submission, $return=false) { |
1682 | //nothing by default |
1683 | return ''; |
1684 | } |
73097f07 |
1685 | |
b0f2597e |
1686 | } ////// End of the assignment_base class |
d699cd1e |
1687 | |
18b8fbfa |
1688 | |
04eba58f |
1689 | |
b0f2597e |
1690 | /// OTHER STANDARD FUNCTIONS //////////////////////////////////////////////////////// |
1691 | |
7af1e882 |
1692 | /** |
1693 | * Deletes an assignment instance |
1694 | * |
1695 | * This is done by calling the delete_instance() method of the assignment type class |
1696 | */ |
b0f2597e |
1697 | function assignment_delete_instance($id){ |
26b90e70 |
1698 | global $CFG; |
1699 | |
b0f2597e |
1700 | if (! $assignment = get_record('assignment', 'id', $id)) { |
1701 | return false; |
26b90e70 |
1702 | } |
1703 | |
b0f2597e |
1704 | require_once("$CFG->dirroot/mod/assignment/type/$assignment->assignmenttype/assignment.class.php"); |
1705 | $assignmentclass = "assignment_$assignment->assignmenttype"; |
1706 | $ass = new $assignmentclass(); |
1707 | return $ass->delete_instance($assignment); |
1708 | } |
f466c9ed |
1709 | |
ac21ad39 |
1710 | |
7af1e882 |
1711 | /** |
1712 | * Updates an assignment instance |
1713 | * |
1714 | * This is done by calling the update_instance() method of the assignment type class |
1715 | */ |
b0f2597e |
1716 | function assignment_update_instance($assignment){ |
1717 | global $CFG; |
26b90e70 |
1718 | |
200c19fb |
1719 | $assignment->assignmenttype = clean_param($assignment->assignmenttype, PARAM_SAFEDIR); |
1720 | |
b0f2597e |
1721 | require_once("$CFG->dirroot/mod/assignment/type/$assignment->assignmenttype/assignment.class.php"); |
1722 | $assignmentclass = "assignment_$assignment->assignmenttype"; |
1723 | $ass = new $assignmentclass(); |
1724 | return $ass->update_instance($assignment); |
1725 | } |
26b90e70 |
1726 | |
26b90e70 |
1727 | |
7af1e882 |
1728 | /** |
1729 | * Adds an assignment instance |
1730 | * |
1731 | * This is done by calling the add_instance() method of the assignment type class |
1732 | */ |
b0f2597e |
1733 | function assignment_add_instance($assignment) { |
1734 | global $CFG; |
f466c9ed |
1735 | |
200c19fb |
1736 | $assignment->assignmenttype = clean_param($assignment->assignmenttype, PARAM_SAFEDIR); |
1737 | |
b0f2597e |
1738 | require_once("$CFG->dirroot/mod/assignment/type/$assignment->assignmenttype/assignment.class.php"); |
1739 | $assignmentclass = "assignment_$assignment->assignmenttype"; |
1740 | $ass = new $assignmentclass(); |
1741 | return $ass->add_instance($assignment); |
1742 | } |
f466c9ed |
1743 | |
73097f07 |
1744 | |
7af1e882 |
1745 | /** |
1746 | * Returns an outline of a user interaction with an assignment |
1747 | * |
1748 | * This is done by calling the user_outline() method of the assignment type class |
1749 | */ |
73097f07 |
1750 | function assignment_user_outline($course, $user, $mod, $assignment) { |
1751 | global $CFG; |
1752 | |
1753 | require_once("$CFG->dirroot/mod/assignment/type/$assignment->assignmenttype/assignment.class.php"); |
1754 | $assignmentclass = "assignment_$assignment->assignmenttype"; |
1755 | $ass = new $assignmentclass($mod->id, $assignment, $mod, $course); |
1756 | return $ass->user_outline($user); |
1757 | } |
1758 | |
7af1e882 |
1759 | /** |
1760 | * Prints the complete info about a user's interaction with an assignment |
1761 | * |
1762 | * This is done by calling the user_complete() method of the assignment type class |
1763 | */ |
73097f07 |
1764 | function assignment_user_complete($course, $user, $mod, $assignment) { |
1765 | global $CFG; |
1766 | |
1767 | require_once("$CFG->dirroot/mod/assignment/type/$assignment->assignmenttype/assignment.class.php"); |
1768 | $assignmentclass = "assignment_$assignment->assignmenttype"; |
1769 | $ass = new $assignmentclass($mod->id, $assignment, $mod, $course); |
1770 | return $ass->user_complete($user); |
1771 | } |
1772 | |
7af1e882 |
1773 | /** |
1774 | * Function to be run periodically according to the moodle cron |
1775 | * |
1776 | * Finds all assignment notifications that have yet to be mailed out, and mails them |
1777 | */ |
73097f07 |
1778 | function assignment_cron () { |
73097f07 |
1779 | |
1780 | global $CFG, $USER; |
1781 | |
1782 | /// Notices older than 1 day will not be mailed. This is to avoid the problem where |
1783 | /// cron has not been running for a long time, and then suddenly people are flooded |
1784 | /// with mail from the past few weeks or months |
1785 | |
1786 | $timenow = time(); |
1787 | $endtime = $timenow - $CFG->maxeditingtime; |
1788 | $starttime = $endtime - 24 * 3600; /// One day earlier |
1789 | |
1790 | if ($submissions = assignment_get_unmailed_submissions($starttime, $endtime)) { |
1791 | |
98be6ed8 |
1792 | $CFG->enablerecordcache = true; // We want all the caching we can get |
1793 | |
1794 | $realuser = clone($USER); |
1795 | |
73097f07 |
1796 | foreach ($submissions as $key => $submission) { |
1797 | if (! set_field("assignment_submissions", "mailed", "1", "id", "$submission->id")) { |
1798 | echo "Could not update the mailed field for id $submission->id. Not mailed.\n"; |
1799 | unset($submissions[$key]); |
1800 | } |
1801 | } |
1802 | |
1803 | $timenow = time(); |
1804 | |
1805 | foreach ($submissions as $submission) { |
1806 | |
1807 | echo "Processing assignment submission $submission->id\n"; |
1808 | |
1809 | if (! $user = get_record("user", "id", "$submission->userid")) { |
1810 | echo "Could not find user $post->userid\n"; |
1811 | continue; |
1812 | } |
1813 | |
73097f07 |
1814 | if (! $course = get_record("course", "id", "$submission->course")) { |
1815 | echo "Could not find course $submission->course\n"; |
1816 | continue; |
1817 | } |
98be6ed8 |
1818 | |
1819 | /// Override the language and timezone of the "current" user, so that |
1820 | /// mail is customised for the receiver. |
1821 | $USER = $user; |
1822 | course_setup($course); |
1823 | |
dbbb712e |
1824 | if (!has_capability('moodle/course:view', get_context_instance(CONTEXT_COURSE, $submission->course), $user->id)) { |
6ba65fa0 |
1825 | echo fullname($user)." not an active participant in " . format_string($course->shortname) . "\n"; |
73097f07 |
1826 | continue; |
1827 | } |
1828 | |
1829 | if (! $teacher = get_record("user", "id", "$submission->teacher")) { |
1830 | echo "Could not find teacher $submission->teacher\n"; |
1831 | continue; |
1832 | } |
1833 | |
1834 | if (! $mod = get_coursemodule_from_instance("assignment", $submission->assignment, $course->id)) { |
1835 | echo "Could not find course module for assignment id $submission->assignment\n"; |
1836 | continue; |
1837 | } |
1838 | |
1839 | if (! $mod->visible) { /// Hold mail notification for hidden assignments until later |
1840 | continue; |
1841 | } |
1842 | |
1843 | $strassignments = get_string("modulenameplural", "assignment"); |
1844 | $strassignment = get_string("modulename", "assignment"); |
1845 | |
98be6ed8 |
1846 | $assignmentinfo = new object(); |
73097f07 |
1847 | $assignmentinfo->teacher = fullname($teacher); |
1848 | $assignmentinfo->assignment = format_string($submission->name,true); |
1849 | $assignmentinfo->url = "$CFG->wwwroot/mod/assignment/view.php?id=$mod->id"; |
1850 | |
1851 | $postsubject = "$course->shortname: $strassignments: ".format_string($submission->name,true); |
1852 | $posttext = "$course->shortname -> $strassignments -> ".format_string($submission->name,true)."\n"; |
1853 | $posttext .= "---------------------------------------------------------------------\n"; |
3f19bff3 |
1854 | $posttext .= get_string("assignmentmail", "assignment", $assignmentinfo)."\n"; |
73097f07 |
1855 | $posttext .= "---------------------------------------------------------------------\n"; |
1856 | |
1857 | if ($user->mailformat == 1) { // HTML |
1858 | $posthtml = "<p><font face=\"sans-serif\">". |
1859 | "<a href=\"$CFG->wwwroot/course/view.php?id=$course->id\">$course->shortname</a> ->". |
1860 | "<a href=\"$CFG->wwwroot/mod/assignment/index.php?id=$course->id\">$strassignments</a> ->". |
1861 | "<a href=\"$CFG->wwwroot/mod/assignment/view.php?id=$mod->id\">".format_string($submission->name,true)."</a></font></p>"; |
1862 | $posthtml .= "<hr /><font face=\"sans-serif\">"; |
1863 | $posthtml .= "<p>".get_string("assignmentmailhtml", "assignment", $assignmentinfo)."</p>"; |
1864 | $posthtml .= "</font><hr />"; |
1865 | } else { |
1866 | $posthtml = ""; |
1867 | } |
1868 | |
1869 | if (! email_to_user($user, $teacher, $postsubject, $posttext, $posthtml)) { |
1870 | echo "Error: assignment cron: Could not send out mail for id $submission->id to user $user->id ($user->email)\n"; |
1871 | } |
1872 | } |
98be6ed8 |
1873 | |
1874 | $USER = $realuser; |
1875 | course_setup(SITEID); // reset cron user language, theme and timezone settings |
1876 | |
73097f07 |
1877 | } |
1878 | |
1879 | return true; |
1880 | } |
1881 | |
7af1e882 |
1882 | /** |
1883 | * Return an array of grades, indexed by user, and a max grade. |
1884 | * |
1885 | * @param $assignmentid int |
1886 | * @return object with properties ->grades (an array of grades) and ->maxgrade. |
1887 | */ |
73097f07 |
1888 | function assignment_grades($assignmentid) { |
73097f07 |
1889 | |
082215e6 |
1890 | if (!$assignment = get_record('assignment', 'id', $assignmentid)) { |
73097f07 |
1891 | return NULL; |
1892 | } |
3262ee10 |
1893 | if ($assignment->grade == 0) { // No grading |
1894 | return NULL; |
1895 | } |
73097f07 |
1896 | |
082215e6 |
1897 | $grades = get_records_menu('assignment_submissions', 'assignment', |
1898 | $assignment->id, '', 'userid,grade'); |
73097f07 |
1899 | |
98be6ed8 |
1900 | $return = new object(); |
1901 | |
3262ee10 |
1902 | if ($assignment->grade > 0) { |
fa22fd5f |
1903 | if ($grades) { |
1904 | foreach ($grades as $userid => $grade) { |
1905 | if ($grade == -1) { |
1906 | $grades[$userid] = '-'; |
1907 | } |
082215e6 |
1908 | } |
1909 | } |
73097f07 |
1910 | $return->grades = $grades; |
1911 | $return->maxgrade = $assignment->grade; |
1912 | |
1913 | } else { // Scale |
1914 | if ($grades) { |
1915 | $scaleid = - ($assignment->grade); |
bed24ce7 |
1916 | $maxgrade = ""; |
73097f07 |
1917 | if ($scale = get_record('scale', 'id', $scaleid)) { |
1918 | $scalegrades = make_menu_from_list($scale->scale); |
082215e6 |
1919 | foreach ($grades as $userid => $grade) { |
de4564ee |
1920 | if (empty($scalegrades[$grade])) { |
39e11905 |
1921 | $grades[$userid] = '-'; |
0a3f66a2 |
1922 | } else { |
082215e6 |
1923 | $grades[$userid] = $scalegrades[$grade]; |
0a3f66a2 |
1924 | } |
73097f07 |
1925 | } |
bed24ce7 |
1926 | $maxgrade = $scale->name; |
73097f07 |
1927 | } |
1928 | } |
1929 | $return->grades = $grades; |
bed24ce7 |
1930 | $return->maxgrade = $maxgrade; |
73097f07 |
1931 | } |
1932 | |
1933 | return $return; |
1934 | } |
1935 | |
7af1e882 |
1936 | /** |
1937 | * Returns the users with data in one assignment (students and teachers) |
1938 | * |
1939 | * @param $assignmentid int |
1940 | * @return array of user objects |
1941 | */ |
73097f07 |
1942 | function assignment_get_participants($assignmentid) { |
73097f07 |
1943 | |
1944 | global $CFG; |
1945 | |
1946 | //Get students |
1947 | $students = get_records_sql("SELECT DISTINCT u.id, u.id |
1948 | FROM {$CFG->prefix}user u, |
1949 | {$CFG->prefix}assignment_submissions a |
1950 | WHERE a.assignment = '$assignmentid' and |
1951 | u.id = a.userid"); |
1952 | //Get teachers |
1953 | $teachers = get_records_sql("SELECT DISTINCT u.id, u.id |
1954 | FROM {$CFG->prefix}user u, |
1955 | {$CFG->prefix}assignment_submissions a |
1956 | WHERE a.assignment = '$assignmentid' and |
1957 | u.id = a.teacher"); |
1958 | |
1959 | //Add teachers to students |
1960 | if ($teachers) { |
1961 | foreach ($teachers as $teacher) { |
1962 | $students[$teacher->id] = $teacher; |
1963 | } |
1964 | } |
1965 | //Return students array (it contains an array of unique users) |
1966 | return ($students); |
1967 | } |
1968 | |
7af1e882 |
1969 | /** |
1970 | * Checks if a scale is being used by an assignment |
1971 | * |
1972 | * This is used by the backup code to decide whether to back up a scale |
1973 | * @param $assignmentid int |
1974 | * @param $scaleid int |
1975 | * @return boolean True if the scale is used by the assignment |
1976 | */ |
1977 | function assignment_scale_used ($assignmentid, $scaleid) { |
73097f07 |
1978 | |
1979 | $return = false; |
1980 | |
1981 | $rec = get_record('assignment','id',$assignmentid,'grade',-$scaleid); |
1982 | |
1983 | if (!empty($rec) && !empty($scaleid)) { |
1984 | $return = true; |
1985 | } |
1986 | |
1987 | return $return; |
1988 | } |
1989 | |
7af1e882 |
1990 | /** |
1991 | * Make sure up-to-date events are created for all assignment instances |
1992 | * |
1993 | * This standard function will check all instances of this module |
1994 | * and make sure there are up-to-date events created for each of them. |
1995 | * If courseid = 0, then every assignment event in the site is checked, else |
1996 | * only assignment events belonging to the course specified are checked. |
1997 | * This function is used, in its new format, by restore_refresh_events() |
1998 | * |
1999 | * @param $courseid int optional If zero then all assignments for all courses are covered |
2000 | * @return boolean Always returns true |
2001 | */ |
73097f07 |
2002 | function assignment_refresh_events($courseid = 0) { |
73097f07 |
2003 | |
2004 | if ($courseid == 0) { |
2005 | if (! $assignments = get_records("assignment")) { |
2006 | return true; |
2007 | } |
2008 | } else { |
2009 | if (! $assignments = get_records("assignment", "course", $courseid)) { |
2010 | return true; |
2011 | } |
2012 | } |
2013 | $moduleid = get_field('modules', 'id', 'name', 'assignment'); |
2014 | |
2015 | foreach ($assignments as $assignment) { |
2016 | $event = NULL; |
2017 | $event->name = addslashes($assignment->name); |
2018 | $event->description = addslashes($assignment->description); |
2019 | $event->timestart = $assignment->timedue; |
2020 | |
2021 | if ($event->id = get_field('event', 'id', 'modulename', 'assignment', 'instance', $assignment->id)) { |
2022 | update_event($event); |
2023 | |
2024 | } else { |
2025 | $event->courseid = $assignment->course; |
2026 | $event->groupid = 0; |
2027 | $event->userid = 0; |
2028 | $event->modulename = 'assignment'; |
2029 | $event->instance = $assignment->id; |
2030 | $event->eventtype = 'due'; |
2031 | $event->timeduration = 0; |
2032 | $event->visible = get_field('course_modules', 'visible', 'module', $moduleid, 'instance', $assignment->id); |
2033 | add_event($event); |
2034 | } |
2035 | |
2036 | } |
2037 | return true; |
2038 | } |
2039 | |
7af1e882 |
2040 | /** |
2041 | * Print recent activity from all assignments in a given course |
2042 | * |
2043 | * This is used by the recent activity block |
2044 | */ |
73097f07 |
2045 | function assignment_print_recent_activity($course, $isteacher, $timestart) { |
2046 | global $CFG; |
2047 | |
2048 | $content = false; |
70b5660a |
2049 | $assignments = array(); |
73097f07 |
2050 | |
2051 | if (!$logs = get_records_select('log', 'time > \''.$timestart.'\' AND '. |
2052 | 'course = \''.$course->id.'\' AND '. |
2053 | 'module = \'assignment\' AND '. |
2054 | 'action = \'upload\' ', 'time ASC')) { |
2055 | return false; |
2056 | } |
2057 | |
2058 | foreach ($logs as $log) { |
2059 | //Create a temp valid module structure (course,id) |
70b5660a |
2060 | $tempmod = new object(); |
73097f07 |
2061 | $tempmod->course = $log->course; |
2062 | $tempmod->id = $log->info; |
2063 | //Obtain the visible property from the instance |
2064 | $modvisible = instance_is_visible($log->module,$tempmod); |
2065 | |
2066 | //Only if the mod is visible |
2067 | if ($modvisible) { |
70b5660a |
2068 | if ($info = assignment_log_info($log)) { |
2069 | $assignments[$log->info] = $info; |
2070 | $assignments[$log->info]->time = $log->time; |
2071 | $assignments[$log->info]->url = str_replace('&', '&', $log->url); |
2072 | } |
73097f07 |
2073 | } |
2074 | } |
2075 | |
70b5660a |
2076 | if (!empty($assignments)) { |
73097f07 |
2077 | print_headline(get_string('newsubmissions', 'assignment').':'); |
2078 | foreach ($assignments as $assignment) { |
583b57b4 |
2079 | print_recent_activity_note($assignment->time, $assignment, $assignment->name, |
73097f07 |
2080 | $CFG->wwwroot.'/mod/assignment/'.$assignment->url); |
2081 | } |
2082 | $content = true; |
2083 | } |
2084 | |
2085 | return $content; |
2086 | } |
2087 | |
2088 | |
7af1e882 |
2089 | /** |
2090 | * Returns all assignments since a given time. |
2091 | * |
2092 | * If assignment is specified then this restricts the results |
2093 | */ |
73097f07 |
2094 | function assignment_get_recent_mod_activity(&$activities, &$index, $sincetime, $courseid, $assignment="0", $user="", $groupid="") { |
73097f07 |
2095 | |
2096 | global $CFG; |
2097 | |
2098 | if ($assignment) { |
2099 | $assignmentselect = " AND cm.id = '$assignment'"; |
2100 | } else { |
2101 | $assignmentselect = ""; |
2102 | } |
2103 | if ($user) { |
2104 | $userselect = " AND u.id = '$user'"; |
2105 | } else { |
2106 | $userselect = ""; |
2107 | } |
2108 | |
2109 | $assignments = get_records_sql("SELECT asub.*, u.firstname, u.lastname, u.picture, u.id as userid, |
2110 | a.grade as maxgrade, name, cm.instance, cm.section, a.assignmenttype |
2111 | FROM {$CFG->prefix}assignment_submissions asub, |
2112 | {$CFG->prefix}user u, |
2113 | {$CFG->prefix}assignment a, |
2114 | {$CFG->prefix}course_modules cm |
2115 | WHERE asub.timemodified > '$sincetime' |
2116 | AND asub.userid = u.id $userselect |
2117 | AND a.id = asub.assignment $assignmentselect |
2118 | AND cm.course = '$courseid' |
2119 | AND cm.instance = a.id |
2120 | ORDER BY asub.timemodified ASC"); |
2121 | |
2122 | if (empty($assignments)) |
2123 | return; |
2124 | |
2125 | foreach ($assignments as $assignment) { |
2126 | if (empty($groupid) || ismember($groupid, $assignment->userid)) { |
2127 | |
2128 | $tmpactivity = new Object; |
2129 | |
2130 | $tmpactivity->type = "assignment"; |
2131 | $tmpactivity->defaultindex = $index; |
2132 | $tmpactivity->instance = $assignment->instance; |
2133 | $tmpactivity->name = $assignment->name; |
2134 | $tmpactivity->section = $assignment->section; |
2135 | |
2136 | $tmpactivity->content->grade = $assignment->grade; |
2137 | $tmpactivity->content->maxgrade = $assignment->maxgrade; |
2138 | $tmpactivity->content->type = $assignment->assignmenttype; |
2139 | |
2140 | $tmpactivity->user->userid = $assignment->userid; |
2141 | $tmpactivity->user->fullname = fullname($assignment); |
2142 | $tmpactivity->user->picture = $assignment->picture; |
2143 | |
2144 | $tmpactivity->timestamp = $assignment->timemodified; |
2145 | |
2146 | $activities[] = $tmpactivity; |
2147 | |
2148 | $index++; |
2149 | } |
2150 | } |
2151 | |
2152 | return; |
2153 | } |
2154 | |
7af1e882 |
2155 | /** |
2156 | * Print recent activity from all assignments in a given course |
2157 | * |
2158 | * This is used by course/recent.php |
2159 | */ |
73097f07 |
2160 | function assignment_print_recent_mod_activity($activity, $course, $detail=false) { |
2161 | global $CFG; |
2162 | |
2163 | echo '<table border="0" cellpadding="3" cellspacing="0">'; |
2164 | |
141a922c |
2165 | echo "<tr><td class=\"userpicture\" valign=\"top\">"; |
73097f07 |
2166 | print_user_picture($activity->user->userid, $course, $activity->user->picture); |
2167 | echo "</td><td width=\"100%\"><font size=2>"; |
2168 | |
2169 | if ($detail) { |
2170 | echo "<img src=\"$CFG->modpixpath/$activity->type/icon.gif\" ". |
0d905d9f |
2171 | "class=\"icon\" alt=\"$activity->type\"> "; |
73097f07 |
2172 | echo "<a href=\"$CFG->wwwroot/mod/assignment/view.php?id=" . $activity->instance . "\">" |
2173 | . format_string($activity->name,true) . "</a> - "; |
2174 | |
2175 | } |
2176 | |
0bde6300 |
2177 | if (has_capability('moodle/course:viewrecent', get_context_instance(CONTEXT_COURSE, $course))) { |
73097f07 |
2178 | $grades = "(" . $activity->content->grade . " / " . $activity->content->maxgrade . ") "; |
2179 | |
2180 | $assignment->id = $activity->instance; |
2181 | $assignment->course = $course; |
2182 | $user->id = $activity->user->userid; |
2183 | |
2184 | echo $grades; |
2185 | echo "<br />"; |
2186 | } |
2187 | echo "<a href=\"$CFG->wwwroot/user/view.php?id=" |
2188 | . $activity->user->userid . "&course=$course\">" |
2189 | . $activity->user->fullname . "</a> "; |
2190 | |
2191 | echo " - " . userdate($activity->timestamp); |
2192 | |
2193 | echo "</font></td></tr>"; |
2194 | echo "</table>"; |
73097f07 |
2195 | } |
2196 | |
2197 | /// GENERIC SQL FUNCTIONS |
2198 | |
7af1e882 |
2199 | /** |
2200 | * Fetch info from logs |
2201 | * |
2202 | * @param $log object with properties ->info (the assignment id) and ->userid |
2203 | * @return array with assignment name and user firstname and lastname |
2204 | */ |
73097f07 |
2205 | function assignment_log_info($log) { |
2206 | global $CFG; |
2207 | return get_record_sql("SELECT a.name, u.firstname, u.lastname |
2208 | FROM {$CFG->prefix}assignment a, |
2209 | {$CFG->prefix}user u |
2210 | WHERE a.id = '$log->info' |
2211 | AND u.id = '$log->userid'"); |
2212 | } |
2213 | |
7af1e882 |
2214 | /** |
2215 | * Return list of marked submissions that have not been mailed out for currently enrolled students |
2216 | * |
2217 | * @return array |
2218 | */ |
73097f07 |
2219 | function assignment_get_unmailed_submissions($starttime, $endtime) { |
7af1e882 |
2220 | |
73097f07 |
2221 | global $CFG; |
ea8158c1 |
2222 | |
73097f07 |
2223 | return get_records_sql("SELECT s.*, a.course, a.name |
ea8158c1 |
2224 | FROM {$CFG->prefix}assignment_submissions s, |
4be6bced |
2225 | {$CFG->prefix}assignment a |
ea8158c1 |
2226 | WHERE s.mailed = 0 |
2227 | AND s.timemarked <= $endtime |
2228 | AND s.timemarked >= $starttime |
4be6bced |
2229 | AND s.assignment = a.id"); |
ea8158c1 |
2230 | |
2231 | /* return get_records_sql("SELECT s.*, a.course, a.name |
73097f07 |
2232 | FROM {$CFG->prefix}assignment_submissions s, |
2233 | {$CFG->prefix}assignment a, |
2234 | {$CFG->prefix}user_students us |
2235 | WHERE s.mailed = 0 |
2236 | AND s.timemarked <= $endtime |
2237 | AND s.timemarked >= $starttime |
2238 | AND s.assignment = a.id |
2239 | AND s.userid = us.userid |
2240 | AND a.course = us.course"); |
ea8158c1 |
2241 | */ |
73097f07 |
2242 | } |
2243 | |
7af1e882 |
2244 | /** |
2245 | * Counts all real assignment submissions by ENROLLED students (not empty ones) |
2246 | * |
2247 | * There are also assignment type methods count_real_submissions() wich in the default |
2248 | * implementation simply call this function. |
2249 | * @param $groupid int optional If nonzero then count is restricted to this group |
2250 | * @return int The number of submissions |
2251 | */ |
73097f07 |
2252 | function assignment_count_real_submissions($assignment, $groupid=0) { |
73097f07 |
2253 | global $CFG; |
2254 | |
2255 | if ($groupid) { /// How many in a particular group? |
2256 | return count_records_sql("SELECT COUNT(DISTINCT g.userid, g.groupid) |
2257 | FROM {$CFG->prefix}assignment_submissions a, |
e25cb710 |
2258 | ".groups_members_from_sql()." |
73097f07 |
2259 | WHERE a.assignment = $assignment->id |
2260 | AND a.timemodified > 0 |
e25cb710 |
2261 | AND ".groups_members_where_sql($groupid, 'a.userid')); |
73097f07 |
2262 | } else { |
1648afb2 |
2263 | $cm = get_coursemodule_from_instance('assignment', $assignment->id); |
2264 | $context = get_context_instance(CONTEXT_MODULE, $cm->id); |
01194b77 |
2265 | |
1648afb2 |
2266 | // this is all the users with this capability set, in this context or higher |
01194b77 |
2267 | if ($users = get_users_by_capability($context, 'mod/assignment:submit')) { |
2268 | foreach ($users as $user) { |
2269 | $array[] = $user->id; |
2270 | } |
2271 | |
2272 | $userlists = '('.implode(',',$array).')'; |
2273 | |
2274 | return count_records_sql("SELECT COUNT(*) |
2275 | FROM {$CFG->prefix}assignment_submissions |
2276 | WHERE assignment = '$assignment->id' |
2277 | AND timemodified > 0 |
2278 | AND userid IN $userlists "); |
2279 | } else { |
2280 | return 0; // no users enroled in course |
73097f07 |
2281 | } |
73097f07 |
2282 | } |
2283 | } |
2284 | |
7af1e882 |
2285 | |
2286 | /** |
2287 | * Return all assignment submissions by ENROLLED students (even empty) |
2288 | * |
2289 | * There are also assignment type methods get_submissions() wich in the default |
2290 | * implementation simply call this function. |
2291 | * @param $sort string optional field names for the ORDER BY in the sql query |
2292 | * @param $dir string optional specifying the sort direction, defaults to DESC |
2293 | * @return array The submission objects indexed by id |
2294 | */ |
73097f07 |
2295 | function assignment_get_all_submissions($assignment, $sort="", $dir="DESC") { |
2296 | /// Return all assignment submissions by ENROLLED students (even empty) |
2297 | global $CFG; |
2298 | |
2299 | if ($sort == "lastname" or $sort == "firstname") { |
2300 | $sort = "u.$sort $dir"; |
2301 | } else if (empty($sort)) { |
2302 | $sort = "a.timemodified DESC"; |
2303 | } else { |
2304 | $sort = "a.$sort $dir"; |
2305 | } |
2306 | |
ea8158c1 |
2307 | /* not sure this is needed at all since assignmenet already has a course define, so this join? |
73097f07 |
2308 | $select = "s.course = '$assignment->course' AND"; |
2309 | if ($assignment->course == SITEID) { |
2310 | $select = ''; |
ea8158c1 |
2311 | }*/ |
2312 | |
73097f07 |
2313 | return get_records_sql("SELECT a.* |
ea8158c1 |
2314 | FROM {$CFG->prefix}assignment_submissions a, |
2315 | {$CFG->prefix}user u |
2316 | WHERE u.id = a.userid |
2317 | AND a.assignment = '$assignment->id' |
2318 | ORDER BY $sort"); |
2319 | |
2320 | /* return get_records_sql("SELECT a.* |
73097f07 |
2321 | FROM {$CFG->prefix}assignment_submissions a, |
2322 | {$CFG->prefix}user_students s, |
2323 | {$CFG->prefix}user u |
2324 | WHERE a.userid = s.userid |
2325 | AND u.id = a.userid |
2326 | AND $select a.assignment = '$assignment->id' |
2327 | ORDER BY $sort"); |
ea8158c1 |
2328 | */ |
73097f07 |
2329 | } |
2330 | |
2331 | |
2332 | |
2333 | |
2334 | /// OTHER GENERAL FUNCTIONS FOR ASSIGNMENTS /////////////////////////////////////// |
2335 | |
7af1e882 |
2336 | /** |
2337 | * Returns an array of installed assignment types indexed and sorted by name |
2338 | * |
2339 | * @return array The index is the name of the assignment type, the value its full name from the language strings |
2340 | */ |
b0f2597e |
2341 | function assignment_types() { |
2342 | $types = array(); |
2343 | $names = get_list_of_plugins('mod/assignment/type'); |
2344 | foreach ($names as $name) { |
2345 | $types[$name] = get_string('type'.$name, 'assignment'); |
ffeca120 |
2346 | } |
b0f2597e |
2347 | asort($types); |
2348 | return $types; |
f466c9ed |
2349 | } |
2350 | |
7af1e882 |
2351 | /** |
2352 | * Executes upgrade scripts for assignment types when necessary |
2353 | */ |
b0f2597e |
2354 | function assignment_upgrade_submodules() { |
f1c1d2f1 |
2355 | global $CFG; |
26b90e70 |
2356 | |
b0f2597e |
2357 | $types = assignment_types(); |
26b90e70 |
2358 | |
d175966b |
2359 | include($CFG->dirroot.'/mod/assignment/version.php'); // defines $module with version etc |
26b90e70 |
2360 | |
d175966b |
2361 | foreach ($types as $type => $typename) { |
26b90e70 |
2362 | |
b0f2597e |
2363 | $fullpath = $CFG->dirroot.'/mod/assignment/type/'.$type; |
26b90e70 |
2364 | |
b0f2597e |
2365 | /// Check for an external version file (defines $submodule) |
26b90e70 |
2366 | |
b0f2597e |
2367 | if (!is_readable($fullpath .'/version.php')) { |
2368 | continue; |
ffeca120 |
2369 | } |
b0f2597e |
2370 | include_once($fullpath .'/version.php'); |
26b90e70 |
2371 | |
b0f2597e |
2372 | /// Check whether we need to upgrade |
26b90e70 |
2373 | |
b0f2597e |
2374 | if (!isset($submodule->version)) { |
2375 | continue; |
2376 | } |
26b90e70 |
2377 | |
b0f2597e |
2378 | /// Make sure this submodule will work with this assignment version |
26b90e70 |
2379 | |
d175966b |
2380 | if (isset($submodule->requires) and ($submodule->requires > $module->version)) { |
b0f2597e |
2381 | notify("Assignment submodule '$type' is too new for your assignment"); |
2382 | continue; |
2383 | } |
f466c9ed |
2384 | |
a86a538f |
2385 | /// If the submodule is new, then let's install it! |
f466c9ed |
2386 | |
b0f2597e |
2387 | $currentversion = 'assignment_'.$type.'_version'; |
f466c9ed |
2388 | |
a86a538f |
2389 | if (!isset($CFG->$currentversion)) { // First install! |
2390 | set_config($currentversion, $submodule->version); // Must keep track of version |
2391 | |
2392 | if (!is_readable($fullpath .'/db/'.$CFG->dbtype.'.sql')) { |
2393 | continue; |
2394 | } |
2395 | |
583fad99 |
2396 | upgrade_log_start(); |
a86a538f |
2397 | $db->debug=true; |
2398 | if (!modify_database($fullpath .'/db/'.$CFG->dbtype.'.sql')) { |
2399 | notify("Error installing tables for submodule '$type'!"); |
2400 | } |
2401 | $db->debug=false; |
2402 | continue; |
f466c9ed |
2403 | } |
f466c9ed |
2404 | |
b0f2597e |
2405 | /// See if we need to upgrade |
2406 | |
2407 | if ($submodule->version <= $CFG->$currentversion) { |
2408 | continue; |
59c005b7 |
2409 | } |
59c005b7 |
2410 | |
b0f2597e |
2411 | /// Look for the upgrade file |
59c005b7 |
2412 | |
b0f2597e |
2413 | if (!is_readable($fullpath .'/db/'.$CFG->dbtype.'.php')) { |
2414 | continue; |
2415 | } |
59c005b7 |
2416 | |
b0f2597e |
2417 | include_once($fullpath .'/db/'. $CFG->dbtype .'.php'); // defines assignment_xxx_upgrade |
59c005b7 |
2418 | |
b0f2597e |
2419 | /// Perform the upgrade |
59c005b7 |
2420 | |
b0f2597e |
2421 | $upgrade_function = 'assignment_'.$type.'_upgrade'; |
2422 | if (function_exists($upgrade_function)) { |
583fad99 |
2423 | upgrade_log_start(); |
b0f2597e |
2424 | $db->debug=true; |
2425 | if ($upgrade_function($CFG->$currentversion)) { |
2426 | $db->debug=false; |
2427 | set_config($currentversion, $submodule->version); |
59c005b7 |
2428 | } |
b0f2597e |
2429 | $db->debug=false; |
59c005b7 |
2430 | } |
2431 | } |
2432 | } |
2433 | |
84fa8f5f |
2434 | function assignment_print_overview($courses, &$htmlarray) { |
afe35ec4 |
2435 | |
84fa8f5f |
2436 | global $USER, $CFG; |
2437 | |
2438 | if (empty($courses) || !is_array($courses) || count($courses) == 0) { |
2439 | return array(); |
2440 | } |
2441 | |
2442 | if (!$assignments = get_all_instances_in_courses('assignment',$courses)) { |
2443 | return; |
2444 | } |
2445 | |
2446 | // Do assignment_base::isopen() here without loading the whole thing for speed |
2447 | foreach ($assignments as $key => $assignment) { |
2448 | $time = time(); |
d6da4a1a |
2449 | if ($assignment->timedue) { |
2450 | if ($assignment->preventlate) { |
2451 | $isopen = ($assignment->timeavailable <= $time && $time <= $assignment->timedue); |
2452 | } else { |
2453 | $isopen = ($assignment->timeavailable <= $time); |
2454 | } |
84fa8f5f |
2455 | } |
d6da4a1a |
2456 | if (empty($isopen) || empty($assignment->timedue)) { |
84fa8f5f |
2457 | unset($assignments[$key]); |
2458 | } |
2459 | } |
2460 | |
2461 | $strduedate = get_string('duedate', 'assignment'); |
8f643c81 |
2462 | $strduedateno = get_string('duedateno', 'assignment'); |
84fa8f5f |
2463 | $strgraded = get_string('graded', 'assignment'); |
2464 | $strnotgradedyet = get_string('notgradedyet', 'assignment'); |
2465 | $strnotsubmittedyet = get_string('notsubmittedyet', 'assignment'); |
2466 | $strsubmitted = get_string('submitted', 'assignment'); |
76a60031 |
2467 | $strassignment = get_string('modulename', 'assignment'); |
c664a036 |
2468 | $strreviewed = get_string('reviewed','assignment'); |
84fa8f5f |
2469 | |
2470 | foreach ($assignments as $assignment) { |
a2a37336 |
2471 | $str = '<div class="assignment overview"><div class="name">'.$strassignment. ': '. |
a7a74d77 |
2472 | '<a '.($assignment->visible ? '':' class="dimmed"'). |
76a60031 |
2473 | 'title="'.$strassignment.'" href="'.$CFG->wwwroot. |
a7a74d77 |
2474 | '/mod/assignment/view.php?id='.$assignment->coursemodule.'">'. |
5d45c04f |
2475 | $assignment->name.'</a></div>'; |
8f643c81 |
2476 | if ($assignment->timedue) { |
2477 | $str .= '<div class="info">'.$strduedate.': '.userdate($assignment->timedue).'</div>'; |
2478 | } else { |
2479 | $str .= '<div class="info">'.$strduedateno.'</div>'; |
2480 | } |
793a8c3a |
2481 | $context = get_context_instance(CONTEXT_MODULE, $assignment->coursemodule); |
0468976c |
2482 | if (has_capability('mod/assignment:grade', $context)) { |
ea8158c1 |
2483 | |
2484 | // count how many people can submit |
2485 | $submissions = 0; // init |
c2adcc90 |
2486 | if ($students = get_users_by_capability($context, 'mod/assignment:submit')) { |
2487 | foreach ($students as $student) { |
afe35ec4 |
2488 | if (get_records_sql("SELECT id,id FROM {$CFG->prefix}assignment_submissions |
2489 | WHERE assignment = $assignment->id AND |
2490 | userid = $student->id AND |
2491 | teacher = 0 AND |
2492 | timemarked = 0")) { |
c2adcc90 |
2493 | $submissions++; |
2494 | } |
ea8158c1 |
2495 | } |
2496 | } |
2497 | |
84fa8f5f |
2498 | if ($submissions) { |
2499 | $str .= get_string('submissionsnotgraded', 'assignment', $submissions); |
2500 | } |
2501 | } else { |
2502 | $sql = "SELECT * |
2503 | FROM {$CFG->prefix}assignment_submissions |
b3d4840d |
2504 | WHERE userid = '$USER->id' |
2505 | AND assignment = '{$assignment->id}'"; |
84fa8f5f |
2506 | if ($submission = get_record_sql($sql)) { |
2507 | if ($submission->teacher == 0 && $submission->timemarked == 0) { |
2508 | $str .= $strsubmitted . ', ' . $strnotgradedyet; |
c664a036 |
2509 | } else if ($submission->grade <= 0) { |
2510 | $str .= $strsubmitted . ', ' . $strreviewed; |
84fa8f5f |
2511 | } else { |
2512 | $str .= $strsubmitted . ', ' . $strgraded; |
2513 | } |
2514 | } else { |
76a60031 |
2515 | $str .= $strnotsubmittedyet . ' ' . assignment_display_lateness(time(), $assignment->timedue); |
84fa8f5f |
2516 | } |
2517 | } |
a7a74d77 |
2518 | $str .= '</div>'; |
76a60031 |
2519 | if (empty($htmlarray[$assignment->course]['assignment'])) { |
2520 | $htmlarray[$assignment->course]['assignment'] = $str; |
2521 | } else { |
2522 | $htmlarray[$assignment->course]['assignment'] .= $str; |
2523 | } |
2524 | } |
2525 | } |
2526 | |
2527 | function assignment_display_lateness($timesubmitted, $timedue) { |
2528 | if (!$timedue) { |
2529 | return ''; |
2530 | } |
2531 | $time = $timedue - $timesubmitted; |
2532 | if ($time < 0) { |
2533 | $timetext = get_string('late', 'assignment', format_time($time)); |
2534 | return ' (<span class="late">'.$timetext.'</span>)'; |
2535 | } else { |
2536 | $timetext = get_string('early', 'assignment', format_time($time)); |
2537 | return ' (<span class="early">'.$timetext.'</span>)'; |
84fa8f5f |
2538 | } |
2539 | } |
2540 | |
ac15a2d5 |
2541 | function assignment_get_view_actions() { |
2542 | return array('view'); |
2543 | } |
2544 | |
2545 | function assignment_get_post_actions() { |
2546 | return array('upload'); |
2547 | } |
2548 | |
89bfeee0 |
2549 | function assignment_get_types() { |
0ac1cfc3 |
2550 | global $CFG; |
89bfeee0 |
2551 | $types = array(); |
2552 | |
2553 | $type = new object(); |
2554 | $type->modclass = MOD_CLASS_ACTIVITY; |
2555 | $type->type = "assignment_group_start"; |
2556 | $type->typestr = '--'.get_string('modulenameplural', 'assignment'); |
2557 | $types[] = $type; |
2558 | |
2559 | $standardassignments = array('upload','online','uploadsingle','offline'); |
2560 | foreach ($standardassignments as $assignmenttype) { |
2561 | $type = new object(); |
2562 | $type->modclass = MOD_CLASS_ACTIVITY; |
2563 | $type->type = "assignment&type=$assignmenttype"; |
2564 | $type->typestr = get_string("type$assignmenttype", 'assignment'); |
2565 | $types[] = $type; |
2566 | } |
2567 | |
2568 | /// Drop-in extra assignment types |
2569 | $assignmenttypes = get_list_of_plugins('mod/assignment/type'); |
2570 | foreach ($assignmenttypes as $assignmenttype) { |
2571 | if (!empty($CFG->{'assignment_hide_'.$assignmenttype})) { // Not wanted |
2572 | continue; |
2573 | } |
2574 | if (!in_array($assignmenttype, $standardassignments)) { |
2575 | $type = new object(); |
2576 | $type->modclass = MOD_CLASS_ACTIVITY; |
2577 | $type->type = "assignment&type=$assignmenttype"; |
2578 | $type->typestr = get_string("type$assignmenttype", 'assignment'); |
2579 | $types[] = $type; |
2580 | } |
2581 | } |
2582 | |
2583 | $type = new object(); |
2584 | $type->modclass = MOD_CLASS_ACTIVITY; |
2585 | $type->type = "assignment_group_end"; |
2586 | $type->typestr = '--'; |
2587 | $types[] = $type; |
2588 | |
2589 | return $types; |
2590 | } |
2591 | |
76a60031 |
2592 | ?> |