1d68566c336d8a215b0a5273d3092e26227cd9f3
[moodle.git] / mod / assignment / type / upload / assignment.class.php
1 <?php // $Id$
2 require_once($CFG->libdir.'/formslib.php');
3 require_once($CFG->libdir . '/portfoliolib.php');
4 require_once($CFG->dirroot . '/mod/assignment/lib.php');
6 define('ASSIGNMENT_STATUS_SUBMITTED', 'submitted'); // student thinks it is finished
7 define('ASSIGNMENT_STATUS_CLOSED', 'closed');       // teacher prevents more submissions
9 /**
10  * Extend the base assignment class for assignments where you upload a single file
11  *
12  */
13 class assignment_upload extends assignment_base {
15     function assignment_upload($cmid='staticonly', $assignment=NULL, $cm=NULL, $course=NULL) {
16         parent::assignment_base($cmid, $assignment, $cm, $course);
17         $this->type = 'upload';
18     }
20     function view() {
21         global $USER;
23         require_capability('mod/assignment:view', $this->context);
25         add_to_log($this->course->id, 'assignment', 'view', "view.php?id={$this->cm->id}", $this->assignment->id, $this->cm->id);
27         $this->view_header();
29         if ($this->assignment->timeavailable > time()
30           and !has_capability('mod/assignment:grade', $this->context)      // grading user can see it anytime
31           and $this->assignment->var3) {                                   // force hiding before available date
32             print_simple_box_start('center', '', '', 0, 'generalbox', 'intro');
33             print_string('notavailableyet', 'assignment');
34             print_simple_box_end();
35         } else {
36             $this->view_intro();
37         }
39         $this->view_dates();
41         if (has_capability('mod/assignment:submit', $this->context)) {
42             $filecount = $this->count_user_files($USER->id);
43             $submission = $this->get_submission($USER->id);
45             $this->view_feedback();
47             if (!$this->drafts_tracked() or !$this->isopen() or $this->is_finalized($submission)) {
48                 print_heading(get_string('submission', 'assignment'), '', 3);
49             } else {
50                 print_heading(get_string('submissiondraft', 'assignment'), '', 3);
51             }
53             if ($filecount and $submission) {
54                 print_simple_box($this->print_user_files($USER->id, true), 'center');
55             } else {
56                 if (!$this->isopen() or $this->is_finalized($submission)) {
57                     print_simple_box(get_string('nofiles', 'assignment'), 'center');
58                 } else {
59                     print_simple_box(get_string('nofilesyet', 'assignment'), 'center');
60                 }
61             }
63             $this->view_upload_form();
65             if ($this->notes_allowed()) {
66                 print_heading(get_string('notes', 'assignment'), '', 3);
67                 $this->view_notes();
68             }
70             $this->view_final_submission();
71         }
72         $this->view_footer();
73     }
76     function view_feedback($submission=NULL) {
77         global $USER, $CFG, $DB;
78         require_once($CFG->libdir.'/gradelib.php');
80         if (!$submission) { /// Get submission for this assignment
81             $submission = $this->get_submission($USER->id);
82         }
84         if (empty($submission->timemarked)) {   /// Nothing to show, so print nothing
85             if ($this->count_responsefiles($USER->id)) {
86                 print_heading(get_string('responsefiles', 'assignment', $this->course->teacher), '', 3);
87                 $responsefiles = $this->print_responsefiles($USER->id, true);
88                 print_simple_box($responsefiles, 'center');
89             }
90             return;
91         }
93         $grading_info = grade_get_grades($this->course->id, 'mod', 'assignment', $this->assignment->id, $USER->id);
94         $item = $grading_info->items[0];
95         $grade = $item->grades[$USER->id];
97         if ($grade->hidden or $grade->grade === false) { // hidden or error
98             return;
99         }
101         if ($grade->grade === null and empty($grade->str_feedback)) {   /// Nothing to show yet
102             return;
103         }
105         $graded_date = $grade->dategraded;
106         $graded_by   = $grade->usermodified;
108     /// We need the teacher info
109         if (!$teacher = $DB->get_record('user', array('id'=>$graded_by))) {
110             print_error('cannotfindteacher');
111         }
113     /// Print the feedback
114         print_heading(get_string('submissionfeedback', 'assignment'), '', 3);
116         echo '<table cellspacing="0" class="feedback">';
118         echo '<tr>';
119         echo '<td class="left picture">';
120         print_user_picture($teacher, $this->course->id, $teacher->picture);
121         echo '</td>';
122         echo '<td class="topic">';
123         echo '<div class="from">';
124         echo '<div class="fullname">'.fullname($teacher).'</div>';
125         echo '<div class="time">'.userdate($graded_date).'</div>';
126         echo '</div>';
127         echo '</td>';
128         echo '</tr>';
130         echo '<tr>';
131         echo '<td class="left side">&nbsp;</td>';
132         echo '<td class="content">';
133         if ($this->assignment->grade) {
134             echo '<div class="grade">';
135             echo get_string("grade").': '.$grade->str_long_grade;
136             echo '</div>';
137             echo '<div class="clearer"></div>';
138         }
140         echo '<div class="comment">';
141         echo $grade->str_feedback;
142         echo '</div>';
143         echo '</tr>';
145         echo '<tr>';
146         echo '<td class="left side">&nbsp;</td>';
147         echo '<td class="content">';
148         echo $this->print_responsefiles($USER->id, true);
149         echo '</tr>';
151         echo '</table>';
152     }
155     function view_upload_form() {
156         global $CFG, $USER;
158         $submission = $this->get_submission($USER->id);
160         $struploadafile = get_string('uploadafile');
161         $maxbytes = $this->assignment->maxbytes == 0 ? $this->course->maxbytes : $this->assignment->maxbytes;
162         $strmaxsize = get_string('maxsize', '', display_size($maxbytes));
164         if ($this->is_finalized($submission)) {
165             // no uploading
166             return;
167         }
169         if ($this->can_upload_file($submission)) {
170             echo '<div style="text-align:center">';
171             echo '<form enctype="multipart/form-data" method="post" action="upload.php">';
172             echo '<fieldset class="invisiblefieldset">';
173             echo "<p>$struploadafile ($strmaxsize)</p>";
174             echo '<input type="hidden" name="id" value="'.$this->cm->id.'" />';
175             echo '<input type="hidden" name="action" value="uploadfile" />';
176             require_once($CFG->libdir.'/uploadlib.php');
177             upload_print_form_fragment(1,array('newfile'),null,false,null,0,$this->assignment->maxbytes,false);
178             echo '<input type="submit" name="save" value="'.get_string('uploadthisfile').'" />';
179             echo '</fieldset>';
180             echo '</form>';
181             echo '</div>';
182             echo '<br />';
183         }
185     }
187     function view_notes() {
188         global $USER;
190         if ($submission = $this->get_submission($USER->id)
191           and !empty($submission->data1)) {
192             print_simple_box(format_text($submission->data1, FORMAT_HTML), 'center', '630px');
193         } else {
194             print_simple_box(get_string('notesempty', 'assignment'), 'center');
195         }
196         if ($this->can_update_notes($submission)) {
197             $options = array ('id'=>$this->cm->id, 'action'=>'editnotes');
198             echo '<div style="text-align:center">';
199             print_single_button('upload.php', $options, get_string('edit'), 'post', '_self', false);
200             echo '</div>';
201         }
202     }
204     function view_final_submission() {
205         global $CFG, $USER;
207         $submission = $this->get_submission($USER->id);
209         if ($this->isopen() and $this->can_finalize($submission)) {
210             //print final submit button
211             print_heading(get_string('submitformarking','assignment'), '', 3);
212             echo '<div style="text-align:center">';
213             echo '<form method="post" action="upload.php">';
214             echo '<fieldset class="invisiblefieldset">';
215             echo '<input type="hidden" name="id" value="'.$this->cm->id.'" />';
216             echo '<input type="hidden" name="action" value="finalize" />';
217             echo '<input type="submit" name="formarking" value="'.get_string('sendformarking', 'assignment').'" />';
218             echo '</fieldset>';
219             echo '</form>';
220             echo '</div>';
221         } else if (!$this->isopen()) {
222             print_heading(get_string('nomoresubmissions','assignment'), '', 3);
224         } else if ($this->drafts_tracked() and $state = $this->is_finalized($submission)) {
225             if ($state == ASSIGNMENT_STATUS_SUBMITTED) {
226                 print_heading(get_string('submitedformarking','assignment'), '', 3);
227             } else {
228                 print_heading(get_string('nomoresubmissions','assignment'), '', 3);
229             }
230         } else {
231             //no submission yet
232         }
233     }
236     /**
237      * Return true if var3 == hide description till available day
238      *
239      *@return boolean
240      */
241     function description_is_hidden() {
242         return ($this->assignment->var3 && (time() <= $this->assignment->timeavailable));
243     }
245     function custom_feedbackform($submission, $return=false) {
246         global $CFG;
248         $mode         = optional_param('mode', '', PARAM_ALPHA);
249         $offset       = optional_param('offset', 0, PARAM_INT);
250         $forcerefresh = optional_param('forcerefresh', 0, PARAM_BOOL);
252         $output = get_string('responsefiles', 'assignment').': ';
254         $output .= '<form enctype="multipart/form-data" method="post" '.
255              "action=\"$CFG->wwwroot/mod/assignment/upload.php\">";
256         $output .= '<div>';
257         $output .= '<input type="hidden" name="id" value="'.$this->cm->id.'" />';
258         $output .= '<input type="hidden" name="action" value="uploadresponse" />';
259         $output .= '<input type="hidden" name="mode" value="'.$mode.'" />';
260         $output .= '<input type="hidden" name="offset" value="'.$offset.'" />';
261         $output .= '<input type="hidden" name="userid" value="'.$submission->userid.'" />';
262         require_once($CFG->libdir.'/uploadlib.php');
263         $output .= upload_print_form_fragment(1,array('newfile'),null,false,null,0,0,true);
264         $output .= '<input type="submit" name="save" value="'.get_string('uploadthisfile').'" />';
265         $output .= '</div>';
266         $output .= '</form>';
268         if ($forcerefresh) {
269             $output .= $this->update_main_listing($submission);
270         }
272         $responsefiles = $this->print_responsefiles($submission->userid, true);
273         if (!empty($responsefiles)) {
274             $output .= $responsefiles;
275         }
277         if ($return) {
278             return $output;
279         }
280         echo $output;
281         return;
282     }
285     function print_student_answer($userid, $return=false){
286         global $CFG;
288         $filearea = $this->file_area_name($userid);
289         $submission = $this->get_submission($userid);
291         $output = '';
293         if ($basedir = $this->file_area($userid)) {
294             if ($this->drafts_tracked() and $this->isopen() and !$this->is_finalized($submission)) {
295                 $output .= '<strong>'.get_string('draft', 'assignment').':</strong> ';
296             }
298             if ($this->notes_allowed() and !empty($submission->data1)) {
299                 $output .= link_to_popup_window ('/mod/assignment/type/upload/notes.php?id='.$this->cm->id.'&amp;userid='.$userid,
300                                                 'notes'.$userid, get_string('notes', 'assignment'), 500, 780, get_string('notes', 'assignment'), 'none', true, 'notesbutton'.$userid);
301                 $output .= '&nbsp;';
302             }
304             if ($files = get_directory_list($basedir, 'responses')) {
305                 require_once($CFG->libdir.'/filelib.php');
306                 foreach ($files as $key => $file) {
307                     $icon = mimeinfo('icon', $file);
308                     $ffurl = get_file_url("$filearea/$file");
309                     $output .= '<a href="'.$ffurl.'" ><img class="icon" src="'.$CFG->pixpath.'/f/'.$icon.'" alt="'.$icon.'" />'.$file.'</a>&nbsp;';
310                 }
311             }
312         }
313         $output = '<div class="files">'.$output.'</div>';
314         $output .= '<br />';
316         return $output;
317     }
320     /**
321      * Produces a list of links to the files uploaded by a user
322      *
323      * @param $userid int optional id of the user. If 0 then $USER->id is used.
324      * @param $return boolean optional defaults to false. If true the list is returned rather than printed
325      * @return string optional
326      */
327     function print_user_files($userid=0, $return=false) {
328         global $CFG, $USER;
330         $mode    = optional_param('mode', '', PARAM_ALPHA);
331         $offset  = optional_param('offset', 0, PARAM_INT);
333         if (!$userid) {
334             if (!isloggedin()) {
335                 return '';
336             }
337             $userid = $USER->id;
338         }
340         $filearea = $this->file_area_name($userid);
342         $output = '';
344         $submission = $this->get_submission($userid);
346         $candelete = $this->can_delete_files($submission);
347         $strdelete   = get_string('delete');
349         if ($this->drafts_tracked() and $this->isopen() and !$this->is_finalized($submission) and !empty($mode)) {                 // only during grading
350             $output .= '<strong>'.get_string('draft', 'assignment').':</strong><br />';
351         }
353         if ($this->notes_allowed() and !empty($submission->data1) and !empty($mode)) { // only during grading
355             $npurl = $CFG->wwwroot."/mod/assignment/type/upload/notes.php?id={$this->cm->id}&amp;userid=$userid&amp;offset=$offset&amp;mode=single";
356             $output .= '<a href="'.$npurl.'">'.get_string('notes', 'assignment').'</a><br />';
358         }
360         if ($basedir = $this->file_area($userid)) {
361             if ($files = get_directory_list($basedir, 'responses')) {
362                 require_once($CFG->libdir.'/filelib.php');
363                 $p = array(
364                     'userid' => $userid,
365                     'assignmentid' => $this->cm->id,
366                 );
367                 foreach ($files as $key => $file) {
369                     $icon = mimeinfo('icon', $file);
370                     $ffurl = get_file_url("$filearea/$file");
372                     $output .= '<a href="'.$ffurl.'" ><img src="'.$CFG->pixpath.'/f/'.$icon.'" class="icon" alt="'.$icon.'" />'.$file.'</a>';
374                     if ($candelete) {
375                         $delurl  = "$CFG->wwwroot/mod/assignment/delete.php?id={$this->cm->id}&amp;file=$file&amp;userid={$submission->userid}&amp;mode=$mode&amp;offset=$offset";
377                         $output .= '<a href="'.$delurl.'">&nbsp;'
378                                   .'<img title="'.$strdelete.'" src="'.$CFG->pixpath.'/t/delete.gif" class="iconsmall" alt="" /></a> ';
379                     }
380                     if (true) { // @todo penny replace with capability check
381                         $p['file'] = $file;
382                         $output .= portfolio_add_button('assignment_portfolio_caller', $p, '/mod/assignment/lib.php', false, true);
383                     }
384                     $output .= '<br />';
385                 }
386                 if (true) { //@todo penny replace with check capability
387                     unset($p['file']);// for all files
388                     $output .= '<br />' . portfolio_add_button('assignment_portfolio_caller', $p, '/mod/assignment/lib.php', true, true);
389                 }
390             }
391         }
393         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
394             if ($this->can_unfinalize($submission)) {
395                 $options = array ('id'=>$this->cm->id, 'userid'=>$userid, 'action'=>'unfinalize', 'mode'=>$mode, 'offset'=>$offset);
396                 $output .= print_single_button('upload.php', $options, get_string('unfinalize', 'assignment'), 'post', '_self', true);
397             } else if ($this->can_finalize($submission)) {
398                 $options = array ('id'=>$this->cm->id, 'userid'=>$userid, 'action'=>'finalizeclose', 'mode'=>$mode, 'offset'=>$offset);
399                 $output .= print_single_button('upload.php', $options, get_string('finalize', 'assignment'), 'post', '_self', true);
400             }
401         }
403         $output = '<div class="files">'.$output.'</div>';
405         if ($return) {
406             return $output;
407         }
408         echo $output;
409     }
411     function print_responsefiles($userid, $return=false) {
412         global $CFG, $USER;
414         $mode    = optional_param('mode', '', PARAM_ALPHA);
415         $offset  = optional_param('offset', 0, PARAM_INT);
417         $filearea = $this->file_area_name($userid).'/responses';
419         $output = '';
421         $candelete = $this->can_manage_responsefiles();
422         $strdelete   = get_string('delete');
424         if ($basedir = $this->file_area($userid)) {
425             $basedir .= '/responses';
427             if ($files = get_directory_list($basedir)) {
428                 require_once($CFG->libdir.'/filelib.php');
429                 foreach ($files as $key => $file) {
431                     $icon = mimeinfo('icon', $file);
433                     $ffurl = get_file_url("$filearea/$file");
435                     $output .= '<a href="'.$ffurl.'" ><img src="'.$CFG->pixpath.'/f/'.$icon.'" alt="'.$icon.'" />'.$file.'</a>';
437                     if ($candelete) {
438                         $delurl  = "$CFG->wwwroot/mod/assignment/delete.php?id={$this->cm->id}&amp;file=$file&amp;userid=$userid&amp;mode=$mode&amp;offset=$offset&amp;action=response";
440                         $output .= '<a href="'.$delurl.'">&nbsp;'
441                                   .'<img title="'.$strdelete.'" src="'.$CFG->pixpath.'/t/delete.gif" class="iconsmall" alt=""/></a> ';
442                     }
444                     $output .= '&nbsp;';
445                 }
446             }
449             $output = '<div class="responsefiles">'.$output.'</div>';
451         }
453         if ($return) {
454             return $output;
455         }
456         echo $output;
457     }
460     function upload() {
461         $action = required_param('action', PARAM_ALPHA);
463         switch ($action) {
464             case 'finalize':
465                 $this->finalize();
466                 break;
467             case 'finalizeclose':
468                 $this->finalizeclose();
469                 break;
470             case 'unfinalize':
471                 $this->unfinalize();
472                 break;
473             case 'uploadresponse':
474                 $this->upload_responsefile();
475                 break;
476             case 'uploadfile':
477                 $this->upload_file();
478             case 'savenotes':
479             case 'editnotes':
480                 $this->upload_notes();
481             default:
482                 print_error('unknowuploadaction', '', '', $action);
483         }
484     }
486     function upload_notes() {
487         global $CFG, $USER;
489         $action = required_param('action', PARAM_ALPHA);
491         $returnurl = 'view.php?id='.$this->cm->id;
493         $mform = new mod_assignment_upload_notes_form();
495         $defaults = new object();
496         $defaults->id = $this->cm->id;
498         if ($submission = $this->get_submission($USER->id)) {
499             $defaults->text = $submission->data1;
500         } else {
501             $defaults->text = '';
502         }
504         $mform->set_data($defaults);
506         if ($mform->is_cancelled()) {
507             redirect('view.php?id='.$this->cm->id);
508         }
510         if (!$this->can_update_notes($submission)) {
511             $this->view_header(get_string('upload'));
512             notify(get_string('uploaderror', 'assignment'));
513             print_continue($returnurl);
514             $this->view_footer();
515             die;
516         }
518         if ($data = $mform->get_data() and $action == 'savenotes') {
519             $submission = $this->get_submission($USER->id, true); // get or create submission
520             $updated = new object();
521             $updated->id           = $submission->id;
522             $updated->timemodified = time();
523             $updated->data1        = $data->text;
525             if ($DB->update_record('assignment_submissions', $updated)) {
526                 add_to_log($this->course->id, 'assignment', 'upload', 'view.php?a='.$this->assignment->id, $this->assignment->id, $this->cm->id);
527                 redirect($returnurl);
528                 $submission = $this->get_submission($USER->id);
529                 $this->update_grade($submission);
531             } else {
532                 $this->view_header(get_string('notes', 'assignment'));
533                 notify(get_string('notesupdateerror', 'assignment'));
534                 print_continue($returnurl);
535                 $this->view_footer();
536                 die;
537             }
538         }
540         /// show notes edit form
541         $this->view_header(get_string('notes', 'assignment'));
543         print_heading(get_string('notes', 'assignment'), '');
545         $mform->display();
547         $this->view_footer();
548         die;
549     }
551     function upload_responsefile() {
552         global $CFG;
554         $userid = required_param('userid', PARAM_INT);
555         $mode   = required_param('mode', PARAM_ALPHA);
556         $offset = required_param('offset', PARAM_INT);
558         $returnurl = "submissions.php?id={$this->cm->id}&amp;userid=$userid&amp;mode=$mode&amp;offset=$offset";
560         if (data_submitted() and $this->can_manage_responsefiles()) {
561             $dir = $this->file_area_name($userid).'/responses';
562             check_dir_exists($CFG->dataroot.'/'.$dir, true, true);
564             require_once($CFG->dirroot.'/lib/uploadlib.php');
565             $um = new upload_manager('newfile',false,true,$this->course,false,0,true);
567             if (!$um->process_file_uploads($dir)) {
568                 print_header(get_string('upload'));
569                 notify(get_string('uploaderror', 'assignment'));
570                 echo $um->get_errors();
571                 print_continue($returnurl);
572                 print_footer('none');
573                 die;
574             }
575         }
576         redirect($returnurl);
577     }
579     function upload_file() {
580         global $CFG, $USER, $DB;
582         $mode   = optional_param('mode', '', PARAM_ALPHA);
583         $offset = optional_param('offset', 0, PARAM_INT);
585         $returnurl = 'view.php?id='.$this->cm->id;
587         $filecount = $this->count_user_files($USER->id);
588         $submission = $this->get_submission($USER->id);
590         if (!$this->can_upload_file($submission)) {
591             $this->view_header(get_string('upload'));
592             notify(get_string('uploaderror', 'assignment'));
593             print_continue($returnurl);
594             $this->view_footer();
595             die;
596         }
598         $dir = $this->file_area_name($USER->id);
599         check_dir_exists($CFG->dataroot.'/'.$dir, true, true); // better to create now so that student submissions do not block it later
601         require_once($CFG->dirroot.'/lib/uploadlib.php');
602         $um = new upload_manager('newfile',false,true,$this->course,false,$this->assignment->maxbytes,true);
604         if ($um->process_file_uploads($dir)) {
605             $submission = $this->get_submission($USER->id, true); //create new submission if needed
606             $updated = new object();
607             $updated->id           = $submission->id;
608             $updated->timemodified = time();
610             if ($DB->update_record('assignment_submissions', $updated)) {
611                 add_to_log($this->course->id, 'assignment', 'upload',
612                         'view.php?a='.$this->assignment->id, $this->assignment->id, $this->cm->id);
613                 $submission = $this->get_submission($USER->id);
614                 $this->update_grade($submission);
615                 if (!$this->drafts_tracked()) {
616                     $this->email_teachers($submission);
617                 }
618             } else {
619                 $new_filename = $um->get_new_filename();
620                 $this->view_header(get_string('upload'));
621                 notify(get_string('uploadnotregistered', 'assignment', $new_filename));
622                 print_continue($returnurl);
623                 $this->view_footer();
624                 die;
625             }
626             redirect('view.php?id='.$this->cm->id);
627         }
628         $this->view_header(get_string('upload'));
629         notify(get_string('uploaderror', 'assignment'));
630         echo $um->get_errors();
631         print_continue($returnurl);
632         $this->view_footer();
633         die;
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         $dir = $this->file_area_name($userid).'/responses';
781         $filepath = $CFG->dataroot.'/'.$dir.'/'.$file;
782         if (file_exists($filepath)) {
783             if (@unlink($filepath)) {
784                 redirect($returnurl);
785             }
786         }
788         // print delete error
789         print_header(get_string('delete'));
790         notify(get_string('deletefilefailed', 'assignment'));
791         print_continue($returnurl);
792         print_footer('none');
793         die;
795     }
798     function delete_file() {
799         global $CFG, $DB;
801         $file     = required_param('file', PARAM_FILE);
802         $userid   = required_param('userid', PARAM_INT);
803         $confirm  = optional_param('confirm', 0, PARAM_BOOL);
804         $mode     = optional_param('mode', '', PARAM_ALPHA);
805         $offset   = optional_param('offset', 0, PARAM_INT);
807         require_login($this->course->id, false, $this->cm);
809         if (empty($mode)) {
810             $urlreturn = 'view.php';
811             $optionsreturn = array('id'=>$this->cm->id);
812             $returnurl = 'view.php?id='.$this->cm->id;
813         } else {
814             $urlreturn = 'submissions.php';
815             $optionsreturn = array('id'=>$this->cm->id, 'offset'=>$offset, 'mode'=>$mode, 'userid'=>$userid);
816             $returnurl = "submissions.php?id={$this->cm->id}&amp;offset=$offset&amp;mode=$mode&amp;userid=$userid";
817         }
819         if (!$submission = $this->get_submission($userid) // incorrect submission
820           or !$this->can_delete_files($submission)) {     // can not delete
821             $this->view_header(get_string('delete'));
822             notify(get_string('cannotdeletefiles', 'assignment'));
823             print_continue($returnurl);
824             $this->view_footer();
825             die;
826         }
827         $dir = $this->file_area_name($userid);
829         if (!data_submitted() or !$confirm) {
830             $optionsyes = array ('id'=>$this->cm->id, 'file'=>$file, 'userid'=>$userid, 'confirm'=>1, 'sesskey'=>sesskey(), 'mode'=>$mode, 'offset'=>$offset);
831             if (empty($mode)) {
832                 $this->view_header(get_string('delete'));
833             } else {
834                 print_header(get_string('delete'));
835             }
836             print_heading(get_string('delete'));
837             notice_yesno(get_string('confirmdeletefile', 'assignment', $file), 'delete.php', $urlreturn, $optionsyes, $optionsreturn, 'post', 'get');
838             if (empty($mode)) {
839                 $this->view_footer();
840             } else {
841                 print_footer('none');
842             }
843             die;
844         }
846         $filepath = $CFG->dataroot.'/'.$dir.'/'.$file;
847         if (file_exists($filepath)) {
848             if (@unlink($filepath)) {
849                 $updated = new object();
850                 $updated->id = $submission->id;
851                 $updated->timemodified = time();
852                 if ($DB->update_record('assignment_submissions', $updated)) {
853                     add_to_log($this->course->id, 'assignment', 'upload', //TODO: add delete action to log
854                             'view.php?a='.$this->assignment->id, $this->assignment->id, $this->cm->id);
855                     $submission = $this->get_submission($userid);
856                     $this->update_grade($submission);
857                 }
858                 redirect($returnurl);
859             }
860         }
862         // print delete error
863         if (empty($mode)) {
864             $this->view_header(get_string('delete'));
865         } else {
866             print_header(get_string('delete'));
867         }
868         notify(get_string('deletefilefailed', 'assignment'));
869         print_continue($returnurl);
870         if (empty($mode)) {
871             $this->view_footer();
872         } else {
873             print_footer('none');
874         }
875         die;
876     }
879     function can_upload_file($submission) {
880         global $USER;
882         if (has_capability('mod/assignment:submit', $this->context)           // can submit
883           and $this->isopen()                                                 // assignment not closed yet
884           and (empty($submission) or $submission->userid == $USER->id)        // his/her own submission
885           and $this->count_user_files($USER->id) < $this->assignment->var1    // file limit not reached
886           and !$this->is_finalized($submission)) {                            // no uploading after final submission
887             return true;
888         } else {
889             return false;
890         }
891     }
893     function can_manage_responsefiles() {
894         if (has_capability('mod/assignment:grade', $this->context)) {
895             return true;
896         } else {
897             return false;
898         }
899     }
901     function can_delete_files($submission) {
902         global $USER;
904         if (has_capability('mod/assignment:grade', $this->context)) {
905             return true;
906         }
908         if (has_capability('mod/assignment:submit', $this->context)
909           and $this->isopen()                                      // assignment not closed yet
910           and $this->assignment->resubmit                          // deleting allowed
911           and $USER->id == $submission->userid                     // his/her own submission
912           and !$this->is_finalized($submission)) {                 // no deleting after final submission
913             return true;
914         } else {
915             return false;
916         }
917     }
919     function drafts_tracked() {
920         return !empty($this->assignment->var4);
921     }
923     /**
924      * Returns submission status
925      * @param object $submission - may be empty
926      * @return string submission state - empty, ASSIGNMENT_STATUS_SUBMITTED or ASSIGNMENT_STATUS_CLOSED
927      */
928     function is_finalized($submission) {
929         if (!$this->drafts_tracked()) {
930             return '';
932         } else if (empty($submission)) {
933             return '';
935         } else if ($submission->data2 == ASSIGNMENT_STATUS_SUBMITTED or $submission->data2 == ASSIGNMENT_STATUS_CLOSED) {
936             return $submission->data2;
938         } else {
939             return '';
940         }
941     }
943     function can_unfinalize($submission) {
944         if (!$this->drafts_tracked()) {
945             return false;
946         }
947         if (has_capability('mod/assignment:grade', $this->context)
948           and $this->isopen()
949           and $this->is_finalized($submission)) {
950             return true;
951         } else {
952             return false;
953         }
954     }
956     function can_finalize($submission) {
957         global $USER;
958         if (!$this->drafts_tracked()) {
959             return false;
960         }
962                 if ($this->is_finalized($submission)) {
963                     return false;
964                 }
966         if (has_capability('mod/assignment:grade', $this->context)) {
967             return true;
969         } else if (has_capability('mod/assignment:submit', $this->context)    // can submit
970           and $this->isopen()                                                 // assignment not closed yet
971           and !empty($submission)                                             // submission must exist
972           and $submission->userid == $USER->id                                // his/her own submission
973           and ($this->count_user_files($USER->id)
974             or ($this->notes_allowed() and !empty($submission->data1)))) {    // something must be submitted
976             return true;
977         } else {
978             return false;
979         }
980     }
982     function can_update_notes($submission) {
983         global $USER;
985         if (has_capability('mod/assignment:submit', $this->context)
986           and $this->notes_allowed()                                          // notesd must be allowed
987           and $this->isopen()                                                 // assignment not closed yet
988           and (empty($submission) or $USER->id == $submission->userid)        // his/her own submission
989           and !$this->is_finalized($submission)) {                            // no updateingafter final submission
990             return true;
991         } else {
992             return false;
993         }
994     }
996     function notes_allowed() {
997         return (boolean)$this->assignment->var2;
998     }
1000     /**
1001      * Count the files uploaded by a given user
1002      *
1003      * @param $userid int The user id
1004      * @return int
1005      */
1006     function count_user_files($userid) {
1007         global $CFG;
1009         $filearea = $this->file_area_name($userid);
1011         if ( is_dir($CFG->dataroot.'/'.$filearea) && $basedir = $this->file_area($userid)) {
1012             if ($files = get_directory_list($basedir, 'responses')) {
1013                 return count($files);
1014             }
1015         }
1016         return 0;
1017     }
1019     function count_responsefiles($userid) {
1020         global $CFG;
1022         $filearea = $this->file_area_name($userid).'/responses';
1024         if ( is_dir($CFG->dataroot.'/'.$filearea) && $basedir = $this->file_area($userid)) {
1025             $basedir .= '/responses';
1026             if ($files = get_directory_list($basedir)) {
1027                 return count($files);
1028             }
1029         }
1030         return 0;
1031     }
1033     function setup_elements(&$mform) {
1034         global $CFG, $COURSE;
1036         $ynoptions = array( 0 => get_string('no'), 1 => get_string('yes'));
1038         $choices = get_max_upload_sizes($CFG->maxbytes, $COURSE->maxbytes);
1039         $choices[0] = get_string('courseuploadlimit') . ' ('.display_size($COURSE->maxbytes).')';
1040         $mform->addElement('select', 'maxbytes', get_string('maximumsize', 'assignment'), $choices);
1041         $mform->setDefault('maxbytes', $CFG->assignment_maxbytes);
1043         $mform->addElement('select', 'resubmit', get_string("allowdeleting", "assignment"), $ynoptions);
1044         $mform->setHelpButton('resubmit', array('allowdeleting', get_string('allowdeleting', 'assignment'), 'assignment'));
1045         $mform->setDefault('resubmit', 1);
1047         $options = array();
1048         for($i = 1; $i <= 20; $i++) {
1049             $options[$i] = $i;
1050         }
1051         $mform->addElement('select', 'var1', get_string("allowmaxfiles", "assignment"), $options);
1052         $mform->setHelpButton('var1', array('allowmaxfiles', get_string('allowmaxfiles', 'assignment'), 'assignment'));
1053         $mform->setDefault('var1', 3);
1055         $mform->addElement('select', 'var2', get_string("allownotes", "assignment"), $ynoptions);
1056         $mform->setHelpButton('var2', array('allownotes', get_string('allownotes', 'assignment'), 'assignment'));
1057         $mform->setDefault('var2', 0);
1059         $mform->addElement('select', 'var3', get_string("hideintro", "assignment"), $ynoptions);
1060         $mform->setHelpButton('var3', array('hideintro', get_string('hideintro', 'assignment'), 'assignment'));
1061         $mform->setDefault('var3', 0);
1063         $mform->addElement('select', 'emailteachers', get_string("emailteachers", "assignment"), $ynoptions);
1064         $mform->setHelpButton('emailteachers', array('emailteachers', get_string('emailteachers', 'assignment'), 'assignment'));
1065         $mform->setDefault('emailteachers', 0);
1067         $mform->addElement('select', 'var4', get_string("trackdrafts", "assignment"), $ynoptions);
1068         $mform->setHelpButton('var4', array('trackdrafts', get_string('trackdrafts', 'assignment'), 'assignment'));
1069         $mform->setDefault('trackdrafts', 1);
1071     }
1073     function portfolio_exportable() {
1074         return true;
1075     }
1079 class mod_assignment_upload_notes_form extends moodleform {
1080     function definition() {
1081         $mform =& $this->_form;
1083         // visible elements
1084         $mform->addElement('htmleditor', 'text', get_string('notes', 'assignment'), array('cols'=>85, 'rows'=>30));
1085         $mform->setType('text', PARAM_RAW); // to be cleaned before display
1086         $mform->setHelpButton('text', array('reading', 'writing'), false, 'editorhelpbutton');
1088         // hidden params
1089         $mform->addElement('hidden', 'id', 0);
1090         $mform->setType('id', PARAM_INT);
1091         $mform->addElement('hidden', 'action', 'savenotes');
1092         $mform->setType('id', PARAM_ALPHA);
1094         // buttons
1095         $this->add_action_buttons();
1096     }
1101 ?>