diff --git a/admin/roles/lib.php b/admin/roles/lib.php index 3e9624eece2..7fc5782eb2d 100644 --- a/admin/roles/lib.php +++ b/admin/roles/lib.php @@ -1316,6 +1316,7 @@ abstract class role_allow_role_page { foreach ($rs as $allow) { $this->allowed[$allow->roleid][$allow->{$this->targetcolname}] = true; } + $rs->close(); } /** diff --git a/backup/util/xml/parser/processors/grouped_parser_processor.class.php b/backup/util/xml/parser/processors/grouped_parser_processor.class.php index ca5d3f494ff..46391e62975 100644 --- a/backup/util/xml/parser/processors/grouped_parser_processor.class.php +++ b/backup/util/xml/parser/processors/grouped_parser_processor.class.php @@ -70,16 +70,6 @@ abstract class grouped_parser_processor extends simplified_parser_processor { parent::add_path($path); } - /** - * Notify start of path if selected and not under grouped - */ - public function before_path($path) { - if ($this->path_is_selected($path) && !$this->grouped_parent_exists($path)) { - parent::before_path($path); - } - } - - /** * Dispatch grouped chunks safely once their end tag happens. * Also notify end of path if selected and not under grouped @@ -110,6 +100,7 @@ abstract class grouped_parser_processor extends simplified_parser_processor { $path = $data['path']; // If the chunk is a grouped one, simply put it into currentdata if ($this->path_is_grouped($path)) { + $this->notify_path_start($path); $this->currentdata[$path] = $data; // If the chunk is child of grouped one, add it to currentdata @@ -119,6 +110,7 @@ abstract class grouped_parser_processor extends simplified_parser_processor { // No grouped nor child of grouped, dispatch it } else { + $this->notify_path_start($path); $this->dispatch_chunk($data); } } diff --git a/backup/util/xml/parser/processors/simplified_parser_processor.class.php b/backup/util/xml/parser/processors/simplified_parser_processor.class.php index e4432af9b48..0544b436445 100644 --- a/backup/util/xml/parser/processors/simplified_parser_processor.class.php +++ b/backup/util/xml/parser/processors/simplified_parser_processor.class.php @@ -149,15 +149,6 @@ abstract class simplified_parser_processor extends progressive_parser_processor return true; } - /** - * The parser fires this each time one path is going to be parsed - */ - public function before_path($path) { - if ($this->path_is_selected($path)) { - $this->notify_path_start($path); - } - } - /** * The parser fires this each time one path has been parsed */ @@ -170,6 +161,7 @@ abstract class simplified_parser_processor extends progressive_parser_processor // Protected API starts here protected function postprocess_chunk($data) { + $this->notify_path_start($data['path']); $this->dispatch_chunk($data); } diff --git a/backup/util/xml/parser/simpletest/testparser.php b/backup/util/xml/parser/simpletest/testparser.php index eccc2c44741..02983041833 100644 --- a/backup/util/xml/parser/simpletest/testparser.php +++ b/backup/util/xml/parser/simpletest/testparser.php @@ -330,6 +330,13 @@ class progressive_parser_test extends UnitTestCase { sort($snotifs); sort($enotifs); $this->assertEqual($snotifs, $enotifs); + + // Now verify that the start/process/end order is correct + $allnotifs = $pr->get_all_notifications(); + $this->assertEqual(count($allnotifs), count($snotifs) + count($enotifs) + count($chunks)); // The count + // Check integrity of the notifications + $errcount = $this->helper_check_notifications_order_integrity($allnotifs); + $this->assertEqual($errcount, 0); // No errors found, plz } /* @@ -498,6 +505,67 @@ class progressive_parser_test extends UnitTestCase { sort($snotifs); sort($enotifs); $this->assertEqual($snotifs, $enotifs); + + // Now verify that the start/process/end order is correct + $allnotifs = $pr->get_all_notifications(); + $this->assertEqual(count($allnotifs), count($snotifs) + count($enotifs) + count($chunks)); // The count + // Check integrity of the notifications + $errcount = $this->helper_check_notifications_order_integrity($allnotifs); + $this->assertEqual($errcount, 0); // No errors found, plz + } + + /** + * Helper function that given one array of ordered start/process/end notifications will + * check it of integrity like: + * - process only happens if start is the previous notification + * - end only happens if dispatch is the previous notification + * - start only happen with level > than last one and if there is no already started like that + * + * @param array $notifications ordered array of notifications with format [start|process|end]:path + * @return int number of integrity problems found (errors) + */ + function helper_check_notifications_order_integrity($notifications) { + $numerrors = 0; + $notifpile = array('pilebase' => 'start'); + $lastpile = 'start:pilebase'; + foreach ($notifications as $notif) { + $lastpilelevel = strlen(preg_replace('/[^\/]/', '', $lastpile)); + $lastpiletype = preg_replace('/:.*/', '', $lastpile); + $lastpilepath = preg_replace('/.*:/', '', $lastpile); + + $notiflevel = strlen(preg_replace('/[^\/]/', '', $notif)); + $notiftype = preg_replace('/:.*/', '', $notif); + $notifpath = preg_replace('/.*:/', '', $notif); + + switch ($notiftype) { + case 'process': + if ($lastpilepath != $notifpath or $lastpiletype != 'start') { + $numerrors++; // Only start for same path is allowed before process + } + $notifpile[$notifpath] = 'process'; // Update the status in the pile + break; + case 'end': + if ($lastpilepath != $notifpath or $lastpiletype != 'process') { + $numerrors++; // Only process for same path is allowed before end + } + unset($notifpile[$notifpath]); // Delete from the pile + break; + case 'start': + if (array_key_exists($notifpath, $notifpile) or $notiflevel <= $lastpilelevel) { + $numerrors++; // If same path exists or the level is < than the last one + } + $notifpile[$notifpath] = 'start'; // Add to the pile + break; + default: + $numerrors++; // Incorrect type of notification => error + } + // Update lastpile + end($notifpile); + $path = key($notifpile); + $type = $notifpile[$path]; + $lastpile = $type. ':' . $path; + } + return $numerrors; } } @@ -572,17 +640,21 @@ class mock_simplified_parser_processor extends simplified_parser_processor { private $chunksarr = array(); // To accumulate the found chunks private $startarr = array(); // To accumulate all the notified path starts private $endarr = array(); // To accumulate all the notified path ends + private $allnotif = array(); // To accumulate all the notified and dispatched events in an ordered way public function dispatch_chunk($data) { $this->chunksarr[] = $data; + $this->allnotif[] = 'process:' . $data['path']; } public function notify_path_start($path) { $this->startarr[] = $path; + $this->allnotif[] = 'start:' . $path; } public function notify_path_end($path) { $this->endarr[] = $path; + $this->allnotif[] = 'end:' . $path; } public function get_chunks() { @@ -596,6 +668,10 @@ class mock_simplified_parser_processor extends simplified_parser_processor { public function get_end_notifications() { return $this->endarr; } + + public function get_all_notifications() { + return $this->allnotif; + } } /* @@ -606,17 +682,21 @@ class mock_grouped_parser_processor extends grouped_parser_processor { private $chunksarr = array(); // To accumulate the found chunks private $startarr = array(); // To accumulate all the notified path starts private $endarr = array(); // To accumulate all the notified path ends + private $allnotif = array(); // To accumulate all the notified and dispatched events in an ordered way public function dispatch_chunk($data) { $this->chunksarr[] = $data; + $this->allnotif[] = 'process:' . $data['path']; } public function notify_path_start($path) { $this->startarr[] = $path; + $this->allnotif[] = 'start:' . $path; } public function notify_path_end($path) { $this->endarr[] = $path; + $this->allnotif[] = 'end:' . $path; } public function get_chunks() { @@ -630,4 +710,8 @@ class mock_grouped_parser_processor extends grouped_parser_processor { public function get_end_notifications() { return $this->endarr; } + + public function get_all_notifications() { + return $this->allnotif; + } } diff --git a/calendar/export_execute.php b/calendar/export_execute.php index 3fe48f14f44..bfda4578521 100644 --- a/calendar/export_execute.php +++ b/calendar/export_execute.php @@ -13,7 +13,7 @@ if (empty($CFG->enablecalendarexport)) { } //Fetch user information -if (!$user = get_complete_user_data('username', $username)) { +if (!$user = $DB->get_record('user', array('username' => $username), 'id,password')) { //No such user die('Invalid authentication'); } diff --git a/comment/lib.php b/comment/lib.php index 2bf59795394..184e320f569 100644 --- a/comment/lib.php +++ b/comment/lib.php @@ -127,16 +127,14 @@ class comment { */ protected $totalcommentcount = null; /** - * By default a user must have the generic comment capabilities plus any capabilities the - * component being commented on requires. - * When set to true only the component capabilities are checked, the system capabilities are - * ignored. - * This can be toggled by the component defining a callback in its lib.php e.g. - * function forum_comment_allow_anonymous_access(comment $comment) {} - * Note: On the front page this defaults to true. + * When set to true any user to the system is able to view comments. + * + * This can be set to true by a plugin by implementing a allow_anonymous_access callback. + * By default it is false except on the front page. + * * @var bool */ - protected $ignoresystempermissions = false; + protected $allowanonymousaccess = false; /**#@+ * static variable will be used by non-js comments UI diff --git a/lib/xhprof/xhprof_moodle.php b/lib/xhprof/xhprof_moodle.php index 853e5f50d3b..28c41f30065 100644 --- a/lib/xhprof/xhprof_moodle.php +++ b/lib/xhprof/xhprof_moodle.php @@ -152,7 +152,7 @@ function profiling_start() { * Stop profiling, gathering results and storing them */ function profiling_stop() { - global $CFG, $SCRIPT; + global $CFG, $DB, $SCRIPT; // If profiling isn't available, nothing to stop if (!extension_loaded('xhprof') || !function_exists('xhprof_enable')) { @@ -176,6 +176,14 @@ function profiling_stop() { profiling_is_running(false); $data = xhprof_disable(); + // We only save the run after ensuring the DB table exists + // (this prevents problems with profiling runs enabled in + // config.php before Moodle is installed. Rare but... + $tables = $DB->get_tables(); + if (!in_array('profiling', $tables)) { + return false; + } + $run = new moodle_xhprofrun(); $run->prepare_run($script); $runid = $run->save_run($data, null); diff --git a/message/lib.php b/message/lib.php index 280542aba8f..611abc88c36 100644 --- a/message/lib.php +++ b/message/lib.php @@ -200,6 +200,8 @@ function message_get_blocked_users($user1=null, $user2=null) { $user2->isblocked = false; } + $blockedusers = array(); + $userfields = user_picture::fields('u', array('lastaccess')); $blockeduserssql = "SELECT $userfields, COUNT(m.id) AS messagecount FROM {message_contacts} mc @@ -210,18 +212,14 @@ function message_get_blocked_users($user1=null, $user2=null) { ORDER BY u.firstname ASC"; $rs = $DB->get_recordset_sql($blockeduserssql, array('user1id1' => $user1->id, 'user1id2' => $user1->id)); - $blockedusers = array(); - if (!empty($rs)) { - foreach($rs as $rd) { - $blockedusers[] = $rd; + foreach($rs as $rd) { + $blockedusers[] = $rd; - if (!empty($user2) && $user2->id == $rd->id) { - $user2->isblocked = true; - } + if (!empty($user2) && $user2->id == $rd->id) { + $user2->isblocked = true; } - unset($rd); - $rs->close(); } + $rs->close(); return $blockedusers; } @@ -2129,6 +2127,8 @@ function message_mark_messages_read($touserid, $fromuserid){ foreach ($messages as $message) { message_mark_message_read($message, time()); } + + $messages->close(); } /** diff --git a/mod/assignment/lang/en/assignment.php b/mod/assignment/lang/en/assignment.php index b56aa8e525f..9540c4d6a0a 100644 --- a/mod/assignment/lang/en/assignment.php +++ b/mod/assignment/lang/en/assignment.php @@ -144,12 +144,13 @@ $string['noblogs'] = 'You have no blog entries to submit!'; $string['nofiles'] = 'No files were submitted'; $string['nofilesyet'] = 'No files submitted yet'; $string['nomoresubmissions'] = 'No further submissions are allowed.'; -$string['nosubmitusers'] = 'No users were found with permissions to submit this assignment'; $string['notavailableyet'] = 'Sorry, this assignment is not yet available.
Assignment instructions will be displayed here on the date given below.'; $string['notes'] = 'Notes'; $string['notesempty'] = 'No entry'; $string['notesupdateerror'] = 'Error when updating notes'; $string['notgradedyet'] = 'Not graded yet'; +$string['norequiregrading'] = 'There are no assignments that require grading'; +$string['nosubmisson'] = 'No assignments have been submit'; $string['notsubmittedyet'] = 'Not submitted yet'; $string['onceassignmentsent'] = 'Once the assignment is sent for marking, you will no longer be able to delete or attach file(s). Do you want to continue?'; $string['operation'] = 'Operation'; diff --git a/mod/assignment/lib.php b/mod/assignment/lib.php index c27ca95d50b..c681a3c57b5 100644 --- a/mod/assignment/lib.php +++ b/mod/assignment/lib.php @@ -1128,6 +1128,7 @@ class assignment_base { $course = $this->course; $assignment = $this->assignment; $cm = $this->cm; + $hassubmission = false; $tabindex = 1; //tabindex for quick grading tabbing; Not working for dropdowns yet add_to_log($course->id, 'assignment', 'view submission', 'submissions.php?id='.$this->cm->id, $this->assignment->id, $this->cm->id); @@ -1264,16 +1265,7 @@ class assignment_base { // Start working -- this is necessary as soon as the niceties are over $table->setup(); - if (empty($users)) { - echo $OUTPUT->heading(get_string('nosubmitusers','assignment')); - echo ''; - return true; - } - if ($this->assignment->assignmenttype=='upload' || $this->assignment->assignmenttype=='online' || $this->assignment->assignmenttype=='uploadsingle') { //TODO: this is an ugly hack, where is the plugin spirit? (skodak) - echo '
'.get_string('downloadall', 'assignment').'
'; - } /// Construct the SQL - list($where, $params) = $table->get_sql_where(); if ($where) { $where .= ' AND '; @@ -1290,179 +1282,192 @@ class assignment_base { } $ufields = user_picture::fields('u'); + if (!empty($users)) { + $select = "SELECT $ufields, + s.id AS submissionid, s.grade, s.submissioncomment, + s.timemodified, s.timemarked, + COALESCE(SIGN(SIGN(s.timemarked) + SIGN(s.timemarked - s.timemodified)), 0) AS status "; + $sql = 'FROM {user} u '. + 'LEFT JOIN {assignment_submissions} s ON u.id = s.userid + AND s.assignment = '.$this->assignment->id.' '. + 'WHERE '.$where.'u.id IN ('.implode(',',$users).') '; - $select = "SELECT $ufields, - s.id AS submissionid, s.grade, s.submissioncomment, - s.timemodified, s.timemarked, - COALESCE(SIGN(SIGN(s.timemarked) + SIGN(s.timemarked - s.timemodified)), 0) AS status "; - $sql = 'FROM {user} u '. - 'LEFT JOIN {assignment_submissions} s ON u.id = s.userid - AND s.assignment = '.$this->assignment->id.' '. - 'WHERE '.$where.'u.id IN ('.implode(',',$users).') '; + $ausers = $DB->get_records_sql($select.$sql.$sort, $params, $table->get_page_start(), $table->get_page_size()); - $ausers = $DB->get_records_sql($select.$sql.$sort, $params, $table->get_page_start(), $table->get_page_size()); + $table->pagesize($perpage, count($users)); - $table->pagesize($perpage, count($users)); + ///offset used to calculate index of student in that particular query, needed for the pop up to know who's next + $offset = $page * $perpage; + $strupdate = get_string('update'); + $strgrade = get_string('grade'); + $grademenu = make_grades_menu($this->assignment->grade); - ///offset used to calculate index of student in that particular query, needed for the pop up to know who's next - $offset = $page * $perpage; - $strupdate = get_string('update'); - $strgrade = get_string('grade'); - $grademenu = make_grades_menu($this->assignment->grade); + if ($ausers !== false) { + $grading_info = grade_get_grades($this->course->id, 'mod', 'assignment', $this->assignment->id, array_keys($ausers)); + $endposition = $offset + $perpage; + $currentposition = 0; + foreach ($ausers as $auser) { + if ($currentposition == $offset && $offset < $endposition) { + $final_grade = $grading_info->items[0]->grades[$auser->id]; + $grademax = $grading_info->items[0]->grademax; + $final_grade->formatted_grade = round($final_grade->grade,2) .' / ' . round($grademax,2); + $locked_overridden = 'locked'; + if ($final_grade->overridden) { + $locked_overridden = 'overridden'; + } - if ($ausers !== false) { - $grading_info = grade_get_grades($this->course->id, 'mod', 'assignment', $this->assignment->id, array_keys($ausers)); - $endposition = $offset + $perpage; - $currentposition = 0; - foreach ($ausers as $auser) { - if ($currentposition == $offset && $offset < $endposition) { - $final_grade = $grading_info->items[0]->grades[$auser->id]; - $grademax = $grading_info->items[0]->grademax; - $final_grade->formatted_grade = round($final_grade->grade,2) .' / ' . round($grademax,2); - $locked_overridden = 'locked'; - if ($final_grade->overridden) { - $locked_overridden = 'overridden'; - } + /// Calculate user status + $auser->status = ($auser->timemarked > 0) && ($auser->timemarked >= $auser->timemodified); + $picture = $OUTPUT->user_picture($auser); - /// Calculate user status - $auser->status = ($auser->timemarked > 0) && ($auser->timemarked >= $auser->timemodified); - $picture = $OUTPUT->user_picture($auser); + if (empty($auser->submissionid)) { + $auser->grade = -1; //no submission yet + } - if (empty($auser->submissionid)) { - $auser->grade = -1; //no submission yet - } + if (!empty($auser->submissionid)) { + $hassubmission = true; + ///Prints student answer and student modified date + ///attach file or print link to student answer, depending on the type of the assignment. + ///Refer to print_student_answer in inherited classes. + if ($auser->timemodified > 0) { + $studentmodified = '
'.$this->print_student_answer($auser->id) + . userdate($auser->timemodified).'
'; + } else { + $studentmodified = '
 
'; + } + ///Print grade, dropdown or text + if ($auser->timemarked > 0) { + $teachermodified = '
'.userdate($auser->timemarked).'
'; - if (!empty($auser->submissionid)) { - ///Prints student answer and student modified date - ///attach file or print link to student answer, depending on the type of the assignment. - ///Refer to print_student_answer in inherited classes. - if ($auser->timemodified > 0) { - $studentmodified = '
'.$this->print_student_answer($auser->id) - . userdate($auser->timemodified).'
'; + if ($final_grade->locked or $final_grade->overridden) { + $grade = '
'.$final_grade->formatted_grade.'
'; + } else if ($quickgrade) { + $attributes = array(); + $attributes['tabindex'] = $tabindex++; + $menu = html_writer::select(make_grades_menu($this->assignment->grade), 'menu['.$auser->id.']', $auser->grade, array(-1=>get_string('nograde')), $attributes); + $grade = '
'. $menu .'
'; + } else { + $grade = '
'.$this->display_grade($auser->grade).'
'; + } + + } else { + $teachermodified = '
 
'; + if ($final_grade->locked or $final_grade->overridden) { + $grade = '
'.$final_grade->formatted_grade.'
'; + } else if ($quickgrade) { + $attributes = array(); + $attributes['tabindex'] = $tabindex++; + $menu = html_writer::select(make_grades_menu($this->assignment->grade), 'menu['.$auser->id.']', $auser->grade, array(-1=>get_string('nograde')), $attributes); + $grade = '
'.$menu.'
'; + } else { + $grade = '
'.$this->display_grade($auser->grade).'
'; + } + } + ///Print Comment + if ($final_grade->locked or $final_grade->overridden) { + $comment = '
'.shorten_text(strip_tags($final_grade->str_feedback),15).'
'; + + } else if ($quickgrade) { + $comment = '
' + . '
'; + } else { + $comment = '
'.shorten_text(strip_tags($auser->submissioncomment),15).'
'; + } } else { $studentmodified = '
 
'; - } - ///Print grade, dropdown or text - if ($auser->timemarked > 0) { - $teachermodified = '
'.userdate($auser->timemarked).'
'; - - if ($final_grade->locked or $final_grade->overridden) { - $grade = '
'.$final_grade->formatted_grade.'
'; - } else if ($quickgrade) { - $attributes = array(); - $attributes['tabindex'] = $tabindex++; - $menu = html_writer::select(make_grades_menu($this->assignment->grade), 'menu['.$auser->id.']', $auser->grade, array(-1=>get_string('nograde')), $attributes); - $grade = '
'. $menu .'
'; - } else { - $grade = '
'.$this->display_grade($auser->grade).'
'; - } - - } else { $teachermodified = '
 
'; + $status = '
 
'; + if ($final_grade->locked or $final_grade->overridden) { - $grade = '
'.$final_grade->formatted_grade.'
'; - } else if ($quickgrade) { + $grade = '
'.$final_grade->formatted_grade . '
'; + $hassubmission = true; + } else if ($quickgrade) { // allow editing $attributes = array(); $attributes['tabindex'] = $tabindex++; $menu = html_writer::select(make_grades_menu($this->assignment->grade), 'menu['.$auser->id.']', $auser->grade, array(-1=>get_string('nograde')), $attributes); $grade = '
'.$menu.'
'; + $hassubmission = true; } else { - $grade = '
'.$this->display_grade($auser->grade).'
'; + $grade = '
-
'; + } + + if ($final_grade->locked or $final_grade->overridden) { + $comment = '
'.$final_grade->str_feedback.'
'; + } else if ($quickgrade) { + $comment = '
' + . '
'; + } else { + $comment = '
 
'; } } - ///Print Comment - if ($final_grade->locked or $final_grade->overridden) { - $comment = '
'.shorten_text(strip_tags($final_grade->str_feedback),15).'
'; - } else if ($quickgrade) { - $comment = '
' - . '
'; + if (empty($auser->status)) { /// Confirm we have exclusively 0 or 1 + $auser->status = 0; } else { - $comment = '
'.shorten_text(strip_tags($auser->submissioncomment),15).'
'; - } - } else { - $studentmodified = '
 
'; - $teachermodified = '
 
'; - $status = '
 
'; - - if ($final_grade->locked or $final_grade->overridden) { - $grade = '
'.$final_grade->formatted_grade . '
'; - } else if ($quickgrade) { // allow editing - $attributes = array(); - $attributes['tabindex'] = $tabindex++; - $menu = html_writer::select(make_grades_menu($this->assignment->grade), 'menu['.$auser->id.']', $auser->grade, array(-1=>get_string('nograde')), $attributes); - $grade = '
'.$menu.'
'; - } else { - $grade = '
-
'; + $auser->status = 1; } - if ($final_grade->locked or $final_grade->overridden) { - $comment = '
'.$final_grade->str_feedback.'
'; - } else if ($quickgrade) { - $comment = '
' - . '
'; - } else { - $comment = '
 
'; - } - } + $buttontext = ($auser->status == 1) ? $strupdate : $strgrade; - if (empty($auser->status)) { /// Confirm we have exclusively 0 or 1 - $auser->status = 0; - } else { - $auser->status = 1; - } + ///No more buttons, we use popups ;-). + $popup_url = '/mod/assignment/submissions.php?id='.$this->cm->id + . '&userid='.$auser->id.'&mode=single'.'&filter='.$filter.'&offset='.$offset++; - $buttontext = ($auser->status == 1) ? $strupdate : $strgrade; + $button = $OUTPUT->action_link($popup_url, $buttontext); - ///No more buttons, we use popups ;-). - $popup_url = '/mod/assignment/submissions.php?id='.$this->cm->id - . '&userid='.$auser->id.'&mode=single'.'&filter='.$filter.'&offset='.$offset++; + $status = '
'.$button.'
'; - $button = $OUTPUT->action_link($popup_url, $buttontext); + $finalgrade = ''.$final_grade->str_grade.''; - $status = '
'.$button.'
'; + $outcomes = ''; - $finalgrade = ''.$final_grade->str_grade.''; + if ($uses_outcomes) { - $outcomes = ''; + foreach($grading_info->outcomes as $n=>$outcome) { + $outcomes .= '
'; + $options = make_grades_menu(-$outcome->scaleid); - if ($uses_outcomes) { - - foreach($grading_info->outcomes as $n=>$outcome) { - $outcomes .= '
'; - $options = make_grades_menu(-$outcome->scaleid); - - if ($outcome->grades[$auser->id]->locked or !$quickgrade) { - $options[0] = get_string('nooutcome', 'grades'); - $outcomes .= ': '.$options[$outcome->grades[$auser->id]->grade].''; - } else { - $attributes = array(); - $attributes['tabindex'] = $tabindex++; - $attributes['id'] = 'outcome_'.$n.'_'.$auser->id; - $outcomes .= ' '.html_writer::select($options, 'outcome_'.$n.'['.$auser->id.']', $outcome->grades[$auser->id]->grade, array(0=>get_string('nooutcome', 'grades')), $attributes); + if ($outcome->grades[$auser->id]->locked or !$quickgrade) { + $options[0] = get_string('nooutcome', 'grades'); + $outcomes .= ': '.$options[$outcome->grades[$auser->id]->grade].''; + } else { + $attributes = array(); + $attributes['tabindex'] = $tabindex++; + $attributes['id'] = 'outcome_'.$n.'_'.$auser->id; + $outcomes .= ' '.html_writer::select($options, 'outcome_'.$n.'['.$auser->id.']', $outcome->grades[$auser->id]->grade, array(0=>get_string('nooutcome', 'grades')), $attributes); + } + $outcomes .= '
'; } - $outcomes .= '
'; } - } - $userlink = '' . fullname($auser, has_capability('moodle/site:viewfullnames', $this->context)) . ''; - $row = array($picture, $userlink, $grade, $comment, $studentmodified, $teachermodified, $status, $finalgrade); - if ($uses_outcomes) { - $row[] = $outcomes; + $userlink = '' . fullname($auser, has_capability('moodle/site:viewfullnames', $this->context)) . ''; + $row = array($picture, $userlink, $grade, $comment, $studentmodified, $teachermodified, $status, $finalgrade); + if ($uses_outcomes) { + $row[] = $outcomes; + } + $table->add_data($row); } - - $table->add_data($row); + $currentposition++; } - $currentposition++; + } + 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) + echo html_writer::start_tag('div', array('class' => 'mod-assignment-download-link')); + echo html_writer::link(new moodle_url('/mod/assignment/submissions.php', array('id' => $this->cm->id, 'download' => 'zip')), get_string('downloadall', 'assignment')); + echo html_writer::end_tag('div'); + } + $table->print_html(); /// Print the whole table + } else { + if ($filter == self::FILTER_SUBMITTED) { + echo html_writer::tag('div', get_string('nosubmisson', 'assignment'), array('class'=>'nosubmisson')); + } else if ($filter == self::FILTER_REQUIRE_GRADING) { + echo html_writer::tag('div', get_string('norequiregrading', 'assignment'), array('class'=>'norequiregrading')); } } - $table->print_html(); /// Print the whole table - /// Print quickgrade form around the table - if ($quickgrade && $table->started_output){ + if ($quickgrade && $table->started_output && !empty($users)){ $mailinfopref = false; if (get_user_preferences('assignment_mailinfo', 1)) { $mailinfopref = true; diff --git a/mod/assignment/styles.css b/mod/assignment/styles.css index 62a660e5183..356ac17bb1b 100644 --- a/mod/assignment/styles.css +++ b/mod/assignment/styles.css @@ -23,6 +23,7 @@ #page-mod-assignment-submissions .submissions .grade, #page-mod-assignment-submissions .submissions .outcome, #page-mod-assignment-submissions .submissions .finalgrade {text-align: right;} +#page-mod-assignment-submissions .submissions .header.noheader {display:none;} #page-mod-assignment-submissions .qgprefs #optiontable {text-align:right;margin-left:auto;} /** Styles for view.php **/ @@ -42,4 +43,6 @@ #page-mod-assignment-submissions.dir-rtl .timemodified, #page-mod-assignment-submissions.dir-rtl .timemarked {text-align:right;} #page-mod-assignment-submissions.dir-rtl .mform.optionspref .fitem .fitemtitle {text-align:left;} -#page-mod-assignment-type-uploadsingle-upload.dir-rtl .mdl-left {text-align:right;} \ No newline at end of file +#page-mod-assignment-type-uploadsingle-upload.dir-rtl .mdl-left {text-align:right;} + +.mod-assignment-download-link {text-align:right;} \ No newline at end of file diff --git a/mod/choice/backup/moodle2/backup_choice_stepslib.php b/mod/choice/backup/moodle2/backup_choice_stepslib.php index d211a2dbd8e..bd9b0c24a8f 100644 --- a/mod/choice/backup/moodle2/backup_choice_stepslib.php +++ b/mod/choice/backup/moodle2/backup_choice_stepslib.php @@ -39,7 +39,7 @@ class backup_choice_activity_structure_step extends backup_activity_structure_st // Define each element separated $choice = new backup_nested_element('choice', array('id'), array( 'name', 'intro', 'introformat', 'publish', - 'showresults', 'display', 'allowupdate', 'allowunanswered', + 'showresults', 'display', 'allowupdate', 'showunanswered', 'limitanswers', 'timeopen', 'timeclose', 'timemodified', 'completionsubmit')); diff --git a/mod/data/lib.php b/mod/data/lib.php index 2437ff37dc5..4ab2ee5ea10 100644 --- a/mod/data/lib.php +++ b/mod/data/lib.php @@ -962,7 +962,16 @@ function data_user_outline($course, $user, $mod, $data) { } else if ($grade) { $result = new stdClass(); $result->info = get_string('grade') . ': ' . $grade->str_long_grade; - $result->time = $grade->dategraded; + + //datesubmitted == time created. dategraded == time modified or time overridden + //if grade was last modified by the user themselves use date graded. Otherwise use date submitted + //TODO: move this copied & pasted code somewhere in the grades API. See MDL-26704 + if ($grade->usermodified == $user->id || empty($grade->datesubmitted)) { + $result->time = $grade->dategraded; + } else { + $result->time = $grade->datesubmitted; + } + return $result; } return NULL; @@ -1378,11 +1387,14 @@ function data_rating_permissions($options) { function data_rating_validate($params) { global $DB, $USER; - if (!array_key_exists('itemid', $params) || !array_key_exists('context', $params) || !array_key_exists('rateduserid', $params)) { + if (!array_key_exists('itemid', $params) + || !array_key_exists('context', $params) + || !array_key_exists('rateduserid', $params) + || !array_key_exists('scaleid', $params)) { throw new rating_exception('missingparameter'); } - $datasql = "SELECT d.id as did, d.course, r.userid as userid, d.approval, r.approved, r.timecreated, d.assesstimestart, d.assesstimefinish, r.groupid + $datasql = "SELECT d.id as did, d.scale, d.course, r.userid as userid, d.approval, r.approved, r.timecreated, d.assesstimestart, d.assesstimefinish, r.groupid FROM {data_records} r JOIN {data} d ON r.dataid = d.id WHERE r.id = :itemid"; @@ -1392,16 +1404,40 @@ function data_rating_validate($params) { throw new rating_exception('invaliditemid'); } + if ($info->scale != $params['scaleid']) { + //the scale being submitted doesnt match the one in the database + throw new rating_exception('invalidscaleid'); + } + if ($info->userid == $USER->id) { //user is attempting to rate their own glossary entry throw new rating_exception('nopermissiontorate'); } - if ($params['rateduserid'] != $info->userid) { + if ($info->userid != $params['rateduserid']) { //supplied user ID doesnt match the user ID from the database throw new rating_exception('invaliduserid'); } + //check that the submitted rating is valid for the scale + if ($params['rating'] < 0) { + throw new rating_exception('invalidnum'); + } else if ($info->scale < 0) { + //its a custom scale + $scalerecord = $DB->get_record('scale', array('id' => -$params['scaleid'])); + if ($scalerecord) { + $scalearray = explode(',', $scalerecord->scale); + if ($params['rating'] > count($scalearray)) { + throw new rating_exception('invalidnum'); + } + } else { + throw new rating_exception('invalidscaleid'); + } + } else if ($params['rating'] > $info->scale) { + //if its numeric and submitted rating is above maximum + throw new rating_exception('invalidnum'); + } + if ($info->approval && !$info->approved) { //database requires approval but this item isnt approved throw new rating_exception('nopermissiontorate'); diff --git a/mod/feedback/db/messages.php b/mod/feedback/db/messages.php index 0cdead137b0..e99c9197724 100644 --- a/mod/feedback/db/messages.php +++ b/mod/feedback/db/messages.php @@ -27,6 +27,9 @@ $messageproviders = array ( /// Submitting a feedback 'submission' => array ( + ), +/// Message to nonrespondents + 'message' => array ( ) ); diff --git a/mod/feedback/show_nonrespondents.php b/mod/feedback/show_nonrespondents.php index 4bbc51bfd4f..92a3d82dbfb 100644 --- a/mod/feedback/show_nonrespondents.php +++ b/mod/feedback/show_nonrespondents.php @@ -75,8 +75,8 @@ foreach ($messageuser as $userid) { $senduser = $DB->get_record('user', array('id'=>$userid)); $eventdata = new stdClass(); - $eventdata->name = 'feedback'; - $eventdata->component = 'mod'; + $eventdata->name = 'message'; + $eventdata->component = 'mod_feedback'; $eventdata->userfrom = $USER; $eventdata->userto = $senduser; $eventdata->subject = $subject; diff --git a/mod/feedback/version.php b/mod/feedback/version.php index 460a9d5ff85..78178bd8128 100644 --- a/mod/feedback/version.php +++ b/mod/feedback/version.php @@ -9,7 +9,7 @@ */ - $module->version = 2010112302; // The current module version (Date: YYYYMMDDXX) + $module->version = 2011051600; // The current module version (Date: YYYYMMDDXX) $module->requires = 2010080300; // Requires this Moodle version $feedback_version_intern = 1; //this version is used for restore older backups $module->cron = 0; // Period for cron to check this module (secs) diff --git a/mod/forum/lib.php b/mod/forum/lib.php index 9599e72e452..d850e57682c 100644 --- a/mod/forum/lib.php +++ b/mod/forum/lib.php @@ -1131,7 +1131,16 @@ function forum_user_outline($course, $user, $mod, $forum) { } else if ($grade) { $result = new stdClass(); $result->info = get_string('grade') . ': ' . $grade->str_long_grade; - $result->time = $grade->dategraded; + + //datesubmitted == time created. dategraded == time modified or time overridden + //if grade was last modified by the user themselves use date graded. Otherwise use date submitted + //TODO: move this copied & pasted code somewhere in the grades API. See MDL-26704 + if ($grade->usermodified == $user->id || empty($grade->datesubmitted)) { + $result->time = $grade->dategraded; + } else { + $result->time = $grade->datesubmitted; + } + return $result; } return NULL; @@ -3470,11 +3479,14 @@ function forum_rating_permissions($contextid) { function forum_rating_validate($params) { global $DB, $USER; - if (!array_key_exists('itemid', $params) || !array_key_exists('context', $params) || !array_key_exists('rateduserid', $params)) { + if (!array_key_exists('itemid', $params) + || !array_key_exists('context', $params) + || !array_key_exists('rateduserid', $params) + || !array_key_exists('scaleid', $params)) { throw new rating_exception('missingparameter'); } - $forumsql = "SELECT f.id as fid, f.course, d.id as did, p.userid as userid, p.created, f.assesstimestart, f.assesstimefinish, d.groupid + $forumsql = "SELECT f.id as fid, f.course, f.scale, d.id as did, p.userid as userid, p.created, f.assesstimestart, f.assesstimefinish, d.groupid FROM {forum_posts} p JOIN {forum_discussions} d ON p.discussion = d.id JOIN {forum} f ON d.forum = f.id @@ -3485,16 +3497,40 @@ function forum_rating_validate($params) { throw new rating_exception('invaliditemid'); } + if ($info->scale != $params['scaleid']) { + //the scale being submitted doesnt match the one in the database + throw new rating_exception('invalidscaleid'); + } + if ($info->userid == $USER->id) { //user is attempting to rate their own post throw new rating_exception('nopermissiontorate'); } - if ($params['rateduserid'] != $info->userid) { + if ($info->userid != $params['rateduserid']) { //supplied user ID doesnt match the user ID from the database throw new rating_exception('invaliduserid'); } + //check that the submitted rating is valid for the scale + if ($params['rating'] < 0) { + throw new rating_exception('invalidnum'); + } else if ($info->scale < 0) { + //its a custom scale + $scalerecord = $DB->get_record('scale', array('id' => -$params['scaleid'])); + if ($scalerecord) { + $scalearray = explode(',', $scalerecord->scale); + if ($params['rating'] > count($scalearray)) { + throw new rating_exception('invalidnum'); + } + } else { + throw new rating_exception('invalidscaleid'); + } + } else if ($params['rating'] > $info->scale) { + //if its numeric and submitted rating is above maximum + throw new rating_exception('invalidnum'); + } + //check the item we're rating was created in the assessable time window if (!empty($info->assesstimestart) && !empty($info->assesstimefinish)) { if ($info->timecreated < $info->assesstimestart || $info->timecreated > $info->assesstimefinish) { diff --git a/mod/glossary/lib.php b/mod/glossary/lib.php index ec5a023857f..edd9e421157 100644 --- a/mod/glossary/lib.php +++ b/mod/glossary/lib.php @@ -243,7 +243,16 @@ function glossary_user_outline($course, $user, $mod, $glossary) { } else if ($grade) { $result = new stdClass(); $result->info = get_string('grade') . ': ' . $grade->str_long_grade; - $result->time = $grade->dategraded; + + //datesubmitted == time created. dategraded == time modified or time overridden + //if grade was last modified by the user themselves use date graded. Otherwise use date submitted + //TODO: move this copied & pasted code somewhere in the grades API. See MDL-26704 + if ($grade->usermodified == $user->id || empty($grade->datesubmitted)) { + $result->time = $grade->dategraded; + } else { + $result->time = $grade->datesubmitted; + } + return $result; } return NULL; @@ -484,11 +493,14 @@ function glossary_rating_permissions($options) { function glossary_rating_validate($params) { global $DB, $USER; - if (!array_key_exists('itemid', $params) || !array_key_exists('context', $params) || !array_key_exists('rateduserid', $params)) { + if (!array_key_exists('itemid', $params) + || !array_key_exists('context', $params) + || !array_key_exists('rateduserid', $params) + || !array_key_exists('scaleid', $params)) { throw new rating_exception('missingparameter'); } - $glossarysql = "SELECT g.id as gid, e.userid as userid, e.approved, e.timecreated, g.assesstimestart, g.assesstimefinish + $glossarysql = "SELECT g.id as gid, g.scale, e.userid as userid, e.approved, e.timecreated, g.assesstimestart, g.assesstimefinish FROM {glossary_entries} e JOIN {glossary} g ON e.glossaryid = g.id WHERE e.id = :itemid"; @@ -498,16 +510,40 @@ function glossary_rating_validate($params) { throw new rating_exception('invaliditemid'); } + if ($info->scale != $params['scaleid']) { + //the scale being submitted doesnt match the one in the database + throw new rating_exception('invalidscaleid'); + } + if ($info->userid == $USER->id) { //user is attempting to rate their own glossary entry throw new rating_exception('nopermissiontorate'); } - if ($params['rateduserid'] != $info->userid) { + if ($info->userid != $params['rateduserid']) { //supplied user ID doesnt match the user ID from the database throw new rating_exception('invaliduserid'); } + //check that the submitted rating is valid for the scale + if ($params['rating'] < 0) { + throw new rating_exception('invalidnum'); + } else if ($info->scale < 0) { + //its a custom scale + $scalerecord = $DB->get_record('scale', array('id' => -$params['scaleid'])); + if ($scalerecord) { + $scalearray = explode(',', $scalerecord->scale); + if ($params['rating'] > count($scalearray)) { + throw new rating_exception('invalidnum'); + } + } else { + throw new rating_exception('invalidscaleid'); + } + } else if ($params['rating'] > $info->scale) { + //if its numeric and submitted rating is above maximum + throw new rating_exception('invalidnum'); + } + if (!$info->approved) { //item isnt approved throw new rating_exception('nopermissiontorate'); diff --git a/mod/lesson/essay.php b/mod/lesson/essay.php index 981a833c987..a0a611c466a 100644 --- a/mod/lesson/essay.php +++ b/mod/lesson/essay.php @@ -46,41 +46,59 @@ if ($mode !== 'display') { } $PAGE->set_url($url); +$attempt = new stdClass(); +$user = new stdClass(); +$attemptid = optional_param('attemptid', 0, PARAM_INT); + +if ($attemptid > 0) { + $attempt = $DB->get_record('lesson_attempts', array('id' => $attemptid)); + $answer = $DB->get_record('lesson_answers', array('lessonid' => $lesson->id, 'pageid' => $attempt->pageid)); + $user = $DB->get_record('user', array('id' => $attempt->userid)); + $scoreoptions = array(); + if ($lesson->custom) { + $i = $answer->score; + while ($i >= 0) { + $scoreoptions[$i] = (string)$i; + $i--; + } + } else { + $scoreoptions[0] = get_string('nocredit', 'lesson'); + $scoreoptions[1] = get_string('credit', 'lesson'); + } +} + /// Handle any preprocessing before header is printed - based on $mode switch ($mode) { case 'grade': // Grading form - get the necessary data require_sesskey(); - $attemptid = required_param('attemptid', PARAM_INT); - - if (!$attempt = $DB->get_record('lesson_attempts', array('id' => $attemptid))) { + if (empty($attempt)) { print_error('cannotfindattempt', 'lesson'); } - $page = $lesson->load_page($attempt->pageid); - if (!$user = $DB->get_record('user', array('id' => $attempt->userid))) { + if (empty($user)) { print_error('cannotfinduser', 'lesson'); } - if (!$answer = $DB->get_record('lesson_answers', array('lessonid' => $lesson->id, 'pageid' => $page->id))) { + if (empty($answer)) { print_error('cannotfindanswer', 'lesson'); } break; case 'update': require_sesskey(); - $mform = new essay_grading_form(); + + if (empty($attempt)) { + print_error('cannotfindattempt', 'lesson'); + } + if (empty($user)) { + print_error('cannotfinduser', 'lesson'); + } + + $mform = new essay_grading_form(null, array('scoreoptions'=>$scoreoptions, 'user'=>$user)); + if ($mform->is_cancelled()) { + redirect("$CFG->wwwroot/mod/lesson/essay.php?id=$cm->id"); + } if ($form = $mform->get_data()) { - - if (optional_param('cancel', false, PARAM_RAW)) { - redirect("$CFG->wwwroot/mod/lesson/essay.php?id=$cm->id"); - } - - $attemptid = required_param('attemptid', PARAM_INT); - $score = optional_param('score', 0, PARAM_INT); - - if (!$attempt = $DB->get_record('lesson_attempts', array('id' => $attemptid))) { - print_error('cannotfindattempt', 'lesson'); - } if (!$grades = $DB->get_records('lesson_grades', array("lessonid"=>$lesson->id, "userid"=>$attempt->userid), 'completed', '*', $attempt->retry, 1)) { print_error('cannotfindgrade', 'lesson'); } @@ -89,7 +107,7 @@ switch ($mode) { $essayinfo = unserialize($attempt->useranswer); $essayinfo->graded = 1; - $essayinfo->score = $score; + $essayinfo->score = $form->score; $essayinfo->response = clean_param($form->response, PARAM_RAW); $essayinfo->sent = 0; if (!$lesson->custom && $essayinfo->score == 1) { @@ -368,22 +386,9 @@ switch ($mode) { case 'grade': // Grading form // Expects the following to be set: $attemptid, $answer, $user, $page, $attempt - - $essayinfo = unserialize($attempt->useranswer); - $options = array(); - if ($lesson->custom) { - $i = $answer->score; - while ($i >= 0) { - $options[$i] = (string)$i; - $i--; - } - } else { - $options[0] = get_string('nocredit', 'lesson'); - $options[1] = get_string('credit', 'lesson'); - } - $mform = new essay_grading_form(null, array('scoreoptions'=>$options, 'user'=>$user)); + $mform = new essay_grading_form(null, array('scoreoptions'=>$scoreoptions, 'user'=>$user)); $data = new stdClass; $data->id = $cm->id; $data->attemptid = $attemptid; diff --git a/mod/lesson/lib.php b/mod/lesson/lib.php index 813ff4c4381..4c866b7b0ef 100644 --- a/mod/lesson/lib.php +++ b/mod/lesson/lib.php @@ -166,8 +166,15 @@ function lesson_user_outline($course, $user, $mod, $lesson) { } else { $grade = reset($grades->items[0]->grades); $return->info = get_string("grade") . ': ' . $grade->str_long_grade; - $return->time = $grade->dategraded; - $return->info = get_string("no")." ".get_string("attempts", "lesson"); + + //datesubmitted == time created. dategraded == time modified or time overridden + //if grade was last modified by the user themselves use date graded. Otherwise use date submitted + //TODO: move this copied & pasted code somewhere in the grades API. See MDL-26704 + if ($grade->usermodified == $user->id || empty($grade->datesubmitted)) { + $result->time = $grade->dategraded; + } else { + $result->time = $grade->datesubmitted; + } } return $return; } diff --git a/mod/quiz/lib.php b/mod/quiz/lib.php index ac8e09b90f9..be6b2b64971 100644 --- a/mod/quiz/lib.php +++ b/mod/quiz/lib.php @@ -381,7 +381,16 @@ function quiz_user_outline($course, $user, $mod, $quiz) { $result = new stdClass; $result->info = get_string('grade') . ': ' . $grade->str_long_grade; - $result->time = $grade->dategraded; + + //datesubmitted == time created. dategraded == time modified or time overridden + //if grade was last modified by the user themselves use date graded. Otherwise use date submitted + //TODO: move this copied & pasted code somewhere in the grades API. See MDL-26704 + if ($grade->usermodified == $user->id || empty($grade->datesubmitted)) { + $result->time = $grade->dategraded; + } else { + $result->time = $grade->datesubmitted; + } + return $result; } diff --git a/mod/scorm/lib.php b/mod/scorm/lib.php index 88ecd280917..80b8c7ddd39 100644 --- a/mod/scorm/lib.php +++ b/mod/scorm/lib.php @@ -294,7 +294,16 @@ function scorm_user_outline($course, $user, $mod, $scorm) { $grade = reset($grades->items[0]->grades); $result = new stdClass(); $result->info = get_string('grade') . ': '. $grade->str_long_grade; - $result->time = $grade->dategraded; + + //datesubmitted == time created. dategraded == time modified or time overridden + //if grade was last modified by the user themselves use date graded. Otherwise use date submitted + //TODO: move this copied & pasted code somewhere in the grades API. See MDL-26704 + if ($grade->usermodified == $user->id || empty($grade->datesubmitted)) { + $result->time = $grade->dategraded; + } else { + $result->time = $grade->datesubmitted; + } + return $result; } return null; diff --git a/version.php b/version.php index 41ca75bf2e6..89dfcb5aa4f 100644 --- a/version.php +++ b/version.php @@ -30,10 +30,10 @@ defined('MOODLE_INTERNAL') || die(); -$version = 2011051100.00; // YYYYMMDD = weekly release date of this DEV branch +$version = 2011051800.00; // YYYYMMDD = weekly release date of this DEV branch // RR = release increments - 00 in DEV branches // .XX = incremental changes -$release = '2.1dev (Build: 20110511)'; // Human-friendly version name +$release = '2.1dev (Build: 20110518)'; // Human-friendly version name $maturity = MATURITY_ALPHA; // this version's maturity level