Merge branch 'MDL-48709' of git://github.com/jmvedrine/moodle
authorDavid Monllao <davidm@moodle.com>
Tue, 17 Feb 2015 01:17:10 +0000 (09:17 +0800)
committerDavid Monllao <davidm@moodle.com>
Tue, 17 Feb 2015 01:17:10 +0000 (09:17 +0800)
19 files changed:
admin/settings/security.php
config-dist.php
filter/mathjaxloader/db/upgrade.php
filter/mathjaxloader/settings.php
filter/mathjaxloader/upgrade.txt
filter/mathjaxloader/version.php
filter/mathjaxloader/yui/build/moodle-filter_mathjaxloader-loader/moodle-filter_mathjaxloader-loader-debug.js
filter/mathjaxloader/yui/build/moodle-filter_mathjaxloader-loader/moodle-filter_mathjaxloader-loader-min.js
filter/mathjaxloader/yui/build/moodle-filter_mathjaxloader-loader/moodle-filter_mathjaxloader-loader.js
filter/mathjaxloader/yui/src/loader/js/loader.js
grade/report/outcomes/index.php
lang/en/admin.php
lib/classes/task/manager.php
lib/tests/behat/behat_hooks.php
lib/tests/scheduled_task_test.php
mod/assign/lib.php
mod/assign/tests/lib_test.php
report/security/lang/en/report_security.php
report/security/locallib.php

index af1e6c8..66cae6b 100644 (file)
@@ -55,7 +55,8 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
 
     $temp->add(new admin_setting_configcheckbox('profilesforenrolledusersonly', new lang_string('profilesforenrolledusersonly','admin'),new lang_string('configprofilesforenrolledusersonly', 'admin'),'1'));
 
-    $temp->add(new admin_setting_configcheckbox('cronclionly', new lang_string('cronclionly', 'admin'), new lang_string('configcronclionly', 'admin'), 0));
+    $temp->add(new admin_setting_configcheckbox('cronclionly', new lang_string('cronclionly', 'admin'), new lang_string
+            ('configcronclionly', 'admin'), 1));
     $temp->add(new admin_setting_configpasswordunmask('cronremotepassword', new lang_string('cronremotepassword', 'admin'), new lang_string('configcronremotepassword', 'admin'), ''));
 
     $options = array(0=>get_string('no'), 3=>3, 5=>5, 7=>7, 10=>10, 20=>20, 30=>30, 50=>50, 100=>100);
index 4338d7e..c91ccb1 100644 (file)
@@ -507,7 +507,7 @@ $CFG->admin = 'admin';
 //      Uses lock files stored by default in the dataroot. Whether this
 //      works on clusters depends on the file system used for the dataroot.
 //
-// "\\core\\lock\\db_row_lock_factory" - DB locking based on table rows.
+// "\\core\\lock\\db_record_lock_factory" - DB locking based on table rows.
 //
 // "\\core\\lock\\postgres_lock_factory" - DB locking based on postgres advisory locks.
 //
index acab499..bf7fedd 100644 (file)
@@ -47,5 +47,25 @@ function xmldb_filter_mathjaxloader_upgrade($oldversion) {
     // Moodle v2.8.0 release upgrade line.
     // Put any upgrade step following this.
 
+    // Moodle v2.9.0 release upgrade line.
+    // Put any upgrade step following this.
+
+    if ($oldversion < 2015021200) {
+
+        $httpurl = get_config('filter_mathjaxloader', 'httpurl');
+        // Don't change the config if it has been manually changed to something besides the default setting value.
+        if ($httpurl === "http://cdn.mathjax.org/mathjax/2.3-latest/MathJax.js") {
+            set_config('httpurl', 'http://cdn.mathjax.org/mathjax/2.5-latest/MathJax.js', 'filter_mathjaxloader');
+        }
+
+        $httpsurl = get_config('filter_mathjaxloader', 'httpsurl');
+        // Don't change the config if it has been manually changed to something besides the default setting value.
+        if ($httpsurl === "https://cdn.mathjax.org/mathjax/2.3-latest/MathJax.js") {
+            set_config('httpsurl', 'https://cdn.mathjax.org/mathjax/2.5-latest/MathJax.js', 'filter_mathjaxloader');
+        }
+
+        upgrade_plugin_savepoint(true, 2015021200, 'filter', 'mathjaxloader');
+    }
+
     return true;
 }
index 978587c..1ca7670 100644 (file)
@@ -33,14 +33,14 @@ if ($ADMIN->fulltree) {
     $item = new admin_setting_configtext('filter_mathjaxloader/httpurl',
                                          new lang_string('httpurl', 'filter_mathjaxloader'),
                                          new lang_string('httpurl_help', 'filter_mathjaxloader'),
-                                         'http://cdn.mathjax.org/mathjax/2.3-latest/MathJax.js',
+                                         'http://cdn.mathjax.org/mathjax/2.5-latest/MathJax.js',
                                          PARAM_RAW);
     $settings->add($item);
 
     $item = new admin_setting_configtext('filter_mathjaxloader/httpsurl',
                                          new lang_string('httpsurl', 'filter_mathjaxloader'),
                                          new lang_string('httpsurl_help', 'filter_mathjaxloader'),
-                                         'https://cdn.mathjax.org/mathjax/2.3-latest/MathJax.js',
+                                         'https://cdn.mathjax.org/mathjax/2.5-latest/MathJax.js',
                                          PARAM_RAW);
     $settings->add($item);
 
index ca95016..87db75e 100644 (file)
@@ -1,3 +1,14 @@
+=== 2.9 ===
+
+* Update to the latest version of MathJax setting "httpurl" and "httpsurl" to:
+  http://cdn.mathjax.org/mathjax/2.5-latest/MathJax.js
+
+  and
+
+  https://cdn.mathjax.org/mathjax/2.5-latest/MathJax.js
+
+=== Before 2.9 ===
+
 Setting "httpsurl" default changed from:
 
 https://c328740.ssl.cf1.rackcdn.com/mathjax/2.3-latest/MathJax.js
index b825781..21e2f19 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version  = 2014111000;
+$plugin->version  = 2015021200;
 $plugin->requires = 2014110400;  // Requires this Moodle version
 $plugin->component= 'filter_mathjaxloader';
index 11b4a9d..83b6d8d 100644 (file)
Binary files a/filter/mathjaxloader/yui/build/moodle-filter_mathjaxloader-loader/moodle-filter_mathjaxloader-loader-debug.js and b/filter/mathjaxloader/yui/build/moodle-filter_mathjaxloader-loader/moodle-filter_mathjaxloader-loader-debug.js differ
index ccebf0c..809018e 100644 (file)
Binary files a/filter/mathjaxloader/yui/build/moodle-filter_mathjaxloader-loader/moodle-filter_mathjaxloader-loader-min.js and b/filter/mathjaxloader/yui/build/moodle-filter_mathjaxloader-loader/moodle-filter_mathjaxloader-loader-min.js differ
index 11b4a9d..83b6d8d 100644 (file)
Binary files a/filter/mathjaxloader/yui/build/moodle-filter_mathjaxloader-loader/moodle-filter_mathjaxloader-loader.js and b/filter/mathjaxloader/yui/build/moodle-filter_mathjaxloader-loader/moodle-filter_mathjaxloader-loader.js differ
index aad01b3..835a864 100644 (file)
@@ -111,14 +111,20 @@ M.filter_mathjaxloader = M.filter_mathjaxloader || {
     contentUpdated: function(event) {
         var self = this;
         Y.use('mathjax', function() {
+            if (typeof window.MathJax === "undefined") {
+                return;
+            }
+            var processdelay = window.MathJax.Hub.processSectionDelay;
+            // Set the process section delay to 0 when updating the formula.
+            window.MathJax.Hub.processSectionDelay = 0;
             self._setLocale();
             event.nodes.each(function (node) {
                 node.all('.filter_mathjaxloader_equation').each(function(node) {
-                    if (typeof window.MathJax !== "undefined") {
-                        window.MathJax.Hub.Queue(["Typeset", window.MathJax.Hub, node.getDOMNode()]);
-                    }
+                    window.MathJax.Hub.Queue(["Typeset", window.MathJax.Hub, node.getDOMNode()]);
                 });
             });
+            // Set the delay back to normal after processing.
+            window.MathJax.Hub.processSectionDelay = processdelay;
         });
     }
 };
index 7ffc08e..cc809ab 100644 (file)
@@ -74,7 +74,7 @@ foreach ($outcomes as $outcomeid => $outcome) {
                       FROM {grade_grades}
                      WHERE itemid = ?".
                      $hidesuspendedsql.
-                  "GROUP BY itemid";
+                  " GROUP BY itemid";
             $info = $DB->get_records_sql($sql, $params);
 
             if (!$info) {
index fd3471d..d9193b9 100644 (file)
@@ -161,7 +161,7 @@ $string['configcourserequestnotify'] = 'Type username of user to be notified whe
 $string['configcourserequestnotify2'] = 'Users who will be notified when a course is requested. Only users who can approve course requests are listed here.';
 $string['configcoursesperpage'] = 'Enter the number of courses to be displayed per page in a course listing.';
 $string['configcourseswithsummarieslimit'] = 'The maximum number of courses to display in a course listing including summaries before falling back to a simpler listing.';
-$string['configcronclionly'] = 'If this is set, then the cron script can only be run from the command line instead of via the web.  This overrides the cron password setting below.';
+$string['configcronclionly'] = 'If this is set, then the cron script can only be run from the command line instead of via the web. This overrides the cron password setting below. Please note that, running cron from web can expose secure information to site users.';
 $string['configcronremotepassword'] = 'This means that the cron.php script cannot be run from a web browser without supplying the password using the following form of URL:<pre>
     http://site.example.com/admin/cron.php?password=opensesame
 </pre>If this is left empty, no password is required.';
index 5c6bef2..36772ee 100644 (file)
@@ -85,53 +85,31 @@ class manager {
      */
     public static function reset_scheduled_tasks_for_component($componentname) {
         global $DB;
-        $cronlockfactory = \core\lock\lock_config::get_lock_factory('cron');
-
-        if (!$cronlock = $cronlockfactory->get_lock('core_cron', 10, 60)) {
-            throw new \moodle_exception('locktimeout');
-        }
         $tasks = self::load_default_scheduled_tasks_for_component($componentname);
 
-        $tasklocks = array();
         foreach ($tasks as $taskid => $task) {
             $classname = get_class($task);
             if (strpos($classname, '\\') !== 0) {
                 $classname = '\\' . $classname;
             }
 
-            // For tasks, the first run should also follow the schedule.
-            $task->set_next_run_time($task->get_next_scheduled_time());
-
-            // If there is an existing task with a custom schedule, do not override it.
-            $currenttask = self::get_scheduled_task($classname);
-            if ($currenttask && $currenttask->is_customised()) {
-                $tasks[$taskid] = $currenttask;
-            }
-
-            if (!$lock = $cronlockfactory->get_lock($classname, 10, 60)) {
-                // Could not get all the locks required - release all locks and fail.
-                foreach ($tasklocks as $tasklock) {
-                    $tasklock->release();
+            if ($currenttask = self::get_scheduled_task($classname)) {
+                if ($currenttask->is_customised()) {
+                    // If there is an existing task with a custom schedule, do not override it.
+                    continue;
                 }
-                $cronlock->release();
-                throw new \moodle_exception('locktimeout');
-            }
-            $tasklocks[] = $lock;
-        }
 
-        // Got a lock on cron and all the tasks for this component, time to reset the config.
-        $DB->delete_records('task_scheduled', array('component' => $componentname));
-        foreach ($tasks as $task) {
-            $record = self::record_from_scheduled_task($task);
-            $DB->insert_record('task_scheduled', $record);
-        }
+                // Update the record from the default task data.
+                self::configure_scheduled_task($task);
+            } else {
+                // Ensure that the first run follows the schedule.
+                $task->set_next_run_time($task->get_next_scheduled_time());
 
-        // Release the locks.
-        foreach ($tasklocks as $tasklock) {
-            $tasklock->release();
+                // Insert the new task in the database.
+                $record = self::record_from_scheduled_task($task);
+                $DB->insert_record('task_scheduled', $record);
+            }
         }
-
-        $cronlock->release();
     }
 
     /**
@@ -160,20 +138,11 @@ class manager {
      */
     public static function configure_scheduled_task(scheduled_task $task) {
         global $DB;
-        $cronlockfactory = \core\lock\lock_config::get_lock_factory('cron');
-
-        if (!$cronlock = $cronlockfactory->get_lock('core_cron', 10, 60)) {
-            throw new \moodle_exception('locktimeout');
-        }
 
         $classname = get_class($task);
         if (strpos($classname, '\\') !== 0) {
             $classname = '\\' . $classname;
         }
-        if (!$lock = $cronlockfactory->get_lock($classname, 10, 60)) {
-            $cronlock->release();
-            throw new \moodle_exception('locktimeout');
-        }
 
         $original = $DB->get_record('task_scheduled', array('classname'=>$classname), 'id', MUST_EXIST);
 
@@ -182,8 +151,6 @@ class manager {
         $record->nextruntime = $task->get_next_scheduled_time();
         $result = $DB->update_record('task_scheduled', $record);
 
-        $lock->release();
-        $cronlock->release();
         return $result;
     }
 
index 6e2653f..9ba9ae5 100644 (file)
@@ -205,6 +205,9 @@ class behat_hooks extends behat_base {
         $user = $DB->get_record('user', array('username' => 'admin'));
         \core\session\manager::set_user($user);
 
+        // Enable web cron.
+        set_config('cronclionly', 0);
+
         // Reset the browser if specified in config.php.
         if (!empty($CFG->behat_restart_browser_after) && $this->running_javascript()) {
             $now = time();
index e05edd6..2d5e205 100644 (file)
@@ -177,6 +177,25 @@ class core_scheduled_task_testcase extends advanced_testcase {
         // We reset this field, because we do not want to compare it.
         $firsttaskrecord->nextruntime = '0';
 
+        // Delete a task to simulate the fact that its new.
+        $secondtask = next($defaulttasks);
+        $DB->delete_records('task_scheduled', array('classname' => '\\' . trim(get_class($secondtask), '\\')));
+        $this->assertFalse(\core\task\manager::get_scheduled_task(get_class($secondtask)));
+
+        // Edit a task to simulate a change in its definition (as if it was not customised).
+        $thirdtask = next($defaulttasks);
+        $thirdtask->set_minute('1');
+        $thirdtask->set_hour('2');
+        $thirdtask->set_month('3');
+        $thirdtask->set_day_of_week('4');
+        $thirdtask->set_day('5');
+        $thirdtaskbefore = \core\task\manager::get_scheduled_task(get_class($thirdtask));
+        $thirdtaskbefore->set_next_run_time(null);      // Ignore this value when comparing.
+        \core\task\manager::configure_scheduled_task($thirdtask);
+        $thirdtask = \core\task\manager::get_scheduled_task(get_class($thirdtask));
+        $thirdtask->set_next_run_time(null);            // Ignore this value when comparing.
+        $this->assertNotEquals($thirdtaskbefore, $thirdtask);
+
         // Now call reset on all the tasks.
         \core\task\manager::reset_scheduled_tasks_for_component('moodle');
 
@@ -192,6 +211,17 @@ class core_scheduled_task_testcase extends advanced_testcase {
         // Assert a customised task was not altered by reset.
         $this->assertEquals($firsttaskrecord, $newfirsttaskrecord);
 
+        // Assert that the second task was added back.
+        $secondtaskafter = \core\task\manager::get_scheduled_task(get_class($secondtask));
+        $secondtaskafter->set_next_run_time(null);   // Do not compare the nextruntime.
+        $secondtask->set_next_run_time(null);
+        $this->assertEquals($secondtask, $secondtaskafter);
+
+        // Assert that the third task edits were overridden.
+        $thirdtaskafter = \core\task\manager::get_scheduled_task(get_class($thirdtask));
+        $thirdtaskafter->set_next_run_time(null);
+        $this->assertEquals($thirdtaskbefore, $thirdtaskafter);
+
         // Assert we have the same number of tasks.
         $this->assertEquals($initcount, $finalcount);
     }
index 56887bf..c516786 100644 (file)
@@ -293,16 +293,18 @@ function assign_page_type_list($pagetype, $parentcontext, $currentcontext) {
  *
  * @param mixed $courses The list of courses to print the overview for
  * @param array $htmlarray The array of html to return
+ *
+ * @return true
  */
 function assign_print_overview($courses, &$htmlarray) {
-    global $USER, $CFG, $DB;
+    global $CFG, $DB;
 
     if (empty($courses) || !is_array($courses) || count($courses) == 0) {
-        return array();
+        return true;
     }
 
     if (!$assignments = get_all_instances_in_courses('assign', $courses)) {
-        return;
+        return true;
     }
 
     $assignmentids = array();
@@ -339,13 +341,7 @@ function assign_print_overview($courses, &$htmlarray) {
     $strcutoffdate = get_string('nosubmissionsacceptedafter', 'assign');
     $strnolatesubmissions = get_string('nolatesubmissions', 'assign');
     $strduedateno = get_string('duedateno', 'assign');
-    $strduedateno = get_string('duedateno', 'assign');
-    $strgraded = get_string('graded', 'assign');
-    $strnotgradedyet = get_string('notgradedyet', 'assign');
-    $strnotsubmittedyet = get_string('notsubmittedyet', 'assign');
-    $strsubmitted = get_string('submitted', 'assign');
     $strassignment = get_string('modulename', 'assign');
-    $strreviewed = get_string('reviewed', 'assign');
 
     // We do all possible database work here *outside* of the loop to ensure this scales.
     list($sqlassignmentids, $assignmentidparams) = $DB->get_in_or_equal($assignmentids);
@@ -354,16 +350,42 @@ function assign_print_overview($courses, &$htmlarray) {
     $unmarkedsubmissions = null;
 
     foreach ($assignments as $assignment) {
+
         // Do not show assignments that are not open.
         if (!in_array($assignment->id, $assignmentids)) {
             continue;
         }
+
+        $context = context_module::instance($assignment->coursemodule);
+
+        // Does the submission status of the assignment require notification?
+        if (has_capability('mod/assign:submit', $context)) {
+            // Does the submission status of the assignment require notification?
+            $submitdetails = assign_get_mysubmission_details_for_print_overview($mysubmissions, $sqlassignmentids,
+                    $assignmentidparams, $assignment);
+        } else {
+            $submitdetails = false;
+        }
+
+        if (has_capability('mod/assign:grade', $context)) {
+            // Does the grading status of the assignment require notification ?
+            $gradedetails = assign_get_grade_details_for_print_overview($unmarkedsubmissions, $sqlassignmentids,
+                    $assignmentidparams, $assignment, $context);
+        } else {
+            $gradedetails = false;
+        }
+
+        if (empty($submitdetails) && empty($gradedetails)) {
+            // There is no need to display this assignment as there is nothing to notify.
+            continue;
+        }
+
         $dimmedclass = '';
         if (!$assignment->visible) {
             $dimmedclass = ' class="dimmed"';
         }
         $href = $CFG->wwwroot . '/mod/assign/view.php?id=' . $assignment->coursemodule;
-        $str = '<div class="assign overview">' .
+        $basestr = '<div class="assign overview">' .
                '<div class="name">' .
                $strassignment . ': '.
                '<a ' . $dimmedclass .
@@ -373,133 +395,192 @@ function assign_print_overview($courses, &$htmlarray) {
                '</a></div>';
         if ($assignment->duedate) {
             $userdate = userdate($assignment->duedate);
-            $str .= '<div class="info">' . $strduedate . ': ' . $userdate . '</div>';
+            $basestr .= '<div class="info">' . $strduedate . ': ' . $userdate . '</div>';
         } else {
-            $str .= '<div class="info">' . $strduedateno . '</div>';
+            $basestr .= '<div class="info">' . $strduedateno . '</div>';
         }
         if ($assignment->cutoffdate) {
             if ($assignment->cutoffdate == $assignment->duedate) {
-                $str .= '<div class="info">' . $strnolatesubmissions . '</div>';
+                $basestr .= '<div class="info">' . $strnolatesubmissions . '</div>';
             } else {
                 $userdate = userdate($assignment->cutoffdate);
-                $str .= '<div class="info">' . $strcutoffdate . ': ' . $userdate . '</div>';
+                $basestr .= '<div class="info">' . $strcutoffdate . ': ' . $userdate . '</div>';
             }
         }
-        $context = context_module::instance($assignment->coursemodule);
-        if (has_capability('mod/assign:grade', $context)) {
-            if (!isset($unmarkedsubmissions)) {
-                // Build up and array of unmarked submissions indexed by assignment id/ userid
-                // for use where the user has grading rights on assignment.
-                $dbparams = array_merge(array(ASSIGN_SUBMISSION_STATUS_SUBMITTED), $assignmentidparams);
-                $rs = $DB->get_recordset_sql('SELECT
-                                                  s.assignment as assignment,
-                                                  s.userid as userid,
-                                                  s.id as id,
-                                                  s.status as status,
-                                                  g.timemodified as timegraded
-                                              FROM {assign_submission} s
-                                              LEFT JOIN {assign_grades} g ON
-                                                  s.userid = g.userid AND
-                                                  s.assignment = g.assignment AND
-                                                  g.attemptnumber = s.attemptnumber
-                                              WHERE
-                                                  ( g.timemodified is NULL OR
-                                                  s.timemodified > g.timemodified OR
-                                                  g.grade IS NULL ) AND
-                                                  s.timemodified IS NOT NULL AND
-                                                  s.status = ? AND
-                                                  s.latest = 1 AND
-                                                  s.assignment ' . $sqlassignmentids, $dbparams);
-
-                $unmarkedsubmissions = array();
-                foreach ($rs as $rd) {
-                    $unmarkedsubmissions[$rd->assignment][$rd->userid] = $rd->id;
-                }
-                $rs->close();
-            }
 
-            // Count how many people can submit.
-            $submissions = 0;
-            if ($students = get_enrolled_users($context, 'mod/assign:view', 0, 'u.id')) {
-                foreach ($students as $student) {
-                    if (isset($unmarkedsubmissions[$assignment->id][$student->id])) {
-                        $submissions++;
-                    }
-                }
-            }
-
-            if ($submissions) {
-                $urlparams = array('id'=>$assignment->coursemodule, 'action'=>'grading');
-                $url = new moodle_url('/mod/assign/view.php', $urlparams);
-                $str .= '<div class="details">' .
-                        '<a href="' . $url . '">' .
-                        get_string('submissionsnotgraded', 'assign', $submissions) .
-                        '</a></div>';
-            }
+        // Show only relevant information.
+        if (!empty($submitdetails)) {
+            $basestr .= $submitdetails;
         }
-        if (has_capability('mod/assign:submit', $context)) {
-            if (!isset($mysubmissions)) {
-
-                // Get all user submissions, indexed by assignment id.
-                $dbparams = array_merge(array($USER->id), $assignmentidparams, array($USER->id));
-                $mysubmissions = $DB->get_records_sql('SELECT
-                                                           a.id AS assignment,
-                                                           a.nosubmissions AS nosubmissions,
-                                                           g.timemodified AS timemarked,
-                                                           g.grader AS grader,
-                                                           g.grade AS grade,
-                                                           s.status AS status
-                                                       FROM {assign} a, {assign_submission} s
-                                                       LEFT JOIN {assign_grades} g ON
-                                                           g.assignment = s.assignment AND
-                                                           g.userid = ? AND
-                                                           g.attemptnumber = s.attemptnumber
-                                                       WHERE a.id ' . $sqlassignmentids . ' AND
-                                                           s.latest = 1 AND
-                                                           s.assignment = a.id AND
-                                                           s.userid = ?', $dbparams);
-            }
 
-            $str .= '<div class="details">';
-            $str .= get_string('mysubmission', 'assign');
-            $submission = false;
-            if (isset($mysubmissions[$assignment->id])) {
-                $submission = $mysubmissions[$assignment->id];
-            }
-            if ($submission && $submission->nosubmissions) {
-                $str .= get_string('offline', 'assign');
-            } else if (!$submission ||
-                    !$submission->status ||
-                    $submission->status == 'draft' ||
-                    $submission->status == 'new') {
-                $str .= $strnotsubmittedyet;
-            } else {
-                $str .= get_string('submissionstatus_' . $submission->status, 'assign');
-            }
-
-            if ($assignment->markingworkflow) {
-                $workflowstate = $DB->get_field('assign_user_flags', 'workflowstate', array('assignment' =>
-                    $assignment->id, 'userid' => $USER->id));
-                if ($workflowstate) {
-                    $gradingstatus = 'markingworkflowstate' . $workflowstate;
-                } else {
-                    $gradingstatus = 'markingworkflowstate' . ASSIGN_MARKING_WORKFLOW_STATE_NOTMARKED;
-                }
-            } else if (!empty($submission->grade) && $submission->grade !== null && $submission->grade >= 0) {
-                $gradingstatus = ASSIGN_GRADING_STATUS_GRADED;
-            } else {
-                $gradingstatus = ASSIGN_GRADING_STATUS_NOT_GRADED;
-            }
-            $str .= ', ' . get_string($gradingstatus, 'assign');
-            $str .= '</div>';
+        if (!empty($gradedetails)) {
+            $basestr .= $gradedetails;
         }
-        $str .= '</div>';
+        $basestr .= '</div>';
+
         if (empty($htmlarray[$assignment->course]['assign'])) {
-            $htmlarray[$assignment->course]['assign'] = $str;
+            $htmlarray[$assignment->course]['assign'] = $basestr;
         } else {
-            $htmlarray[$assignment->course]['assign'] .= $str;
+            $htmlarray[$assignment->course]['assign'] .= $basestr;
         }
     }
+    return true;
+}
+
+/**
+ * This api generates html to be displayed to students in print overview section, related to their submission status of the given
+ * assignment.
+ *
+ * @param array $mysubmissions list of submissions of current user indexed by assignment id.
+ * @param string $sqlassignmentids sql clause used to filter open assignments.
+ * @param array $assignmentidparams sql params used to filter open assignments.
+ * @param stdClass $assignment current assignment
+ *
+ * @return bool|string html to display , false if nothing needs to be displayed.
+ * @throws coding_exception
+ */
+function assign_get_mysubmission_details_for_print_overview(&$mysubmissions, $sqlassignmentids, $assignmentidparams,
+                                                            $assignment) {
+    global $USER, $DB;
+
+    if ($assignment->nosubmissions) {
+        // Offline assignment. No need to display alerts for offline assignments.
+        return false;
+    }
+
+    $strnotsubmittedyet = get_string('notsubmittedyet', 'assign');
+
+    if (!isset($mysubmissions)) {
+
+        // Get all user submissions, indexed by assignment id.
+        $dbparams = array_merge(array($USER->id), $assignmentidparams, array($USER->id));
+        $mysubmissions = $DB->get_records_sql('SELECT a.id AS assignment,
+                                                      a.nosubmissions AS nosubmissions,
+                                                      g.timemodified AS timemarked,
+                                                      g.grader AS grader,
+                                                      g.grade AS grade,
+                                                      s.status AS status
+                                                 FROM {assign} a, {assign_submission} s
+                                            LEFT JOIN {assign_grades} g ON
+                                                      g.assignment = s.assignment AND
+                                                      g.userid = ? AND
+                                                      g.attemptnumber = s.attemptnumber
+                                                WHERE a.id ' . $sqlassignmentids . ' AND
+                                                      s.latest = 1 AND
+                                                      s.assignment = a.id AND
+                                                      s.userid = ?', $dbparams);
+    }
+
+    $submitdetails = '';
+    $submitdetails .= '<div class="details">';
+    $submitdetails .= get_string('mysubmission', 'assign');
+    $submission = false;
+
+    if (isset($mysubmissions[$assignment->id])) {
+        $submission = $mysubmissions[$assignment->id];
+    }
+
+    if ($submission && $submission->status == ASSIGN_SUBMISSION_STATUS_SUBMITTED) {
+        // A valid submission already exists, no need to notify students about this.
+        return false;
+    }
+
+    // We need to show details only if a valid submission doesn't exist.
+    if (!$submission ||
+        !$submission->status ||
+        $submission->status == ASSIGN_SUBMISSION_STATUS_DRAFT ||
+        $submission->status == ASSIGN_SUBMISSION_STATUS_NEW
+    ) {
+        $submitdetails .= $strnotsubmittedyet;
+    } else {
+        $submitdetails .= get_string('submissionstatus_' . $submission->status, 'assign');
+    }
+    if ($assignment->markingworkflow) {
+        $workflowstate = $DB->get_field('assign_user_flags', 'workflowstate', array('assignment' =>
+                $assignment->id, 'userid' => $USER->id));
+        if ($workflowstate) {
+            $gradingstatus = 'markingworkflowstate' . $workflowstate;
+        } else {
+            $gradingstatus = 'markingworkflowstate' . ASSIGN_MARKING_WORKFLOW_STATE_NOTMARKED;
+        }
+    } else if (!empty($submission->grade) && $submission->grade !== null && $submission->grade >= 0) {
+        $gradingstatus = ASSIGN_GRADING_STATUS_GRADED;
+    } else {
+        $gradingstatus = ASSIGN_GRADING_STATUS_NOT_GRADED;
+    }
+    $submitdetails .= ', ' . get_string($gradingstatus, 'assign');
+    $submitdetails .= '</div>';
+    return $submitdetails;
+}
+
+/**
+ * This api generates html to be displayed to teachers in print overview section, related to the grading status of the given
+ * assignment's submissions.
+ *
+ * @param array $unmarkedsubmissions list of submissions of that are currently unmarked indexed by assignment id.
+ * @param string $sqlassignmentids sql clause used to filter open assignments.
+ * @param array $assignmentidparams sql params used to filter open assignments.
+ * @param stdClass $assignment current assignment
+ * @param context $context context of the assignment.
+ *
+ * @return bool|string html to display , false if nothing needs to be displayed.
+ * @throws coding_exception
+ */
+function assign_get_grade_details_for_print_overview(&$unmarkedsubmissions, $sqlassignmentids, $assignmentidparams,
+                                                     $assignment, $context) {
+    global $DB;
+    if (!isset($unmarkedsubmissions)) {
+        // Build up and array of unmarked submissions indexed by assignment id/ userid
+        // for use where the user has grading rights on assignment.
+        $dbparams = array_merge(array(ASSIGN_SUBMISSION_STATUS_SUBMITTED), $assignmentidparams);
+        $rs = $DB->get_recordset_sql('SELECT s.assignment as assignment,
+                                             s.userid as userid,
+                                             s.id as id,
+                                             s.status as status,
+                                             g.timemodified as timegraded
+                                        FROM {assign_submission} s
+                                   LEFT JOIN {assign_grades} g ON
+                                             s.userid = g.userid AND
+                                             s.assignment = g.assignment AND
+                                             g.attemptnumber = s.attemptnumber
+                                       WHERE
+                                             ( g.timemodified is NULL OR
+                                             s.timemodified > g.timemodified OR
+                                             g.grade IS NULL ) AND
+                                             s.timemodified IS NOT NULL AND
+                                             s.status = ? AND
+                                             s.latest = 1 AND
+                                             s.assignment ' . $sqlassignmentids, $dbparams);
+
+        $unmarkedsubmissions = array();
+        foreach ($rs as $rd) {
+            $unmarkedsubmissions[$rd->assignment][$rd->userid] = $rd->id;
+        }
+        $rs->close();
+    }
+
+    // Count how many people can submit.
+    $submissions = 0;
+    if ($students = get_enrolled_users($context, 'mod/assign:view', 0, 'u.id')) {
+        foreach ($students as $student) {
+            if (isset($unmarkedsubmissions[$assignment->id][$student->id])) {
+                $submissions++;
+            }
+        }
+    }
+
+    if ($submissions) {
+        $urlparams = array('id' => $assignment->coursemodule, 'action' => 'grading');
+        $url = new moodle_url('/mod/assign/view.php', $urlparams);
+        $gradedetails = '<div class="details">' .
+                '<a href="' . $url . '">' .
+                get_string('submissionsnotgraded', 'assign', $submissions) .
+                '</a></div>';
+        return $gradedetails;
+    } else {
+        return false;
+    }
+
 }
 
 /**
index 367a2b7..da657d3 100644 (file)
@@ -103,23 +103,83 @@ class mod_assign_lib_testcase extends mod_assign_base_testcase {
 
     public function test_assign_print_overview() {
         global $DB;
+
+        // Create one more assignment instance.
+        $this->setAdminUser();
         $courses = $DB->get_records('course', array('id' => $this->course->id));
+        // Past assignments should not show up.
+        $pastassign = $this->create_instance(array('duedate' => time(),
+                                                   'cutoffdate' => time() - 370000,
+                                                   'nosubmissions' => 0,
+                                                   'assignsubmission_onlinetext_enabled' => 1));
+        // Open assignments should show up only if relevant.
+        $openassign = $this->create_instance(array('duedate' => time(),
+                                                   'cutoffdate' => time() + 370000,
+                                                   'nosubmissions' => 0,
+                                                   'assignsubmission_onlinetext_enabled' => 1));
+        $pastsubmission = $pastassign->get_user_submission($this->students[0]->id, true);
+        $opensubmission = $openassign->get_user_submission($this->students[0]->id, true);
 
         // Check the overview as the different users.
+        // For students , open assignments should show only when there are no valid submissions.
         $this->setUser($this->students[0]);
         $overview = array();
         assign_print_overview($courses, $overview);
-        $this->assertEquals(count($overview), 1);
+        $this->assertEquals(1, count($overview));
+        $this->assertRegExp('/.*Assignment 4.*/', $overview[$this->course->id]['assign']); // No valid submission.
+        $this->assertNotRegExp('/.*Assignment 1.*/', $overview[$this->course->id]['assign']); // Has valid submission.
+
+        // And now submit the submission.
+        $opensubmission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
+        $openassign->testable_update_submission($opensubmission, $this->students[0]->id, true, false);
+
+        $overview = array();
+        assign_print_overview($courses, $overview);
+        $this->assertEquals(0, count($overview));
 
         $this->setUser($this->teachers[0]);
         $overview = array();
         assign_print_overview($courses, $overview);
-        $this->assertEquals(count($overview), 1);
+        $this->assertEquals(1, count($overview));
+        // Submissions without a grade.
+        $this->assertRegExp('/.*Assignment 4.*/', $overview[$this->course->id]['assign']);
+        $this->assertRegExp('/.*Assignment 2.*/', $overview[$this->course->id]['assign']);
 
         $this->setUser($this->editingteachers[0]);
         $overview = array();
         assign_print_overview($courses, $overview);
         $this->assertEquals(1, count($overview));
+        // Submissions without a grade.
+        $this->assertRegExp('/.*Assignment 4.*/', $overview[$this->course->id]['assign']);
+        $this->assertRegExp('/.*Assignment 2.*/', $overview[$this->course->id]['assign']);
+
+        // Let us grade a submission.
+        $this->setUser($this->teachers[0]);
+        $data = new stdClass();
+        $data->grade = '50.0';
+        $openassign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
+        $overview = array();
+        assign_print_overview($courses, $overview);
+        $this->assertEquals(1, count($overview));
+        // Now assignment 4 should not show up.
+        $this->assertNotRegExp('/.*Assignment 4.*/', $overview[$this->course->id]['assign']);
+        $this->assertRegExp('/.*Assignment 2.*/', $overview[$this->course->id]['assign']);
+
+        $this->setUser($this->editingteachers[0]);
+        $overview = array();
+        assign_print_overview($courses, $overview);
+        $this->assertEquals(1, count($overview));
+        // Now assignment 4 should not show up.
+        $this->assertNotRegExp('/.*Assignment 4.*/', $overview[$this->course->id]['assign']);
+        $this->assertRegExp('/.*Assignment 2.*/', $overview[$this->course->id]['assign']);
+
+        // Open offline assignments should not show any notification to students.
+        $openassign = $this->create_instance(array('duedate' => time(),
+                                                   'cutoffdate' => time() + 370000));
+        $this->setUser($this->students[0]);
+        $overview = array();
+        assign_print_overview($courses, $overview);
+        $this->assertEquals(0, count($overview));
     }
 
     public function test_print_recent_activity() {
index f3eb608..d8d8c0c 100644 (file)
@@ -116,6 +116,10 @@ $string['check_unsecuredataroot_error'] = 'Your dataroot directory <code>{$a}</c
 $string['check_unsecuredataroot_name'] = 'Insecure dataroot';
 $string['check_unsecuredataroot_ok'] = 'Dataroot directory must not be accessible via the web.';
 $string['check_unsecuredataroot_warning'] = 'Your dataroot directory <code>{$a}</code> is in the wrong location and might be exposed to the web.';
+$string['check_webcron_details'] = '<p>Web cron can expose priviedged information to anonymous users. It is recommended to use CLI cron or protect the cron page with a passphrase.</p>';
+$string['check_webcron_warning'] = 'Anonymous users can access cron.';
+$string['check_webcron_name'] = 'Web cron';
+$string['check_webcron_ok'] = 'Anonymous users can not access cron.';
 $string['issue'] = 'Issue';
 $string['pluginname'] = 'Security overview';
 $string['security:view'] = 'View security report';
index 41507c0..0add8e7 100644 (file)
@@ -56,6 +56,7 @@ function report_security_get_issue_list() {
         'report_security_check_defaultuserrole',
         'report_security_check_guestrole',
         'report_security_check_frontpagerole',
+        'report_security_check_webcron',
 
     );
 }
@@ -830,3 +831,37 @@ function report_security_check_riskbackup($detailed=false) {
 
     return $result;
 }
+
+/**
+ * Verifies the status of web cron
+ *
+ * @param bool $detailed
+ * @return object result
+ */
+function report_security_check_webcron($detailed = false) {
+    global $CFG;
+
+    $croncli = $CFG->cronclionly;
+    $cronremotepassword = $CFG->cronremotepassword;
+
+    $result = new stdClass();
+    $result->issue   = 'report_security_check_webcron';
+    $result->name    = get_string('check_webcron_name', 'report_security');
+    $result->details = null;
+    $result->link    = "<a href=\"$CFG->wwwroot/$CFG->admin/settings.php?section=sitepolicies\">"
+            .get_string('sitepolicies', 'admin').'</a>';
+
+    if (empty($croncli) && empty($cronremotepassword)) {
+        $result->status = REPORT_SECURITY_WARNING;
+        $result->info   = get_string('check_webcron_warning', 'report_security');
+    } else {
+        $result->status = REPORT_SECURITY_OK;
+        $result->info   = get_string('check_webcron_ok', 'report_security');
+    }
+
+    if ($detailed) {
+        $result->details = get_string('check_webcron_details', 'report_security');
+    }
+
+    return $result;
+}
\ No newline at end of file