MDL-15758 - remove dependence on 'userid' callback parameter in assignment portfolio...
[moodle.git] / mod / assignment / type / upload / assignment.class.php
1 <?php // $Id$
2 require_once($CFG->libdir . '/portfoliolib.php');
3 require_once($CFG->dirroot . '/mod/assignment/lib.php');
5 define('ASSIGNMENT_STATUS_SUBMITTED', 'submitted'); // student thinks it is finished
6 define('ASSIGNMENT_STATUS_CLOSED', 'closed');       // teacher prevents more submissions
8 /**
9  * Extend the base assignment class for assignments where you upload a single file
10  *
11  */
12 class assignment_upload extends assignment_base {
14     function assignment_upload($cmid='staticonly', $assignment=NULL, $cm=NULL, $course=NULL) {
15         parent::assignment_base($cmid, $assignment, $cm, $course);
16         $this->type = 'upload';
17     }
19     function view() {
20         global $USER;
22         require_capability('mod/assignment:view', $this->context);
24         add_to_log($this->course->id, 'assignment', 'view', "view.php?id={$this->cm->id}", $this->assignment->id, $this->cm->id);
26         $this->view_header();
28         if ($this->assignment->timeavailable > time()
29           and !has_capability('mod/assignment:grade', $this->context)      // grading user can see it anytime
30           and $this->assignment->var3) {                                   // force hiding before available date
31             print_simple_box_start('center', '', '', 0, 'generalbox', 'intro');
32             print_string('notavailableyet', 'assignment');
33             print_simple_box_end();
34         } else {
35             $this->view_intro();
36         }
38         $this->view_dates();
40         if (has_capability('mod/assignment:submit', $this->context)) {
41             $filecount = $this->count_user_files($USER->id);
42             $submission = $this->get_submission($USER->id);
44             $this->view_feedback();
46             if (!$this->drafts_tracked() or !$this->isopen() or $this->is_finalized($submission)) {
47                 print_heading(get_string('submission', 'assignment'), '', 3);
48             } else {
49                 print_heading(get_string('submissiondraft', 'assignment'), '', 3);
50             }
52             if ($filecount and $submission) {
53                 print_simple_box($this->print_user_files($USER->id, true), 'center');
54             } else {
55                 if (!$this->isopen() or $this->is_finalized($submission)) {
56                     print_simple_box(get_string('nofiles', 'assignment'), 'center');
57                 } else {
58                     print_simple_box(get_string('nofilesyet', 'assignment'), 'center');
59                 }
60             }
62             $this->view_upload_form();
64             if ($this->notes_allowed()) {
65                 print_heading(get_string('notes', 'assignment'), '', 3);
66                 $this->view_notes();
67             }
69             $this->view_final_submission();
70         }
71         $this->view_footer();
72     }
75     function view_feedback($submission=NULL) {
76         global $USER, $CFG, $DB;
77         require_once($CFG->libdir.'/gradelib.php');
79         if (!$submission) { /// Get submission for this assignment
80             $submission = $this->get_submission($USER->id);
81         }
83         if (empty($submission->timemarked)) {   /// Nothing to show, so print nothing
84             if ($this->count_responsefiles($USER->id)) {
85                 print_heading(get_string('responsefiles', 'assignment', $this->course->teacher), '', 3);
86                 $responsefiles = $this->print_responsefiles($USER->id, true);
87                 print_simple_box($responsefiles, 'center');
88             }
89             return;
90         }
92         $grading_info = grade_get_grades($this->course->id, 'mod', 'assignment', $this->assignment->id, $USER->id);
93         $item = $grading_info->items[0];
94         $grade = $item->grades[$USER->id];
96         if ($grade->hidden or $grade->grade === false) { // hidden or error
97             return;
98         }
100         if ($grade->grade === null and empty($grade->str_feedback)) {   /// Nothing to show yet
101             return;
102         }
104         $graded_date = $grade->dategraded;
105         $graded_by   = $grade->usermodified;
107     /// We need the teacher info
108         if (!$teacher = $DB->get_record('user', array('id'=>$graded_by))) {
109             print_error('cannotfindteacher');
110         }
112     /// Print the feedback
113         print_heading(get_string('submissionfeedback', 'assignment'), '', 3);
115         echo '<table cellspacing="0" class="feedback">';
117         echo '<tr>';
118         echo '<td class="left picture">';
119         print_user_picture($teacher, $this->course->id, $teacher->picture);
120         echo '</td>';
121         echo '<td class="topic">';
122         echo '<div class="from">';
123         echo '<div class="fullname">'.fullname($teacher).'</div>';
124         echo '<div class="time">'.userdate($graded_date).'</div>';
125         echo '</div>';
126         echo '</td>';
127         echo '</tr>';
129         echo '<tr>';
130         echo '<td class="left side">&nbsp;</td>';
131         echo '<td class="content">';
132         if ($this->assignment->grade) {
133             echo '<div class="grade">';
134             echo get_string("grade").': '.$grade->str_long_grade;
135             echo '</div>';
136             echo '<div class="clearer"></div>';
137         }
139         echo '<div class="comment">';
140         echo $grade->str_feedback;
141         echo '</div>';
142         echo '</tr>';
144         echo '<tr>';
145         echo '<td class="left side">&nbsp;</td>';
146         echo '<td class="content">';
147         echo $this->print_responsefiles($USER->id, true);
148         echo '</tr>';
150         echo '</table>';
151     }
154     function view_upload_form() {
155         global $CFG, $USER;
157         $submission = $this->get_submission($USER->id);
159         if ($this->is_finalized($submission)) {
160             // no uploading
161             return;
162         }
164         if ($this->can_upload_file($submission)) {
165             $mform = new mod_assignment_upload_file_form('upload.php', $this);
166             $mform->display();
167         }
169     }
171     function view_notes() {
172         global $USER;
174         if ($submission = $this->get_submission($USER->id)
175           and !empty($submission->data1)) {
176             print_simple_box(format_text($submission->data1, FORMAT_HTML), 'center', '630px');
177         } else {
178             print_simple_box(get_string('notesempty', 'assignment'), 'center');
179         }
180         if ($this->can_update_notes($submission)) {
181             $options = array ('id'=>$this->cm->id, 'action'=>'editnotes');
182             echo '<div style="text-align:center">';
183             print_single_button('upload.php', $options, get_string('edit'), 'post', '_self', false);
184             echo '</div>';
185         }
186     }
188     function view_final_submission() {
189         global $CFG, $USER;
191         $submission = $this->get_submission($USER->id);
193         if ($this->isopen() and $this->can_finalize($submission)) {
194             //print final submit button
195             print_heading(get_string('submitformarking','assignment'), '', 3);
196             echo '<div style="text-align:center">';
197             echo '<form method="post" action="upload.php">';
198             echo '<fieldset class="invisiblefieldset">';
199             echo '<input type="hidden" name="id" value="'.$this->cm->id.'" />';
200             echo '<input type="hidden" name="action" value="finalize" />';
201             echo '<input type="submit" name="formarking" value="'.get_string('sendformarking', 'assignment').'" />';
202             echo '</fieldset>';
203             echo '</form>';
204             echo '</div>';
205         } else if (!$this->isopen()) {
206             print_heading(get_string('nomoresubmissions','assignment'), '', 3);
208         } else if ($this->drafts_tracked() and $state = $this->is_finalized($submission)) {
209             if ($state == ASSIGNMENT_STATUS_SUBMITTED) {
210                 print_heading(get_string('submitedformarking','assignment'), '', 3);
211             } else {
212                 print_heading(get_string('nomoresubmissions','assignment'), '', 3);
213             }
214         } else {
215             //no submission yet
216         }
217     }
220     /**
221      * Return true if var3 == hide description till available day
222      *
223      *@return boolean
224      */
225     function description_is_hidden() {
226         return ($this->assignment->var3 && (time() <= $this->assignment->timeavailable));
227     }
229     function custom_feedbackform($submission, $return=false) {
230         global $CFG;
232         $mode         = optional_param('mode', '', PARAM_ALPHA);
233         $offset       = optional_param('offset', 0, PARAM_INT);
234         $forcerefresh = optional_param('forcerefresh', 0, PARAM_BOOL);
236         $mform = new mod_assignment_upload_response_form("$CFG->wwwroot/mod/assignment/upload.php", $this);
238         $mform->set_data(array('id'=>$this->cm->id, 'offset'=>$offset, 'forcerefresh'=>$forcerefresh, 'userid'=>$submission->userid, 'mode'=>$mode));
240         $output = get_string('responsefiles', 'assignment').': ';
242         ob_start();
243         $mform->display();
244         $output = ob_get_clean();
246         if ($forcerefresh) {
247             $output .= $this->update_main_listing($submission);
248         }
250         $responsefiles = $this->print_responsefiles($submission->userid, true);
251         if (!empty($responsefiles)) {
252             $output .= $responsefiles;
253         }
255         if ($return) {
256             return $output;
257         }
258         echo $output;
259         return;
260     }
263     function print_student_answer($userid, $return=false){
264         global $CFG;
266         $submission = $this->get_submission($userid);
268         $output = '';
270         if ($this->drafts_tracked() and $this->isopen() and !$this->is_finalized($submission)) {
271             $output .= '<strong>'.get_string('draft', 'assignment').':</strong> ';
272         }
274         if ($this->notes_allowed() and !empty($submission->data1)) {
275             $output .= link_to_popup_window ('/mod/assignment/type/upload/notes.php?id='.$this->cm->id.'&amp;userid='.$userid,
276                                             'notes'.$userid, get_string('notes', 'assignment'), 500, 780, get_string('notes', 'assignment'), 'none', true, 'notesbutton'.$userid);
277             $output .= '&nbsp;';
278         }
280         $fs = get_file_storage();
281         $browser = get_file_browser();
283         if ($files = $fs->get_area_files($this->context->id, 'assignment_submission', $userid, "timemodified", false)) {
285             foreach ($files as $file) {
286                 $filename = $file->get_filename();
287                 $found = true;
288                 $mimetype = $file->get_mimetype();
289                 $icon = mimeinfo_from_type('icon', $mimetype);
290                 $path = $browser->encodepath($CFG->wwwroot.'/pluginfile.php', '/'.$this->context->id.'/assignment_submission/'.$userid.'/'.$filename);
291                 $output .= '<a href="'.$path.'" ><img class="icon" src="'.$CFG->pixpath.'/f/'.$icon.'" alt="'.$icon.'" />'.s($filename).'</a>&nbsp;';
292     
293             }
295         }
296         $output = '<div class="files">'.$output.'</div>';
297         $output .= '<br />';
299         return $output;
300     }
303     /**
304      * Produces a list of links to the files uploaded by a user
305      *
306      * @param $userid int optional id of the user. If 0 then $USER->id is used.
307      * @param $return boolean optional defaults to false. If true the list is returned rather than printed
308      * @return string optional
309      */
310     function print_user_files($userid=0, $return=false) {
311         global $CFG, $USER;
313         $mode    = optional_param('mode', '', PARAM_ALPHA);
314         $offset  = optional_param('offset', 0, PARAM_INT);
316         if (!$userid) {
317             if (!isloggedin()) {
318                 return '';
319             }
320             $userid = $USER->id;
321         }
323         $output = '';
325         $submission = $this->get_submission($userid);
327         $candelete = $this->can_delete_files($submission);
328         $strdelete   = get_string('delete');
330         if ($this->drafts_tracked() and $this->isopen() and !$this->is_finalized($submission) and !empty($mode)) {                 // only during grading
331             $output .= '<strong>'.get_string('draft', 'assignment').':</strong><br />';
332         }
334         if ($this->notes_allowed() and !empty($submission->data1) and !empty($mode)) { // only during grading
336             $npurl = $CFG->wwwroot."/mod/assignment/type/upload/notes.php?id={$this->cm->id}&amp;userid=$userid&amp;offset=$offset&amp;mode=single";
337             $output .= '<a href="'.$npurl.'">'.get_string('notes', 'assignment').'</a><br />';
339         }
341         $fs = get_file_storage();
342         $browser = get_file_browser();
344         if ($files = $fs->get_area_files($this->context->id, 'assignment_submission', $userid, "timemodified", false)) {
345             $p = array(
346                 'assignmentid' => $this->cm->id,
347             );
348             foreach ($files as $file) {
349                 $filename = $file->get_filename();
350                 $mimetype = $file->get_mimetype();
351                 $icon = mimeinfo_from_type('icon', $mimetype);
352                 $path = $browser->encodepath($CFG->wwwroot.'/pluginfile.php', '/'.$this->context->id.'/assignment_submission/'.$userid.'/'.$filename);
353                 $output .= '<a href="'.$path.'" ><img src="'.$CFG->pixpath.'/f/'.$icon.'" class="icon" alt="'.$icon.'" />'.s($filename).'</a>';
354     
355                 if ($candelete) {
356                     $delurl  = "$CFG->wwwroot/mod/assignment/delete.php?id={$this->cm->id}&amp;file=".rawurlencode($filename)."&amp;userid={$submission->userid}&amp;mode=$mode&amp;offset=$offset";
357     
358                     $output .= '<a href="'.$delurl.'">&nbsp;'
359                               .'<img title="'.$strdelete.'" src="'.$CFG->pixpath.'/t/delete.gif" class="iconsmall" alt="" /></a> ';
360                 }
361     
362                 if (has_capability('mod/assignment:exportownsubmission', $this->context)) {
363                     $p['file'] = $file->get_id();
364                     $output .= portfolio_add_button('assignment_portfolio_caller', $p, '/mod/assignment/lib.php', PORTFOLIO_ADD_ICON_LINK, null, true);
365                 }
366                 $output .= '<br />';
367             }
368             if (has_capability('mod/assignment:exportownsubmission', $this->context)) {
369                 unset($p['file']);// for all files
370                 $output .= '<br />' . portfolio_add_button('assignment_portfolio_caller', $p, '/mod/assignment/lib.php', null, null, true);
371             }
372         }
374         if ($this->drafts_tracked() and $this->isopen() and has_capability('mod/assignment:grade', $this->context) and $mode != '') { // we do not want it on view.php page
375             if ($this->can_unfinalize($submission)) {
376                 $options = array ('id'=>$this->cm->id, 'userid'=>$userid, 'action'=>'unfinalize', 'mode'=>$mode, 'offset'=>$offset);
377                 $output .= print_single_button('upload.php', $options, get_string('unfinalize', 'assignment'), 'post', '_self', true);
378             } else if ($this->can_finalize($submission)) {
379                 $options = array ('id'=>$this->cm->id, 'userid'=>$userid, 'action'=>'finalizeclose', 'mode'=>$mode, 'offset'=>$offset);
380                 $output .= print_single_button('upload.php', $options, get_string('finalize', 'assignment'), 'post', '_self', true);
381             }
382         }
384         $output = '<div class="files">'.$output.'</div>';
386         if ($return) {
387             return $output;
388         }
389         echo $output;
390     }
392     function print_responsefiles($userid, $return=false) {
393         global $CFG, $USER;
395         $mode    = optional_param('mode', '', PARAM_ALPHA);
396         $offset  = optional_param('offset', 0, PARAM_INT);
398         $output = '';
400         $candelete = $this->can_manage_responsefiles();
401         $strdelete   = get_string('delete');
403         $fs = get_file_storage();
404         $browser = get_file_browser();
406         if ($files = $fs->get_area_files($this->context->id, 'assignment_response', $userid, "timemodified", false)) {
407             foreach ($files as $file) {
408                 $filename = $file->get_filename();
409                 $found = true;
410                 $mimetype = $file->get_mimetype();
411                 $icon = mimeinfo_from_type('icon', $mimetype);
412                 $path = $browser->encodepath($CFG->wwwroot.'/pluginfile.php', '/'.$this->context->id.'/assignment_response/'.$userid.'/'.$filename);
414                 $output .= '<a href="'.$path.'" ><img src="'.$CFG->pixpath.'/f/'.$icon.'" alt="'.$icon.'" />'.$filename.'</a>';
416                 if ($candelete) {
417                     $delurl  = "$CFG->wwwroot/mod/assignment/delete.php?id={$this->cm->id}&amp;file=".rawurlencode($filename)."&amp;userid=$userid&amp;mode=$mode&amp;offset=$offset&amp;action=response";
419                     $output .= '<a href="'.$delurl.'">&nbsp;'
420                               .'<img title="'.$strdelete.'" src="'.$CFG->pixpath.'/t/delete.gif" class="iconsmall" alt=""/></a> ';
421                 }
423                 $output .= '&nbsp;';
424             }
426             $output = '<div class="responsefiles">'.$output.'</div>';
427         }
429         if ($return) {
430             return $output;
431         }
432         echo $output;
433     }
436     function upload() {
437         $action = required_param('action', PARAM_ALPHA);
439         switch ($action) {
440             case 'finalize':
441                 $this->finalize();
442                 break;
443             case 'finalizeclose':
444                 $this->finalizeclose();
445                 break;
446             case 'unfinalize':
447                 $this->unfinalize();
448                 break;
449             case 'uploadresponse':
450                 $this->upload_responsefile();
451                 break;
452             case 'uploadfile':
453                 $this->upload_file();
454             case 'savenotes':
455             case 'editnotes':
456                 $this->upload_notes();
457             default:
458                 print_error('unknowuploadaction', '', '', $action);
459         }
460     }
462     function upload_notes() {
463         global $CFG, $USER;
465         $action = required_param('action', PARAM_ALPHA);
467         $returnurl = 'view.php?id='.$this->cm->id;
469         $mform = new mod_assignment_upload_notes_form();
471         $defaults = new object();
472         $defaults->id = $this->cm->id;
474         if ($submission = $this->get_submission($USER->id)) {
475             $defaults->text = $submission->data1;
476         } else {
477             $defaults->text = '';
478         }
480         $mform->set_data($defaults);
482         if ($mform->is_cancelled()) {
483             redirect('view.php?id='.$this->cm->id);
484         }
486         if (!$this->can_update_notes($submission)) {
487             $this->view_header(get_string('upload'));
488             notify(get_string('uploaderror', 'assignment'));
489             print_continue($returnurl);
490             $this->view_footer();
491             die;
492         }
494         if ($data = $mform->get_data() and $action == 'savenotes') {
495             $submission = $this->get_submission($USER->id, true); // get or create submission
496             $updated = new object();
497             $updated->id           = $submission->id;
498             $updated->timemodified = time();
499             $updated->data1        = $data->text;
501             if ($DB->update_record('assignment_submissions', $updated)) {
502                 add_to_log($this->course->id, 'assignment', 'upload', 'view.php?a='.$this->assignment->id, $this->assignment->id, $this->cm->id);
503                 redirect($returnurl);
504                 $submission = $this->get_submission($USER->id);
505                 $this->update_grade($submission);
507             } else {
508                 $this->view_header(get_string('notes', 'assignment'));
509                 notify(get_string('notesupdateerror', 'assignment'));
510                 print_continue($returnurl);
511                 $this->view_footer();
512                 die;
513             }
514         }
516         /// show notes edit form
517         $this->view_header(get_string('notes', 'assignment'));
519         print_heading(get_string('notes', 'assignment'), '');
521         $mform->display();
523         $this->view_footer();
524         die;
525     }
527     function upload_responsefile() {
528         global $CFG, $USER;
530         $userid = required_param('userid', PARAM_INT);
531         $mode   = required_param('mode', PARAM_ALPHA);
532         $offset = required_param('offset', PARAM_INT);
534         $returnurl = "submissions.php?id={$this->cm->id}&amp;userid=$userid&amp;mode=$mode&amp;offset=$offset";
536         $mform = new mod_assignment_upload_response_form(null, $this);
537         if ($mform->get_data() and $this->can_manage_responsefiles()) {
538             $fs = get_file_storage();
539             $filename = $mform->get_new_filename('newfile');
540             if ($filename !== false) {
541                 if (!$fs->file_exists($this->context->id, 'assignment_response', $userid, '/', $filename)) {
542                     if ($file = $mform->save_stored_file('newfile', $this->context->id, 'assignment_response', $userid, '/', $filename, false, $USER->id)) {
543                         redirect($returnurl);
544                     }
545                 }
546             }
547         }
548         print_header(get_string('upload'));
549         notify(get_string('uploaderror', 'assignment'));
550         print_continue($returnurl);
551         print_footer('none');
552         die;
553     }
555     function upload_file() {
556         global $CFG, $USER, $DB;
558         $returnurl = 'view.php?id='.$this->cm->id;
560         $filecount = $this->count_user_files($USER->id);
561         $submission = $this->get_submission($USER->id);
563         if (!$this->can_upload_file($submission)) {
564             $this->view_header(get_string('upload'));
565             notify(get_string('uploaderror', 'assignment'));
566             print_continue($returnurl);
567             $this->view_footer();
568             die;
569         }
571         $mform = new mod_assignment_upload_file_form('upload.php', $this);
572         if ($mform->get_data()) {
573             $fs = get_file_storage();
574             $filename = $mform->get_new_filename('newfile');
575             if ($filename !== false) {
576                 if (!$fs->file_exists($this->context->id, 'assignment_submission', $USER->id, '/', $filename)) {
577                     if ($file = $mform->save_stored_file('newfile', $this->context->id, 'assignment_submission', $USER->id, '/', $filename, false, $USER->id)) {
578                         $submission = $this->get_submission($USER->id, true); //create new submission if needed
579                         $submission->timemodified = time();
580                         if ($DB->update_record('assignment_submissions', $submission)) {
581                             add_to_log($this->course->id, 'assignment', 'upload',
582                                     'view.php?a='.$this->assignment->id, $this->assignment->id, $this->cm->id);
583                             $this->update_grade($submission);
584                             if (!$this->drafts_tracked()) {
585                                 $this->email_teachers($submission);
586                             }
587                             redirect('view.php?id='.$this->cm->id);
588                         } else {
589                             $file->delete();
590                         }
591                     }
592                 }
593             }
594         }
596         $this->view_header(get_string('upload'));
597         notify(get_string('uploaderror', 'assignment'));
598         print_continue($returnurl);
599         $this->view_footer();
600         die;
601     }
603     function send_file($filearea, $args) {
604         global $CFG, $DB, $USER;
605         require_once($CFG->libdir.'/filelib.php');
607         require_login($this->course, false, $this->cm);
609         $userid = (int)array_shift($args);
610         $relativepath = '/'.implode('/', $args);
611         $fullpath = $this->context->id.$filearea.$userid.$relativepath;
613         $fs = get_file_storage();
615         if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
616             return false;
617         }
619         if ($filearea === 'assignment_submission') {
620             if ($USER->id != $userid and !has_capability('mod/assignment:grade', $this->context)) {
621                 return false;
622             }
624         } else if ($filearea === 'assignment_response') {
625             if ($USER->id != $userid and !has_capability('mod/assignment:grade', $this->context)) {
626                 return false;
627             }
629         } else {
630             return false;
631         }
633         send_stored_file($file, 0, 0, true); // download MUST be forced - security!
634     }
636     function finalize() {
637         global $USER, $DB;
639         $confirm    = optional_param('confirm', 0, PARAM_BOOL);
640         $returnurl  = 'view.php?id='.$this->cm->id;
641         $submission = $this->get_submission($USER->id);
643         if (!$this->can_finalize($submission)) {
644             redirect($returnurl); // probably already graded, redirect to assignment page, the reason should be obvious
645         }
647         if (!data_submitted() or !$confirm) {
648             $optionsno = array('id'=>$this->cm->id);
649             $optionsyes = array ('id'=>$this->cm->id, 'confirm'=>1, 'action'=>'finalize');
650             $this->view_header(get_string('submitformarking', 'assignment'));
651             print_heading(get_string('submitformarking', 'assignment'));
652             notice_yesno(get_string('onceassignmentsent', 'assignment'), 'upload.php', 'view.php', $optionsyes, $optionsno, 'post', 'get');
653             $this->view_footer();
654             die;
656         }
657         $updated = new object();
658         $updated->id           = $submission->id;
659         $updated->data2        = ASSIGNMENT_STATUS_SUBMITTED;
660         $updated->timemodified = time();
662         if ($DB->update_record('assignment_submissions', $updated)) {
663             add_to_log($this->course->id, 'assignment', 'upload', //TODO: add finalize action to log
664                     'view.php?a='.$this->assignment->id, $this->assignment->id, $this->cm->id);
665             $submission = $this->get_submission($USER->id);
666             $this->update_grade($submission);
667             $this->email_teachers($submission);
668         } else {
669             $this->view_header(get_string('submitformarking', 'assignment'));
670             notify(get_string('finalizeerror', 'assignment'));
671             print_continue($returnurl);
672             $this->view_footer();
673             die;
674         }
675         redirect($returnurl);
676     }
678     function finalizeclose() {
679         global $DB;
681         $userid    = optional_param('userid', 0, PARAM_INT);
682         $mode      = required_param('mode', PARAM_ALPHA);
683         $offset    = required_param('offset', PARAM_INT);
684         $returnurl = "submissions.php?id={$this->cm->id}&amp;userid=$userid&amp;mode=$mode&amp;offset=$offset&amp;forcerefresh=1";
686         // create but do not add student submission date
687         $submission = $this->get_submission($userid, true, true);
689         if (!data_submitted() or !$this->can_finalize($submission)) {
690             redirect($returnurl); // probably closed already
691         }
693         $updated = new object();
694         $updated->id    = $submission->id;
695         $updated->data2 = ASSIGNMENT_STATUS_CLOSED;
697         if ($DB->update_record('assignment_submissions', $updated)) {
698             add_to_log($this->course->id, 'assignment', 'upload', //TODO: add finalize action to log
699                     'view.php?a='.$this->assignment->id, $this->assignment->id, $this->cm->id);
700             $submission = $this->get_submission($userid, false, true);
701             $this->update_grade($submission);
702         }
703         redirect($returnurl);
704     }
706     function unfinalize() {
707         global $DB;
709         $userid = required_param('userid', PARAM_INT);
710         $mode   = required_param('mode', PARAM_ALPHA);
711         $offset = required_param('offset', PARAM_INT);
713         $returnurl = "submissions.php?id={$this->cm->id}&amp;userid=$userid&amp;mode=$mode&amp;offset=$offset&amp;forcerefresh=1";
715         if (data_submitted()
716           and $submission = $this->get_submission($userid)
717           and $this->can_unfinalize($submission)) {
719             $updated = new object();
720             $updated->id = $submission->id;
721             $updated->data2 = '';
722             if ($DB->update_record('assignment_submissions', $updated)) {
723                 //TODO: add unfinalize action to log
724                 add_to_log($this->course->id, 'assignment', 'view submission', 'submissions.php?id='.$this->assignment->id, $this->assignment->id, $this->cm->id);
725                 $submission = $this->get_submission($userid);
726                 $this->update_grade($submission);
727             } else {
728                 $this->view_header(get_string('submitformarking', 'assignment'));
729                 notify(get_string('unfinalizeerror', 'assignment'));
730                 print_continue($returnurl);
731                 $this->view_footer();
732                 die;
733             }
734         }
735         redirect($returnurl);
736     }
739     function delete() {
740         $action   = optional_param('action', '', PARAM_ALPHA);
742         switch ($action) {
743             case 'response':
744                 $this->delete_responsefile();
745                 break;
746             default:
747                 $this->delete_file();
748         }
749         die;
750     }
753     function delete_responsefile() {
754         global $CFG;
756         $file     = required_param('file', PARAM_FILE);
757         $userid   = required_param('userid', PARAM_INT);
758         $mode     = required_param('mode', PARAM_ALPHA);
759         $offset   = required_param('offset', PARAM_INT);
760         $confirm  = optional_param('confirm', 0, PARAM_BOOL);
762         $returnurl = "submissions.php?id={$this->cm->id}&amp;userid=$userid&amp;mode=$mode&amp;offset=$offset";
764         if (!$this->can_manage_responsefiles()) {
765            redirect($returnurl);
766         }
768         $urlreturn = 'submissions.php';
769         $optionsreturn = array('id'=>$this->cm->id, 'offset'=>$offset, 'mode'=>$mode, 'userid'=>$userid);
771         if (!data_submitted() or !$confirm) {
772             $optionsyes = array ('id'=>$this->cm->id, 'file'=>$file, 'userid'=>$userid, 'confirm'=>1, 'action'=>'response', 'mode'=>$mode, 'offset'=>$offset);
773             print_header(get_string('delete'));
774             print_heading(get_string('delete'));
775             notice_yesno(get_string('confirmdeletefile', 'assignment', $file), 'delete.php', $urlreturn, $optionsyes, $optionsreturn, 'post', 'get');
776             print_footer('none');
777             die;
778         }
780         $fs = get_file_storage();
781         if ($file = $fs->get_file($this->context->id, 'assignment_submission', $userid, '/', $file)) {
782             if ($file->delete()) {
783                 redirect($returnurl);
784             }
785         }
787         // print delete error
788         print_header(get_string('delete'));
789         notify(get_string('deletefilefailed', 'assignment'));
790         print_continue($returnurl);
791         print_footer('none');
792         die;
794     }
797     function delete_file() {
798         global $CFG, $DB;
800         $file     = required_param('file', PARAM_FILE);
801         $userid   = required_param('userid', PARAM_INT);
802         $confirm  = optional_param('confirm', 0, PARAM_BOOL);
803         $mode     = optional_param('mode', '', PARAM_ALPHA);
804         $offset   = optional_param('offset', 0, PARAM_INT);
806         require_login($this->course->id, false, $this->cm);
808         if (empty($mode)) {
809             $urlreturn = 'view.php';
810             $optionsreturn = array('id'=>$this->cm->id);
811             $returnurl = 'view.php?id='.$this->cm->id;
812         } else {
813             $urlreturn = 'submissions.php';
814             $optionsreturn = array('id'=>$this->cm->id, 'offset'=>$offset, 'mode'=>$mode, 'userid'=>$userid);
815             $returnurl = "submissions.php?id={$this->cm->id}&amp;offset=$offset&amp;mode=$mode&amp;userid=$userid";
816         }
818         if (!$submission = $this->get_submission($userid) // incorrect submission
819           or !$this->can_delete_files($submission)) {     // can not delete
820             $this->view_header(get_string('delete'));
821             notify(get_string('cannotdeletefiles', 'assignment'));
822             print_continue($returnurl);
823             $this->view_footer();
824             die;
825         }
827         if (!data_submitted() or !$confirm) {
828             $optionsyes = array ('id'=>$this->cm->id, 'file'=>$file, 'userid'=>$userid, 'confirm'=>1, 'sesskey'=>sesskey(), 'mode'=>$mode, 'offset'=>$offset);
829             if (empty($mode)) {
830                 $this->view_header(get_string('delete'));
831             } else {
832                 print_header(get_string('delete'));
833             }
834             print_heading(get_string('delete'));
835             notice_yesno(get_string('confirmdeletefile', 'assignment', $file), 'delete.php', $urlreturn, $optionsyes, $optionsreturn, 'post', 'get');
836             if (empty($mode)) {
837                 $this->view_footer();
838             } else {
839                 print_footer('none');
840             }
841             die;
842         }
844         $fs = get_file_storage();
845         if ($file = $fs->get_file($this->context->id, 'assignment_submission', $userid, '/', $file)) {
846             if ($file->delete()) {
847                 $submission->timemodified = time();
848                 if ($DB->update_record('assignment_submissions', $submission)) {
849                     add_to_log($this->course->id, 'assignment', 'upload', //TODO: add delete action to log
850                             'view.php?a='.$this->assignment->id, $this->assignment->id, $this->cm->id);
851                     $this->update_grade($submission);
852                 }
853                 redirect($returnurl);
854             }
855         }
857         // print delete error
858         if (empty($mode)) {
859             $this->view_header(get_string('delete'));
860         } else {
861             print_header(get_string('delete'));
862         }
863         notify(get_string('deletefilefailed', 'assignment'));
864         print_continue($returnurl);
865         if (empty($mode)) {
866             $this->view_footer();
867         } else {
868             print_footer('none');
869         }
870         die;
871     }
874     function can_upload_file($submission) {
875         global $USER;
877         if (has_capability('mod/assignment:submit', $this->context)           // can submit
878           and $this->isopen()                                                 // assignment not closed yet
879           and (empty($submission) or $submission->userid == $USER->id)        // his/her own submission
880           and $this->count_user_files($USER->id) < $this->assignment->var1    // file limit not reached
881           and !$this->is_finalized($submission)) {                            // no uploading after final submission
882             return true;
883         } else {
884             return false;
885         }
886     }
888     function can_manage_responsefiles() {
889         if (has_capability('mod/assignment:grade', $this->context)) {
890             return true;
891         } else {
892             return false;
893         }
894     }
896     function can_delete_files($submission) {
897         global $USER;
899         if (has_capability('mod/assignment:grade', $this->context)) {
900             return true;
901         }
903         if (has_capability('mod/assignment:submit', $this->context)
904           and $this->isopen()                                      // assignment not closed yet
905           and $this->assignment->resubmit                          // deleting allowed
906           and $USER->id == $submission->userid                     // his/her own submission
907           and !$this->is_finalized($submission)) {                 // no deleting after final submission
908             return true;
909         } else {
910             return false;
911         }
912     }
914     function drafts_tracked() {
915         return !empty($this->assignment->var4);
916     }
918     /**
919      * Returns submission status
920      * @param object $submission - may be empty
921      * @return string submission state - empty, ASSIGNMENT_STATUS_SUBMITTED or ASSIGNMENT_STATUS_CLOSED
922      */
923     function is_finalized($submission) {
924         if (!$this->drafts_tracked()) {
925             return '';
927         } else if (empty($submission)) {
928             return '';
930         } else if ($submission->data2 == ASSIGNMENT_STATUS_SUBMITTED or $submission->data2 == ASSIGNMENT_STATUS_CLOSED) {
931             return $submission->data2;
933         } else {
934             return '';
935         }
936     }
938     function can_unfinalize($submission) {
939         if (!$this->drafts_tracked()) {
940             return false;
941         }
942         if (has_capability('mod/assignment:grade', $this->context)
943           and $this->isopen()
944           and $this->is_finalized($submission)) {
945             return true;
946         } else {
947             return false;
948         }
949     }
951     function can_finalize($submission) {
952         global $USER;
953         if (!$this->drafts_tracked()) {
954             return false;
955         }
957                 if ($this->is_finalized($submission)) {
958                     return false;
959                 }
961         if (has_capability('mod/assignment:grade', $this->context)) {
962             return true;
964         } else if (has_capability('mod/assignment:submit', $this->context)    // can submit
965           and $this->isopen()                                                 // assignment not closed yet
966           and !empty($submission)                                             // submission must exist
967           and $submission->userid == $USER->id                                // his/her own submission
968           and ($this->count_user_files($USER->id)
969             or ($this->notes_allowed() and !empty($submission->data1)))) {    // something must be submitted
971             return true;
972         } else {
973             return false;
974         }
975     }
977     function can_update_notes($submission) {
978         global $USER;
980         if (has_capability('mod/assignment:submit', $this->context)
981           and $this->notes_allowed()                                          // notesd must be allowed
982           and $this->isopen()                                                 // assignment not closed yet
983           and (empty($submission) or $USER->id == $submission->userid)        // his/her own submission
984           and !$this->is_finalized($submission)) {                            // no updateingafter final submission
985             return true;
986         } else {
987             return false;
988         }
989     }
991     function notes_allowed() {
992         return (boolean)$this->assignment->var2;
993     }
995     function count_responsefiles($userid) {
996         $fs = get_file_storage();
997         $files = $fs->get_area_files($this->context->id, 'assignment_response', $userid, "id", false);
998         return count($files);
999     }
1001     function setup_elements(&$mform) {
1002         global $CFG, $COURSE;
1004         $ynoptions = array( 0 => get_string('no'), 1 => get_string('yes'));
1006         $choices = get_max_upload_sizes($CFG->maxbytes, $COURSE->maxbytes);
1007         $choices[0] = get_string('courseuploadlimit') . ' ('.display_size($COURSE->maxbytes).')';
1008         $mform->addElement('select', 'maxbytes', get_string('maximumsize', 'assignment'), $choices);
1009         $mform->setDefault('maxbytes', $CFG->assignment_maxbytes);
1011         $mform->addElement('select', 'resubmit', get_string("allowdeleting", "assignment"), $ynoptions);
1012         $mform->setHelpButton('resubmit', array('allowdeleting', get_string('allowdeleting', 'assignment'), 'assignment'));
1013         $mform->setDefault('resubmit', 1);
1015         $options = array();
1016         for($i = 1; $i <= 20; $i++) {
1017             $options[$i] = $i;
1018         }
1019         $mform->addElement('select', 'var1', get_string("allowmaxfiles", "assignment"), $options);
1020         $mform->setHelpButton('var1', array('allowmaxfiles', get_string('allowmaxfiles', 'assignment'), 'assignment'));
1021         $mform->setDefault('var1', 3);
1023         $mform->addElement('select', 'var2', get_string("allownotes", "assignment"), $ynoptions);
1024         $mform->setHelpButton('var2', array('allownotes', get_string('allownotes', 'assignment'), 'assignment'));
1025         $mform->setDefault('var2', 0);
1027         $mform->addElement('select', 'var3', get_string("hideintro", "assignment"), $ynoptions);
1028         $mform->setHelpButton('var3', array('hideintro', get_string('hideintro', 'assignment'), 'assignment'));
1029         $mform->setDefault('var3', 0);
1031         $mform->addElement('select', 'emailteachers', get_string("emailteachers", "assignment"), $ynoptions);
1032         $mform->setHelpButton('emailteachers', array('emailteachers', get_string('emailteachers', 'assignment'), 'assignment'));
1033         $mform->setDefault('emailteachers', 0);
1035         $mform->addElement('select', 'var4', get_string("trackdrafts", "assignment"), $ynoptions);
1036         $mform->setHelpButton('var4', array('trackdrafts', get_string('trackdrafts', 'assignment'), 'assignment'));
1037         $mform->setDefault('trackdrafts', 1);
1039     }
1041     function portfolio_exportable() {
1042         return true;
1043     }
1047 class mod_assignment_upload_notes_form extends moodleform {
1048     function definition() {
1049         $mform = $this->_form;
1051         // visible elements
1052         $mform->addElement('htmleditor', 'text', get_string('notes', 'assignment'), array('cols'=>85, 'rows'=>30));
1053         $mform->setType('text', PARAM_RAW); // to be cleaned before display
1054         $mform->setHelpButton('text', array('reading', 'writing'), false, 'editorhelpbutton');
1056         // hidden params
1057         $mform->addElement('hidden', 'id', 0);
1058         $mform->setType('id', PARAM_INT);
1059         $mform->addElement('hidden', 'action', 'savenotes');
1060         $mform->setType('action', PARAM_ALPHA);
1062         // buttons
1063         $this->add_action_buttons();
1064     }
1067 class mod_assignment_upload_response_form extends moodleform {
1068     function definition() {
1069         $mform = $this->_form;
1070         $instance = $this->_customdata;
1072         // visible elements
1073         $mform->addElement('file', 'newfile', get_string('uploadafile'));
1075         // hidden params
1076         $mform->addElement('hidden', 'id', $instance->cm->id);
1077         $mform->setType('id', PARAM_INT);
1078         $mform->addElement('hidden', 'action', 'uploadresponse');
1079         $mform->setType('action', PARAM_ALPHA);
1080         $mform->addElement('hidden', 'mode');
1081         $mform->setType('mode', PARAM_ALPHA);
1082         $mform->addElement('hidden', 'offset');
1083         $mform->setType('offset', PARAM_INT);
1084         $mform->addElement('hidden', 'forcerefresh');
1085         $mform->setType('forcerefresh', PARAM_INT);
1086         $mform->addElement('hidden', 'userid');
1087         $mform->setType('userid', PARAM_INT);
1089         // buttons
1090         $this->add_action_buttons(false, get_string('uploadthisfile'));
1091     }
1096 ?>