Moodle  2.2.1
http://www.collinsharper.com
C:/xampp/htdocs/moodle/mod/assignment/lib.php
Go to the documentation of this file.
00001 <?PHP
00002 
00003 // This file is part of Moodle - http://moodle.org/
00004 //
00005 // Moodle is free software: you can redistribute it and/or modify
00006 // it under the terms of the GNU General Public License as published by
00007 // the Free Software Foundation, either version 3 of the License, or
00008 // (at your option) any later version.
00009 //
00010 // Moodle is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 // GNU General Public License for more details.
00014 //
00015 // You should have received a copy of the GNU General Public License
00016 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
00017 
00029 require_once($CFG->libdir.'/eventslib.php');
00031 require_once($CFG->libdir.'/formslib.php');
00033 require_once($CFG->dirroot.'/calendar/lib.php');
00034 
00036 define('ASSIGNMENT_COUNT_WORDS', 1);
00038 define('ASSIGNMENT_COUNT_LETTERS', 2);
00039 
00047 class assignment_base {
00048 
00049     const FILTER_ALL             = 0;
00050     const FILTER_SUBMITTED       = 1;
00051     const FILTER_REQUIRE_GRADING = 2;
00052 
00054     var $cm;
00056     var $course;
00058     var $coursecontext;
00060     var $assignment;
00062     var $strassignment;
00064     var $strassignments;
00066     var $strsubmissions;
00068     var $strlastmodified;
00070     var $pagetitle;
00072     var $usehtmleditor;
00076     var $defaultformat;
00080     var $context;
00082     var $type;
00083 
00099     function assignment_base($cmid='staticonly', $assignment=NULL, $cm=NULL, $course=NULL) {
00100         global $COURSE, $DB;
00101 
00102         if ($cmid == 'staticonly') {
00103             //use static functions only!
00104             return;
00105         }
00106 
00107         global $CFG;
00108 
00109         if ($cm) {
00110             $this->cm = $cm;
00111         } else if (! $this->cm = get_coursemodule_from_id('assignment', $cmid)) {
00112             print_error('invalidcoursemodule');
00113         }
00114 
00115         $this->context = get_context_instance(CONTEXT_MODULE, $this->cm->id);
00116 
00117         if ($course) {
00118             $this->course = $course;
00119         } else if ($this->cm->course == $COURSE->id) {
00120             $this->course = $COURSE;
00121         } else if (! $this->course = $DB->get_record('course', array('id'=>$this->cm->course))) {
00122             print_error('invalidid', 'assignment');
00123         }
00124         $this->coursecontext = get_context_instance(CONTEXT_COURSE, $this->course->id);
00125         $courseshortname = format_text($this->course->shortname, true, array('context' => $this->coursecontext));
00126 
00127         if ($assignment) {
00128             $this->assignment = $assignment;
00129         } else if (! $this->assignment = $DB->get_record('assignment', array('id'=>$this->cm->instance))) {
00130             print_error('invalidid', 'assignment');
00131         }
00132 
00133         $this->assignment->cmidnumber = $this->cm->idnumber; // compatibility with modedit assignment obj
00134         $this->assignment->courseid   = $this->course->id; // compatibility with modedit assignment obj
00135 
00136         $this->strassignment = get_string('modulename', 'assignment');
00137         $this->strassignments = get_string('modulenameplural', 'assignment');
00138         $this->strsubmissions = get_string('submissions', 'assignment');
00139         $this->strlastmodified = get_string('lastmodified');
00140         $this->pagetitle = strip_tags($courseshortname.': '.$this->strassignment.': '.format_string($this->assignment->name, true, array('context' => $this->context)));
00141 
00142         // visibility handled by require_login() with $cm parameter
00143         // get current group only when really needed
00144 
00146         $this->defaultformat = editors_get_preferred_format();
00147     }
00148 
00154     function view() {
00155 
00156         $context = get_context_instance(CONTEXT_MODULE,$this->cm->id);
00157         require_capability('mod/assignment:view', $context);
00158 
00159         add_to_log($this->course->id, "assignment", "view", "view.php?id={$this->cm->id}",
00160                    $this->assignment->id, $this->cm->id);
00161 
00162         $this->view_header();
00163 
00164         $this->view_intro();
00165 
00166         $this->view_dates();
00167 
00168         $this->view_feedback();
00169 
00170         $this->view_footer();
00171     }
00172 
00184     function view_header($subpage='') {
00185         global $CFG, $PAGE, $OUTPUT;
00186 
00187         if ($subpage) {
00188             $PAGE->navbar->add($subpage);
00189         }
00190 
00191         $PAGE->set_title($this->pagetitle);
00192         $PAGE->set_heading($this->course->fullname);
00193 
00194         echo $OUTPUT->header();
00195 
00196         groups_print_activity_menu($this->cm, $CFG->wwwroot . '/mod/assignment/view.php?id=' . $this->cm->id);
00197 
00198         echo '<div class="reportlink">'.$this->submittedlink().'</div>';
00199         echo '<div class="clearer"></div>';
00200     }
00201 
00202 
00209     function view_intro() {
00210         global $OUTPUT;
00211         echo $OUTPUT->box_start('generalbox boxaligncenter', 'intro');
00212         echo format_module_intro('assignment', $this->assignment, $this->cm->id);
00213         echo $OUTPUT->box_end();
00214         echo plagiarism_print_disclosure($this->cm->id);
00215     }
00216 
00223     function view_dates() {
00224         global $OUTPUT;
00225         if (!$this->assignment->timeavailable && !$this->assignment->timedue) {
00226             return;
00227         }
00228 
00229         echo $OUTPUT->box_start('generalbox boxaligncenter', 'dates');
00230         echo '<table>';
00231         if ($this->assignment->timeavailable) {
00232             echo '<tr><td class="c0">'.get_string('availabledate','assignment').':</td>';
00233             echo '    <td class="c1">'.userdate($this->assignment->timeavailable).'</td></tr>';
00234         }
00235         if ($this->assignment->timedue) {
00236             echo '<tr><td class="c0">'.get_string('duedate','assignment').':</td>';
00237             echo '    <td class="c1">'.userdate($this->assignment->timedue).'</td></tr>';
00238         }
00239         echo '</table>';
00240         echo $OUTPUT->box_end();
00241     }
00242 
00243 
00250     function view_footer() {
00251         global $OUTPUT;
00252         echo $OUTPUT->footer();
00253     }
00254 
00268     function view_feedback($submission=NULL) {
00269         global $USER, $CFG, $DB, $OUTPUT, $PAGE;
00270         require_once($CFG->libdir.'/gradelib.php');
00271         require_once("$CFG->dirroot/grade/grading/lib.php");
00272 
00273         if (!$submission) { 
00274             $userid = $USER->id;
00275             $submission = $this->get_submission($userid);
00276         } else {
00277             $userid = $submission->userid;
00278         }
00279         // Check the user can submit
00280         $canviewfeedback = ($userid == $USER->id && has_capability('mod/assignment:submit', $this->context, $USER->id, false));
00281         // If not then check if the user still has the view cap and has a previous submission
00282         $canviewfeedback = $canviewfeedback || (!empty($submission) && $submission->userid == $USER->id && has_capability('mod/assignment:view', $this->context));
00283         // Or if user can grade (is a teacher or admin)
00284         $canviewfeedback = $canviewfeedback || has_capability('mod/assignment:grade', $this->context);
00285 
00286         if (!$canviewfeedback) {
00287             // can not view or submit assignments -> no feedback
00288             return;
00289         }
00290 
00291         $grading_info = grade_get_grades($this->course->id, 'mod', 'assignment', $this->assignment->id, $userid);
00292         $item = $grading_info->items[0];
00293         $grade = $item->grades[$userid];
00294 
00295         if ($grade->hidden or $grade->grade === false) { // hidden or error
00296             return;
00297         }
00298 
00299         if ($grade->grade === null and empty($grade->str_feedback)) {   
00300             return;
00301         }
00302 
00303         $graded_date = $grade->dategraded;
00304         $graded_by   = $grade->usermodified;
00305 
00307         if (!$teacher = $DB->get_record('user', array('id'=>$graded_by))) {
00308             print_error('cannotfindteacher');
00309         }
00310 
00312         echo $OUTPUT->heading(get_string('feedbackfromteacher', 'assignment', fullname($teacher)));
00313 
00314         echo '<table cellspacing="0" class="feedback">';
00315 
00316         echo '<tr>';
00317         echo '<td class="left picture">';
00318         if ($teacher) {
00319             echo $OUTPUT->user_picture($teacher);
00320         }
00321         echo '</td>';
00322         echo '<td class="topic">';
00323         echo '<div class="from">';
00324         if ($teacher) {
00325             echo '<div class="fullname">'.fullname($teacher).'</div>';
00326         }
00327         echo '<div class="time">'.userdate($graded_date).'</div>';
00328         echo '</div>';
00329         echo '</td>';
00330         echo '</tr>';
00331 
00332         echo '<tr>';
00333         echo '<td class="left side">&nbsp;</td>';
00334         echo '<td class="content">';
00335         $gradestr = '<div class="grade">'. get_string("grade").': '.$grade->str_long_grade. '</div>';
00336         if (!empty($submission) && $controller = get_grading_manager($this->context, 'mod_assignment', 'submission')->get_active_controller()) {
00337             $controller->set_grade_range(make_grades_menu($this->assignment->grade));
00338             echo $controller->render_grade($PAGE, $submission->id, $item, $gradestr, has_capability('mod/assignment:grade', $this->context));
00339         } else {
00340             echo $gradestr;
00341         }
00342         echo '<div class="clearer"></div>';
00343 
00344         echo '<div class="comment">';
00345         echo $grade->str_feedback;
00346         echo '</div>';
00347         echo '</tr>';
00348 
00349          if ($this->type == 'uploadsingle') { //@TODO: move to overload view_feedback method in the class or is uploadsingle merging into upload?
00350             $responsefiles = $this->print_responsefiles($submission->userid, true);
00351             if (!empty($responsefiles)) {
00352                 echo '<tr>';
00353                 echo '<td class="left side">&nbsp;</td>';
00354                 echo '<td class="content">';
00355                 echo $responsefiles;
00356                 echo '</tr>';
00357             }
00358          }
00359 
00360         echo '</table>';
00361     }
00362 
00376     function submittedlink($allgroups=false) {
00377         global $USER;
00378         global $CFG;
00379 
00380         $submitted = '';
00381         $urlbase = "{$CFG->wwwroot}/mod/assignment/";
00382 
00383         $context = get_context_instance(CONTEXT_MODULE,$this->cm->id);
00384         if (has_capability('mod/assignment:grade', $context)) {
00385             if ($allgroups and has_capability('moodle/site:accessallgroups', $context)) {
00386                 $group = 0;
00387             } else {
00388                 $group = groups_get_activity_group($this->cm);
00389             }
00390             if ($this->type == 'offline') {
00391                 $submitted = '<a href="'.$urlbase.'submissions.php?id='.$this->cm->id.'">'.
00392                              get_string('viewfeedback', 'assignment').'</a>';
00393             } else if ($count = $this->count_real_submissions($group)) {
00394                 $submitted = '<a href="'.$urlbase.'submissions.php?id='.$this->cm->id.'">'.
00395                              get_string('viewsubmissions', 'assignment', $count).'</a>';
00396             } else {
00397                 $submitted = '<a href="'.$urlbase.'submissions.php?id='.$this->cm->id.'">'.
00398                              get_string('noattempts', 'assignment').'</a>';
00399             }
00400         } else {
00401             if (isloggedin()) {
00402                 if ($submission = $this->get_submission($USER->id)) {
00403                     // If the submission has been completed
00404                     if ($this->is_submitted_with_required_data($submission)) {
00405                         if ($submission->timemodified <= $this->assignment->timedue || empty($this->assignment->timedue)) {
00406                             $submitted = '<span class="early">'.userdate($submission->timemodified).'</span>';
00407                         } else {
00408                             $submitted = '<span class="late">'.userdate($submission->timemodified).'</span>';
00409                         }
00410                     }
00411                 }
00412             }
00413         }
00414 
00415         return $submitted;
00416     }
00417 
00418 
00422     function setup_elements(&$mform) {
00423 
00424     }
00425 
00435     function form_data_preprocessing(&$default_values, $form) {
00436     }
00437 
00444     function form_validation($data, $files) {
00445         return array();
00446     }
00447 
00463     function add_instance($assignment) {
00464         global $COURSE, $DB;
00465 
00466         $assignment->timemodified = time();
00467         $assignment->courseid = $assignment->course;
00468 
00469         $returnid = $DB->insert_record("assignment", $assignment);
00470         $assignment->id = $returnid;
00471 
00472         if ($assignment->timedue) {
00473             $event = new stdClass();
00474             $event->name        = $assignment->name;
00475             $event->description = format_module_intro('assignment', $assignment, $assignment->coursemodule);
00476             $event->courseid    = $assignment->course;
00477             $event->groupid     = 0;
00478             $event->userid      = 0;
00479             $event->modulename  = 'assignment';
00480             $event->instance    = $returnid;
00481             $event->eventtype   = 'due';
00482             $event->timestart   = $assignment->timedue;
00483             $event->timeduration = 0;
00484 
00485             calendar_event::create($event);
00486         }
00487 
00488         assignment_grade_item_update($assignment);
00489 
00490         return $returnid;
00491     }
00492 
00503     function delete_instance($assignment) {
00504         global $CFG, $DB;
00505 
00506         $assignment->courseid = $assignment->course;
00507 
00508         $result = true;
00509 
00510         // now get rid of all files
00511         $fs = get_file_storage();
00512         if ($cm = get_coursemodule_from_instance('assignment', $assignment->id)) {
00513             $context = get_context_instance(CONTEXT_MODULE, $cm->id);
00514             $fs->delete_area_files($context->id);
00515         }
00516 
00517         if (! $DB->delete_records('assignment_submissions', array('assignment'=>$assignment->id))) {
00518             $result = false;
00519         }
00520 
00521         if (! $DB->delete_records('event', array('modulename'=>'assignment', 'instance'=>$assignment->id))) {
00522             $result = false;
00523         }
00524 
00525         if (! $DB->delete_records('assignment', array('id'=>$assignment->id))) {
00526             $result = false;
00527         }
00528         $mod = $DB->get_field('modules','id',array('name'=>'assignment'));
00529 
00530         assignment_grade_item_delete($assignment);
00531 
00532         return $result;
00533     }
00534 
00549     function update_instance($assignment) {
00550         global $COURSE, $DB;
00551 
00552         $assignment->timemodified = time();
00553 
00554         $assignment->id = $assignment->instance;
00555         $assignment->courseid = $assignment->course;
00556 
00557         $DB->update_record('assignment', $assignment);
00558 
00559         if ($assignment->timedue) {
00560             $event = new stdClass();
00561 
00562             if ($event->id = $DB->get_field('event', 'id', array('modulename'=>'assignment', 'instance'=>$assignment->id))) {
00563 
00564                 $event->name        = $assignment->name;
00565                 $event->description = format_module_intro('assignment', $assignment, $assignment->coursemodule);
00566                 $event->timestart   = $assignment->timedue;
00567 
00568                 $calendarevent = calendar_event::load($event->id);
00569                 $calendarevent->update($event);
00570             } else {
00571                 $event = new stdClass();
00572                 $event->name        = $assignment->name;
00573                 $event->description = format_module_intro('assignment', $assignment, $assignment->coursemodule);
00574                 $event->courseid    = $assignment->course;
00575                 $event->groupid     = 0;
00576                 $event->userid      = 0;
00577                 $event->modulename  = 'assignment';
00578                 $event->instance    = $assignment->id;
00579                 $event->eventtype   = 'due';
00580                 $event->timestart   = $assignment->timedue;
00581                 $event->timeduration = 0;
00582 
00583                 calendar_event::create($event);
00584             }
00585         } else {
00586             $DB->delete_records('event', array('modulename'=>'assignment', 'instance'=>$assignment->id));
00587         }
00588 
00589         // get existing grade item
00590         assignment_grade_item_update($assignment);
00591 
00592         return true;
00593     }
00594 
00598     function update_grade($submission) {
00599         assignment_update_grades($this->assignment, $submission->userid);
00600     }
00601 
00611     function submissions($mode) {
00616 
00617         //make user global so we can use the id
00618         global $USER, $OUTPUT, $DB, $PAGE;
00619 
00620         $mailinfo = optional_param('mailinfo', null, PARAM_BOOL);
00621 
00622         if (optional_param('next', null, PARAM_BOOL)) {
00623             $mode='next';
00624         }
00625         if (optional_param('saveandnext', null, PARAM_BOOL)) {
00626             $mode='saveandnext';
00627         }
00628 
00629         if (is_null($mailinfo)) {
00630             if (optional_param('sesskey', null, PARAM_BOOL)) {
00631                 set_user_preference('assignment_mailinfo', 0);
00632             } else {
00633                 $mailinfo = get_user_preferences('assignment_mailinfo', 0);
00634             }
00635         } else {
00636             set_user_preference('assignment_mailinfo', $mailinfo);
00637         }
00638 
00639         if (!($this->validate_and_preprocess_feedback())) {
00640             // form was submitted ('Save' or 'Save and next' was pressed, but validation failed)
00641             $this->display_submission();
00642             return;
00643         }
00644 
00645         switch ($mode) {
00646             case 'grade':                         // We are in a main window grading
00647                 if ($submission = $this->process_feedback()) {
00648                     $this->display_submissions(get_string('changessaved'));
00649                 } else {
00650                     $this->display_submissions();
00651                 }
00652                 break;
00653 
00654             case 'single':                        // We are in a main window displaying one submission
00655                 if ($submission = $this->process_feedback()) {
00656                     $this->display_submissions(get_string('changessaved'));
00657                 } else {
00658                     $this->display_submission();
00659                 }
00660                 break;
00661 
00662             case 'all':                          // Main window, display everything
00663                 $this->display_submissions();
00664                 break;
00665 
00666             case 'fastgrade':
00668                 $grading    = false;
00669                 $commenting = false;
00670                 $col        = false;
00671                 if (isset($_POST['submissioncomment'])) {
00672                     $col = 'submissioncomment';
00673                     $commenting = true;
00674                 }
00675                 if (isset($_POST['menu'])) {
00676                     $col = 'menu';
00677                     $grading = true;
00678                 }
00679                 if (!$col) {
00680                     //both submissioncomment and grade columns collapsed..
00681                     $this->display_submissions();
00682                     break;
00683                 }
00684 
00685                 foreach ($_POST[$col] as $id => $unusedvalue){
00686 
00687                     $id = (int)$id; //clean parameter name
00688 
00689                     $this->process_outcomes($id);
00690 
00691                     if (!$submission = $this->get_submission($id)) {
00692                         $submission = $this->prepare_new_submission($id);
00693                         $newsubmission = true;
00694                     } else {
00695                         $newsubmission = false;
00696                     }
00697                     unset($submission->data1);  // Don't need to update this.
00698                     unset($submission->data2);  // Don't need to update this.
00699 
00700                     //for fast grade, we need to check if any changes take place
00701                     $updatedb = false;
00702 
00703                     if ($grading) {
00704                         $grade = $_POST['menu'][$id];
00705                         $updatedb = $updatedb || ($submission->grade != $grade);
00706                         $submission->grade = $grade;
00707                     } else {
00708                         if (!$newsubmission) {
00709                             unset($submission->grade);  // Don't need to update this.
00710                         }
00711                     }
00712                     if ($commenting) {
00713                         $commentvalue = trim($_POST['submissioncomment'][$id]);
00714                         $updatedb = $updatedb || ($submission->submissioncomment != $commentvalue);
00715                         $submission->submissioncomment = $commentvalue;
00716                     } else {
00717                         unset($submission->submissioncomment);  // Don't need to update this.
00718                     }
00719 
00720                     $submission->teacher    = $USER->id;
00721                     if ($updatedb) {
00722                         $submission->mailed = (int)(!$mailinfo);
00723                     }
00724 
00725                     $submission->timemarked = time();
00726 
00727                     //if it is not an update, we don't change the last modified time etc.
00728                     //this will also not write into database if no submissioncomment and grade is entered.
00729 
00730                     if ($updatedb){
00731                         if ($newsubmission) {
00732                             if (!isset($submission->submissioncomment)) {
00733                                 $submission->submissioncomment = '';
00734                             }
00735                             $sid = $DB->insert_record('assignment_submissions', $submission);
00736                             $submission->id = $sid;
00737                         } else {
00738                             $DB->update_record('assignment_submissions', $submission);
00739                         }
00740 
00741                         // trigger grade event
00742                         $this->update_grade($submission);
00743 
00744                         //add to log only if updating
00745                         add_to_log($this->course->id, 'assignment', 'update grades',
00746                                    'submissions.php?id='.$this->cm->id.'&user='.$submission->userid,
00747                                    $submission->userid, $this->cm->id);
00748                     }
00749 
00750                 }
00751 
00752                 $message = $OUTPUT->notification(get_string('changessaved'), 'notifysuccess');
00753 
00754                 $this->display_submissions($message);
00755                 break;
00756 
00757 
00758             case 'saveandnext':
00760                 //first we save the current changes
00761                 if ($submission = $this->process_feedback()) {
00762                     //print_heading(get_string('changessaved'));
00763                     //$extra_javascript = $this->update_main_listing($submission);
00764                 }
00765 
00766             case 'next':
00770                 $offset = required_param('offset', PARAM_INT);
00771                 $nextid = required_param('nextid', PARAM_INT);
00772                 $id = required_param('id', PARAM_INT);
00773                 $filter = optional_param('filter', self::FILTER_ALL, PARAM_INT);
00774 
00775                 if ($mode == 'next' || $filter !== self::FILTER_REQUIRE_GRADING) {
00776                     $offset = (int)$offset+1;
00777                 }
00778                 $redirect = new moodle_url('submissions.php',
00779                         array('id' => $id, 'offset' => $offset, 'userid' => $nextid,
00780                         'mode' => 'single', 'filter' => $filter));
00781 
00782                 redirect($redirect);
00783                 break;
00784 
00785             case 'singlenosave':
00786                 $this->display_submission();
00787                 break;
00788 
00789             default:
00790                 echo "something seriously is wrong!!";
00791                 break;
00792         }
00793     }
00794 
00803     public final function quickgrade_mode_allowed() {
00804         global $CFG;
00805         require_once("$CFG->dirroot/grade/grading/lib.php");
00806         if ($controller = get_grading_manager($this->context, 'mod_assignment', 'submission')->get_active_controller()) {
00807             return false;
00808         }
00809         return true;
00810     }
00811 
00819     function update_main_listing($submission) {
00820         global $SESSION, $CFG, $OUTPUT;
00821 
00822         $output = '';
00823 
00824         $perpage = get_user_preferences('assignment_perpage', 10);
00825 
00826         $quickgrade = get_user_preferences('assignment_quickgrade', 0) && $this->quickgrade_mode_allowed();
00827 
00829         $output .= '<script type="text/javascript">'."\n<!--\n";
00830         if (empty($SESSION->flextable['mod-assignment-submissions']->collapse['submissioncomment'])) {
00831             if ($quickgrade){
00832                 $output.= 'opener.document.getElementById("submissioncomment'.$submission->userid.'").value="'
00833                 .trim($submission->submissioncomment).'";'."\n";
00834              } else {
00835                 $output.= 'opener.document.getElementById("com'.$submission->userid.
00836                 '").innerHTML="'.shorten_text(trim(strip_tags($submission->submissioncomment)), 15)."\";\n";
00837             }
00838         }
00839 
00840         if (empty($SESSION->flextable['mod-assignment-submissions']->collapse['grade'])) {
00841             //echo optional_param('menuindex');
00842             if ($quickgrade){
00843                 $output.= 'opener.document.getElementById("menumenu'.$submission->userid.
00844                 '").selectedIndex="'.optional_param('menuindex', 0, PARAM_INT).'";'."\n";
00845             } else {
00846                 $output.= 'opener.document.getElementById("g'.$submission->userid.'").innerHTML="'.
00847                 $this->display_grade($submission->grade)."\";\n";
00848             }
00849         }
00850         //need to add student's assignments in there too.
00851         if (empty($SESSION->flextable['mod-assignment-submissions']->collapse['timemodified']) &&
00852             $submission->timemodified) {
00853             $output.= 'opener.document.getElementById("ts'.$submission->userid.
00854                  '").innerHTML="'.addslashes_js($this->print_student_answer($submission->userid)).userdate($submission->timemodified)."\";\n";
00855         }
00856 
00857         if (empty($SESSION->flextable['mod-assignment-submissions']->collapse['timemarked']) &&
00858             $submission->timemarked) {
00859             $output.= 'opener.document.getElementById("tt'.$submission->userid.
00860                  '").innerHTML="'.userdate($submission->timemarked)."\";\n";
00861         }
00862 
00863         if (empty($SESSION->flextable['mod-assignment-submissions']->collapse['status'])) {
00864             $output.= 'opener.document.getElementById("up'.$submission->userid.'").className="s1";';
00865             $buttontext = get_string('update');
00866             $url = new moodle_url('/mod/assignment/submissions.php', array(
00867                     'id' => $this->cm->id,
00868                     'userid' => $submission->userid,
00869                     'mode' => 'single',
00870                     'offset' => (optional_param('offset', '', PARAM_INT)-1)));
00871             $button = $OUTPUT->action_link($url, $buttontext, new popup_action('click', $url, 'grade'.$submission->userid, array('height' => 450, 'width' => 700)), array('ttile'=>$buttontext));
00872 
00873             $output .= 'opener.document.getElementById("up'.$submission->userid.'").innerHTML="'.addslashes_js($button).'";';
00874         }
00875 
00876         $grading_info = grade_get_grades($this->course->id, 'mod', 'assignment', $this->assignment->id, $submission->userid);
00877 
00878         if (empty($SESSION->flextable['mod-assignment-submissions']->collapse['finalgrade'])) {
00879             $output.= 'opener.document.getElementById("finalgrade_'.$submission->userid.
00880             '").innerHTML="'.$grading_info->items[0]->grades[$submission->userid]->str_grade.'";'."\n";
00881         }
00882 
00883         if (!empty($CFG->enableoutcomes) and empty($SESSION->flextable['mod-assignment-submissions']->collapse['outcome'])) {
00884 
00885             if (!empty($grading_info->outcomes)) {
00886                 foreach($grading_info->outcomes as $n=>$outcome) {
00887                     if ($outcome->grades[$submission->userid]->locked) {
00888                         continue;
00889                     }
00890 
00891                     if ($quickgrade){
00892                         $output.= 'opener.document.getElementById("outcome_'.$n.'_'.$submission->userid.
00893                         '").selectedIndex="'.$outcome->grades[$submission->userid]->grade.'";'."\n";
00894 
00895                     } else {
00896                         $options = make_grades_menu(-$outcome->scaleid);
00897                         $options[0] = get_string('nooutcome', 'grades');
00898                         $output.= 'opener.document.getElementById("outcome_'.$n.'_'.$submission->userid.'").innerHTML="'.$options[$outcome->grades[$submission->userid]->grade]."\";\n";
00899                     }
00900 
00901                 }
00902             }
00903         }
00904 
00905         $output .= "\n-->\n</script>";
00906         return $output;
00907     }
00908 
00916     function display_grade($grade) {
00917         global $DB;
00918 
00919         static $scalegrades = array();   // Cache scales for each assignment - they might have different scales!!
00920 
00921         if ($this->assignment->grade >= 0) {    // Normal number
00922             if ($grade == -1) {
00923                 return '-';
00924             } else {
00925                 return $grade.' / '.$this->assignment->grade;
00926             }
00927 
00928         } else {                                // Scale
00929             if (empty($scalegrades[$this->assignment->id])) {
00930                 if ($scale = $DB->get_record('scale', array('id'=>-($this->assignment->grade)))) {
00931                     $scalegrades[$this->assignment->id] = make_menu_from_list($scale->scale);
00932                 } else {
00933                     return '-';
00934                 }
00935             }
00936             if (isset($scalegrades[$this->assignment->id][$grade])) {
00937                 return $scalegrades[$this->assignment->id][$grade];
00938             }
00939             return '-';
00940         }
00941     }
00942 
00958     function display_submission($offset=-1,$userid =-1, $display=true) {
00959         global $CFG, $DB, $PAGE, $OUTPUT, $USER;
00960         require_once($CFG->libdir.'/gradelib.php');
00961         require_once($CFG->libdir.'/tablelib.php');
00962         require_once("$CFG->dirroot/repository/lib.php");
00963         require_once("$CFG->dirroot/grade/grading/lib.php");
00964         if ($userid==-1) {
00965             $userid = required_param('userid', PARAM_INT);
00966         }
00967         if ($offset==-1) {
00968             $offset = required_param('offset', PARAM_INT);//offset for where to start looking for student.
00969         }
00970         $filter = optional_param('filter', 0, PARAM_INT);
00971 
00972         if (!$user = $DB->get_record('user', array('id'=>$userid))) {
00973             print_error('nousers');
00974         }
00975 
00976         if (!$submission = $this->get_submission($user->id)) {
00977             $submission = $this->prepare_new_submission($userid);
00978         }
00979         if ($submission->timemodified > $submission->timemarked) {
00980             $subtype = 'assignmentnew';
00981         } else {
00982             $subtype = 'assignmentold';
00983         }
00984 
00985         $grading_info = grade_get_grades($this->course->id, 'mod', 'assignment', $this->assignment->id, array($user->id));
00986         $gradingdisabled = $grading_info->items[0]->grades[$userid]->locked || $grading_info->items[0]->grades[$userid]->overridden;
00987 
00989         $course     = $this->course;
00990         $assignment = $this->assignment;
00991         $cm         = $this->cm;
00992         $context    = get_context_instance(CONTEXT_MODULE, $cm->id);
00993 
00994         //reset filter to all for offline assignment
00995         if ($assignment->assignmenttype == 'offline' && $filter == self::FILTER_SUBMITTED) {
00996             $filter = self::FILTER_ALL;
00997         }
00999 
01000         $currentgroup = groups_get_activity_group($cm);
01001         $users = get_enrolled_users($context, 'mod/assignment:submit', $currentgroup, 'u.id');
01002         if ($users) {
01003             $users = array_keys($users);
01004             // if groupmembersonly used, remove users who are not in any group
01005             if (!empty($CFG->enablegroupmembersonly) and $cm->groupmembersonly) {
01006                 if ($groupingusers = groups_get_grouping_members($cm->groupingid, 'u.id', 'u.id')) {
01007                     $users = array_intersect($users, array_keys($groupingusers));
01008                 }
01009             }
01010         }
01011 
01012         $nextid = 0;
01013         $where = '';
01014         if($filter == self::FILTER_SUBMITTED) {
01015             $where .= 's.timemodified > 0 AND ';
01016         } else if($filter == self::FILTER_REQUIRE_GRADING) {
01017             $where .= 's.timemarked < s.timemodified AND ';
01018         }
01019 
01020         if ($users) {
01021             $userfields = user_picture::fields('u', array('lastaccess'));
01022             $select = "SELECT $userfields,
01023                               s.id AS submissionid, s.grade, s.submissioncomment,
01024                               s.timemodified, s.timemarked,
01025                               CASE WHEN s.timemarked > 0 AND s.timemarked >= s.timemodified THEN 1
01026                                    ELSE 0 END AS status ";
01027 
01028             $sql = 'FROM {user} u '.
01029                    'LEFT JOIN {assignment_submissions} s ON u.id = s.userid
01030                    AND s.assignment = '.$this->assignment->id.' '.
01031                    'WHERE '.$where.'u.id IN ('.implode(',', $users).') ';
01032 
01033             if ($sort = flexible_table::get_sort_for_table('mod-assignment-submissions')) {
01034                 $sort = 'ORDER BY '.$sort.' ';
01035             }
01036             $auser = $DB->get_records_sql($select.$sql.$sort, null, $offset, 2);
01037 
01038             if (is_array($auser) && count($auser)>1) {
01039                 $nextuser = next($auser);
01040                 $nextid = $nextuser->id;
01041             }
01042         }
01043 
01044         if ($submission->teacher) {
01045             $teacher = $DB->get_record('user', array('id'=>$submission->teacher));
01046         } else {
01047             global $USER;
01048             $teacher = $USER;
01049         }
01050 
01051         $this->preprocess_submission($submission);
01052 
01053         $mformdata = new stdClass();
01054         $mformdata->context = $this->context;
01055         $mformdata->maxbytes = $this->course->maxbytes;
01056         $mformdata->courseid = $this->course->id;
01057         $mformdata->teacher = $teacher;
01058         $mformdata->assignment = $assignment;
01059         $mformdata->submission = $submission;
01060         $mformdata->lateness = $this->display_lateness($submission->timemodified);
01061         $mformdata->auser = $auser;
01062         $mformdata->user = $user;
01063         $mformdata->offset = $offset;
01064         $mformdata->userid = $userid;
01065         $mformdata->cm = $this->cm;
01066         $mformdata->grading_info = $grading_info;
01067         $mformdata->enableoutcomes = $CFG->enableoutcomes;
01068         $mformdata->grade = $this->assignment->grade;
01069         $mformdata->gradingdisabled = $gradingdisabled;
01070         $mformdata->nextid = $nextid;
01071         $mformdata->submissioncomment= $submission->submissioncomment;
01072         $mformdata->submissioncommentformat= FORMAT_HTML;
01073         $mformdata->submission_content= $this->print_user_files($user->id,true);
01074         $mformdata->filter = $filter;
01075         $mformdata->mailinfo = get_user_preferences('assignment_mailinfo', 0);
01076          if ($assignment->assignmenttype == 'upload') {
01077             $mformdata->fileui_options = array('subdirs'=>1, 'maxbytes'=>$assignment->maxbytes, 'maxfiles'=>$assignment->var1, 'accepted_types'=>'*', 'return_types'=>FILE_INTERNAL);
01078         } elseif ($assignment->assignmenttype == 'uploadsingle') {
01079             $mformdata->fileui_options = array('subdirs'=>0, 'maxbytes'=>$CFG->userquota, 'maxfiles'=>1, 'accepted_types'=>'*', 'return_types'=>FILE_INTERNAL);
01080         }
01081         $advancedgradingwarning = false;
01082         $gradingmanager = get_grading_manager($this->context, 'mod_assignment', 'submission');
01083         if ($gradingmethod = $gradingmanager->get_active_method()) {
01084             $controller = $gradingmanager->get_controller($gradingmethod);
01085             if ($controller->is_form_available()) {
01086                 $itemid = null;
01087                 if (!empty($submission->id)) {
01088                     $itemid = $submission->id;
01089                 }
01090                 if ($gradingdisabled && $itemid) {
01091                     $mformdata->advancedgradinginstance = $controller->get_current_instance($USER->id, $itemid);
01092                 } else if (!$gradingdisabled) {
01093                     $instanceid = optional_param('advancedgradinginstanceid', 0, PARAM_INT);
01094                     $mformdata->advancedgradinginstance = $controller->get_or_create_instance($instanceid, $USER->id, $itemid);
01095                 }
01096             } else {
01097                 $advancedgradingwarning = $controller->form_unavailable_notification();
01098             }
01099         }
01100 
01101         $submitform = new mod_assignment_grading_form( null, $mformdata );
01102 
01103          if (!$display) {
01104             $ret_data = new stdClass();
01105             $ret_data->mform = $submitform;
01106             if (isset($mformdata->fileui_options)) {
01107                 $ret_data->fileui_options = $mformdata->fileui_options;
01108             }
01109             return $ret_data;
01110         }
01111 
01112         if ($submitform->is_cancelled()) {
01113             redirect('submissions.php?id='.$this->cm->id);
01114         }
01115 
01116         $submitform->set_data($mformdata);
01117 
01118         $PAGE->set_title($this->course->fullname . ': ' .get_string('feedback', 'assignment').' - '.fullname($user, true));
01119         $PAGE->set_heading($this->course->fullname);
01120         $PAGE->navbar->add(get_string('submissions', 'assignment'), new moodle_url('/mod/assignment/submissions.php', array('id'=>$cm->id)));
01121         $PAGE->navbar->add(fullname($user, true));
01122 
01123         echo $OUTPUT->header();
01124         echo $OUTPUT->heading(get_string('feedback', 'assignment').': '.fullname($user, true));
01125 
01126         // display mform here...
01127         if ($advancedgradingwarning) {
01128             echo $OUTPUT->notification($advancedgradingwarning, 'error');
01129         }
01130         $submitform->display();
01131 
01132         $customfeedback = $this->custom_feedbackform($submission, true);
01133         if (!empty($customfeedback)) {
01134             echo $customfeedback;
01135         }
01136 
01137         echo $OUTPUT->footer();
01138     }
01139 
01148     function preprocess_submission(&$submission) {
01149     }
01150 
01161     function display_submissions($message='') {
01162         global $CFG, $DB, $USER, $DB, $OUTPUT, $PAGE;
01163         require_once($CFG->libdir.'/gradelib.php');
01164 
01165         /* first we check to see if the form has just been submitted
01166          * to request user_preference updates
01167          */
01168 
01169        $filters = array(self::FILTER_ALL             => get_string('all'),
01170                         self::FILTER_REQUIRE_GRADING => get_string('requiregrading', 'assignment'));
01171 
01172         $updatepref = optional_param('updatepref', 0, PARAM_BOOL);
01173         if ($updatepref) {
01174             $perpage = optional_param('perpage', 10, PARAM_INT);
01175             $perpage = ($perpage <= 0) ? 10 : $perpage ;
01176             $filter = optional_param('filter', 0, PARAM_INT);
01177             set_user_preference('assignment_perpage', $perpage);
01178             set_user_preference('assignment_quickgrade', optional_param('quickgrade', 0, PARAM_BOOL));
01179             set_user_preference('assignment_filter', $filter);
01180         }
01181 
01182         /* next we get perpage and quickgrade (allow quick grade) params
01183          * from database
01184          */
01185         $perpage    = get_user_preferences('assignment_perpage', 10);
01186         $quickgrade = get_user_preferences('assignment_quickgrade', 0) && $this->quickgrade_mode_allowed();
01187         $filter = get_user_preferences('assignment_filter', 0);
01188         $grading_info = grade_get_grades($this->course->id, 'mod', 'assignment', $this->assignment->id);
01189 
01190         if (!empty($CFG->enableoutcomes) and !empty($grading_info->outcomes)) {
01191             $uses_outcomes = true;
01192         } else {
01193             $uses_outcomes = false;
01194         }
01195 
01196         $page    = optional_param('page', 0, PARAM_INT);
01197         $strsaveallfeedback = get_string('saveallfeedback', 'assignment');
01198 
01200 
01201         $course     = $this->course;
01202         $assignment = $this->assignment;
01203         $cm         = $this->cm;
01204         $hassubmission = false;
01205 
01206         // reset filter to all for offline assignment only.
01207         if ($assignment->assignmenttype == 'offline') {
01208             if ($filter == self::FILTER_SUBMITTED) {
01209                 $filter = self::FILTER_ALL;
01210             }
01211         } else {
01212             $filters[self::FILTER_SUBMITTED] = get_string('submitted', 'assignment');
01213         }
01214 
01215         $tabindex = 1; //tabindex for quick grading tabbing; Not working for dropdowns yet
01216         add_to_log($course->id, 'assignment', 'view submission', 'submissions.php?id='.$this->cm->id, $this->assignment->id, $this->cm->id);
01217 
01218         $PAGE->set_title(format_string($this->assignment->name,true));
01219         $PAGE->set_heading($this->course->fullname);
01220         echo $OUTPUT->header();
01221 
01222         echo '<div class="usersubmissions">';
01223 
01224         //hook to allow plagiarism plugins to update status/print links.
01225         echo plagiarism_update_status($this->course, $this->cm);
01226 
01227         $course_context = get_context_instance(CONTEXT_COURSE, $course->id);
01228         if (has_capability('gradereport/grader:view', $course_context) && has_capability('moodle/grade:viewall', $course_context)) {
01229             echo '<div class="allcoursegrades"><a href="' . $CFG->wwwroot . '/grade/report/grader/index.php?id=' . $course->id . '">'
01230                 . get_string('seeallcoursegrades', 'grades') . '</a></div>';
01231         }
01232 
01233         if (!empty($message)) {
01234             echo $message;   // display messages here if any
01235         }
01236 
01237         $context = get_context_instance(CONTEXT_MODULE, $cm->id);
01238 
01240 
01242         $groupmode = groups_get_activity_groupmode($cm);
01243         $currentgroup = groups_get_activity_group($cm, true);
01244         groups_print_activity_menu($cm, $CFG->wwwroot . '/mod/assignment/submissions.php?id=' . $this->cm->id);
01245 
01247         if ($quickgrade) {
01248             $formattrs = array();
01249             $formattrs['action'] = new moodle_url('/mod/assignment/submissions.php');
01250             $formattrs['id'] = 'fastg';
01251             $formattrs['method'] = 'post';
01252 
01253             echo html_writer::start_tag('form', $formattrs);
01254             echo html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>'id',      'value'=> $this->cm->id));
01255             echo html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>'mode',    'value'=> 'fastgrade'));
01256             echo html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>'page',    'value'=> $page));
01257             echo html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>'sesskey', 'value'=> sesskey()));
01258         }
01259 
01261         list($esql, $params) = get_enrolled_sql($context, 'mod/assignment:submit', $currentgroup);
01262 
01263         if ($filter == self::FILTER_ALL) {
01264             $sql = "SELECT u.id FROM {user} u ".
01265                    "LEFT JOIN ($esql) eu ON eu.id=u.id ".
01266                    "WHERE u.deleted = 0 AND eu.id=u.id ";
01267         } else {
01268             $wherefilter = ' AND s.assignment = '. $this->assignment->id;
01269             $assignmentsubmission = "LEFT JOIN {assignment_submissions} s ON (u.id = s.userid) ";
01270             if($filter == self::FILTER_SUBMITTED) {
01271                 $wherefilter .= ' AND s.timemodified > 0 ';
01272             } else if($filter == self::FILTER_REQUIRE_GRADING && $assignment->assignmenttype != 'offline') {
01273                 $wherefilter .= ' AND s.timemarked < s.timemodified ';
01274             } else { // require grading for offline assignment
01275                 $assignmentsubmission = "";
01276                 $wherefilter = "";
01277             }
01278 
01279             $sql = "SELECT u.id FROM {user} u ".
01280                    "LEFT JOIN ($esql) eu ON eu.id=u.id ".
01281                    $assignmentsubmission.
01282                    "WHERE u.deleted = 0 AND eu.id=u.id ".
01283                    $wherefilter;
01284         }
01285 
01286         $users = $DB->get_records_sql($sql, $params);
01287         if (!empty($users)) {
01288             if($assignment->assignmenttype == 'offline' && $filter == self::FILTER_REQUIRE_GRADING) {
01289                 //remove users who has submitted their assignment
01290                 foreach ($this->get_submissions() as $submission) {
01291                     if (array_key_exists($submission->userid, $users)) {
01292                         unset($users[$submission->userid]);
01293                     }
01294                 }
01295             }
01296             $users = array_keys($users);
01297         }
01298 
01299         // if groupmembersonly used, remove users who are not in any group
01300         if ($users and !empty($CFG->enablegroupmembersonly) and $cm->groupmembersonly) {
01301             if ($groupingusers = groups_get_grouping_members($cm->groupingid, 'u.id', 'u.id')) {
01302                 $users = array_intersect($users, array_keys($groupingusers));
01303             }
01304         }
01305 
01306         $extrafields = get_extra_user_fields($context);
01307         $tablecolumns = array_merge(array('picture', 'fullname'), $extrafields,
01308                 array('grade', 'submissioncomment', 'timemodified', 'timemarked', 'status', 'finalgrade'));
01309         if ($uses_outcomes) {
01310             $tablecolumns[] = 'outcome'; // no sorting based on outcomes column
01311         }
01312 
01313         $extrafieldnames = array();
01314         foreach ($extrafields as $field) {
01315             $extrafieldnames[] = get_user_field_name($field);
01316         }
01317         $tableheaders = array_merge(
01318                 array('', get_string('fullnameuser')),
01319                 $extrafieldnames,
01320                 array(
01321                     get_string('grade'),
01322                     get_string('comment', 'assignment'),
01323                     get_string('lastmodified').' ('.get_string('submission', 'assignment').')',
01324                     get_string('lastmodified').' ('.get_string('grade').')',
01325                     get_string('status'),
01326                     get_string('finalgrade', 'grades'),
01327                 ));
01328         if ($uses_outcomes) {
01329             $tableheaders[] = get_string('outcome', 'grades');
01330         }
01331 
01332         require_once($CFG->libdir.'/tablelib.php');
01333         $table = new flexible_table('mod-assignment-submissions');
01334 
01335         $table->define_columns($tablecolumns);
01336         $table->define_headers($tableheaders);
01337         $table->define_baseurl($CFG->wwwroot.'/mod/assignment/submissions.php?id='.$this->cm->id.'&amp;currentgroup='.$currentgroup);
01338 
01339         $table->sortable(true, 'lastname');//sorted by lastname by default
01340         $table->collapsible(true);
01341         $table->initialbars(true);
01342 
01343         $table->column_suppress('picture');
01344         $table->column_suppress('fullname');
01345 
01346         $table->column_class('picture', 'picture');
01347         $table->column_class('fullname', 'fullname');
01348         foreach ($extrafields as $field) {
01349             $table->column_class($field, $field);
01350         }
01351         $table->column_class('grade', 'grade');
01352         $table->column_class('submissioncomment', 'comment');
01353         $table->column_class('timemodified', 'timemodified');
01354         $table->column_class('timemarked', 'timemarked');
01355         $table->column_class('status', 'status');
01356         $table->column_class('finalgrade', 'finalgrade');
01357         if ($uses_outcomes) {
01358             $table->column_class('outcome', 'outcome');
01359         }
01360 
01361         $table->set_attribute('cellspacing', '0');
01362         $table->set_attribute('id', 'attempts');
01363         $table->set_attribute('class', 'submissions');
01364         $table->set_attribute('width', '100%');
01365 
01366         $table->no_sorting('finalgrade');
01367         $table->no_sorting('outcome');
01368 
01369         // Start working -- this is necessary as soon as the niceties are over
01370         $table->setup();
01371 
01373         list($where, $params) = $table->get_sql_where();
01374         if ($where) {
01375             $where .= ' AND ';
01376         }
01377 
01378         if ($filter == self::FILTER_SUBMITTED) {
01379            $where .= 's.timemodified > 0 AND ';
01380         } else if($filter == self::FILTER_REQUIRE_GRADING) {
01381             $where = '';
01382             if ($assignment->assignmenttype != 'offline') {
01383                $where .= 's.timemarked < s.timemodified AND ';
01384             }
01385         }
01386 
01387         if ($sort = $table->get_sql_sort()) {
01388             $sort = ' ORDER BY '.$sort;
01389         }
01390 
01391         $ufields = user_picture::fields('u', $extrafields);
01392         if (!empty($users)) {
01393             $select = "SELECT $ufields,
01394                               s.id AS submissionid, s.grade, s.submissioncomment,
01395                               s.timemodified, s.timemarked,
01396                               CASE WHEN s.timemarked > 0 AND s.timemarked >= s.timemodified THEN 1
01397                                    ELSE 0 END AS status ";
01398 
01399             $sql = 'FROM {user} u '.
01400                    'LEFT JOIN {assignment_submissions} s ON u.id = s.userid
01401                     AND s.assignment = '.$this->assignment->id.' '.
01402                    'WHERE '.$where.'u.id IN ('.implode(',',$users).') ';
01403 
01404             $ausers = $DB->get_records_sql($select.$sql.$sort, $params, $table->get_page_start(), $table->get_page_size());
01405 
01406             $table->pagesize($perpage, count($users));
01407 
01409             $offset = $page * $perpage;
01410             $strupdate = get_string('update');
01411             $strgrade  = get_string('grade');
01412             $grademenu = make_grades_menu($this->assignment->grade);
01413 
01414             if ($ausers !== false) {
01415                 $grading_info = grade_get_grades($this->course->id, 'mod', 'assignment', $this->assignment->id, array_keys($ausers));
01416                 $endposition = $offset + $perpage;
01417                 $currentposition = 0;
01418                 foreach ($ausers as $auser) {
01419                     if ($currentposition == $offset && $offset < $endposition) {
01420                         $rowclass = null;
01421                         $final_grade = $grading_info->items[0]->grades[$auser->id];
01422                         $grademax = $grading_info->items[0]->grademax;
01423                         $final_grade->formatted_grade = round($final_grade->grade,2) .' / ' . round($grademax,2);
01424                         $locked_overridden = 'locked';
01425                         if ($final_grade->overridden) {
01426                             $locked_overridden = 'overridden';
01427                         }
01428 
01429                         // TODO add here code if advanced grading grade must be reviewed => $auser->status=0
01430 
01431                         $picture = $OUTPUT->user_picture($auser);
01432 
01433                         if (empty($auser->submissionid)) {
01434                             $auser->grade = -1; //no submission yet
01435                         }
01436 
01437                         if (!empty($auser->submissionid)) {
01438                             $hassubmission = true;
01442                             if ($auser->timemodified > 0) {
01443                                 $studentmodifiedcontent = $this->print_student_answer($auser->id)
01444                                         . userdate($auser->timemodified);
01445                                 if ($assignment->timedue && $auser->timemodified > $assignment->timedue) {
01446                                     $studentmodifiedcontent .= assignment_display_lateness($auser->timemodified, $assignment->timedue);
01447                                     $rowclass = 'late';
01448                                 }
01449                             } else {
01450                                 $studentmodifiedcontent = '&nbsp;';
01451                             }
01452                             $studentmodified = html_writer::tag('div', $studentmodifiedcontent, array('id' => 'ts' . $auser->id));
01454                             if ($auser->timemarked > 0) {
01455                                 $teachermodified = '<div id="tt'.$auser->id.'">'.userdate($auser->timemarked).'</div>';
01456 
01457                                 if ($final_grade->locked or $final_grade->overridden) {
01458                                     $grade = '<div id="g'.$auser->id.'" class="'. $locked_overridden .'">'.$final_grade->formatted_grade.'</div>';
01459                                 } else if ($quickgrade) {
01460                                     $attributes = array();
01461                                     $attributes['tabindex'] = $tabindex++;
01462                                     $menu = html_writer::select(make_grades_menu($this->assignment->grade), 'menu['.$auser->id.']', $auser->grade, array(-1=>get_string('nograde')), $attributes);
01463                                     $grade = '<div id="g'.$auser->id.'">'. $menu .'</div>';
01464                                 } else {
01465                                     $grade = '<div id="g'.$auser->id.'">'.$this->display_grade($auser->grade).'</div>';
01466                                 }
01467 
01468                             } else {
01469                                 $teachermodified = '<div id="tt'.$auser->id.'">&nbsp;</div>';
01470                                 if ($final_grade->locked or $final_grade->overridden) {
01471                                     $grade = '<div id="g'.$auser->id.'" class="'. $locked_overridden .'">'.$final_grade->formatted_grade.'</div>';
01472                                 } else if ($quickgrade) {
01473                                     $attributes = array();
01474                                     $attributes['tabindex'] = $tabindex++;
01475                                     $menu = html_writer::select(make_grades_menu($this->assignment->grade), 'menu['.$auser->id.']', $auser->grade, array(-1=>get_string('nograde')), $attributes);
01476                                     $grade = '<div id="g'.$auser->id.'">'.$menu.'</div>';
01477                                 } else {
01478                                     $grade = '<div id="g'.$auser->id.'">'.$this->display_grade($auser->grade).'</div>';
01479                                 }
01480                             }
01482                             if ($final_grade->locked or $final_grade->overridden) {
01483                                 $comment = '<div id="com'.$auser->id.'">'.shorten_text(strip_tags($final_grade->str_feedback),15).'</div>';
01484 
01485                             } else if ($quickgrade) {
01486                                 $comment = '<div id="com'.$auser->id.'">'
01487                                          . '<textarea tabindex="'.$tabindex++.'" name="submissioncomment['.$auser->id.']" id="submissioncomment'
01488                                          . $auser->id.'" rows="2" cols="20">'.($auser->submissioncomment).'</textarea></div>';
01489                             } else {
01490                                 $comment = '<div id="com'.$auser->id.'">'.shorten_text(strip_tags($auser->submissioncomment),15).'</div>';
01491                             }
01492                         } else {
01493                             $studentmodified = '<div id="ts'.$auser->id.'">&nbsp;</div>';
01494                             $teachermodified = '<div id="tt'.$auser->id.'">&nbsp;</div>';
01495                             $status          = '<div id="st'.$auser->id.'">&nbsp;</div>';
01496 
01497                             if ($final_grade->locked or $final_grade->overridden) {
01498                                 $grade = '<div id="g'.$auser->id.'">'.$final_grade->formatted_grade . '</div>';
01499                                 $hassubmission = true;
01500                             } else if ($quickgrade) {   // allow editing
01501                                 $attributes = array();
01502                                 $attributes['tabindex'] = $tabindex++;
01503                                 $menu = html_writer::select(make_grades_menu($this->assignment->grade), 'menu['.$auser->id.']', $auser->grade, array(-1=>get_string('nograde')), $attributes);
01504                                 $grade = '<div id="g'.$auser->id.'">'.$menu.'</div>';
01505                                 $hassubmission = true;
01506                             } else {
01507                                 $grade = '<div id="g'.$auser->id.'">-</div>';
01508                             }
01509 
01510                             if ($final_grade->locked or $final_grade->overridden) {
01511                                 $comment = '<div id="com'.$auser->id.'">'.$final_grade->str_feedback.'</div>';
01512                             } else if ($quickgrade) {
01513                                 $comment = '<div id="com'.$auser->id.'">'
01514                                          . '<textarea tabindex="'.$tabindex++.'" name="submissioncomment['.$auser->id.']" id="submissioncomment'
01515                                          . $auser->id.'" rows="2" cols="20">'.($auser->submissioncomment).'</textarea></div>';
01516                             } else {
01517                                 $comment = '<div id="com'.$auser->id.'">&nbsp;</div>';
01518                             }
01519                         }
01520 
01521                         if (empty($auser->status)) { 
01522                             $auser->status = 0;
01523                         } else {
01524                             $auser->status = 1;
01525                         }
01526 
01527                         $buttontext = ($auser->status == 1) ? $strupdate : $strgrade;
01528 
01530                         $popup_url = '/mod/assignment/submissions.php?id='.$this->cm->id
01531                                    . '&amp;userid='.$auser->id.'&amp;mode=single'.'&amp;filter='.$filter.'&amp;offset='.$offset++;
01532 
01533                         $button = $OUTPUT->action_link($popup_url, $buttontext);
01534 
01535                         $status  = '<div id="up'.$auser->id.'" class="s'.$auser->status.'">'.$button.'</div>';
01536 
01537                         $finalgrade = '<span id="finalgrade_'.$auser->id.'">'.$final_grade->str_grade.'</span>';
01538 
01539                         $outcomes = '';
01540 
01541                         if ($uses_outcomes) {
01542 
01543                             foreach($grading_info->outcomes as $n=>$outcome) {
01544                                 $outcomes .= '<div class="outcome"><label>'.$outcome->name.'</label>';
01545                                 $options = make_grades_menu(-$outcome->scaleid);
01546 
01547                                 if ($outcome->grades[$auser->id]->locked or !$quickgrade) {
01548                                     $options[0] = get_string('nooutcome', 'grades');
01549                                     $outcomes .= ': <span id="outcome_'.$n.'_'.$auser->id.'">'.$options[$outcome->grades[$auser->id]->grade].'</span>';
01550                                 } else {
01551                                     $attributes = array();
01552                                     $attributes['tabindex'] = $tabindex++;
01553                                     $attributes['id'] = 'outcome_'.$n.'_'.$auser->id;
01554                                     $outcomes .= ' '.html_writer::select($options, 'outcome_'.$n.'['.$auser->id.']', $outcome->grades[$auser->id]->grade, array(0=>get_string('nooutcome', 'grades')), $attributes);
01555                                 }
01556                                 $outcomes .= '</div>';
01557                             }
01558                         }
01559 
01560                         $userlink = '<a href="' . $CFG->wwwroot . '/user/view.php?id=' . $auser->id . '&amp;course=' . $course->id . '">' . fullname($auser, has_capability('moodle/site:viewfullnames', $this->context)) . '</a>';
01561                         $extradata = array();
01562                         foreach ($extrafields as $field) {
01563                             $extradata[] = $auser->{$field};
01564                         }
01565                         $row = array_merge(array($picture, $userlink), $extradata,
01566                                 array($grade, $comment, $studentmodified, $teachermodified,
01567                                 $status, $finalgrade));
01568                         if ($uses_outcomes) {
01569                             $row[] = $outcomes;
01570                         }
01571                         $table->add_data($row, $rowclass);
01572                     }
01573                     $currentposition++;
01574                 }
01575                 if ($hassubmission && ($this->assignment->assignmenttype=='upload' || $this->assignment->assignmenttype=='online' || $this->assignment->assignmenttype=='uploadsingle')) { //TODO: this is an ugly hack, where is the plugin spirit? (skodak)
01576                     echo html_writer::start_tag('div', array('class' => 'mod-assignment-download-link'));
01577                     echo html_writer::link(new moodle_url('/mod/assignment/submissions.php', array('id' => $this->cm->id, 'download' => 'zip')), get_string('downloadall', 'assignment'));
01578                     echo html_writer::end_tag('div');
01579                 }
01580                 $table->print_html();  
01581             } else {
01582                 if ($filter == self::FILTER_SUBMITTED) {
01583                     echo html_writer::tag('div', get_string('nosubmisson', 'assignment'), array('class'=>'nosubmisson'));
01584                 } else if ($filter == self::FILTER_REQUIRE_GRADING) {
01585                     echo html_writer::tag('div', get_string('norequiregrading', 'assignment'), array('class'=>'norequiregrading'));
01586                 }
01587             }
01588         }
01589 
01591         if ($quickgrade && $table->started_output && !empty($users)){
01592             $mailinfopref = false;
01593             if (get_user_preferences('assignment_mailinfo', 1)) {
01594                 $mailinfopref = true;
01595             }
01596             $emailnotification =  html_writer::checkbox('mailinfo', 1, $mailinfopref, get_string('enablenotification','assignment'));
01597 
01598             $emailnotification .= $OUTPUT->help_icon('enablenotification', 'assignment');
01599             echo html_writer::tag('div', $emailnotification, array('class'=>'emailnotification'));
01600 
01601             $savefeedback = html_writer::empty_tag('input', array('type'=>'submit', 'name'=>'fastg', 'value'=>get_string('saveallfeedback', 'assignment')));
01602             echo html_writer::tag('div', $savefeedback, array('class'=>'fastgbutton'));
01603 
01604             echo html_writer::end_tag('form');
01605         } else if ($quickgrade) {
01606             echo html_writer::end_tag('form');
01607         }
01608 
01609         echo '</div>';
01611 
01613 
01614         $formaction = new moodle_url('/mod/assignment/submissions.php', array('id'=>$this->cm->id));
01615         $mform = new MoodleQuickForm('optionspref', 'post', $formaction, '', array('class'=>'optionspref'));
01616 
01617         $mform->addElement('hidden', 'updatepref');
01618         $mform->setDefault('updatepref', 1);
01619         $mform->addElement('header', 'qgprefs', get_string('optionalsettings', 'assignment'));
01620         $mform->addElement('select', 'filter', get_string('show'),  $filters);
01621 
01622         $mform->setDefault('filter', $filter);
01623 
01624         $mform->addElement('text', 'perpage', get_string('pagesize', 'assignment'), array('size'=>1));
01625         $mform->setDefault('perpage', $perpage);
01626 
01627         if ($this->quickgrade_mode_allowed()) {
01628             $mform->addElement('checkbox', 'quickgrade', get_string('quickgrade','assignment'));
01629             $mform->setDefault('quickgrade', $quickgrade);
01630             $mform->addHelpButton('quickgrade', 'quickgrade', 'assignment');
01631         }
01632 
01633         $mform->addElement('submit', 'savepreferences', get_string('savepreferences'));
01634 
01635         $mform->display();
01636 
01637         echo $OUTPUT->footer();
01638     }
01639 
01655     protected function validate_and_preprocess_feedback() {
01656         global $USER, $CFG;
01657         require_once($CFG->libdir.'/gradelib.php');
01658         if (!($feedback = data_submitted()) || !isset($feedback->userid) || !isset($feedback->offset)) {
01659             return true;      // No incoming data, nothing to validate
01660         }
01661         $userid = required_param('userid', PARAM_INT);
01662         $offset = required_param('offset', PARAM_INT);
01663         $gradinginfo = grade_get_grades($this->course->id, 'mod', 'assignment', $this->assignment->id, array($userid));
01664         $gradingdisabled = $gradinginfo->items[0]->grades[$userid]->locked || $gradinginfo->items[0]->grades[$userid]->overridden;
01665         if ($gradingdisabled) {
01666             return true;
01667         }
01668         $submissiondata = $this->display_submission($offset, $userid, false);
01669         $mform = $submissiondata->mform;
01670         $gradinginstance = $mform->use_advanced_grading();
01671         if (optional_param('cancel', false, PARAM_BOOL) || optional_param('next', false, PARAM_BOOL)) {
01672             // form was cancelled
01673             if ($gradinginstance) {
01674                 $gradinginstance->cancel();
01675             }
01676         } else if ($mform->is_submitted()) {
01677             // form was submitted (= a submit button other than 'cancel' or 'next' has been clicked)
01678             if (!$mform->is_validated()) {
01679                 return false;
01680             }
01681             // preprocess advanced grading here
01682             if ($gradinginstance) {
01683                 $data = $mform->get_data();
01684                 // create submission if it did not exist yet because we need submission->id for storing the grading instance
01685                 $submission = $this->get_submission($userid, true);
01686                 $_POST['xgrade'] = $gradinginstance->submit_and_get_grade($data->advancedgrading, $submission->id);
01687             }
01688         }
01689         return true;
01690     }
01691 
01703     function process_feedback($formdata=null) {
01704         global $CFG, $USER, $DB;
01705         require_once($CFG->libdir.'/gradelib.php');
01706 
01707         if (!$feedback = data_submitted() or !confirm_sesskey()) {      // No incoming data?
01708             return false;
01709         }
01710 
01714         if ((int)$feedback->saveuserid !== -1){
01715             $feedback->userid = $feedback->saveuserid;
01716         }
01717 
01718         if (!empty($feedback->cancel)) {          // User hit cancel button
01719             return false;
01720         }
01721 
01722         $grading_info = grade_get_grades($this->course->id, 'mod', 'assignment', $this->assignment->id, $feedback->userid);
01723 
01724         // store outcomes if needed
01725         $this->process_outcomes($feedback->userid);
01726 
01727         $submission = $this->get_submission($feedback->userid, true);  // Get or make one
01728 
01729         if (!($grading_info->items[0]->grades[$feedback->userid]->locked ||
01730             $grading_info->items[0]->grades[$feedback->userid]->overridden) ) {
01731 
01732             $submission->grade      = $feedback->xgrade;
01733             $submission->submissioncomment    = $feedback->submissioncomment_editor['text'];
01734             $submission->teacher    = $USER->id;
01735             $mailinfo = get_user_preferences('assignment_mailinfo', 0);
01736             if (!$mailinfo) {
01737                 $submission->mailed = 1;       // treat as already mailed
01738             } else {
01739                 $submission->mailed = 0;       // Make sure mail goes out (again, even)
01740             }
01741             $submission->timemarked = time();
01742 
01743             unset($submission->data1);  // Don't need to update this.
01744             unset($submission->data2);  // Don't need to update this.
01745 
01746             if (empty($submission->timemodified)) {   // eg for offline assignments
01747                 // $submission->timemodified = time();
01748             }
01749 
01750             $DB->update_record('assignment_submissions', $submission);
01751 
01752             // triger grade event
01753             $this->update_grade($submission);
01754 
01755             add_to_log($this->course->id, 'assignment', 'update grades',
01756                        'submissions.php?id='.$this->cm->id.'&user='.$feedback->userid, $feedback->userid, $this->cm->id);
01757              if (!is_null($formdata)) {
01758                     if ($this->type == 'upload' || $this->type == 'uploadsingle') {
01759                         $mformdata = $formdata->mform->get_data();
01760                         $mformdata = file_postupdate_standard_filemanager($mformdata, 'files', $formdata->fileui_options, $this->context, 'mod_assignment', 'response', $submission->id);
01761                     }
01762              }
01763         }
01764 
01765         return $submission;
01766 
01767     }
01768 
01769     function process_outcomes($userid) {
01770         global $CFG, $USER;
01771 
01772         if (empty($CFG->enableoutcomes)) {
01773             return;
01774         }
01775 
01776         require_once($CFG->libdir.'/gradelib.php');
01777 
01778         if (!$formdata = data_submitted() or !confirm_sesskey()) {
01779             return;
01780         }
01781 
01782         $data = array();
01783         $grading_info = grade_get_grades($this->course->id, 'mod', 'assignment', $this->assignment->id, $userid);
01784 
01785         if (!empty($grading_info->outcomes)) {
01786             foreach($grading_info->outcomes as $n=>$old) {
01787                 $name = 'outcome_'.$n;
01788                 if (isset($formdata->{$name}[$userid]) and $old->grades[$userid]->grade != $formdata->{$name}[$userid]) {
01789                     $data[$n] = $formdata->{$name}[$userid];
01790                 }
01791             }
01792         }
01793         if (count($data) > 0) {
01794             grade_update_outcomes('mod/assignment', $this->course->id, 'mod', 'assignment', $this->assignment->id, $userid, $data);
01795         }
01796 
01797     }
01798 
01809     function get_submission($userid=0, $createnew=false, $teachermodified=false) {
01810         global $USER, $DB;
01811 
01812         if (empty($userid)) {
01813             $userid = $USER->id;
01814         }
01815 
01816         $submission = $DB->get_record('assignment_submissions', array('assignment'=>$this->assignment->id, 'userid'=>$userid));
01817 
01818         if ($submission || !$createnew) {
01819             return $submission;
01820         }
01821         $newsubmission = $this->prepare_new_submission($userid, $teachermodified);
01822         $DB->insert_record("assignment_submissions", $newsubmission);
01823 
01824         return $DB->get_record('assignment_submissions', array('assignment'=>$this->assignment->id, 'userid'=>$userid));
01825     }
01826 
01835     public function is_submitted_with_required_data($submission) {
01836         return $submission->timemodified;
01837     }
01838 
01848     function prepare_new_submission($userid, $teachermodified=false) {
01849         $submission = new stdClass();
01850         $submission->assignment   = $this->assignment->id;
01851         $submission->userid       = $userid;
01852         $submission->timecreated = time();
01853         // teachers should not be modifying modified date, except offline assignments
01854         if ($teachermodified) {
01855             $submission->timemodified = 0;
01856         } else {
01857             $submission->timemodified = $submission->timecreated;
01858         }
01859         $submission->numfiles     = 0;
01860         $submission->data1        = '';
01861         $submission->data2        = '';
01862         $submission->grade        = -1;
01863         $submission->submissioncomment      = '';
01864         $submission->format       = 0;
01865         $submission->teacher      = 0;
01866         $submission->timemarked   = 0;
01867         $submission->mailed       = 0;
01868         return $submission;
01869     }
01870 
01878     function get_submissions($sort='', $dir='DESC') {
01879         return assignment_get_all_submissions($this->assignment, $sort, $dir);
01880     }
01881 
01888     function count_real_submissions($groupid=0) {
01889         return assignment_count_real_submissions($this->cm, $groupid);
01890     }
01891 
01904     function email_teachers($submission) {
01905         global $CFG, $DB;
01906 
01907         if (empty($this->assignment->emailteachers)) {          // No need to do anything
01908             return;
01909         }
01910 
01911         $user = $DB->get_record('user', array('id'=>$submission->userid));
01912 
01913         if ($teachers = $this->get_graders($user)) {
01914 
01915             $strassignments = get_string('modulenameplural', 'assignment');
01916             $strassignment  = get_string('modulename', 'assignment');
01917             $strsubmitted  = get_string('submitted', 'assignment');
01918 
01919             foreach ($teachers as $teacher) {
01920                 $info = new stdClass();
01921                 $info->username = fullname($user, true);
01922                 $info->assignment = format_string($this->assignment->name,true);
01923                 $info->url = $CFG->wwwroot.'/mod/assignment/submissions.php?id='.$this->cm->id;
01924                 $info->timeupdated = userdate($submission->timemodified, '%c', $teacher->timezone);
01925 
01926                 $postsubject = $strsubmitted.': '.$info->username.' -> '.$this->assignment->name;
01927                 $posttext = $this->email_teachers_text($info);
01928                 $posthtml = ($teacher->mailformat == 1) ? $this->email_teachers_html($info) : '';
01929 
01930                 $eventdata = new stdClass();
01931                 $eventdata->modulename       = 'assignment';
01932                 $eventdata->userfrom         = $user;
01933                 $eventdata->userto           = $teacher;
01934                 $eventdata->subject          = $postsubject;
01935                 $eventdata->fullmessage      = $posttext;
01936                 $eventdata->fullmessageformat = FORMAT_PLAIN;
01937                 $eventdata->fullmessagehtml  = $posthtml;
01938                 $eventdata->smallmessage     = $postsubject;
01939 
01940                 $eventdata->name            = 'assignment_updates';
01941                 $eventdata->component       = 'mod_assignment';
01942                 $eventdata->notification    = 1;
01943                 $eventdata->contexturl      = $info->url;
01944                 $eventdata->contexturlname  = $info->assignment;
01945 
01946                 message_send($eventdata);
01947             }
01948         }
01949     }
01950 
01956     function send_file($filearea, $args) {
01957         debugging('plugin does not implement file sending', DEBUG_DEVELOPER);
01958         return false;
01959     }
01960 
01967     function get_graders($user) {
01968         //potential graders
01969         $potgraders = get_users_by_capability($this->context, 'mod/assignment:grade', '', '', '', '', '', '', false, false);
01970 
01971         $graders = array();
01972         if (groups_get_activity_groupmode($this->cm) == SEPARATEGROUPS) {   // Separate groups are being used
01973             if ($groups = groups_get_all_groups($this->course->id, $user->id)) {  // Try to find all groups
01974                 foreach ($groups as $group) {
01975                     foreach ($potgraders as $t) {
01976                         if ($t->id == $user->id) {
01977                             continue; // do not send self
01978                         }
01979                         if (groups_is_member($group->id, $t->id)) {
01980                             $graders[$t->id] = $t;
01981                         }
01982                     }
01983                 }
01984             } else {
01985                 // user not in group, try to find graders without group
01986                 foreach ($potgraders as $t) {
01987                     if ($t->id == $user->id) {
01988                         continue; // do not send self
01989                     }
01990                     if (!groups_get_all_groups($this->course->id, $t->id)) { //ugly hack
01991                         $graders[$t->id] = $t;
01992                     }
01993                 }
01994             }
01995         } else {
01996             foreach ($potgraders as $t) {
01997                 if ($t->id == $user->id) {
01998                     continue; // do not send self
01999                 }
02000                 $graders[$t->id] = $t;
02001             }
02002         }
02003         return $graders;
02004     }
02005 
02012     function email_teachers_text($info) {
02013         $posttext  = format_string($this->course->shortname, true, array('context' => $this->coursecontext)).' -> '.
02014                      $this->strassignments.' -> '.
02015                      format_string($this->assignment->name, true, array('context' => $this->context))."\n";
02016         $posttext .= '---------------------------------------------------------------------'."\n";
02017         $posttext .= get_string("emailteachermail", "assignment", $info)."\n";
02018         $posttext .= "\n---------------------------------------------------------------------\n";
02019         return $posttext;
02020     }
02021 
02028     function email_teachers_html($info) {
02029         global $CFG;
02030         $posthtml  = '<p><font face="sans-serif">'.
02031                      '<a href="'.$CFG->wwwroot.'/course/view.php?id='.$this->course->id.'">'.format_string($this->course->shortname, true, array('context' => $this->coursecontext)).'</a> ->'.
02032                      '<a href="'.$CFG->wwwroot.'/mod/assignment/index.php?id='.$this->course->id.'">'.$this->strassignments.'</a> ->'.
02033                      '<a href="'.$CFG->wwwroot.'/mod/assignment/view.php?id='.$this->cm->id.'">'.format_string($this->assignment->name, true, array('context' => $this->context)).'</a></font></p>';
02034         $posthtml .= '<hr /><font face="sans-serif">';
02035         $posthtml .= '<p>'.get_string('emailteachermailhtml', 'assignment', $info).'</p>';
02036         $posthtml .= '</font><hr />';
02037         return $posthtml;
02038     }
02039 
02047     function print_user_files($userid=0, $return=false) {
02048         global $CFG, $USER, $OUTPUT;
02049 
02050         if (!$userid) {
02051             if (!isloggedin()) {
02052                 return '';
02053             }
02054             $userid = $USER->id;
02055         }
02056 
02057         $output = '';
02058 
02059         $submission = $this->get_submission($userid);
02060         if (!$submission) {
02061             return $output;
02062         }
02063 
02064         $fs = get_file_storage();
02065         $files = $fs->get_area_files($this->context->id, 'mod_assignment', 'submission', $submission->id, "timemodified", false);
02066         if (!empty($files)) {
02067             require_once($CFG->dirroot . '/mod/assignment/locallib.php');
02068             if ($CFG->enableportfolios) {
02069                 require_once($CFG->libdir.'/portfoliolib.php');
02070                 $button = new portfolio_add_button();
02071             }
02072             foreach ($files as $file) {
02073                 $filename = $file->get_filename();
02074                 $mimetype = $file->get_mimetype();
02075                 $path = file_encode_url($CFG->wwwroot.'/pluginfile.php', '/'.$this->context->id.'/mod_assignment/submission/'.$submission->id.'/'.$filename);
02076                 $output .= '<a href="'.$path.'" ><img src="'.$OUTPUT->pix_url(file_mimetype_icon($mimetype)).'" class="icon" alt="'.$mimetype.'" />'.s($filename).'</a>';
02077                 if ($CFG->enableportfolios && $this->portfolio_exportable() && has_capability('mod/assignment:exportownsubmission', $this->context)) {
02078                     $button->set_callback_options('assignment_portfolio_caller', array('id' => $this->cm->id, 'submissionid' => $submission->id, 'fileid' => $file->get_id()), '/mod/assignment/locallib.php');
02079                     $button->set_format_by_file($file);
02080                     $output .= $button->to_html(PORTFOLIO_ADD_ICON_LINK);
02081                 }
02082 
02083                 if ($CFG->enableplagiarism) {
02084                     require_once($CFG->libdir.'/plagiarismlib.php');
02085                     $output .= plagiarism_get_links(array('userid'=>$userid, 'file'=>$file, 'cmid'=>$this->cm->id, 'course'=>$this->course, 'assignment'=>$this->assignment));
02086                     $output .= '<br />';
02087                 }
02088             }
02089             if ($CFG->enableportfolios && count($files) > 1  && $this->portfolio_exportable() && has_capability('mod/assignment:exportownsubmission', $this->context)) {
02090                 $button->set_callback_options('assignment_portfolio_caller', array('id' => $this->cm->id, 'submissionid' => $submission->id), '/mod/assignment/locallib.php');
02091                 $output .= '<br />'  . $button->to_html(PORTFOLIO_ADD_TEXT_LINK);
02092             }
02093         }
02094 
02095         $output = '<div class="files">'.$output.'</div>';
02096 
02097         if ($return) {
02098             return $output;
02099         }
02100         echo $output;
02101     }
02102 
02109     function count_user_files($itemid) {
02110         $fs = get_file_storage();
02111         $files = $fs->get_area_files($this->context->id, 'mod_assignment', 'submission', $itemid, "id", false);
02112         return count($files);
02113     }
02114 
02122     function isopen() {
02123         $time = time();
02124         if ($this->assignment->preventlate && $this->assignment->timedue) {
02125             return ($this->assignment->timeavailable <= $time && $time <= $this->assignment->timedue);
02126         } else {
02127             return ($this->assignment->timeavailable <= $time);
02128         }
02129     }
02130 
02131 
02143     function description_is_hidden() {
02144         return false;
02145     }
02146 
02154     function user_outline($grade) {
02155 
02156         $result = new stdClass();
02157         $result->info = get_string('grade').': '.$grade->str_long_grade;
02158         $result->time = $grade->dategraded;
02159         return $result;
02160     }
02161 
02167     function user_complete($user, $grade=null) {
02168         global $OUTPUT;
02169 
02170         if ($submission = $this->get_submission($user->id)) {
02171 
02172             $fs = get_file_storage();
02173 
02174             if ($files = $fs->get_area_files($this->context->id, 'mod_assignment', 'submission', $submission->id, "timemodified", false)) {
02175                 $countfiles = count($files)." ".get_string("uploadedfiles", "assignment");
02176                 foreach ($files as $file) {
02177                     $countfiles .= "; ".$file->get_filename();
02178                 }
02179             }
02180 
02181             echo $OUTPUT->box_start();
02182             echo get_string("lastmodified").": ";
02183             echo userdate($submission->timemodified);
02184             echo $this->display_lateness($submission->timemodified);
02185 
02186             $this->print_user_files($user->id);
02187 
02188             echo '<br />';
02189 
02190             $this->view_feedback($submission);
02191 
02192             echo $OUTPUT->box_end();
02193 
02194         } else {
02195             if ($grade) {
02196                 echo $OUTPUT->container(get_string('grade').': '.$grade->str_long_grade);
02197                 if ($grade->str_feedback) {
02198                     echo $OUTPUT->container(get_string('feedback').': '.$grade->str_feedback);
02199                 }
02200             }
02201             print_string("notsubmittedyet", "assignment");
02202         }
02203     }
02204 
02211     function display_lateness($timesubmitted) {
02212         return assignment_display_lateness($timesubmitted, $this->assignment->timedue);
02213     }
02214 
02218     function delete() {
02219         //nothing by default
02220         redirect('view.php?id='.$this->cm->id);
02221     }
02222 
02226     function custom_feedbackform($submission, $return=false) {
02227         //nothing by default
02228         return '';
02229     }
02230 
02241     function get_coursemodule_info($coursemodule) {
02242         return null;
02243     }
02244 
02249     function cron() {
02250         //no plugin cron by default - override if needed
02251     }
02252 
02256     function reset_userdata($data) {
02257         global $CFG, $DB;
02258 
02259         if (!$DB->count_records('assignment', array('course'=>$data->courseid, 'assignmenttype'=>$this->type))) {
02260             return array(); // no assignments of this type present
02261         }
02262 
02263         $componentstr = get_string('modulenameplural', 'assignment');
02264         $status = array();
02265 
02266         $typestr = get_string('type'.$this->type, 'assignment');
02267         // ugly hack to support pluggable assignment type titles...
02268         if($typestr === '[[type'.$this->type.']]'){
02269             $typestr = get_string('type'.$this->type, 'assignment_'.$this->type);
02270         }
02271 
02272         if (!empty($data->reset_assignment_submissions)) {
02273             $assignmentssql = "SELECT a.id
02274                                  FROM {assignment} a
02275                                 WHERE a.course=? AND a.assignmenttype=?";
02276             $params = array($data->courseid, $this->type);
02277 
02278             // now get rid of all submissions and responses
02279             $fs = get_file_storage();
02280             if ($assignments = $DB->get_records_sql($assignmentssql, $params)) {
02281                 foreach ($assignments as $assignmentid=>$unused) {
02282                     if (!$cm = get_coursemodule_from_instance('assignment', $assignmentid)) {
02283                         continue;
02284                     }
02285                     $context = get_context_instance(CONTEXT_MODULE, $cm->id);
02286                     $fs->delete_area_files($context->id, 'mod_assignment', 'submission');
02287                     $fs->delete_area_files($context->id, 'mod_assignment', 'response');
02288                 }
02289             }
02290 
02291             $DB->delete_records_select('assignment_submissions', "assignment IN ($assignmentssql)", $params);
02292 
02293             $status[] = array('component'=>$componentstr, 'item'=>get_string('deleteallsubmissions','assignment').': '.$typestr, 'error'=>false);
02294 
02295             if (empty($data->reset_gradebook_grades)) {
02296                 // remove all grades from gradebook
02297                 assignment_reset_gradebook($data->courseid, $this->type);
02298             }
02299         }
02300 
02302         if ($data->timeshift) {
02303             shift_course_mod_dates('assignment', array('timedue', 'timeavailable'), $data->timeshift, $data->courseid);
02304             $status[] = array('component'=>$componentstr, 'item'=>get_string('datechanged').': '.$typestr, 'error'=>false);
02305         }
02306 
02307         return $status;
02308     }
02309 
02310 
02311     function portfolio_exportable() {
02312         return false;
02313     }
02314 
02326     static function backup_one_mod($bf, $preferences, $assignment) {
02327         return true;
02328     }
02329 
02342     static function backup_one_submission($bf, $preferences, $assignment, $submission) {
02343         return true;
02344     }
02345 
02357     static function restore_one_mod($info, $restore, $assignment) {
02358         return true;
02359     }
02360 
02373     static function restore_one_submission($info, $restore, $assignment, $submission) {
02374         return true;
02375     }
02376 
02377 } 
02378 
02379 
02380 class mod_assignment_grading_form extends moodleform {
02382     private $advancegradinginstance;
02383 
02384     function definition() {
02385         global $OUTPUT;
02386         $mform =& $this->_form;
02387 
02388         if (isset($this->_customdata->advancedgradinginstance)) {
02389             $this->use_advanced_grading($this->_customdata->advancedgradinginstance);
02390         }
02391 
02392         $formattr = $mform->getAttributes();
02393         $formattr['id'] = 'submitform';
02394         $mform->setAttributes($formattr);
02395         // hidden params
02396         $mform->addElement('hidden', 'offset', ($this->_customdata->offset+1));
02397         $mform->setType('offset', PARAM_INT);
02398         $mform->addElement('hidden', 'userid', $this->_customdata->userid);
02399         $mform->setType('userid', PARAM_INT);
02400         $mform->addElement('hidden', 'nextid', $this->_customdata->nextid);
02401         $mform->setType('nextid', PARAM_INT);
02402         $mform->addElement('hidden', 'id', $this->_customdata->cm->id);
02403         $mform->setType('id', PARAM_INT);
02404         $mform->addElement('hidden', 'sesskey', sesskey());
02405         $mform->setType('sesskey', PARAM_ALPHANUM);
02406         $mform->addElement('hidden', 'mode', 'grade');
02407         $mform->setType('mode', PARAM_TEXT);
02408         $mform->addElement('hidden', 'menuindex', "0");
02409         $mform->setType('menuindex', PARAM_INT);
02410         $mform->addElement('hidden', 'saveuserid', "-1");
02411         $mform->setType('saveuserid', PARAM_INT);
02412         $mform->addElement('hidden', 'filter', "0");
02413         $mform->setType('filter', PARAM_INT);
02414 
02415         $mform->addElement('static', 'picture', $OUTPUT->user_picture($this->_customdata->user),
02416                                                 fullname($this->_customdata->user, true) . '<br/>' .
02417                                                 userdate($this->_customdata->submission->timemodified) .
02418                                                 $this->_customdata->lateness );
02419 
02420         $this->add_submission_content();
02421         $this->add_grades_section();
02422 
02423         $this->add_feedback_section();
02424 
02425         if ($this->_customdata->submission->timemarked) {
02426             $datestring = userdate($this->_customdata->submission->timemarked)."&nbsp; (".format_time(time() - $this->_customdata->submission->timemarked).")";
02427             $mform->addElement('header', 'Last Grade', get_string('lastgrade', 'assignment'));
02428             $mform->addElement('static', 'picture', $OUTPUT->user_picture($this->_customdata->teacher) ,
02429                                                     fullname($this->_customdata->teacher,true).
02430                                                     '<br/>'.$datestring);
02431         }
02432         // buttons
02433         $this->add_action_buttons();
02434 
02435     }
02436 
02442     public function use_advanced_grading($gradinginstance = false) {
02443         if ($gradinginstance !== false) {
02444             $this->advancegradinginstance = $gradinginstance;
02445         }
02446         return $this->advancegradinginstance;
02447     }
02448 
02449     function add_grades_section() {
02450         global $CFG;
02451         $mform =& $this->_form;
02452         $attributes = array();
02453         if ($this->_customdata->gradingdisabled) {
02454             $attributes['disabled'] ='disabled';
02455         }
02456 
02457         $mform->addElement('header', 'Grades', get_string('grades', 'grades'));
02458 
02459         $grademenu = make_grades_menu($this->_customdata->assignment->grade);
02460         if ($gradinginstance = $this->use_advanced_grading()) {
02461             $gradinginstance->get_controller()->set_grade_range($grademenu);
02462             $gradingelement = $mform->addElement('grading', 'advancedgrading', get_string('grade').':', array('gradinginstance' => $gradinginstance));
02463             if ($this->_customdata->gradingdisabled) {
02464                 $gradingelement->freeze();
02465             } else {
02466                 $mform->addElement('hidden', 'advancedgradinginstanceid', $gradinginstance->get_id());
02467             }
02468         } else {
02469             // use simple direct grading
02470             $grademenu['-1'] = get_string('nograde');
02471 
02472             $mform->addElement('select', 'xgrade', get_string('grade').':', $grademenu, $attributes);
02473             $mform->setDefault('xgrade', $this->_customdata->submission->grade ); //@fixme some bug when element called 'grade' makes it break
02474             $mform->setType('xgrade', PARAM_INT);
02475         }
02476 
02477         if (!empty($this->_customdata->enableoutcomes)) {
02478             foreach($this->_customdata->grading_info->outcomes as $n=>$outcome) {
02479                 $options = make_grades_menu(-$outcome->scaleid);
02480                 if ($outcome->grades[$this->_customdata->submission->userid]->locked) {
02481                     $options[0] = get_string('nooutcome', 'grades');
02482                     $mform->addElement('static', 'outcome_'.$n.'['.$this->_customdata->userid.']', $outcome->name.':',
02483                             $options[$outcome->grades[$this->_customdata->submission->userid]->grade]);
02484                 } else {
02485                     $options[''] = get_string('nooutcome', 'grades');
02486                     $attributes = array('id' => 'menuoutcome_'.$n );
02487                     $mform->addElement('select', 'outcome_'.$n.'['.$this->_customdata->userid.']', $outcome->name.':', $options, $attributes );
02488                     $mform->setType('outcome_'.$n.'['.$this->_customdata->userid.']', PARAM_INT);
02489                     $mform->setDefault('outcome_'.$n.'['.$this->_customdata->userid.']', $outcome->grades[$this->_customdata->submission->userid]->grade );
02490                 }
02491             }
02492         }
02493         $course_context = get_context_instance(CONTEXT_MODULE , $this->_customdata->cm->id);
02494         if (has_capability('gradereport/grader:view', $course_context) && has_capability('moodle/grade:viewall', $course_context)) {
02495             $grade = '<a href="'.$CFG->wwwroot.'/grade/report/grader/index.php?id='. $this->_customdata->courseid .'" >'.
02496                         $this->_customdata->grading_info->items[0]->grades[$this->_customdata->userid]->str_grade . '</a>';
02497         }else{
02498             $grade = $this->_customdata->grading_info->items[0]->grades[$this->_customdata->userid]->str_grade;
02499         }
02500         $mform->addElement('static', 'finalgrade', get_string('currentgrade', 'assignment').':' ,$grade);
02501         $mform->setType('finalgrade', PARAM_INT);
02502     }
02503 
02508     function add_feedback_section() {
02509         global $OUTPUT;
02510         $mform =& $this->_form;
02511         $mform->addElement('header', 'Feed Back', get_string('feedback', 'grades'));
02512 
02513         if ($this->_customdata->gradingdisabled) {
02514             $mform->addElement('static', 'disabledfeedback', $this->_customdata->grading_info->items[0]->grades[$this->_customdata->userid]->str_feedback );
02515         } else {
02516             // visible elements
02517 
02518             $mform->addElement('editor', 'submissioncomment_editor', get_string('feedback', 'assignment').':', null, $this->get_editor_options() );
02519             $mform->setType('submissioncomment_editor', PARAM_RAW); // to be cleaned before display
02520             $mform->setDefault('submissioncomment_editor', $this->_customdata->submission->submissioncomment);
02521             //$mform->addRule('submissioncomment', get_string('required'), 'required', null, 'client');
02522             switch ($this->_customdata->assignment->assignmenttype) {
02523                 case 'upload' :
02524                 case 'uploadsingle' :
02525                     $mform->addElement('filemanager', 'files_filemanager', get_string('responsefiles', 'assignment'). ':', null, $this->_customdata->fileui_options);
02526                     break;
02527                 default :
02528                     break;
02529             }
02530             $mform->addElement('hidden', 'mailinfo_h', "0");
02531             $mform->setType('mailinfo_h', PARAM_INT);
02532             $mform->addElement('checkbox', 'mailinfo',get_string('enablenotification','assignment').
02533             $OUTPUT->help_icon('enablenotification', 'assignment') .':' );
02534             $mform->setType('mailinfo', PARAM_INT);
02535         }
02536     }
02537 
02538     function add_action_buttons() {
02539         $mform =& $this->_form;
02540         //if there are more to be graded.
02541         if ($this->_customdata->nextid>0) {
02542             $buttonarray=array();
02543             $buttonarray[] = &$mform->createElement('submit', 'submitbutton', get_string('savechanges'));
02544             //@todo: fix accessibility: javascript dependency not necessary
02545             $buttonarray[] = &$mform->createElement('submit', 'saveandnext', get_string('saveandnext'));
02546             $buttonarray[] = &$mform->createElement('submit', 'next', get_string('next'));
02547             $buttonarray[] = &$mform->createElement('cancel');
02548         } else {
02549             $buttonarray=array();
02550             $buttonarray[] = &$mform->createElement('submit', 'submitbutton', get_string('savechanges'));
02551             $buttonarray[] = &$mform->createElement('cancel');
02552         }
02553         $mform->addGroup($buttonarray, 'grading_buttonar', '', array(' '), false);
02554         $mform->closeHeaderBefore('grading_buttonar');
02555         $mform->setType('grading_buttonar', PARAM_RAW);
02556     }
02557 
02558     function add_submission_content() {
02559         $mform =& $this->_form;
02560         $mform->addElement('header', 'Submission', get_string('submission', 'assignment'));
02561         $mform->addElement('static', '', '' , $this->_customdata->submission_content );
02562     }
02563 
02564     protected function get_editor_options() {
02565         $editoroptions = array();
02566         $editoroptions['component'] = 'mod_assignment';
02567         $editoroptions['filearea'] = 'feedback';
02568         $editoroptions['noclean'] = false;
02569         $editoroptions['maxfiles'] = 0; //TODO: no files for now, we need to first implement assignment_feedback area, integration with gradebook, files support in quickgrading, etc. (skodak)
02570         $editoroptions['maxbytes'] = $this->_customdata->maxbytes;
02571         $editoroptions['context'] = $this->_customdata->context;
02572         return $editoroptions;
02573     }
02574 
02575     public function set_data($data) {
02576         $editoroptions = $this->get_editor_options();
02577         if (!isset($data->text)) {
02578             $data->text = '';
02579         }
02580         if (!isset($data->format)) {
02581             $data->textformat = FORMAT_HTML;
02582         } else {
02583             $data->textformat = $data->format;
02584         }
02585 
02586         if (!empty($this->_customdata->submission->id)) {
02587             $itemid = $this->_customdata->submission->id;
02588         } else {
02589             $itemid = null;
02590         }
02591 
02592         switch ($this->_customdata->assignment->assignmenttype) {
02593                 case 'upload' :
02594                 case 'uploadsingle' :
02595                     $data = file_prepare_standard_filemanager($data, 'files', $editoroptions, $this->_customdata->context, 'mod_assignment', 'response', $itemid);
02596                     break;
02597                 default :
02598                     break;
02599         }
02600 
02601         $data = file_prepare_standard_editor($data, 'submissioncomment', $editoroptions, $this->_customdata->context, $editoroptions['component'], $editoroptions['filearea'], $itemid);
02602         return parent::set_data($data);
02603     }
02604 
02605     public function get_data() {
02606         $data = parent::get_data();
02607 
02608         if (!empty($this->_customdata->submission->id)) {
02609             $itemid = $this->_customdata->submission->id;
02610         } else {
02611             $itemid = null; //TODO: this is wrong, itemid MUST be known when saving files!! (skodak)
02612         }
02613 
02614         if ($data) {
02615             $editoroptions = $this->get_editor_options();
02616             switch ($this->_customdata->assignment->assignmenttype) {
02617                 case 'upload' :
02618                 case 'uploadsingle' :
02619                     $data = file_postupdate_standard_filemanager($data, 'files', $editoroptions, $this->_customdata->context, 'mod_assignment', 'response', $itemid);
02620                     break;
02621                 default :
02622                     break;
02623             }
02624             $data = file_postupdate_standard_editor($data, 'submissioncomment', $editoroptions, $this->_customdata->context, $editoroptions['component'], $editoroptions['filearea'], $itemid);
02625         }
02626 
02627         if ($this->use_advanced_grading() && !isset($data->advancedgrading)) {
02628             $data->advancedgrading = null;
02629         }
02630 
02631         return $data;
02632     }
02633 }
02634 
02636 
02642 function assignment_delete_instance($id){
02643     global $CFG, $DB;
02644 
02645     if (! $assignment = $DB->get_record('assignment', array('id'=>$id))) {
02646         return false;
02647     }
02648 
02649     // fall back to base class if plugin missing
02650     $classfile = "$CFG->dirroot/mod/assignment/type/$assignment->assignmenttype/assignment.class.php";
02651     if (file_exists($classfile)) {
02652         require_once($classfile);
02653         $assignmentclass = "assignment_$assignment->assignmenttype";
02654 
02655     } else {
02656         debugging("Missing assignment plug-in: {$assignment->assignmenttype}. Using base class for deleting instead.");
02657         $assignmentclass = "assignment_base";
02658     }
02659 
02660     $ass = new $assignmentclass();
02661     return $ass->delete_instance($assignment);
02662 }
02663 
02664 
02670 function assignment_update_instance($assignment){
02671     global $CFG;
02672 
02673     $assignment->assignmenttype = clean_param($assignment->assignmenttype, PARAM_PLUGIN);
02674 
02675     require_once("$CFG->dirroot/mod/assignment/type/$assignment->assignmenttype/assignment.class.php");
02676     $assignmentclass = "assignment_$assignment->assignmenttype";
02677     $ass = new $assignmentclass();
02678     return $ass->update_instance($assignment);
02679 }
02680 
02681 
02687 function assignment_add_instance($assignment) {
02688     global $CFG;
02689 
02690     $assignment->assignmenttype = clean_param($assignment->assignmenttype, PARAM_PLUGIN);
02691 
02692     require_once("$CFG->dirroot/mod/assignment/type/$assignment->assignmenttype/assignment.class.php");
02693     $assignmentclass = "assignment_$assignment->assignmenttype";
02694     $ass = new $assignmentclass();
02695     return $ass->add_instance($assignment);
02696 }
02697 
02698 
02704 function assignment_user_outline($course, $user, $mod, $assignment) {
02705     global $CFG;
02706 
02707     require_once("$CFG->libdir/gradelib.php");
02708     require_once("$CFG->dirroot/mod/assignment/type/$assignment->assignmenttype/assignment.class.php");
02709     $assignmentclass = "assignment_$assignment->assignmenttype";
02710     $ass = new $assignmentclass($mod->id, $assignment, $mod, $course);
02711     $grades = grade_get_grades($course->id, 'mod', 'assignment', $assignment->id, $user->id);
02712     if (!empty($grades->items[0]->grades)) {
02713         return $ass->user_outline(reset($grades->items[0]->grades));
02714     } else {
02715         return null;
02716     }
02717 }
02718 
02724 function assignment_user_complete($course, $user, $mod, $assignment) {
02725     global $CFG;
02726 
02727     require_once("$CFG->libdir/gradelib.php");
02728     require_once("$CFG->dirroot/mod/assignment/type/$assignment->assignmenttype/assignment.class.php");
02729     $assignmentclass = "assignment_$assignment->assignmenttype";
02730     $ass = new $assignmentclass($mod->id, $assignment, $mod, $course);
02731     $grades = grade_get_grades($course->id, 'mod', 'assignment', $assignment->id, $user->id);
02732     if (empty($grades->items[0]->grades)) {
02733         $grade = false;
02734     } else {
02735         $grade = reset($grades->items[0]->grades);
02736     }
02737     return $ass->user_complete($user, $grade);
02738 }
02739 
02745 function assignment_cron () {
02746     global $CFG, $USER, $DB;
02747 
02749     if ($plugins = get_plugin_list('assignment')) {
02750         foreach ($plugins as $plugin=>$dir) {
02751             require_once("$dir/assignment.class.php");
02752             $assignmentclass = "assignment_$plugin";
02753             $ass = new $assignmentclass();
02754             $ass->cron();
02755         }
02756     }
02757 
02761 
02762     $timenow   = time();
02763     $endtime   = $timenow - $CFG->maxeditingtime;
02764     $starttime = $endtime - 24 * 3600;   
02765 
02766     if ($submissions = assignment_get_unmailed_submissions($starttime, $endtime)) {
02767 
02768         $realuser = clone($USER);
02769 
02770         foreach ($submissions as $key => $submission) {
02771             $DB->set_field("assignment_submissions", "mailed", "1", array("id"=>$submission->id));
02772         }
02773 
02774         $timenow = time();
02775 
02776         foreach ($submissions as $submission) {
02777 
02778             echo "Processing assignment submission $submission->id\n";
02779 
02780             if (! $user = $DB->get_record("user", array("id"=>$submission->userid))) {
02781                 echo "Could not find user $user->id\n";
02782                 continue;
02783             }
02784 
02785             if (! $course = $DB->get_record("course", array("id"=>$submission->course))) {
02786                 echo "Could not find course $submission->course\n";
02787                 continue;
02788             }
02789 
02792             cron_setup_user($user, $course);
02793 
02794             $coursecontext = get_context_instance(CONTEXT_COURSE, $submission->course);
02795             $courseshortname = format_string($course->shortname, true, array('context' => $coursecontext));
02796             if (!is_enrolled($coursecontext, $user->id)) {
02797                 echo fullname($user)." not an active participant in " . $courseshortname . "\n";
02798                 continue;
02799             }
02800 
02801             if (! $teacher = $DB->get_record("user", array("id"=>$submission->teacher))) {
02802                 echo "Could not find teacher $submission->teacher\n";
02803                 continue;
02804             }
02805 
02806             if (! $mod = get_coursemodule_from_instance("assignment", $submission->assignment, $course->id)) {
02807                 echo "Could not find course module for assignment id $submission->assignment\n";
02808                 continue;
02809             }
02810 
02811             if (! $mod->visible) {    
02812                 continue;
02813             }
02814 
02815             $strassignments = get_string("modulenameplural", "assignment");
02816             $strassignment  = get_string("modulename", "assignment");
02817 
02818             $assignmentinfo = new stdClass();
02819             $assignmentinfo->teacher = fullname($teacher);
02820             $assignmentinfo->assignment = format_string($submission->name,true);
02821             $assignmentinfo->url = "$CFG->wwwroot/mod/assignment/view.php?id=$mod->id";
02822 
02823             $postsubject = "$courseshortname: $strassignments: ".format_string($submission->name,true);
02824             $posttext  = "$courseshortname -> $strassignments -> ".format_string($submission->name,true)."\n";
02825             $posttext .= "---------------------------------------------------------------------\n";
02826             $posttext .= get_string("assignmentmail", "assignment", $assignmentinfo)."\n";
02827             $posttext .= "---------------------------------------------------------------------\n";
02828 
02829             if ($user->mailformat == 1) {  // HTML
02830                 $posthtml = "<p><font face=\"sans-serif\">".
02831                 "<a href=\"$CFG->wwwroot/course/view.php?id=$course->id\">$courseshortname</a> ->".
02832                 "<a href=\"$CFG->wwwroot/mod/assignment/index.php?id=$course->id\">$strassignments</a> ->".
02833                 "<a href=\"$CFG->wwwroot/mod/assignment/view.php?id=$mod->id\">".format_string($submission->name,true)."</a></font></p>";
02834                 $posthtml .= "<hr /><font face=\"sans-serif\">";
02835                 $posthtml .= "<p>".get_string("assignmentmailhtml", "assignment", $assignmentinfo)."</p>";
02836                 $posthtml .= "</font><hr />";
02837             } else {
02838                 $posthtml = "";
02839             }
02840 
02841             $eventdata = new stdClass();
02842             $eventdata->modulename       = 'assignment';
02843             $eventdata->userfrom         = $teacher;
02844             $eventdata->userto           = $user;
02845             $eventdata->subject          = $postsubject;
02846             $eventdata->fullmessage      = $posttext;
02847             $eventdata->fullmessageformat = FORMAT_PLAIN;
02848             $eventdata->fullmessagehtml  = $posthtml;
02849             $eventdata->smallmessage     = get_string('assignmentmailsmall', 'assignment', $assignmentinfo);
02850 
02851             $eventdata->name            = 'assignment_updates';
02852             $eventdata->component       = 'mod_assignment';
02853             $eventdata->notification    = 1;
02854             $eventdata->contexturl      = $assignmentinfo->url;
02855             $eventdata->contexturlname  = $assignmentinfo->assignment;
02856 
02857             message_send($eventdata);
02858         }
02859 
02860         cron_setup_user();
02861     }
02862 
02863     return true;
02864 }
02865 
02873 function assignment_get_user_grades($assignment, $userid=0) {
02874     global $CFG, $DB;
02875 
02876     if ($userid) {
02877         $user = "AND u.id = :userid";
02878         $params = array('userid'=>$userid);
02879     } else {
02880         $user = "";
02881     }
02882     $params['aid'] = $assignment->id;
02883 
02884     $sql = "SELECT u.id, u.id AS userid, s.grade AS rawgrade, s.submissioncomment AS feedback, s.format AS feedbackformat,
02885                    s.teacher AS usermodified, s.timemarked AS dategraded, s.timemodified AS datesubmitted
02886               FROM {user} u, {assignment_submissions} s
02887              WHERE u.id = s.userid AND s.assignment = :aid
02888                    $user";
02889 
02890     return $DB->get_records_sql($sql, $params);
02891 }
02892 
02899 function assignment_update_grades($assignment, $userid=0, $nullifnone=true) {
02900     global $CFG, $DB;
02901     require_once($CFG->libdir.'/gradelib.php');
02902 
02903     if ($assignment->grade == 0) {
02904         assignment_grade_item_update($assignment);
02905 
02906     } else if ($grades = assignment_get_user_grades($assignment, $userid)) {
02907         foreach($grades as $k=>$v) {
02908             if ($v->rawgrade == -1) {
02909                 $grades[$k]->rawgrade = null;
02910             }
02911         }
02912         assignment_grade_item_update($assignment, $grades);
02913 
02914     } else {
02915         assignment_grade_item_update($assignment);
02916     }
02917 }
02918 
02922 function assignment_upgrade_grades() {
02923     global $DB;
02924 
02925     $sql = "SELECT COUNT('x')
02926               FROM {assignment} a, {course_modules} cm, {modules} m
02927              WHERE m.name='assignment' AND m.id=cm.module AND cm.instance=a.id";
02928     $count = $DB->count_records_sql($sql);
02929 
02930     $sql = "SELECT a.*, cm.idnumber AS cmidnumber, a.course AS courseid
02931               FROM {assignment} a, {course_modules} cm, {modules} m
02932              WHERE m.name='assignment' AND m.id=cm.module AND cm.instance=a.id";
02933     $rs = $DB->get_recordset_sql($sql);
02934     if ($rs->valid()) {
02935         // too much debug output
02936         $pbar = new progress_bar('assignmentupgradegrades', 500, true);
02937         $i=0;
02938         foreach ($rs as $assignment) {
02939             $i++;
02940             upgrade_set_timeout(60*5); // set up timeout, may also abort execution
02941             assignment_update_grades($assignment);
02942             $pbar->update($i, $count, "Updating Assignment grades ($i/$count).");
02943         }
02944         upgrade_set_timeout(); // reset to default timeout
02945     }
02946     $rs->close();
02947 }
02948 
02956 function assignment_grade_item_update($assignment, $grades=NULL) {
02957     global $CFG;
02958     require_once($CFG->libdir.'/gradelib.php');
02959 
02960     if (!isset($assignment->courseid)) {
02961         $assignment->courseid = $assignment->course;
02962     }
02963 
02964     $params = array('itemname'=>$assignment->name, 'idnumber'=>$assignment->cmidnumber);
02965 
02966     if ($assignment->grade > 0) {
02967         $params['gradetype'] = GRADE_TYPE_VALUE;
02968         $params['grademax']  = $assignment->grade;
02969         $params['grademin']  = 0;
02970 
02971     } else if ($assignment->grade < 0) {
02972         $params['gradetype'] = GRADE_TYPE_SCALE;
02973         $params['scaleid']   = -$assignment->grade;
02974 
02975     } else {
02976         $params['gradetype'] = GRADE_TYPE_TEXT; // allow text comments only
02977     }
02978 
02979     if ($grades  === 'reset') {
02980         $params['reset'] = true;
02981         $grades = NULL;
02982     }
02983 
02984     return grade_update('mod/assignment', $assignment->courseid, 'mod', 'assignment', $assignment->id, 0, $grades, $params);
02985 }
02986 
02993 function assignment_grade_item_delete($assignment) {
02994     global $CFG;
02995     require_once($CFG->libdir.'/gradelib.php');
02996 
02997     if (!isset($assignment->courseid)) {
02998         $assignment->courseid = $assignment->course;
02999     }
03000 
03001     return grade_update('mod/assignment', $assignment->courseid, 'mod', 'assignment', $assignment->id, 0, NULL, array('deleted'=>1));
03002 }
03003 
03012 function assignment_get_participants($assignmentid) {
03013     global $CFG, $DB;
03014 
03015     //Get students
03016     $students = $DB->get_records_sql("SELECT DISTINCT u.id, u.id
03017                                         FROM {user} u,
03018                                              {assignment_submissions} a
03019                                        WHERE a.assignment = ? and
03020                                              u.id = a.userid", array($assignmentid));
03021     //Get teachers
03022     $teachers = $DB->get_records_sql("SELECT DISTINCT u.id, u.id
03023                                         FROM {user} u,
03024                                              {assignment_submissions} a
03025                                        WHERE a.assignment = ? and
03026                                              u.id = a.teacher", array($assignmentid));
03027 
03028     //Add teachers to students
03029     if ($teachers) {
03030         foreach ($teachers as $teacher) {
03031             $students[$teacher->id] = $teacher;
03032         }
03033     }
03034     //Return students array (it contains an array of unique users)
03035     return ($students);
03036 }
03037 
03049 function assignment_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload) {
03050     global $CFG, $DB;
03051 
03052     if ($context->contextlevel != CONTEXT_MODULE) {
03053         return false;
03054     }
03055 
03056     require_login($course, false, $cm);
03057 
03058     if (!$assignment = $DB->get_record('assignment', array('id'=>$cm->instance))) {
03059         return false;
03060     }
03061 
03062     require_once($CFG->dirroot.'/mod/assignment/type/'.$assignment->assignmenttype.'/assignment.class.php');
03063     $assignmentclass = 'assignment_'.$assignment->assignmenttype;
03064     $assignmentinstance = new $assignmentclass($cm->id, $assignment, $cm, $course);
03065 
03066     return $assignmentinstance->send_file($filearea, $args);
03067 }
03076 function assignment_scale_used($assignmentid, $scaleid) {
03077     global $DB;
03078 
03079     $return = false;
03080 
03081     $rec = $DB->get_record('assignment', array('id'=>$assignmentid,'grade'=>-$scaleid));
03082 
03083     if (!empty($rec) && !empty($scaleid)) {
03084         $return = true;
03085     }
03086 
03087     return $return;
03088 }
03089 
03097 function assignment_scale_used_anywhere($scaleid) {
03098     global $DB;
03099 
03100     if ($scaleid and $DB->record_exists('assignment', array('grade'=>-$scaleid))) {
03101         return true;
03102     } else {
03103         return false;
03104     }
03105 }
03106 
03119 function assignment_refresh_events($courseid = 0) {
03120     global $DB;
03121 
03122     if ($courseid == 0) {
03123         if (! $assignments = $DB->get_records("assignment")) {
03124             return true;
03125         }
03126     } else {
03127         if (! $assignments = $DB->get_records("assignment", array("course"=>$courseid))) {
03128             return true;
03129         }
03130     }
03131     $moduleid = $DB->get_field('modules', 'id', array('name'=>'assignment'));
03132 
03133     foreach ($assignments as $assignment) {
03134         $cm = get_coursemodule_from_id('assignment', $assignment->id);
03135         $event = new stdClass();
03136         $event->name        = $assignment->name;
03137         $event->description = format_module_intro('assignment', $assignment, $cm->id);
03138         $event->timestart   = $assignment->timedue;
03139 
03140         if ($event->id = $DB->get_field('event', 'id', array('modulename'=>'assignment', 'instance'=>$assignment->id))) {
03141             update_event($event);
03142 
03143         } else {
03144             $event->courseid    = $assignment->course;
03145             $event->groupid     = 0;
03146             $event->userid      = 0;
03147             $event->modulename  = 'assignment';
03148             $event->instance    = $assignment->id;
03149             $event->eventtype   = 'due';
03150             $event->timeduration = 0;
03151             $event->visible     = $DB->get_field('course_modules', 'visible', array('module'=>$moduleid, 'instance'=>$assignment->id));
03152             add_event($event);
03153         }
03154 
03155     }
03156     return true;
03157 }
03158 
03164 function assignment_print_recent_activity($course, $viewfullnames, $timestart) {
03165     global $CFG, $USER, $DB, $OUTPUT;
03166 
03167     // do not use log table if possible, it may be huge
03168 
03169     if (!$submissions = $DB->get_records_sql("SELECT asb.id, asb.timemodified, cm.id AS cmid, asb.userid,
03170                                                      u.firstname, u.lastname, u.email, u.picture
03171                                                 FROM {assignment_submissions} asb
03172                                                      JOIN {assignment} a      ON a.id = asb.assignment
03173                                                      JOIN {course_modules} cm ON cm.instance = a.id
03174                                                      JOIN {modules} md        ON md.id = cm.module
03175                                                      JOIN {user} u            ON u.id = asb.userid
03176                                                WHERE asb.timemodified > ? AND
03177                                                      a.course = ? AND
03178                                                      md.name = 'assignment'
03179                                             ORDER BY asb.timemodified ASC", array($timestart, $course->id))) {
03180          return false;
03181     }
03182 
03183     $modinfo =& get_fast_modinfo($course); // reference needed because we might load the groups
03184     $show    = array();
03185     $grader  = array();
03186 
03187     foreach($submissions as $submission) {
03188         if (!array_key_exists($submission->cmid, $modinfo->cms)) {
03189             continue;
03190         }
03191         $cm = $modinfo->cms[$submission->cmid];
03192         if (!$cm->uservisible) {
03193             continue;
03194         }
03195         if ($submission->userid == $USER->id) {
03196             $show[] = $submission;
03197             continue;
03198         }
03199 
03200         // the act of sumbitting of assignment may be considered private - only graders will see it if specified
03201         if (empty($CFG->assignment_showrecentsubmissions)) {
03202             if (!array_key_exists($cm->id, $grader)) {
03203                 $grader[$cm->id] = has_capability('moodle/grade:viewall', get_context_instance(CONTEXT_MODULE, $cm->id));
03204             }
03205             if (!$grader[$cm->id]) {
03206                 continue;
03207             }
03208         }
03209 
03210         $groupmode = groups_get_activity_groupmode($cm, $course);
03211 
03212         if ($groupmode == SEPARATEGROUPS and !has_capability('moodle/site:accessallgroups', get_context_instance(CONTEXT_MODULE, $cm->id))) {
03213             if (isguestuser()) {
03214                 // shortcut - guest user does not belong into any group
03215                 continue;
03216             }
03217 
03218             if (is_null($modinfo->groups)) {
03219                 $modinfo->groups = groups_get_user_groups($course->id); // load all my groups and cache it in modinfo
03220             }
03221 
03222             // this will be slow - show only users that share group with me in this cm
03223             if (empty($modinfo->groups[$cm->id])) {
03224                 continue;
03225             }
03226             $usersgroups =  groups_get_all_groups($course->id, $submission->userid, $cm->groupingid);
03227             if (is_array($usersgroups)) {
03228                 $usersgroups = array_keys($usersgroups);
03229                 $intersect = array_intersect($usersgroups, $modinfo->groups[$cm->id]);
03230                 if (empty($intersect)) {
03231                     continue;
03232                 }
03233             }
03234         }
03235         $show[] = $submission;
03236     }
03237 
03238     if (empty($show)) {
03239         return false;
03240     }
03241 
03242     echo $OUTPUT->heading(get_string('newsubmissions', 'assignment').':', 3);
03243 
03244     foreach ($show as $submission) {
03245         $cm = $modinfo->cms[$submission->cmid];
03246         $link = $CFG->wwwroot.'/mod/assignment/view.php?id='.$cm->id;
03247         print_recent_activity_note($submission->timemodified, $submission, $cm->name, $link, false, $viewfullnames);
03248     }
03249 
03250     return true;
03251 }
03252 
03253 
03257 function assignment_get_recent_mod_activity(&$activities, &$index, $timestart, $courseid, $cmid, $userid=0, $groupid=0)  {
03258     global $CFG, $COURSE, $USER, $DB;
03259 
03260     if ($COURSE->id == $courseid) {
03261         $course = $COURSE;
03262     } else {
03263         $course = $DB->get_record('course', array('id'=>$courseid));
03264     }
03265 
03266     $modinfo =& get_fast_modinfo($course);
03267 
03268     $cm = $modinfo->cms[$cmid];
03269 
03270     $params = array();
03271     if ($userid) {
03272         $userselect = "AND u.id = :userid";
03273         $params['userid'] = $userid;
03274     } else {
03275         $userselect = "";
03276     }
03277 
03278     if ($groupid) {
03279         $groupselect = "AND gm.groupid = :groupid";
03280         $groupjoin   = "JOIN {groups_members} gm ON  gm.userid=u.id";
03281         $params['groupid'] = $groupid;
03282     } else {
03283         $groupselect = "";
03284         $groupjoin   = "";
03285     }
03286 
03287     $params['cminstance'] = $cm->instance;
03288     $params['timestart'] = $timestart;
03289 
03290     $userfields = user_picture::fields('u', null, 'userid');
03291 
03292     if (!$submissions = $DB->get_records_sql("SELECT asb.id, asb.timemodified,
03293                                                      $userfields
03294                                                 FROM {assignment_submissions} asb
03295                                                 JOIN {assignment} a      ON a.id = asb.assignment
03296                                                 JOIN {user} u            ON u.id = asb.userid
03297                                           $groupjoin
03298                                                WHERE asb.timemodified > :timestart AND a.id = :cminstance
03299                                                      $userselect $groupselect
03300                                             ORDER BY asb.timemodified ASC", $params)) {
03301          return;
03302     }
03303 
03304     $groupmode       = groups_get_activity_groupmode($cm, $course);
03305     $cm_context      = get_context_instance(CONTEXT_MODULE, $cm->id);
03306     $grader          = has_capability('moodle/grade:viewall', $cm_context);
03307     $accessallgroups = has_capability('moodle/site:accessallgroups', $cm_context);
03308     $viewfullnames   = has_capability('moodle/site:viewfullnames', $cm_context);
03309 
03310     if (is_null($modinfo->groups)) {
03311         $modinfo->groups = groups_get_user_groups($course->id); // load all my groups and cache it in modinfo
03312     }
03313 
03314     $show = array();
03315 
03316     foreach($submissions as $submission) {
03317         if ($submission->userid == $USER->id) {
03318             $show[] = $submission;
03319             continue;
03320         }
03321         // the act of submitting of assignment may be considered private - only graders will see it if specified
03322         if (empty($CFG->assignment_showrecentsubmissions)) {
03323             if (!$grader) {
03324                 continue;
03325             }
03326         }
03327 
03328         if ($groupmode == SEPARATEGROUPS and !$accessallgroups) {
03329             if (isguestuser()) {
03330                 // shortcut - guest user does not belong into any group
03331                 continue;
03332             }
03333 
03334             // this will be slow - show only users that share group with me in this cm
03335             if (empty($modinfo->groups[$cm->id])) {
03336                 continue;
03337             }
03338             $usersgroups = groups_get_all_groups($course->id, $cm->userid, $cm->groupingid);
03339             if (is_array($usersgroups)) {
03340                 $usersgroups = array_keys($usersgroups);
03341                 $intersect = array_intersect($usersgroups, $modinfo->groups[$cm->id]);
03342                 if (empty($intersect)) {
03343                     continue;
03344                 }
03345             }
03346         }
03347         $show[] = $submission;
03348     }
03349 
03350     if (empty($show)) {
03351         return;
03352     }
03353 
03354     if ($grader) {
03355         require_once($CFG->libdir.'/gradelib.php');
03356         $userids = array();
03357         foreach ($show as $id=>$submission) {
03358             $userids[] = $submission->userid;
03359 
03360         }
03361         $grades = grade_get_grades($courseid, 'mod', 'assignment', $cm->instance, $userids);
03362     }
03363 
03364     $aname = format_string($cm->name,true);
03365     foreach ($show as $submission) {
03366         $tmpactivity = new stdClass();
03367 
03368         $tmpactivity->type         = 'assignment';
03369         $tmpactivity->cmid         = $cm->id;
03370         $tmpactivity->name         = $aname;
03371         $tmpactivity->sectionnum   = $cm->sectionnum;
03372         $tmpactivity->timestamp    = $submission->timemodified;
03373 
03374         if ($grader) {
03375             $tmpactivity->grade = $grades->items[0]->grades[$submission->userid]->str_long_grade;
03376         }
03377 
03378         $userfields = explode(',', user_picture::fields());
03379         foreach ($userfields as $userfield) {
03380             if ($userfield == 'id') {
03381                 $tmpactivity->user->{$userfield} = $submission->userid; // aliased in SQL above
03382             } else {
03383                 $tmpactivity->user->{$userfield} = $submission->{$userfield};
03384             }
03385         }
03386         $tmpactivity->user->fullname = fullname($submission, $viewfullnames);
03387 
03388         $activities[$index++] = $tmpactivity;
03389     }
03390 
03391     return;
03392 }
03393 
03399 function assignment_print_recent_mod_activity($activity, $courseid, $detail, $modnames)  {
03400     global $CFG, $OUTPUT;
03401 
03402     echo '<table border="0" cellpadding="3" cellspacing="0" class="assignment-recent">';
03403 
03404     echo "<tr><td class=\"userpicture\" valign=\"top\">";
03405     echo $OUTPUT->user_picture($activity->user);
03406     echo "</td><td>";
03407 
03408     if ($detail) {
03409         $modname = $modnames[$activity->type];
03410         echo '<div class="title">';
03411         echo "<img src=\"" . $OUTPUT->pix_url('icon', 'assignment') . "\" ".
03412              "class=\"icon\" alt=\"$modname\">";
03413         echo "<a href=\"$CFG->wwwroot/mod/assignment/view.php?id={$activity->cmid}\">{$activity->name}</a>";
03414         echo '</div>';
03415     }
03416 
03417     if (isset($activity->grade)) {
03418         echo '<div class="grade">';
03419         echo get_string('grade').': ';
03420         echo $activity->grade;
03421         echo '</div>';
03422     }
03423 
03424     echo '<div class="user">';
03425     echo "<a href=\"$CFG->wwwroot/user/view.php?id={$activity->user->id}&amp;course=$courseid\">"
03426          ."{$activity->user->fullname}</a>  - ".userdate($activity->timestamp);
03427     echo '</div>';
03428 
03429     echo "</td></tr></table>";
03430 }
03431 
03433 
03440 function assignment_log_info($log) {
03441     global $CFG, $DB;
03442 
03443     return $DB->get_record_sql("SELECT a.name, u.firstname, u.lastname
03444                                   FROM {assignment} a, {user} u
03445                                  WHERE a.id = ? AND u.id = ?", array($log->info, $log->userid));
03446 }
03447 
03453 function assignment_get_unmailed_submissions($starttime, $endtime) {
03454     global $CFG, $DB;
03455 
03456     return $DB->get_records_sql("SELECT s.*, a.course, a.name
03457                                    FROM {assignment_submissions} s,
03458                                         {assignment} a
03459                                   WHERE s.mailed = 0
03460                                         AND s.timemarked <= ?
03461                                         AND s.timemarked >= ?
03462                                         AND s.assignment = a.id", array($endtime, $starttime));
03463 }
03464 
03473 function assignment_count_real_submissions($cm, $groupid=0) {
03474     global $CFG, $DB;
03475 
03476     $context = get_context_instance(CONTEXT_MODULE, $cm->id);
03477 
03478     // this is all the users with this capability set, in this context or higher
03479     if ($users = get_enrolled_users($context, 'mod/assignment:view', $groupid, 'u.id')) {
03480         $users = array_keys($users);
03481     }
03482 
03483     // if groupmembersonly used, remove users who are not in any group
03484     if ($users and !empty($CFG->enablegroupmembersonly) and $cm->groupmembersonly) {
03485         if ($groupingusers = groups_get_grouping_members($cm->groupingid, 'u.id', 'u.id')) {
03486             $users = array_intersect($users, array_keys($groupingusers));
03487         }
03488     }
03489 
03490     if (empty($users)) {
03491         return 0;
03492     }
03493 
03494     $userlists = implode(',', $users);
03495 
03496     return $DB->count_records_sql("SELECT COUNT('x')
03497                                      FROM {assignment_submissions}
03498                                     WHERE assignment = ? AND
03499                                           timemodified > 0 AND
03500                                           userid IN ($userlists)", array($cm->instance));
03501 }
03502 
03503 
03513 function assignment_get_all_submissions($assignment, $sort="", $dir="DESC") {
03515     global $CFG, $DB;
03516 
03517     if ($sort == "lastname" or $sort == "firstname") {
03518         $sort = "u.$sort $dir";
03519     } else if (empty($sort)) {
03520         $sort = "a.timemodified DESC";
03521     } else {
03522         $sort = "a.$sort $dir";
03523     }
03524 
03525     /* not sure this is needed at all since assignment already has a course define, so this join?
03526     $select = "s.course = '$assignment->course' AND";
03527     if ($assignment->course == SITEID) {
03528         $select = '';
03529     }*/
03530 
03531     return $DB->get_records_sql("SELECT a.*
03532                                    FROM {assignment_submissions} a, {user} u
03533                                   WHERE u.id = a.userid
03534                                         AND a.assignment = ?
03535                                ORDER BY $sort", array($assignment->id));
03536 
03537 }
03538 
03549 function assignment_get_coursemodule_info($coursemodule) {
03550     global $CFG, $DB;
03551 
03552     if (! $assignment = $DB->get_record('assignment', array('id'=>$coursemodule->instance),
03553             'id, assignmenttype, name, intro, introformat')) {
03554         return false;
03555     }
03556 
03557     $libfile = "$CFG->dirroot/mod/assignment/type/$assignment->assignmenttype/assignment.class.php";
03558 
03559     if (file_exists($libfile)) {
03560         require_once($libfile);
03561         $assignmentclass = "assignment_$assignment->assignmenttype";
03562         $ass = new $assignmentclass('staticonly');
03563         if (!($result = $ass->get_coursemodule_info($coursemodule))) {
03564             $result = new cached_cm_info();
03565             $result->name = $assignment->name;
03566         }
03567         if ($coursemodule->showdescription) {
03568             // Convert intro to html. Do not filter cached version, filters run at display time.
03569             $result->content = format_module_intro('assignment', $assignment, $coursemodule->id, false);
03570         }
03571         return $result;
03572     } else {
03573         debugging('Incorrect assignment type: '.$assignment->assignmenttype);
03574         return false;
03575     }
03576 }
03577 
03578 
03579 
03581 
03587 function assignment_types() {
03588     $types = array();
03589     $names = get_plugin_list('assignment');
03590     foreach ($names as $name=>$dir) {
03591         $types[$name] = get_string('type'.$name, 'assignment');
03592 
03593         // ugly hack to support pluggable assignment type titles..
03594         if ($types[$name] == '[[type'.$name.']]') {
03595             $types[$name] = get_string('type'.$name, 'assignment_'.$name);
03596         }
03597     }
03598     asort($types);
03599     return $types;
03600 }
03601 
03602 function assignment_print_overview($courses, &$htmlarray) {
03603     global $USER, $CFG, $DB;
03604 
03605     if (empty($courses) || !is_array($courses) || count($courses) == 0) {
03606         return array();
03607     }
03608 
03609     if (!$assignments = get_all_instances_in_courses('assignment',$courses)) {
03610         return;
03611     }
03612 
03613     $assignmentids = array();
03614 
03615     // Do assignment_base::isopen() here without loading the whole thing for speed
03616     foreach ($assignments as $key => $assignment) {
03617         $time = time();
03618         if ($assignment->timedue) {
03619             if ($assignment->preventlate) {
03620                 $isopen = ($assignment->timeavailable <= $time && $time <= $assignment->timedue);
03621             } else {
03622                 $isopen = ($assignment->timeavailable <= $time);
03623             }
03624         }
03625         if (empty($isopen) || empty($assignment->timedue)) {
03626             unset($assignments[$key]);
03627         } else {
03628             $assignmentids[] = $assignment->id;
03629         }
03630     }
03631 
03632     if (empty($assignmentids)){
03633         // no assignments to look at - we're done
03634         return true;
03635     }
03636 
03637     $strduedate = get_string('duedate', 'assignment');
03638     $strduedateno = get_string('duedateno', 'assignment');
03639     $strgraded = get_string('graded', 'assignment');
03640     $strnotgradedyet = get_string('notgradedyet', 'assignment');
03641     $strnotsubmittedyet = get_string('notsubmittedyet', 'assignment');
03642     $strsubmitted = get_string('submitted', 'assignment');
03643     $strassignment = get_string('modulename', 'assignment');
03644     $strreviewed = get_string('reviewed','assignment');
03645 
03646 
03647     // NOTE: we do all possible database work here *outside* of the loop to ensure this scales
03648     //
03649     list($sqlassignmentids, $assignmentidparams) = $DB->get_in_or_equal($assignmentids);
03650 
03651     // build up and array of unmarked submissions indexed by assignment id/ userid
03652     // for use where the user has grading rights on assignment
03653     $rs = $DB->get_recordset_sql("SELECT id, assignment, userid
03654                             FROM {assignment_submissions}
03655                             WHERE teacher = 0 AND timemarked = 0
03656                             AND assignment $sqlassignmentids", $assignmentidparams);
03657 
03658     $unmarkedsubmissions = array();
03659     foreach ($rs as $rd) {
03660         $unmarkedsubmissions[$rd->assignment][$rd->userid] = $rd->id;
03661     }
03662     $rs->close();
03663 
03664 
03665     // get all user submissions, indexed by assignment id
03666     $mysubmissions = $DB->get_records_sql("SELECT assignment, timemarked, teacher, grade
03667                                       FROM {assignment_submissions}
03668                                       WHERE userid = ? AND
03669                                       assignment $sqlassignmentids", array_merge(array($USER->id), $assignmentidparams));
03670 
03671     foreach ($assignments as $assignment) {
03672         $str = '<div class="assignment overview"><div class="name">'.$strassignment. ': '.
03673                '<a '.($assignment->visible ? '':' class="dimmed"').
03674                'title="'.$strassignment.'" href="'.$CFG->wwwroot.
03675                '/mod/assignment/view.php?id='.$assignment->coursemodule.'">'.
03676                $assignment->name.'</a></div>';
03677         if ($assignment->timedue) {
03678             $str .= '<div class="info">'.$strduedate.': '.userdate($assignment->timedue).'</div>';
03679         } else {
03680             $str .= '<div class="info">'.$strduedateno.'</div>';
03681         }
03682         $context = get_context_instance(CONTEXT_MODULE, $assignment->coursemodule);
03683         if (has_capability('mod/assignment:grade', $context)) {
03684 
03685             // count how many people can submit
03686             $submissions = 0; // init
03687             if ($students = get_enrolled_users($context, 'mod/assignment:view', 0, 'u.id')) {
03688                 foreach ($students as $student) {
03689                     if (isset($unmarkedsubmissions[$assignment->id][$student->id])) {
03690                         $submissions++;
03691                     }
03692                 }
03693             }
03694 
03695             if ($submissions) {
03696                 $link = new moodle_url('/mod/assignment/submissions.php', array('id'=>$assignment->coursemodule));
03697                 $str .= '<div class="details"><a href="'.$link.'">'.get_string('submissionsnotgraded', 'assignment', $submissions).'</a></div>';
03698             }
03699         } else {
03700             $str .= '<div class="details">';
03701             if (isset($mysubmissions[$assignment->id])) {
03702 
03703                 $submission = $mysubmissions[$assignment->id];
03704 
03705                 if ($submission->teacher == 0 && $submission->timemarked == 0) {
03706                     $str .= $strsubmitted . ', ' . $strnotgradedyet;
03707                 } else if ($submission->grade <= 0) {
03708                     $str .= $strsubmitted . ', ' . $strreviewed;
03709                 } else {
03710                     $str .= $strsubmitted . ', ' . $strgraded;
03711                 }
03712             } else {
03713                 $str .= $strnotsubmittedyet . ' ' . assignment_display_lateness(time(), $assignment->timedue);
03714             }
03715             $str .= '</div>';
03716         }
03717         $str .= '</div>';
03718         if (empty($htmlarray[$assignment->course]['assignment'])) {
03719             $htmlarray[$assignment->course]['assignment'] = $str;
03720         } else {
03721             $htmlarray[$assignment->course]['assignment'] .= $str;
03722         }
03723     }
03724 }
03725 
03726 function assignment_display_lateness($timesubmitted, $timedue) {
03727     if (!$timedue) {
03728         return '';
03729     }
03730     $time = $timedue - $timesubmitted;
03731     if ($time < 0) {
03732         $timetext = get_string('late', 'assignment', format_time($time));
03733         return ' (<span class="late">'.$timetext.'</span>)';
03734     } else {
03735         $timetext = get_string('early', 'assignment', format_time($time));
03736         return ' (<span class="early">'.$timetext.'</span>)';
03737     }
03738 }
03739 
03740 function assignment_get_view_actions() {
03741     return array('view');
03742 }
03743 
03744 function assignment_get_post_actions() {
03745     return array('upload');
03746 }
03747 
03748 function assignment_get_types() {
03749     global $CFG;
03750     $types = array();
03751 
03752     $type = new stdClass();
03753     $type->modclass = MOD_CLASS_ACTIVITY;
03754     $type->type = "assignment_group_start";
03755     $type->typestr = '--'.get_string('modulenameplural', 'assignment');
03756     $types[] = $type;
03757 
03758     $standardassignments = array('upload','online','uploadsingle','offline');
03759     foreach ($standardassignments as $assignmenttype) {
03760         $type = new stdClass();
03761         $type->modclass = MOD_CLASS_ACTIVITY;
03762         $type->type = "assignment&amp;type=$assignmenttype";
03763         $type->typestr = get_string("type$assignmenttype", 'assignment');
03764         $types[] = $type;
03765     }
03766 
03768     $assignmenttypes = get_list_of_plugins('mod/assignment/type');
03769     foreach ($assignmenttypes as $assignmenttype) {
03770         if (!empty($CFG->{'assignment_hide_'.$assignmenttype})) {  // Not wanted
03771             continue;
03772         }
03773         if (!in_array($assignmenttype, $standardassignments)) {
03774             $type = new stdClass();
03775             $type->modclass = MOD_CLASS_ACTIVITY;
03776             $type->type = "assignment&amp;type=$assignmenttype";
03777             $type->typestr = get_string("type$assignmenttype", 'assignment_'.$assignmenttype);
03778             $types[] = $type;
03779         }
03780     }
03781 
03782     $type = new stdClass();
03783     $type->modclass = MOD_CLASS_ACTIVITY;
03784     $type->type = "assignment_group_end";
03785     $type->typestr = '--';
03786     $types[] = $type;
03787 
03788     return $types;
03789 }
03790 
03796 function assignment_reset_gradebook($courseid, $type='') {
03797     global $CFG, $DB;
03798 
03799     $params = array('courseid'=>$courseid);
03800     if ($type) {
03801         $type = "AND a.assignmenttype= :type";
03802         $params['type'] = $type;
03803     }
03804 
03805     $sql = "SELECT a.*, cm.idnumber as cmidnumber, a.course as courseid
03806               FROM {assignment} a, {course_modules} cm, {modules} m
03807              WHERE m.name='assignment' AND m.id=cm.module AND cm.instance=a.id AND a.course=:courseid $type";
03808 
03809     if ($assignments = $DB->get_records_sql($sql, $params)) {
03810         foreach ($assignments as $assignment) {
03811             assignment_grade_item_update($assignment, 'reset');
03812         }
03813     }
03814 }
03815 
03823 function assignment_reset_userdata($data) {
03824     global $CFG;
03825 
03826     $status = array();
03827     foreach (get_plugin_list('assignment') as $type=>$dir) {
03828         require_once("$dir/assignment.class.php");
03829         $assignmentclass = "assignment_$type";
03830         $ass = new $assignmentclass();
03831         $status = array_merge($status, $ass->reset_userdata($data));
03832     }
03833 
03834     return $status;
03835 }
03836 
03842 function assignment_reset_course_form_definition(&$mform) {
03843     $mform->addElement('header', 'assignmentheader', get_string('modulenameplural', 'assignment'));
03844     $mform->addElement('advcheckbox', 'reset_assignment_submissions', get_string('deleteallsubmissions','assignment'));
03845 }
03846 
03850 function assignment_reset_course_form_defaults($course) {
03851     return array('reset_assignment_submissions'=>1);
03852 }
03853 
03857 function assignment_get_extra_capabilities() {
03858     return array('moodle/site:accessallgroups', 'moodle/site:viewfullnames', 'moodle/grade:managegradingforms');
03859 }
03860 
03865 function assignment_supports($feature) {
03866     switch($feature) {
03867         case FEATURE_GROUPS:                  return true;
03868         case FEATURE_GROUPINGS:               return true;
03869         case FEATURE_GROUPMEMBERSONLY:        return true;
03870         case FEATURE_MOD_INTRO:               return true;
03871         case FEATURE_COMPLETION_TRACKS_VIEWS: return true;
03872         case FEATURE_GRADE_HAS_GRADE:         return true;
03873         case FEATURE_GRADE_OUTCOMES:          return true;
03874         case FEATURE_GRADE_HAS_GRADE:         return true;
03875         case FEATURE_BACKUP_MOODLE2:          return true;
03876         case FEATURE_SHOW_DESCRIPTION:        return true;
03877         case FEATURE_ADVANCED_GRADING:        return true;
03878 
03879         default: return null;
03880     }
03881 }
03882 
03889 function assignment_extend_settings_navigation(settings_navigation $settings, navigation_node $assignmentnode) {
03890     global $PAGE, $DB, $USER, $CFG;
03891 
03892     $assignmentrow = $DB->get_record("assignment", array("id" => $PAGE->cm->instance));
03893     require_once "$CFG->dirroot/mod/assignment/type/$assignmentrow->assignmenttype/assignment.class.php";
03894 
03895     $assignmentclass = 'assignment_'.$assignmentrow->assignmenttype;
03896     $assignmentinstance = new $assignmentclass($PAGE->cm->id, $assignmentrow, $PAGE->cm, $PAGE->course);
03897 
03898     $allgroups = false;
03899 
03900     // Add assignment submission information
03901     if (has_capability('mod/assignment:grade', $PAGE->cm->context)) {
03902         if ($allgroups && has_capability('moodle/site:accessallgroups', $PAGE->cm->context)) {
03903             $group = 0;
03904         } else {
03905             $group = groups_get_activity_group($PAGE->cm);
03906         }
03907         $link = new moodle_url('/mod/assignment/submissions.php', array('id'=>$PAGE->cm->id));
03908         if ($assignmentrow->assignmenttype == 'offline') {
03909             $string = get_string('viewfeedback', 'assignment');
03910         } else if ($count = $assignmentinstance->count_real_submissions($group)) {
03911             $string = get_string('viewsubmissions', 'assignment', $count);
03912         } else {
03913             $string = get_string('noattempts', 'assignment');
03914         }
03915         $assignmentnode->add($string, $link, navigation_node::TYPE_SETTING);
03916     }
03917 
03918     if (is_object($assignmentinstance) && method_exists($assignmentinstance, 'extend_settings_navigation')) {
03919         $assignmentinstance->extend_settings_navigation($assignmentnode);
03920     }
03921 }
03922 
03928 function assignment_pack_files($filesforzipping) {
03929         global $CFG;
03930         //create path for new zip file.
03931         $tempzip = tempnam($CFG->tempdir.'/', 'assignment_');
03932         //zip files
03933         $zipper = new zip_packer();
03934         if ($zipper->archive_to_pathname($filesforzipping, $tempzip)) {
03935             return $tempzip;
03936         }
03937         return false;
03938 }
03939 
03948 function assignment_get_file_areas($course, $cm, $context) {
03949     $areas = array();
03950     if (has_capability('moodle/course:managefiles', $context)) {
03951         $areas['submission'] = get_string('assignmentsubmission', 'assignment');
03952     }
03953     return $areas;
03954 }
03955 
03970 function mod_assignment_get_file_info($browser, $areas, $course, $cm, $context, $filearea, $itemid, $filepath, $filename) {
03971     global $CFG, $DB, $USER;
03972 
03973     if ($context->contextlevel != CONTEXT_MODULE || $filearea != 'submission') {
03974         return null;
03975     }
03976     if (!$submission = $DB->get_record('assignment_submissions', array('id' => $itemid))) {
03977         return null;
03978     }
03979     if (!(($submission->userid == $USER->id && has_capability('mod/assignment:view', $context))
03980             || has_capability('mod/assignment:grade', $context))) {
03981         // no permission to view this submission
03982         return null;
03983     }
03984 
03985     $fs = get_file_storage();
03986     $filepath = is_null($filepath) ? '/' : $filepath;
03987     $filename = is_null($filename) ? '.' : $filename;
03988     if (!($storedfile = $fs->get_file($context->id, 'mod_assignment', $filearea, $itemid, $filepath, $filename))) {
03989         return null;
03990     }
03991     $urlbase = $CFG->wwwroot.'/pluginfile.php';
03992     return new file_info_stored($browser, $context, $storedfile, $urlbase, $filearea, $itemid, true, true, false);
03993 }
03994 
04001 function assignment_page_type_list($pagetype, $parentcontext, $currentcontext) {
04002     $module_pagetype = array(
04003         'mod-assignment-*'=>get_string('page-mod-assignment-x', 'assignment'),
04004         'mod-assignment-view'=>get_string('page-mod-assignment-view', 'assignment'),
04005         'mod-assignment-submissions'=>get_string('page-mod-assignment-submissions', 'assignment')
04006     );
04007     return $module_pagetype;
04008 }
04009 
04015 function assignment_grading_areas_list() {
04016     return array('submission' => get_string('submissions', 'mod_assignment'));
04017 }
 All Data Structures Namespaces Files Functions Variables Enumerations