Assignment MDL-7206 - download all submissions as a zip - finally pushing this into...
[moodle.git] / mod / assignment / type / online / assignment.class.php
CommitLineData
e7521559 1<?php
6cb1b93e 2require_once($CFG->libdir.'/formslib.php');
67a87e7d 3require_once($CFG->dirroot . '/mod/assignment/lib.php');
f77cfb73 4/**
5 * Extend the base assignment class for assignments where you upload a single file
6 *
7 */
8class assignment_online extends assignment_base {
9
7bddd4b7 10 function assignment_online($cmid='staticonly', $assignment=NULL, $cm=NULL, $course=NULL) {
11 parent::assignment_base($cmid, $assignment, $cm, $course);
0b5a80a1 12 $this->type = 'online';
f77cfb73 13 }
14
f77cfb73 15 function view() {
16
007772d6 17 global $OUTPUT;
6cb1b93e 18
19 $edit = optional_param('edit', 0, PARAM_BOOL);
20 $saved = optional_param('saved', 0, PARAM_BOOL);
21
22 $context = get_context_instance(CONTEXT_MODULE, $this->cm->id);
0468976c 23 require_capability('mod/assignment:view', $context);
6cb1b93e 24
61240489 25 $submission = $this->get_submission();
1648afb2 26
2eac7ec1 27 //Guest can not submit nor edit an assignment (bug: 4604)
be07f21b 28 if (!has_capability('mod/assignment:submit', $context)) {
2eac7ec1 29 $editable = null;
6cb1b93e 30 } else {
2eac7ec1 31 $editable = $this->isopen() && (!$submission || $this->assignment->resubmit || !$submission->timemarked);
32 }
6cb1b93e 33 $editmode = ($editable and $edit);
f77cfb73 34
35 if ($editmode) {
f7de5478 36 //guest can not edit or submit assignment
be07f21b 37 if (!has_capability('mod/assignment:submit', $context)) {
cb59ca28 38 print_error('guestnosubmit', 'assignment');
f7de5478 39 }
f77cfb73 40 }
41
cb59ca28 42 add_to_log($this->course->id, "assignment", "view", "view.php?id={$this->cm->id}", $this->assignment->id, $this->cm->id);
43
6cb1b93e 44/// prepare form and process submitted data
c561f44c 45 $mformdata = new stdClass;
c561f44c 46 $mformdata->context = $this->context;
9e6b608f 47 $mformdata->maxbytes = $this->course->maxbytes;
007772d6 48 $mformdata->submission = $submission;
c561f44c 49 $mform = new mod_assignment_online_edit_form(null, $mformdata);
f77cfb73 50
6cb1b93e 51 $defaults = new object();
52 $defaults->id = $this->cm->id;
53 if (!empty($submission)) {
54 if ($this->usehtmleditor) {
55 $options = new object();
56 $options->smiley = false;
57 $options->filter = false;
f77cfb73 58
6cb1b93e 59 $defaults->text = format_text($submission->data1, $submission->data2, $options);
60 $defaults->format = FORMAT_HTML;
61 } else {
cc27235e 62 $defaults->text = clean_text($submission->data1, $submission->data2);
6cb1b93e 63 $defaults->format = $submission->data2;
64 }
65 }
beac4717 66 $mform->set_data($defaults);
6cb1b93e 67
5571b5f4 68 if ($mform->is_cancelled()) {
69 redirect('view.php?id='.$this->cm->id);
70 }
71
beac4717 72 if ($data = $mform->get_data()) { // No incoming data?
f0a99707 73 if ($editable && $this->update_submission($data)) {
ca4fb814 74 //TODO fix log actions - needs db upgrade
418db328 75 $submission = $this->get_submission();
6cb1b93e 76 add_to_log($this->course->id, 'assignment', 'upload',
9bf660b3 77 'view.php?a='.$this->assignment->id, $this->assignment->id, $this->cm->id);
78 $this->email_teachers($submission);
3e7bf58a 79 //redirect to get updated submission date and word count
80 redirect('view.php?id='.$this->cm->id.'&saved=1');
f0a99707 81 } else {
82 // TODO: add better error message
3a003ead 83 echo $OUTPUT->notification(get_string("error")); //submitting not allowed!
f77cfb73 84 }
6cb1b93e 85 }
86
87/// print header, etc. and display form if needed
88 if ($editmode) {
89 $this->view_header(get_string('editmysubmission', 'assignment'));
90 } else {
91 $this->view_header();
92 }
93
94 $this->view_intro();
95
96 $this->view_dates();
97
98 if ($saved) {
3a003ead 99 echo $OUTPUT->notification(get_string('submissionsaved', 'assignment'), 'notifysuccess');
3e7bf58a 100 }
f77cfb73 101
61240489 102 if (has_capability('mod/assignment:submit', $context)) {
61240489 103 if ($editmode) {
01e0da58 104 echo $OUTPUT->box_start('generalbox', 'online');
6cb1b93e 105 $mform->display();
61240489 106 } else {
01e0da58 107 echo $OUTPUT->box_start('generalbox boxwidthwide boxaligncenter', 'online');
728e1931 108 if ($submission && has_capability('mod/assignment:exportownsubmission', $this->context)) {
007772d6 109 $text = file_rewrite_pluginfile_urls($submission->data1, 'pluginfile.php', $this->context->id, 'assignment_online_submission', $submission->id);
c561f44c 110 echo format_text($text, $submission->data2);
0d06b6fd 111 $button = new portfolio_add_button();
5fb29115 112 $button->set_callback_options('assignment_portfolio_caller', array('id' => $this->cm->id), '/mod/assignment/locallib.php');
df346604
PL
113 $fs = get_file_storage();
114 if ($files = $fs->get_area_files($this->context->id, 'assignment_online_submission', $submission->id, "timemodified", false)) {
115 $button->set_formats(PORTFOLIO_FORMAT_RICHHTML);
116 } else {
117 $button->set_formats(PORTFOLIO_FORMAT_PLAINHTML);
118 }
0d06b6fd 119 $button->render();
61240489 120 } else if (!has_capability('mod/assignment:submit', $context)) { //fix for #4604
d9cb14b8 121 echo '<div style="text-align:center">'. get_string('guestnosubmit', 'assignment').'</div>';
61240489 122 } else if ($this->isopen()){ //fix for #4206
d9cb14b8 123 echo '<div style="text-align:center">'.get_string('emptysubmission', 'assignment').'</div>';
61240489 124 }
61240489 125 }
01e0da58 126 echo $OUTPUT->box_end();
12dce253 127 if (!$editmode && $editable) {
128 echo "<div style='text-align:center'>";
5c2ed7e2 129 echo $OUTPUT->single_button(new moodle_url('view.php', array('id'=>$this->cm->id, 'edit'=>'1')), get_string('editmysubmission', 'assignment'));
12dce253 130 echo "</div>";
131 }
6cb1b93e 132
61240489 133 }
f77cfb73 134
135 $this->view_feedback();
136
137 $this->view_footer();
138 }
139
3e7bf58a 140 /*
141 * Display the assignment dates
142 */
143 function view_dates() {
3a003ead 144 global $USER, $CFG, $OUTPUT;
3e7bf58a 145
146 if (!$this->assignment->timeavailable && !$this->assignment->timedue) {
147 return;
148 }
149
3a003ead 150 echo $OUTPUT->box_start('generalbox boxaligncenter', 'dates');
3e7bf58a 151 echo '<table>';
152 if ($this->assignment->timeavailable) {
153 echo '<tr><td class="c0">'.get_string('availabledate','assignment').':</td>';
154 echo ' <td class="c1">'.userdate($this->assignment->timeavailable).'</td></tr>';
155 }
156 if ($this->assignment->timedue) {
157 echo '<tr><td class="c0">'.get_string('duedate','assignment').':</td>';
158 echo ' <td class="c1">'.userdate($this->assignment->timedue).'</td></tr>';
159 }
160 $submission = $this->get_submission($USER->id);
161 if ($submission) {
162 echo '<tr><td class="c0">'.get_string('lastedited').':</td>';
163 echo ' <td class="c1">'.userdate($submission->timemodified);
1884f2a6 164 /// Decide what to count
165 if ($CFG->assignment_itemstocount == ASSIGNMENT_COUNT_WORDS) {
166 echo ' ('.get_string('numwords', '', count_words(format_text($submission->data1, $submission->data2))).')</td></tr>';
167 } else if ($CFG->assignment_itemstocount == ASSIGNMENT_COUNT_LETTERS) {
168 echo ' ('.get_string('numletters', '', count_letters(format_text($submission->data1, $submission->data2))).')</td></tr>';
169 }
3e7bf58a 170 }
171 echo '</table>';
3a003ead 172 echo $OUTPUT->box_end();
3e7bf58a 173 }
174
f77cfb73 175 function update_submission($data) {
74d7d735 176 global $CFG, $USER, $DB;
f77cfb73 177
178 $submission = $this->get_submission($USER->id, true);
179
6cb1b93e 180 $update = new object();
181 $update->id = $submission->id;
182 $update->data1 = $data->text;
183 $update->data2 = $data->format;
0cbc1f11 184 $update->timemodified = time();
f77cfb73 185
9d749339 186 $DB->update_record('assignment_submissions', $update);
12dce253 187
188 $submission = $this->get_submission($USER->id);
189 $this->update_grade($submission);
190 return true;
f77cfb73 191 }
192
193
9bf660b3 194 function print_student_answer($userid, $return=false){
f2a1963c 195 global $OUTPUT;
9bf660b3 196 if (!$submission = $this->get_submission($userid)) {
197 return '';
198 }
e7521559 199
9bf16314
PS
200 $link = new moodle_url("/mod/assignment/type/online/file.php?id={$this->cm->id}&userid={$submission->userid}");
201 $action = new popup_action('click', $link, 'file'.$userid, array('height' => 450, 'width' => 580));
202 $popup = $OUTPUT->action_link($link, shorten_text(trim(strip_tags(format_text($submission->data1,$submission->data2))), 15), $action, array('title'=>get_string('submission', 'assignment')));
e7521559 203
9bf660b3 204 $output = '<div class="files">'.
b5d0cafc 205 '<img src="'.$OUTPUT->pix_url('f/html') . '" class="icon" alt="html" />'.
a9573c08 206 $popup .
9bf660b3 207 '</div>';
208 return $output;
209 }
6cb1b93e 210
f77cfb73 211 function print_user_files($userid, $return=false) {
47c96a77 212 global $OUTPUT, $CFG;
6cb1b93e 213
f77cfb73 214 if (!$submission = $this->get_submission($userid)) {
215 return '';
216 }
e7521559 217
9bf16314
PS
218 $link = new moodle_url("/mod/assignment/type/online/file.php?id={$this->cm->id}&userid={$submission->userid}");
219 $action = new popup_action('click', $link, 'file'.$userid, array('height' => 450, 'width' => 580));
220 $popup = $OUTPUT->action_link($link, shorten_text(trim(strip_tags(format_text($submission->data1,$submission->data2))), 15), $action, array('title'=>get_string('submission', 'assignment')));
6cb1b93e 221
f77cfb73 222 $output = '<div class="files">'.
b5d0cafc 223 '<img align="middle" src="'.$OUTPUT->pix_url('f/html') . '" height="16" width="16" alt="html" />'.
a9573c08 224 $popup .
f77cfb73 225 '</div>';
226
9bf660b3 227 ///Stolen code from file.php
6cb1b93e 228
3a003ead 229 echo $OUTPUT->box_start('generalbox boxaligncenter', 'wordcount');
63d69d54 230 /// Decide what to count
231 if ($CFG->assignment_itemstocount == ASSIGNMENT_COUNT_WORDS) {
232 echo ' ('.get_string('numwords', '', count_words(format_text($submission->data1, $submission->data2))).')';
233 } else if ($CFG->assignment_itemstocount == ASSIGNMENT_COUNT_LETTERS) {
234 echo ' ('.get_string('numletters', '', count_letters(format_text($submission->data1, $submission->data2))).')';
235 }
3a003ead 236 echo $OUTPUT->box_end();
237 echo $OUTPUT->box(format_text($submission->data1, $submission->data2), 'generalbox boxaligncenter boxwidthwide');
6cb1b93e 238
9bf660b3 239 ///End of stolen code from file.php
6cb1b93e 240
f77cfb73 241 if ($return) {
9bf660b3 242 //return $output;
f77cfb73 243 }
9bf660b3 244 //echo $output;
f77cfb73 245 }
246
01e2fdfe 247 function preprocess_submission(&$submission) {
ea6432fe 248 if ($this->assignment->var1 && empty($submission->submissioncomment)) { // comment inline
47263937 249 if ($this->usehtmleditor) {
250 // Convert to html, clean & copy student data to teacher
ea6432fe 251 $submission->submissioncomment = format_text($submission->data1, $submission->data2);
6cb1b93e 252 $submission->format = FORMAT_HTML;
47263937 253 } else {
254 // Copy student data to teacher
ea6432fe 255 $submission->submissioncomment = $submission->data1;
6cb1b93e 256 $submission->format = $submission->data2;
47263937 257 }
01e2fdfe 258 }
259 }
260
436cfa9f 261 function setup_elements(&$mform) {
262 global $CFG, $COURSE;
263
264 $ynoptions = array( 0 => get_string('no'), 1 => get_string('yes'));
265
266 $mform->addElement('select', 'resubmit', get_string("allowresubmit", "assignment"), $ynoptions);
267 $mform->setHelpButton('resubmit', array('resubmit', get_string('allowresubmit', 'assignment'), 'assignment'));
268 $mform->setDefault('resubmit', 0);
269
270 $mform->addElement('select', 'emailteachers', get_string("emailteachers", "assignment"), $ynoptions);
271 $mform->setHelpButton('emailteachers', array('emailteachers', get_string('emailteachers', 'assignment'), 'assignment'));
272 $mform->setDefault('emailteachers', 0);
273
274 $mform->addElement('select', 'var1', get_string("commentinline", "assignment"), $ynoptions);
275 $mform->setHelpButton('var1', array('commentinline', get_string('commentinline', 'assignment'), 'assignment'));
276 $mform->setDefault('var1', 0);
277
278 }
279
67a87e7d 280 function portfolio_exportable() {
281 return true;
282 }
ffcfd8a7 283
df346604
PL
284 function portfolio_load_data($caller) {
285 $submission = $this->get_submission();
286 $fs = get_file_storage();
287 if ($files = $fs->get_area_files($this->context->id, 'assignment_online_submission', $submission->id, "timemodified", false)) {
288 $caller->set('multifiles', $files);
289 }
290 }
291
292 function portfolio_get_sha1($caller) {
293 $submission = $this->get_submission();
294 $textsha1 = sha1(format_text($submission->data1, $submission->data2));
295 $filesha1 = '';
296 try {
297 $filesha1 = $caller->get_sha1_file();
298 } catch (portfolio_caller_exception $e) {} // no files
299 return sha1($textsha1 . $filesha1);
ffcfd8a7 300 }
301
df346604
PL
302 function portfolio_prepare_package($exporter, $user) {
303 $submission = $this->get_submission($user->id);
59dd457e 304 $html = format_text($submission->data1, $submission->data2);
df346604
PL
305 $html = portfolio_rewrite_pluginfile_urls($html, $this->context->id, 'assignment_online_submission', $submission->id, $exporter->get('format'));
306 if (in_array($exporter->get('formatclass'), array(PORTFOLIO_FORMAT_PLAINHTML, PORTFOLIO_FORMAT_RICHHTML))) {
307 if ($files = $exporter->get('caller')->get('multifiles')) {
308 foreach ($files as $f) {
309 $exporter->copy_existing_file($file);
310 }
311 }
312 return $exporter->write_new_file($html, 'assignment.html', !empty($files));
59dd457e
PL
313 } else if ($exporter->get('formatclass') == PORTFOLIO_FORMAT_LEAP2A) {
314 $leapwriter = $exporter->get('format')->leap2a_writer();
df346604 315 $entry = new portfolio_format_leap2a_entry('assignmentonline' . $this->assignment->id, $this->assignment->name, 'resource', $html);
59dd457e 316 $entry->add_category('web', 'resource_type');
df346604
PL
317 $entry->published = $submission->timecreated;
318 $entry->updated = $submission->timemodified;
319 $entry->author = $user;
59dd457e 320 $leapwriter->add_entry($entry);
df346604
PL
321 if ($files = $exporter->get('caller')->get('multifiles')) {
322 foreach ($files as $f) {
323 $exporter->copy_existing_file($f);
324 $entry->add_attachment($f);
325 }
326 }
327 $exporter->write_new_file($leapwriter->to_xml(), $exporter->get('format')->manifest_name(), true);
59dd457e 328 } else {
df346604 329 debugging('invalid format class: ' . $exporter->get('formatclass'));
59dd457e 330 }
ea0de12f 331 }
47c96a77 332
333 function extend_settings_navigation($node) {
334 global $PAGE, $CFG, $USER;
335
336 // get users submission if there is one
337 $submission = $this->get_submission();
338 if (has_capability('mod/assignment:submit', $PAGE->cm->context)) {
339 $editable = $this->isopen() && (!$submission || $this->assignment->resubmit || !$submission->timemarked);
340 } else {
341 $editable = false;
342 }
343
344 // If the user has submitted something add a bit more stuff
345 if ($submission) {
346 // Add a view link to the settings nav
a6855934 347 $link = new moodle_url('/mod/assignment/view.php', array('id'=>$PAGE->cm->id));
47c96a77 348 $node->add(get_string('viewmysubmission', 'assignment'), $link, navigation_node::TYPE_SETTING);
349
350 if (!empty($submission->timemodified)) {
3406acde
SH
351 $submittednode = $node->add(get_string('submitted', 'assignment') . ' ' . userdate($submission->timemodified));
352 $submittednode->text = preg_replace('#([^,])\s#', '$1&nbsp;', $submittednode->text);
353 $submittednode->add_class('note');
47c96a77 354 if ($submission->timemodified <= $this->assignment->timedue || empty($this->assignment->timedue)) {
3406acde 355 $submittednode->add_class('early');
47c96a77 356 } else {
3406acde 357 $submittednode->add_class('late');
47c96a77 358 }
359 }
360 }
361
362 if (!$submission || $editable) {
363 // If this assignment is editable once submitted add an edit link to the settings nav
a6855934 364 $link = new moodle_url('/mod/assignment/view.php', array('id'=>$PAGE->cm->id, 'edit'=>1, 'sesskey'=>sesskey()));
47c96a77 365 $node->add(get_string('editmysubmission', 'assignment'), $link, navigation_node::TYPE_SETTING);
366 }
367 }
c561f44c
SH
368
369 public function send_file($filearea, $args) {
ff284987 370 global $USER;
c561f44c
SH
371 require_capability('mod/assignment:view', $this->context);
372
373 $fullpath = $this->context->id.$filearea.implode('/', $args);
374
ff284987 375 $fs = get_file_storage();
c561f44c
SH
376 if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
377 send_file_not_found();
378 }
379
380 if (($USER->id != $file->get_userid()) && !has_capability('mod/assignment:grade', $this->context)) {
381 send_file_not_found();
382 }
383
384 session_get_instance()->write_close(); // unlock session during fileserving
385 send_stored_file($file, 60*60, 0, true);
386 }
b37ce778
DM
387
388 /**
389 * creates a zip of all assignment submissions and sends a zip to the browser
390 */
391 public function download_submissions() {
392 global $CFG, $DB;
393 require_once($CFG->libdir.'/filelib.php');
394
395 $submissions = $this->get_submissions('','');
396 if (empty($submissions)) {
397 error("there are no submissions to download");
398 }
399 $filesforzipping = array();
400 $tempdir = assignment_create_temp_dir($CFG->dataroot."/temp/", "assignment".$this->assignment->id); //location for temp files.
401 //online assignment can use html
402 $filextn=".html";
403
404 $groupmode = groupmode($this->course,$this->cm);
405 $groupid = 0; // All users
406 $groupname = '';
407 if($groupmode) {
408 $group = get_current_group($this->course->id, true);
409 $groupid = $group->id;
410 $groupname = $group->name.'-';
411 }
412 $filename = str_replace(' ', '_', clean_filename($this->course->shortname.'-'.$this->assignment->name.'-'.$groupname.$this->assignment->id.".zip")); //name of new zip file.
413 foreach ($submissions as $submission) {
414 $a_userid = $submission->userid; //get userid
415 if ((groups_is_member($groupid,$a_userid)or !$groupmode or !$groupid)) {
416 $a_assignid = $submission->assignment; //get name of this assignment for use in the file names.
417 $a_user = $DB->get_record("user", array("id"=>$a_userid),'id,username,firstname,lastname'); //get user firstname/lastname
418 $submissioncontent = "<html><body>". $submission->data1. "</body></html>"; //fetched from database
419 //get file name.html
420 $fileforzipname = $a_user->username . "_" . clean_filename($this->assignment->name) . $filextn;
421 $fd = fopen($tempdir . $fileforzipname,'wb'); //create if not exist, write binary
422 fwrite( $fd, $submissioncontent);
423 fclose( $fd );
424 $filesforzipping[$fileforzipname] = $tempdir.$fileforzipname;
425 }
426 } //end of foreach
427 if ($zipfile = assignment_pack_files($filesforzipping)) {
428 remove_dir($tempdir); //remove old tempdir with individual files.
429 send_temp_file($zipfile, $filename); //send file and delete after sending.
430 }
431 }
f77cfb73 432}
433
f07b9627 434class mod_assignment_online_edit_form extends moodleform {
c561f44c
SH
435
436 public function set_data($data) {
c561f44c
SH
437 $editoroptions = $this->get_editor_options();
438 if (!isset($data->text)) {
439 $data->text = '';
440 }
441 if (!isset($data->format)) {
442 $data->textformat = FORMAT_HTML;
443 } else {
444 $data->textformat = $data->format;
445 }
007772d6
SH
446
447 if (!empty($this->_customdata->submission->id)) {
448 $itemid = $this->_customdata->submission->id;
449 } else {
450 $itemid = null;
451 }
452
453 $data = file_prepare_standard_editor($data, 'text', $editoroptions, $this->_customdata->context, $editoroptions['filearea'], $itemid);
c561f44c
SH
454 return parent::set_data($data);
455 }
456
457 public function get_data() {
c561f44c 458 $data = parent::get_data();
007772d6
SH
459
460 if (!empty($this->_customdata->submission->id)) {
461 $itemid = $this->_customdata->submission->id;
462 } else {
463 $itemid = null;
464 }
465
c561f44c
SH
466 if ($data) {
467 $editoroptions = $this->get_editor_options();
007772d6 468 $data = file_postupdate_standard_editor($data, 'text', $editoroptions, $this->_customdata->context, $editoroptions['filearea'], $itemid);
c561f44c
SH
469 $data->format = $data->textformat;
470 }
471 return $data;
472 }
473
6cb1b93e 474 function definition() {
475 $mform =& $this->_form;
476
477 // visible elements
c561f44c
SH
478 $mform->addElement('editor', 'text_editor', get_string('submission', 'assignment'), null, $this->get_editor_options());
479 $mform->setType('text_editor', PARAM_RAW); // to be cleaned before display
480 $mform->setHelpButton('text_editor', array('reading', 'writing', 'richtext2'), false, 'editorhelpbutton');
481 $mform->addRule('text_editor', get_string('required'), 'required', null, 'client');
6cb1b93e 482
6117edc7 483 // hidden params
6cb1b93e 484 $mform->addElement('hidden', 'id', 0);
485 $mform->setType('id', PARAM_INT);
486
487 // buttons
a23f0aaf 488 $this->add_action_buttons();
6cb1b93e 489 }
c561f44c
SH
490
491 protected function get_editor_options() {
c561f44c
SH
492 $editoroptions = array();
493 $editoroptions['filearea'] = 'assignment_online_submission';
494 $editoroptions['noclean'] = false;
495 $editoroptions['maxfiles'] = EDITOR_UNLIMITED_FILES;
9e6b608f 496 $editoroptions['maxbytes'] = $this->_customdata->maxbytes;
c561f44c
SH
497 return $editoroptions;
498 }
6cb1b93e 499}
500
e7521559 501