|
Moodle
2.2.1
http://www.collinsharper.com
|
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"> </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"> </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.'&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 = ' '; 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.'"> </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.'"> </div>'; 01494 $teachermodified = '<div id="tt'.$auser->id.'"> </div>'; 01495 $status = '<div id="st'.$auser->id.'"> </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.'"> </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 . '&userid='.$auser->id.'&mode=single'.'&filter='.$filter.'&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 . '&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)." (".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}&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&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&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 }