Merge branch 'MDL-65573-master-2' of git://github.com/peterRd/moodle
authorSara Arjona <sara@moodle.com>
Tue, 14 Jan 2020 11:20:00 +0000 (12:20 +0100)
committerSara Arjona <sara@moodle.com>
Tue, 14 Jan 2020 11:20:00 +0000 (12:20 +0100)
36 files changed:
admin/settings/server.php
auth/cas/CAS/CAS.php
auth/cas/CAS/CAS/Client.php
auth/cas/CAS/README.md
auth/cas/CAS/moodle_readme.txt
backup/externallib.php
backup/restore.php
lang/en/moodle.php
lang/en/role.php
lib/antivirus/clamav/adminlib.php
lib/antivirus/clamav/classes/scanner.php
lib/antivirus/clamav/lang/en/antivirus_clamav.php
lib/antivirus/clamav/settings.php
lib/antivirus/clamav/tests/scanner_test.php
lib/antivirus/clamav/version.php
lib/datalib.php
lib/db/access.php
lib/db/install.php
lib/editor/atto/plugins/accessibilitychecker/yui/build/moodle-atto_accessibilitychecker-button/moodle-atto_accessibilitychecker-button-debug.js
lib/editor/atto/plugins/accessibilitychecker/yui/build/moodle-atto_accessibilitychecker-button/moodle-atto_accessibilitychecker-button-min.js
lib/editor/atto/plugins/accessibilitychecker/yui/build/moodle-atto_accessibilitychecker-button/moodle-atto_accessibilitychecker-button.js
lib/editor/atto/plugins/accessibilitychecker/yui/src/button/js/button.js
lib/setup.php
lib/upgrade.txt
lib/yui/build/moodle-core-chooserdialogue/moodle-core-chooserdialogue-debug.js
lib/yui/build/moodle-core-chooserdialogue/moodle-core-chooserdialogue-min.js
lib/yui/build/moodle-core-chooserdialogue/moodle-core-chooserdialogue.js
lib/yui/src/chooserdialogue/js/chooserdialogue.js
mod/assign/locallib.php
mod/forum/classes/post_form.php
mod/forum/lang/en/forum.php
mod/forum/templates/discussion_list.mustache
mod/forum/tests/behat/behat_mod_forum.php
report/log/classes/table_log.php
report/loglive/classes/renderable.php
version.php

index 4b0f427..0d55217 100644 (file)
@@ -44,15 +44,10 @@ $temp = new admin_settingpage('sessionhandling', new lang_string('sessionhandlin
 if (empty($CFG->session_handler_class) and $DB->session_lock_supported()) {
     $temp->add(new admin_setting_configcheckbox('dbsessions', new lang_string('dbsessions', 'admin'), new lang_string('configdbsessions', 'admin'), 0));
 }
-$temp->add(new admin_setting_configselect('sessiontimeout', new lang_string('sessiontimeout', 'admin'), new lang_string('configsessiontimeout', 'admin'), 7200, array(14400 => new lang_string('numhours', '', 4),
-                                                                                                                                                      10800 => new lang_string('numhours', '', 3),
-                                                                                                                                                      7200 => new lang_string('numhours', '', 2),
-                                                                                                                                                      5400 => new lang_string('numhours', '', '1.5'),
-                                                                                                                                                      3600 => new lang_string('numminutes', '', 60),
-                                                                                                                                                      2700 => new lang_string('numminutes', '', 45),
-                                                                                                                                                      1800 => new lang_string('numminutes', '', 30),
-                                                                                                                                                      900 => new lang_string('numminutes', '', 15),
-                                                                                                                                                      300 => new lang_string('numminutes', '', 5))));
+
+$temp->add(new admin_setting_configduration('sessiontimeout', new lang_string('sessiontimeout', 'admin'),
+    new lang_string('configsessiontimeout', 'admin'), 8 * 60 * 60));
+
 $temp->add(new admin_setting_configtext('sessioncookie', new lang_string('sessioncookie', 'admin'), new lang_string('configsessioncookie', 'admin'), '', PARAM_ALPHANUM));
 $temp->add(new admin_setting_configtext('sessioncookiepath', new lang_string('sessioncookiepath', 'admin'), new lang_string('configsessioncookiepath', 'admin'), '', PARAM_RAW));
 $temp->add(new admin_setting_configtext('sessioncookiedomain', new lang_string('sessioncookiedomain', 'admin'), new lang_string('configsessioncookiedomain', 'admin'), '', PARAM_RAW, 50));
index 5d6f881..343a3eb 100644 (file)
@@ -61,7 +61,7 @@ if (!defined('E_USER_DEPRECATED')) {
 /**
  * phpCAS version. accessible for the user by phpCAS::getVersion().
  */
-define('PHPCAS_VERSION', '1.3.7+');
+define('PHPCAS_VERSION', '1.3.8');
 
 /**
  * @addtogroup public
index 338bd50..f06c154 100644 (file)
@@ -997,7 +997,18 @@ class CAS_Client
 
         // set to callback mode if PgtIou and PgtId CGI GET parameters are provided
         if ( $this->isProxy() ) {
-            $this->_setCallbackMode(!empty($_GET['pgtIou'])&&!empty($_GET['pgtId']));
+            if(!empty($_GET['pgtIou'])&&!empty($_GET['pgtId'])) {
+                $this->_setCallbackMode(true);
+                $this->_setCallbackModeUsingPost(false);
+            } elseif (!empty($_POST['pgtIou'])&&!empty($_POST['pgtId'])) {
+                $this->_setCallbackMode(true);
+                $this->_setCallbackModeUsingPost(true);
+            } else {
+                $this->_setCallbackMode(false);
+                $this->_setCallbackModeUsingPost(false);
+            }
+
+            
         }
 
         if ( $this->_isCallbackMode() ) {
@@ -2329,6 +2340,36 @@ class CAS_Client
         return $this->_callback_mode;
     }
 
+    /**
+     * @var bool a boolean to know if the CAS client is using POST parameters when in callback mode.
+     * Written by CAS_Client::_setCallbackModeUsingPost(), read by CAS_Client::_isCallbackModeUsingPost().
+     *
+     * @hideinitializer
+     */
+    private $_callback_mode_using_post = false;
+
+    /**
+     * This method sets/unsets usage of POST parameters in callback mode (default/false is GET parameters)
+     *
+     * @param bool $callback_mode_using_post true to use POST, false to use GET (default).
+     *
+     * @return void
+     */
+    private function _setCallbackModeUsingPost($callback_mode_using_post)
+    {
+        $this->_callback_mode_using_post = $callback_mode_using_post;
+    }
+
+    /**
+     * This method returns true when the callback mode is using POST, false otherwise.
+     *
+     * @return bool A boolean.
+     */
+    private function _isCallbackModeUsingPost()
+    {
+        return $this->_callback_mode_using_post;
+    }
+
     /**
      * the URL that should be used for the PGT callback (in fact the URL of the
      * current request without any CGI parameter). Written and read by
@@ -2387,23 +2428,39 @@ class CAS_Client
     private function _callback()
     {
         phpCAS::traceBegin();
-        if (preg_match('/^PGTIOU-[\.\-\w]+$/', $_GET['pgtIou'])) {
-            if (preg_match('/^[PT]GT-[\.\-\w]+$/', $_GET['pgtId'])) {
-                $this->printHTMLHeader('phpCAS callback');
-                $pgt_iou = $_GET['pgtIou'];
-                $pgt = $_GET['pgtId'];
-                phpCAS::trace('Storing PGT `'.$pgt.'\' (id=`'.$pgt_iou.'\')');
-                echo '<p>Storing PGT `'.$pgt.'\' (id=`'.$pgt_iou.'\').</p>';
-                $this->_storePGT($pgt, $pgt_iou);
-                $this->printHTMLFooter();
+        if ($this->_isCallbackModeUsingPost()) {
+            $pgtId = $_POST['pgtId'];
+            $pgtIou = $_POST['pgtIou'];
+        } else {
+            $pgtId = $_GET['pgtId'];
+            $pgtIou = $_GET['pgtIou'];
+        }
+        if (preg_match('/^PGTIOU-[\.\-\w]+$/', $pgtIou)) {
+            if (preg_match('/^[PT]GT-[\.\-\w]+$/', $pgtId)) {
+                phpCAS::trace('Storing PGT `'.$pgtId.'\' (id=`'.$pgtIou.'\')');
+                $this->_storePGT($pgtId, $pgtIou);
+                if (array_key_exists('HTTP_ACCEPT', $_SERVER) &&
+                    (   $_SERVER['HTTP_ACCEPT'] == 'application/xml' ||
+                        $_SERVER['HTTP_ACCEPT'] == 'text/xml'
+                    )
+                ) {
+                    echo '<?xml version="1.0" encoding="UTF-8"?>' . "\r\n";
+                    echo '<proxySuccess xmlns="http://www.yale.edu/tp/cas" />';
+                    phpCAS::traceExit("XML response sent");
+                } else {
+                    $this->printHTMLHeader('phpCAS callback');
+                    echo '<p>Storing PGT `'.$pgtId.'\' (id=`'.$pgtIou.'\').</p>';
+                    $this->printHTMLFooter();
+                    phpCAS::traceExit("HTML response sent");
+                }
                 phpCAS::traceExit("Successfull Callback");
             } else {
-                phpCAS::error('PGT format invalid' . $_GET['pgtId']);
-                phpCAS::traceExit('PGT format invalid' . $_GET['pgtId']);
+                phpCAS::error('PGT format invalid' . $pgtId);
+                phpCAS::traceExit('PGT format invalid' . $pgtId);
             }
         } else {
-            phpCAS::error('PGTiou format invalid' . $_GET['pgtIou']);
-            phpCAS::traceExit('PGTiou format invalid' . $_GET['pgtIou']);
+            phpCAS::error('PGTiou format invalid' . $pgtIou);
+            phpCAS::traceExit('PGTiou format invalid' . $pgtIou);
         }
 
         // Flush the buffer to prevent from sending anything other then a 200
index 583c1dc..f425edc 100644 (file)
@@ -4,11 +4,16 @@ phpCAS
 phpCAS is an authentication library that allows PHP applications to easily authenticate
 users via a Central Authentication Service (CAS) server.
 
-Please see the phpCAS website for more information:
+Please see the wiki website for more information:
 
 https://wiki.jasig.org/display/CASC/phpCAS
 
-[![Build Status](https://travis-ci.org/Jasig/phpCAS.png)](https://travis-ci.org/Jasig/phpCAS)
+Api documentation can be found here:
+
+https://apereo.github.io/phpCAS/
+
+
+[![Build Status](https://travis-ci.org/apereo/phpCAS.png)](https://travis-ci.org/apereo/phpCAS)
 
 
 LICENSE
index 7894d1c..11cf506 100644 (file)
@@ -1,5 +1,3 @@
-Description of phpCAS 1.3.7 library import
+Description of phpCAS 1.3.8 library import
 
-* downloaded from http://downloads.jasig.org/cas-clients/php/current/
-* applied patch https://github.com/apereo/phpCAS/pull/247 for PHP 7.2 compatibility (MDL-60280)
-* applied patch https://github.com/apereo/phpCAS/pull/278 for PHP 7.3 compatibility (MDL-63422)
+* downloaded from http://downloads.jasig.org/cas-clients/php/current/
\ No newline at end of file
index cb40f59..dd70910 100644 (file)
@@ -91,7 +91,6 @@ class core_backup_external extends external_api {
             require_capability('moodle/backup:backupactivity', $context);
         } else {
             require_capability('moodle/backup:backupcourse', $context);
-            $instanceid = $course->id;
         }
 
         $results = array();
index 4ee134e..750a398 100644 (file)
@@ -55,9 +55,11 @@ require_capability('moodle/restore:restorecourse', $context);
 if (is_null($course)) {
     $coursefullname = $SITE->fullname;
     $courseshortname = $SITE->shortname;
+    $courseurl = new moodle_url('/');
 } else {
     $coursefullname = $course->fullname;
     $courseshortname = $course->shortname;
+    $courseurl = course_get_url($course->id);
 }
 
 // Show page header.
@@ -173,7 +175,6 @@ if ($restore->get_stage() != restore_ui::STAGE_PROCESS) {
     \core\task\manager::queue_adhoc_task($asynctask);
 
     // Add ajax progress bar and initiate ajax via a template.
-    $courseurl = new moodle_url('/course/view.php', array('id' => $course->id));
     $restoreurl = new moodle_url('/backup/restorefile.php', array('contextid' => $contextid));
     $progresssetup = array(
             'backupid' => $restoreid,
@@ -182,7 +183,6 @@ if ($restore->get_stage() != restore_ui::STAGE_PROCESS) {
             'restoreurl' => $restoreurl->out()
     );
     echo $renderer->render_from_template('core/async_backup_status', $progresssetup);
-
 }
 
 $restore->destroy();
index 74644c0..6c17f58 100644 (file)
@@ -1842,6 +1842,7 @@ $string['shortnameuser'] = 'User short name';
 $string['shortsitename'] = 'Short name for site (eg single word)';
 $string['show'] = 'Show';
 $string['showactions'] = 'Show actions';
+$string['showadvancededitor'] = 'Advanced';
 $string['showadvancedsettings'] = 'Show advanced settings';
 $string['showall'] = 'Show all {$a}';
 $string['showallcourses'] = 'Show all courses';
index 72edb50..96d071a 100644 (file)
@@ -423,6 +423,7 @@ $string['site:restore'] = 'Restore courses';
 $string['site:sendmessage'] = 'Send messages to any user';
 $string['site:trustcontent'] = 'Trust submitted content';
 $string['site:uploadusers'] = 'Upload new users from file';
+$string['site:viewanonymousevents'] = 'View anonymous events in reports';
 $string['site:viewfullnames'] = 'Always see full names of users';
 $string['site:viewparticipants'] = 'View participants';
 $string['site:viewreports'] = 'View reports';
index f473cea..488ce71 100644 (file)
@@ -49,17 +49,56 @@ class antivirus_clamav_runningmethod_setting extends admin_setting_configselect
     /**
      * Validate data.
      *
-     * This ensures that unix socket transport is supported by this system.
+     * This ensures that the selected socket transport is supported by this system.
      *
      * @param string $data
      * @return mixed True on success, else error message.
      */
     public function validate($data) {
+        $supportedtransports = stream_get_transports();
         if ($data === 'unixsocket') {
-            $supportedtransports = stream_get_transports();
-            if (!array_search('unix', $supportedtransports)) {
+            if (array_search('unix', $supportedtransports) === false) {
                 return get_string('errornounixsocketssupported', 'antivirus_clamav');
             }
+        } else if ($data === 'tcpsocket') {
+            if (array_search('tcp', $supportedtransports) === false) {
+                return get_string('errornotcpsocketssupported', 'antivirus_clamav');
+            }
+        }
+        return true;
+    }
+}
+
+
+/**
+ * Abstract socket checking class
+ *
+ * @package    antivirus_clamav
+ * @copyright  2015 Ruslan Kabalin, Lancaster University.
+ * @copyright  2019 Didier Raboud, Liip AG.
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class antivirus_clamav_socket_setting extends admin_setting_configtext {
+    /**
+     * Ping ClamAV socket.
+     *
+     * This ensures that a socket setting is correct and that ClamAV is running.
+     *
+     * @param string $socketaddress Address to the socket to connect to (for stream_socket_client)
+     * @return mixed True on success, else error message.
+     */
+    protected function validate_clamav_socket($socketaddress) {
+        $socket = stream_socket_client($socketaddress, $errno, $errstr, ANTIVIRUS_CLAMAV_SOCKET_TIMEOUT);
+        if (!$socket) {
+            return get_string('errorcantopensocket', 'antivirus_clamav', "$errstr ($errno)");
+        } else {
+            // Send PING query to ClamAV socket to check its running state.
+            fwrite($socket, "nPING\n");
+            $response = stream_get_line($socket, 4);
+            fclose($socket);
+            if ($response !== 'PONG') {
+                return get_string('errorclamavnoresponse', 'antivirus_clamav');
+            }
         }
         return true;
     }
@@ -71,7 +110,7 @@ class antivirus_clamav_runningmethod_setting extends admin_setting_configselect
  * @copyright  2015 Ruslan Kabalin, Lancaster University.
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
-class antivirus_clamav_pathtounixsocket_setting extends admin_setting_configtext {
+class antivirus_clamav_pathtounixsocket_setting extends antivirus_clamav_socket_setting {
     /**
      * Validate data.
      *
@@ -87,19 +126,38 @@ class antivirus_clamav_pathtounixsocket_setting extends admin_setting_configtext
         }
         $runningmethod = get_config('antivirus_clamav', 'runningmethod');
         if ($runningmethod === 'unixsocket') {
-            $socket = stream_socket_client('unix://' . $data, $errno, $errstr, ANTIVIRUS_CLAMAV_SOCKET_TIMEOUT);
-            if (!$socket) {
-                return get_string('errorcantopensocket', 'antivirus_clamav', "$errstr ($errno)");
-            } else {
-                // Send PING query to ClamAV socket to check its running state.
-                fwrite($socket, "nPING\n");
-                $response = stream_get_line($socket, 4);
-                fclose($socket);
-                if ($response !== 'PONG') {
-                    return get_string('errorclamavnoresponse', 'antivirus_clamav');
-                }
-            }
+            return $this->validate_clamav_socket('unix://' . $data);
         }
         return true;
     }
 }
+
+/**
+ * Admin setting for Internet domain socket host, adds verification.
+ *
+ * @package    antivirus_clamav
+ * @copyright  2019 Didier Raboud, Liip AG.
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class antivirus_clamav_tcpsockethost_setting extends antivirus_clamav_socket_setting {
+    /**
+     * Validate data.
+     *
+     * This ensures that Internet domain socket setting is correct and ClamAV is running.
+     *
+     * @param string $data
+     * @return mixed True on success, else error message.
+     */
+    public function validate($data) {
+        $result = parent::validate($data);
+        if ($result !== true) {
+            return $result;
+        }
+        $runningmethod = get_config('antivirus_clamav', 'runningmethod');
+        $tcpport = get_config('antivirus_clamav', 'tcpsocketport');
+        if ($runningmethod === 'tcpsocket') {
+            return $this->validate_clamav_socket('tcp://' . $data . ':' . $tcpport);
+        }
+        return true;
+    }
+}
\ No newline at end of file
index 3e55ce4..1bd1cdb 100644 (file)
@@ -34,6 +34,7 @@ define('ANTIVIRUS_CLAMAV_SOCKET_CHUNKSIZE', 1024);
 /**
  * Class implementing ClamAV antivirus.
  * @copyright  2015 Ruslan Kabalin, Lancaster University.
+ * @copyright  2019 Didier Raboud, Liip AG.
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 class scanner extends \core\antivirus\scanner {
@@ -47,6 +48,8 @@ class scanner extends \core\antivirus\scanner {
             return (bool)$this->get_config('pathtoclam');
         } else if ($this->get_config('runningmethod') === 'unixsocket') {
             return (bool)$this->get_config('pathtounixsocket');
+        } else if ($this->get_config('runningmethod') === 'tcpsocket') {
+            return (bool)$this->get_config('tcpsockethost') && (bool)$this->get_config('tcpsocketport');
         }
         return false;
     }
@@ -67,12 +70,22 @@ class scanner extends \core\antivirus\scanner {
             return self::SCAN_RESULT_ERROR;
         }
 
-        // Execute the scan using preferable method.
-        $method = 'scan_file_execute_' . $this->get_config('runningmethod');
-        if (!method_exists($this, $method)) {
-            throw new \coding_exception('Attempting to call non-existing method ' . $method);
+        // We can do direct stream scanning if unixsocket or tcpsocket running methods are in use,
+        // if not, use default process.
+        $runningmethod = $this->get_config('runningmethod');
+        switch ($runningmethod) {
+            case 'unixsocket':
+            case 'tcpsocket':
+                $return = $this->scan_file_execute_socket($file, $runningmethod);
+                break;
+            case 'commandline':
+                $return = $this->scan_file_execute_commandline($file);
+                break;
+            default:
+                // This should not happen.
+                debugging('Unknown running method.');
+                return self::SCAN_RESULT_ERROR;
         }
-        $return = $this->$method($file);
 
         if ($return === self::SCAN_RESULT_ERROR) {
             $this->message_admins($this->get_scanning_notice());
@@ -92,10 +105,11 @@ class scanner extends \core\antivirus\scanner {
      * @return int Scanning result constant.
      */
     public function scan_data($data) {
-        // We can do direct stream scanning if unixsocket running method is in use,
+        // We can do direct stream scanning if unixsocket or tcpsocket running methods are in use,
         // if not, use default process.
-        if ($this->get_config('runningmethod') === 'unixsocket') {
-            $return = $this->scan_data_execute_unixsocket($data);
+        $runningmethod = $this->get_config('runningmethod');
+        if (in_array($runningmethod, array('unixsocket', 'tcpsocket'))) {
+            $return = $this->scan_data_execute_socket($data, $runningmethod);
 
             if ($return === self::SCAN_RESULT_ERROR) {
                 $this->message_admins($this->get_scanning_notice());
@@ -111,6 +125,24 @@ class scanner extends \core\antivirus\scanner {
         }
     }
 
+    /**
+     * Returns a Unix domain socket destination url
+     *
+     * @return string The socket url, fit for stream_socket_client()
+     */
+    private function get_unixsocket_destination() {
+        return 'unix://' . $this->get_config('pathtounixsocket');
+    }
+
+    /**
+     * Returns a Internet domain socket destination url
+     *
+     * @return string The socket url, fit for stream_socket_client()
+     */
+    private function get_tcpsocket_destination() {
+        return 'tcp://' . $this->get_config('tcpsockethost') . ':' . $this->get_config('tcpsocketport');
+    }
+
     /**
      * Returns the string equivalent of a numeric clam error code
      *
@@ -189,13 +221,27 @@ class scanner extends \core\antivirus\scanner {
     }
 
     /**
-     * Scan file using Unix domain sockets.
+     * Scan file using sockets.
      *
      * @param string $file Full path to the file.
+     * @param string $type Either 'tcpsocket' or 'unixsocket'
      * @return int Scanning result constant.
      */
-    public function scan_file_execute_unixsocket($file) {
-        $socket = stream_socket_client('unix://' . $this->get_config('pathtounixsocket'),
+    public function scan_file_execute_socket($file, $type) {
+        switch ($type) {
+            case "tcpsocket":
+                $socketurl = $this->get_tcpsocket_destination();
+                break;
+            case "unixsocket":
+                $socketurl = $this->get_unixsocket_destination();
+                break;
+            default;
+                // This should not happen.
+                debugging('Unknown socket type.');
+                return self::SCAN_RESULT_ERROR;
+        }
+
+        $socket = stream_socket_client($socketurl,
                 $errno, $errstr, ANTIVIRUS_CLAMAV_SOCKET_TIMEOUT);
         if (!$socket) {
             // Can't open socket for some reason, notify admins.
@@ -203,26 +249,57 @@ class scanner extends \core\antivirus\scanner {
             $this->set_scanning_notice($notice);
             return self::SCAN_RESULT_ERROR;
         } else {
-            // Execute scanning. We are running SCAN command and passing file as an argument,
-            // it is the fastest option, but clamav user need to be able to access it, so
-            // we give group read permissions first and assume 'clamav' user is in web server
-            // group (in Debian the default webserver group is 'www-data').
-            // Using 'n' as command prefix is forcing clamav to only treat \n as newline delimeter,
-            // this is to avoid unexpected newline characters on different systems.
-            $perms = fileperms($file);
-            chmod($file, 0640);
-            fwrite($socket, "nSCAN ".$file."\n");
-            $output = stream_get_line($socket, 4096);
+            if ($type == "unixsocket") {
+                // Execute scanning. We are running SCAN command and passing file as an argument,
+                // it is the fastest option, but clamav user need to be able to access it, so
+                // we give group read permissions first and assume 'clamav' user is in web server
+                // group (in Debian the default webserver group is 'www-data').
+                // Using 'n' as command prefix is forcing clamav to only treat \n as newline delimeter,
+                // this is to avoid unexpected newline characters on different systems.
+                $perms = fileperms($file);
+                chmod($file, 0640);
+
+                // Actual scan.
+                fwrite($socket, "nSCAN ".$file."\n");
+                // Get ClamAV answer.
+                $output = stream_get_line($socket, 4096);
+
+                // After scanning we revert permissions to initial ones.
+                chmod($file, $perms);
+            } else if ($type == "tcpsocket") {
+                // Execute scanning by passing the entire file through the TCP socket.
+                // This is not fast, but is the only possibility over a network.
+                // Using 'n' as command prefix is forcing clamav to only treat \n as newline delimeter,
+                // this is to avoid unexpected newline characters on different systems.
+
+                // Actual scan.
+                fwrite($socket, "nINSTREAM\n");
+
+                // Open the file for reading.
+                $fhandle = fopen($file, 'rb');
+                while (!feof($fhandle)) {
+                    // Read it by chunks; write them to the TCP socket.
+                    $chunk = fread($fhandle, ANTIVIRUS_CLAMAV_SOCKET_CHUNKSIZE);
+                    $size = pack('N', strlen($chunk));
+                    fwrite($socket, $size);
+                    fwrite($socket, $chunk);
+                }
+                // Terminate streaming.
+                fwrite($socket, pack('N', 0));
+                // Get ClamAV answer.
+                $output = stream_get_line($socket, 4096);
+
+                fclose($fhandle);
+            }
+            // Free up the ClamAV socket.
             fclose($socket);
-            // After scanning we revert permissions to initial ones.
-            chmod($file, $perms);
             // Parse the output.
-            return $this->parse_unixsocket_response($output);
+            return $this->parse_socket_response($output);
         }
     }
 
     /**
-     * Scan data using unix socket.
+     * Scan data socket.
      *
      * We are running INSTREAM command and passing data stream in chunks.
      * The format of the chunk is: <length><data> where <length> is the size of the following
@@ -231,11 +308,25 @@ class scanner extends \core\antivirus\scanner {
      * Do not exceed StreamMaxLength as defined in clamd.conf, otherwise clamd will
      * reply with INSTREAM size limit exceeded and close the connection.
      *
-     * @param string $data The varaible containing the data to scan.
+     * @param string $data The variable containing the data to scan.
+     * @param string $type Either 'tcpsocket' or 'unixsocket'
      * @return int Scanning result constant.
      */
-    public function scan_data_execute_unixsocket($data) {
-        $socket = stream_socket_client('unix://' . $this->get_config('pathtounixsocket'), $errno, $errstr, ANTIVIRUS_CLAMAV_SOCKET_TIMEOUT);
+    public function scan_data_execute_socket($data, $type) {
+        switch ($type) {
+            case "tcpsocket":
+                $socketurl = $this->get_tcpsocket_destination();
+                break;
+            case "unixsocket":
+                $socketurl = $this->get_unixsocket_destination();
+                break;
+            default;
+                // This should not happen.
+                debugging('Unknown socket type!');
+                return self::SCAN_RESULT_ERROR;
+        }
+
+        $socket = stream_socket_client($socketurl, $errno, $errstr, ANTIVIRUS_CLAMAV_SOCKET_TIMEOUT);
         if (!$socket) {
             // Can't open socket for some reason, notify admins.
             $notice = get_string('errorcantopensocket', 'antivirus_clamav', "$errstr ($errno)");
@@ -261,17 +352,17 @@ class scanner extends \core\antivirus\scanner {
             fclose($socket);
 
             // Parse the output.
-            return $this->parse_unixsocket_response($output);
+            return $this->parse_socket_response($output);
         }
     }
 
     /**
-     * Parse unix socket command response.
+     * Parse socket command response.
      *
-     * @param string $output The unix socket command response.
+     * @param string $output The socket response.
      * @return int Scanning result constant.
      */
-    private function parse_unixsocket_response($output) {
+    private function parse_socket_response($output) {
         $splitoutput = explode(': ', $output);
         $message = trim($splitoutput[1]);
         if ($message === 'OK') {
@@ -289,4 +380,35 @@ class scanner extends \core\antivirus\scanner {
             }
         }
     }
+
+    /**
+     * Scan data using Unix domain socket.
+     *
+     * @deprecated since Moodle 3.9 MDL-64075 - please do not use this function any more.
+     * @see antivirus_clamav\scanner::scan_data_execute_socket()
+     *
+     * @param string $data The variable containing the data to scan.
+     * @return int Scanning result constant.
+     */
+    public function scan_data_execute_unixsocket($data) {
+        debugging('antivirus_clamav\scanner::scan_data_execute_unixsocket() is deprecated. ' .
+                  'Use antivirus_clamav\scanner::scan_data_execute_socket() instead.', DEBUG_DEVELOPER);
+        return $this->scan_data_execute_socket($data, "unixsocket");
+    }
+
+    /**
+     * Scan file using Unix domain socket.
+     *
+     * @deprecated since Moodle 3.9 MDL-64075 - please do not use this function any more.
+     * @see antivirus_clamav\scanner::scan_file_execute_socket()
+     *
+     * @param string $file Full path to the file.
+     * @return int Scanning result constant.
+     */
+    public function scan_file_execute_unixsocket($file) {
+        debugging('antivirus_clamav\scanner::scan_file_execute_unixsocket() is deprecated. ' .
+                  'Use antivirus_clamav\scanner::scan_file_execute_socket() instead.', DEBUG_DEVELOPER);
+        return $this->scan_file_execute_socket($file, "unixsocket");
+    }
+
 }
index 0e90141..a7a397f 100644 (file)
@@ -42,4 +42,9 @@ $string['runningmethod'] = 'Running method';
 $string['runningmethoddesc'] = 'Method of running ClamAV. Command line is used by default, however on Unix systems better performance can be obtained by using system sockets.';
 $string['runningmethodcommandline'] = 'Command line';
 $string['runningmethodunixsocket'] = 'Unix domain socket';
+$string['runningmethodtcpsocket'] = 'TCP socket';
+$string['tcpsockethost'] = 'TCP socket hostname';
+$string['tcpsockethostdesc'] = 'Domain name of the ClamAV server';
+$string['tcpsocketport'] = 'TCP socket port';
+$string['tcpsocketportdesc'] = 'The port to use when connecting to ClamAV';
 $string['unknownerror'] = 'There was an unknown error with ClamAV.';
index 7bf877a..2c895c9 100644 (file)
@@ -32,6 +32,7 @@ if ($ADMIN->fulltree) {
     $runningmethodchoice = array(
         'commandline' => get_string('runningmethodcommandline', 'antivirus_clamav'),
         'unixsocket' => get_string('runningmethodunixsocket', 'antivirus_clamav'),
+        'tcpsocket' => get_string('runningmethodtcpsocket', 'antivirus_clamav'),
     );
     $settings->add(new antivirus_clamav_runningmethod_setting('antivirus_clamav/runningmethod',
             get_string('runningmethod', 'antivirus_clamav'),
@@ -47,6 +48,16 @@ if ($ADMIN->fulltree) {
             new lang_string('pathtounixsocket', 'antivirus_clamav'),
             new lang_string('pathtounixsocketdesc', 'antivirus_clamav'), '', PARAM_PATH));
 
+    // Hostname to reach ClamAV tcp socket (used in tcp socket running method).
+    $settings->add(new antivirus_clamav_tcpsockethost_setting('antivirus_clamav/tcpsockethost',
+            new lang_string('tcpsockethost', 'antivirus_clamav'),
+            new lang_string('tcpsockethostdesc', 'antivirus_clamav'), '', PARAM_HOST));
+
+    // Port to reach ClamAV tcp socket (used in tcp socket running method).
+    $settings->add(new admin_setting_configtext('antivirus_clamav/tcpsocketport',
+            new lang_string('tcpsocketport', 'antivirus_clamav'),
+            new lang_string('tcpsocketportdesc', 'antivirus_clamav'), 3310, PARAM_INT));
+
     // How to act on ClamAV failure.
     $options = array(
         'donothing' => new lang_string('configclamdonothing', 'antivirus_clamav'),
index a29edb2..4a8b9c1 100644 (file)
@@ -44,8 +44,8 @@ class antivirus_clamav_scanner_testcase extends advanced_testcase {
 
     public function test_scan_file_not_exists() {
         $antivirus = $this->getMockBuilder('\antivirus_clamav\scanner')
-                ->setMethods(array('scan_file_execute_commandline', 'message_admins'))
-                ->getMock();
+            ->setMethods(array('scan_file_execute_commandline', 'message_admins'))
+            ->getMock();
 
         // Test specifying file that does not exist.
         $nonexistingfile = $this->tempfile . '_';
@@ -58,21 +58,21 @@ class antivirus_clamav_scanner_testcase extends advanced_testcase {
     public function test_scan_file_no_virus() {
         $methods = array(
             'scan_file_execute_commandline',
-            'scan_file_execute_unixsocket',
+            'scan_file_execute_socket',
             'message_admins',
             'get_config',
         );
         $antivirus = $this->getMockBuilder('\antivirus_clamav\scanner')
-                ->setMethods($methods)
-                ->getMock();
+            ->setMethods($methods)
+            ->getMock();
         // Initiate mock scanning with configuration setting to use commandline.
         $configmap = array(array('runningmethod', 'commandline'));
         $antivirus->method('get_config')->will($this->returnValueMap($configmap));
 
-        // Configure scan_file_execute_commandline and scan_file_execute_unixsocket
+        // Configure scan_file_execute_commandline and scan_file_execute_socket
         // method stubs to behave as if no virus has been found (SCAN_RESULT_OK).
         $antivirus->method('scan_file_execute_commandline')->willReturn(0);
-        $antivirus->method('scan_file_execute_unixsocket')->willReturn(0);
+        $antivirus->method('scan_file_execute_socket')->willReturn(0);
 
         // Set expectation that message_admins is NOT called.
         $antivirus->expects($this->never())->method('message_admins');
@@ -87,26 +87,33 @@ class antivirus_clamav_scanner_testcase extends advanced_testcase {
 
         // Run mock scanning.
         $this->assertEquals(0, $antivirus->scan_file($this->tempfile, ''));
+
+        // Initiate mock scanning with configuration setting to use tcpsocket.
+        $configmap = array(array('runningmethod', 'tcpsocket'));
+        $antivirus->method('get_config')->will($this->returnValueMap($configmap));
+
+        // Run mock scanning.
+        $this->assertEquals(0, $antivirus->scan_file($this->tempfile, ''));
     }
 
     public function test_scan_file_virus() {
         $methods = array(
             'scan_file_execute_commandline',
-            'scan_file_execute_unixsocket',
+            'scan_file_execute_socket',
             'message_admins',
             'get_config',
         );
         $antivirus = $this->getMockBuilder('\antivirus_clamav\scanner')
-                ->setMethods($methods)
-                ->getMock();
+            ->setMethods($methods)
+            ->getMock();
         // Initiate mock scanning with configuration setting to use commandline.
         $configmap = array(array('runningmethod', 'commandline'));
         $antivirus->method('get_config')->will($this->returnValueMap($configmap));
 
-        // Configure scan_file_execute_commandline and scan_file_execute_unixsocket
+        // Configure scan_file_execute_commandline and scan_file_execute_socket
         // method stubs to behave as if virus has been found (SCAN_RESULT_FOUND).
         $antivirus->method('scan_file_execute_commandline')->willReturn(1);
-        $antivirus->method('scan_file_execute_unixsocket')->willReturn(1);
+        $antivirus->method('scan_file_execute_socket')->willReturn(1);
 
         // Set expectation that message_admins is NOT called.
         $antivirus->expects($this->never())->method('message_admins');
@@ -121,24 +128,31 @@ class antivirus_clamav_scanner_testcase extends advanced_testcase {
 
         // Run mock scanning.
         $this->assertEquals(1, $antivirus->scan_file($this->tempfile, ''));
+
+        // Initiate mock scanning with configuration setting to use tcpsocket.
+        $configmap = array(array('runningmethod', 'tcpsocket'));
+        $antivirus->method('get_config')->will($this->returnValueMap($configmap));
+
+        // Run mock scanning.
+        $this->assertEquals(1, $antivirus->scan_file($this->tempfile, ''));
     }
 
     public function test_scan_file_error_donothing() {
         $methods = array(
             'scan_file_execute_commandline',
-            'scan_file_execute_unixsocket',
+            'scan_file_execute_socket',
             'message_admins',
             'get_config',
             'get_scanning_notice',
         );
         $antivirus = $this->getMockBuilder('\antivirus_clamav\scanner')
-                ->setMethods($methods)
-                ->getMock();
+            ->setMethods($methods)
+            ->getMock();
 
-        // Configure scan_file_execute_commandline and scan_file_execute_unixsocket
+        // Configure scan_file_execute_commandline and scan_file_execute_socket
         // method stubs to behave as if there is a scanning error (SCAN_RESULT_ERROR).
         $antivirus->method('scan_file_execute_commandline')->willReturn(2);
-        $antivirus->method('scan_file_execute_unixsocket')->willReturn(2);
+        $antivirus->method('scan_file_execute_socket')->willReturn(2);
         $antivirus->method('get_scanning_notice')->willReturn('someerror');
 
         // Set expectation that message_admins is called.
@@ -160,24 +174,32 @@ class antivirus_clamav_scanner_testcase extends advanced_testcase {
 
         // Run mock scanning.
         $this->assertEquals(2, $antivirus->scan_file($this->tempfile, ''));
+
+        // Initiate mock scanning with configuration setting to do nothing on
+        // scanning error and using tcpsocket.
+        $configmap = array(array('clamfailureonupload', 'donothing'), array('runningmethod', 'tcpsocket'));
+        $antivirus->method('get_config')->will($this->returnValueMap($configmap));
+
+        // Run mock scanning.
+        $this->assertEquals(2, $antivirus->scan_file($this->tempfile, ''));
     }
 
     public function test_scan_file_error_actlikevirus() {
         $methods = array(
             'scan_file_execute_commandline',
-            'scan_file_execute_unixsocket',
+            'scan_file_execute_socket',
             'message_admins',
             'get_config',
             'get_scanning_notice',
         );
         $antivirus = $this->getMockBuilder('\antivirus_clamav\scanner')
-                ->setMethods($methods)
-                ->getMock();
+            ->setMethods($methods)
+            ->getMock();
 
-        // Configure scan_file_execute_commandline and scan_file_execute_unixsocket
+        // Configure scan_file_execute_commandline and scan_file_execute_socket
         // method stubs to behave as if there is a scanning error (SCAN_RESULT_ERROR).
         $antivirus->method('scan_file_execute_commandline')->willReturn(2);
-        $antivirus->method('scan_file_execute_unixsocket')->willReturn(2);
+        $antivirus->method('scan_file_execute_socket')->willReturn(2);
         $antivirus->method('get_scanning_notice')->willReturn('someerror');
 
         // Set expectation that message_admins is called.
@@ -201,24 +223,43 @@ class antivirus_clamav_scanner_testcase extends advanced_testcase {
         // Run mock scanning, we expect SCAN_RESULT_FOUND since configuration
         // require us to act like virus.
         $this->assertEquals(1, $antivirus->scan_file($this->tempfile, ''));
+
+        // Initiate mock scanning with configuration setting to act like virus on
+        // scanning error and using tcpsocket.
+        $configmap = array(array('clamfailureonupload', 'actlikevirus'), array('runningmethod', 'tcpsocket'));
+        $antivirus->method('get_config')->will($this->returnValueMap($configmap));
+
+        // Run mock scanning, we expect SCAN_RESULT_FOUND since configuration
+        // require us to act like virus.
+        $this->assertEquals(1, $antivirus->scan_file($this->tempfile, ''));
     }
 
     public function test_scan_data_no_virus() {
         $methods = array(
-            'scan_data_execute_unixsocket',
+            'scan_data_execute_socket',
             'message_admins',
             'get_config',
         );
         $antivirus = $this->getMockBuilder('\antivirus_clamav\scanner')
-                ->setMethods($methods)
-                ->getMock();
+            ->setMethods($methods)
+            ->getMock();
         // Initiate mock scanning with configuration setting to use unixsocket.
         $configmap = array(array('runningmethod', 'unixsocket'));
         $antivirus->method('get_config')->will($this->returnValueMap($configmap));
 
-        // Configure scan_data_execute_unixsocket method stubs to behave as if
+        // Configure scan_data_execute_socket method stubs to behave as if
         // no virus has been found (SCAN_RESULT_OK).
-        $antivirus->method('scan_data_execute_unixsocket')->willReturn(0);
+        $antivirus->method('scan_data_execute_socket')->willReturn(0);
+
+        // Set expectation that message_admins is NOT called.
+        $antivirus->expects($this->never())->method('message_admins');
+
+        // Run mock scanning.
+        $this->assertEquals(0, $antivirus->scan_data(''));
+
+        // Re-initiate mock scanning with configuration setting to use tcpsocket.
+        $configmap = array(array('runningmethod', 'tcpsocket'));
+        $antivirus->method('get_config')->will($this->returnValueMap($configmap));
 
         // Set expectation that message_admins is NOT called.
         $antivirus->expects($this->never())->method('message_admins');
@@ -229,20 +270,30 @@ class antivirus_clamav_scanner_testcase extends advanced_testcase {
 
     public function test_scan_data_virus() {
         $methods = array(
-            'scan_data_execute_unixsocket',
+            'scan_data_execute_socket',
             'message_admins',
             'get_config',
         );
         $antivirus = $this->getMockBuilder('\antivirus_clamav\scanner')
-                ->setMethods($methods)
-                ->getMock();
+            ->setMethods($methods)
+            ->getMock();
         // Initiate mock scanning with configuration setting to use unixsocket.
         $configmap = array(array('runningmethod', 'unixsocket'));
         $antivirus->method('get_config')->will($this->returnValueMap($configmap));
 
-        // Configure scan_data_execute_unixsocket method stubs to behave as if
+        // Configure scan_data_execute_socket method stubs to behave as if
         // no virus has been found (SCAN_RESULT_FOUND).
-        $antivirus->method('scan_data_execute_unixsocket')->willReturn(1);
+        $antivirus->method('scan_data_execute_socket')->willReturn(1);
+
+        // Set expectation that message_admins is NOT called.
+        $antivirus->expects($this->never())->method('message_admins');
+
+        // Run mock scanning.
+        $this->assertEquals(1, $antivirus->scan_data(''));
+
+        // Re-initiate mock scanning with configuration setting to use tcpsocket.
+        $configmap = array(array('runningmethod', 'tcpsocket'));
+        $antivirus->method('get_config')->will($this->returnValueMap($configmap));
 
         // Set expectation that message_admins is NOT called.
         $antivirus->expects($this->never())->method('message_admins');
@@ -253,22 +304,22 @@ class antivirus_clamav_scanner_testcase extends advanced_testcase {
 
     public function test_scan_data_error_donothing() {
         $methods = array(
-            'scan_data_execute_unixsocket',
+            'scan_data_execute_socket',
             'message_admins',
             'get_config',
             'get_scanning_notice',
         );
         $antivirus = $this->getMockBuilder('\antivirus_clamav\scanner')
-                ->setMethods($methods)
-                ->getMock();
+            ->setMethods($methods)
+            ->getMock();
         // Initiate mock scanning with configuration setting to do nothing on
         // scanning error and using unixsocket.
         $configmap = array(array('clamfailureonupload', 'donothing'), array('runningmethod', 'unixsocket'));
         $antivirus->method('get_config')->will($this->returnValueMap($configmap));
 
-        // Configure scan_data_execute_unixsocket method stubs to behave as if
+        // Configure scan_data_execute_socket method stubs to behave as if
         // there is a scanning error (SCAN_RESULT_ERROR).
-        $antivirus->method('scan_data_execute_unixsocket')->willReturn(2);
+        $antivirus->method('scan_data_execute_socket')->willReturn(2);
         $antivirus->method('get_scanning_notice')->willReturn('someerror');
 
         // Set expectation that message_admins is called.
@@ -276,27 +327,38 @@ class antivirus_clamav_scanner_testcase extends advanced_testcase {
 
         // Run mock scanning.
         $this->assertEquals(2, $antivirus->scan_data(''));
+
+        // Re-initiate mock scanning with configuration setting to do nothing on
+        // scanning error and using tcsocket.
+        $configmap = array(array('clamfailureonupload', 'donothing'), array('runningmethod', 'tcpsocket'));
+        $antivirus->method('get_config')->will($this->returnValueMap($configmap));
+
+        // Set expectation that message_admins is called.
+        $antivirus->expects($this->atLeastOnce())->method('message_admins')->with($this->equalTo('someerror'));
+
+        // Run mock scanning.
+        $this->assertEquals(2, $antivirus->scan_data(''));
     }
 
     public function test_scan_data_error_actlikevirus() {
         $methods = array(
-            'scan_data_execute_unixsocket',
+            'scan_data_execute_socket',
             'message_admins',
             'get_config',
             'get_scanning_notice',
         );
         $antivirus = $this->getMockBuilder('\antivirus_clamav\scanner')
-                ->setMethods($methods)
-                ->getMock();
+            ->setMethods($methods)
+            ->getMock();
 
         // Initiate mock scanning with configuration setting to act like virus on
         // scanning error and using unixsocket.
         $configmap = array(array('clamfailureonupload', 'actlikevirus'), array('runningmethod', 'unixsocket'));
         $antivirus->method('get_config')->will($this->returnValueMap($configmap));
 
-        // Configure scan_data_execute_unixsocket method stubs to behave as if
+        // Configure scan_data_execute_socket method stubs to behave as if
         // there is a scanning error (SCAN_RESULT_ERROR).
-        $antivirus->method('scan_data_execute_unixsocket')->willReturn(2);
+        $antivirus->method('scan_data_execute_socket')->willReturn(2);
         $antivirus->method('get_scanning_notice')->willReturn('someerror');
 
         // Set expectation that message_admins is called.
@@ -305,5 +367,17 @@ class antivirus_clamav_scanner_testcase extends advanced_testcase {
         // Run mock scanning, we expect SCAN_RESULT_FOUND since configuration
         // require us to act like virus.
         $this->assertEquals(1, $antivirus->scan_data(''));
+
+        // Re-initiate mock scanning with configuration setting to act like virus on
+        // scanning error and using tcpsocket.
+        $configmap = array(array('clamfailureonupload', 'actlikevirus'), array('runningmethod', 'tcpsocket'));
+        $antivirus->method('get_config')->will($this->returnValueMap($configmap));
+
+        // Set expectation that message_admins is called.
+        $antivirus->expects($this->atLeastOnce())->method('message_admins')->with($this->equalTo('someerror'));
+
+        // Run mock scanning, we expect SCAN_RESULT_FOUND since configuration
+        // require us to act like virus.
+        $this->assertEquals(1, $antivirus->scan_data(''));
     }
 }
index d19e7a6..5c52c89 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2019111800;          // The current plugin version (Date: YYYYMMDDXX).
+$plugin->version   = 2019122900;          // The current plugin version (Date: YYYYMMDDXX).
 $plugin->requires  = 2019111200;          // Requires this Moodle version.
 $plugin->component = 'antivirus_clamav';  // Full name of the plugin (used for diagnostics).
index 52946fa..2ca8e54 100644 (file)
@@ -1639,6 +1639,10 @@ function print_object($object) {
     if (CLI_SCRIPT) {
         fwrite(STDERR, print_r($object, true));
         fwrite(STDERR, PHP_EOL);
+    } else if (AJAX_SCRIPT) {
+        foreach (explode("\n", print_r($object, true)) as $line) {
+            error_log($line);
+        }
     } else {
         echo html_writer::tag('pre', s(print_r($object, true)), array('class' => 'notifytiny'));
     }
index dacaf5b..a970632 100644 (file)
@@ -391,6 +391,17 @@ $capabilities = array(
         )
     ),
 
+    'moodle/site:viewanonymousevents' => array(
+
+        'captype' => 'read',
+        'contextlevel' => CONTEXT_MODULE,
+        'archetypes' => array(
+            'teacher' => CAP_PROHIBIT,
+            'editingteacher' => CAP_PROHIBIT,
+            'manager' => CAP_ALLOW
+        )
+    ),
+
     'moodle/site:viewfullnames' => array(
 
         'captype' => 'read',
index be9692d..0722a2a 100644 (file)
@@ -125,8 +125,8 @@ function xmldb_main_install() {
         'backup_version'        => 2008111700,
         'backup_release'        => '2.0 dev',
         'mnet_dispatcher_mode'  => 'off',
-        'sessiontimeout'        => 7200, // must be present during roles installation
-        'stringfilters'         => '', // These two are managed in a strange way by the filters
+        'sessiontimeout'        => 8 * 60 * 60, // Must be present during roles installation.
+        'stringfilters'         => '', // These two are managed in a strange way by the filters.
         'filterall'             => 0, // setting page, so have to be initialised here.
         'texteditors'           => 'atto,tinymce,textarea',
         'antiviruses'           => '',
index cdf67fa..c8d7bb6 100644 (file)
Binary files a/lib/editor/atto/plugins/accessibilitychecker/yui/build/moodle-atto_accessibilitychecker-button/moodle-atto_accessibilitychecker-button-debug.js and b/lib/editor/atto/plugins/accessibilitychecker/yui/build/moodle-atto_accessibilitychecker-button/moodle-atto_accessibilitychecker-button-debug.js differ
index 2940890..e4a9c3b 100644 (file)
Binary files a/lib/editor/atto/plugins/accessibilitychecker/yui/build/moodle-atto_accessibilitychecker-button/moodle-atto_accessibilitychecker-button-min.js and b/lib/editor/atto/plugins/accessibilitychecker/yui/build/moodle-atto_accessibilitychecker-button/moodle-atto_accessibilitychecker-button-min.js differ
index 7c14998..89d365c 100644 (file)
Binary files a/lib/editor/atto/plugins/accessibilitychecker/yui/build/moodle-atto_accessibilitychecker-button/moodle-atto_accessibilitychecker-button.js and b/lib/editor/atto/plugins/accessibilitychecker/yui/build/moodle-atto_accessibilitychecker-button/moodle-atto_accessibilitychecker-button.js differ
index 1634ac7..ce6a4e2 100644 (file)
@@ -127,8 +127,11 @@ Y.namespace('M.atto_accessibilitychecker').Button = Y.Base.create('button', Y.M.
 
             // Check for non-empty text.
             if (Y.Lang.trim(node.get('text')) !== '') {
-                foreground = node.getComputedStyle('color');
-                background = node.getComputedStyle('backgroundColor');
+                foreground = Y.Color.fromArray(
+                    this._getComputedBackgroundColor(node, node.getComputedStyle('color')),
+                    Y.Color.TYPES.RGBA
+                );
+                background = Y.Color.fromArray(this._getComputedBackgroundColor(node), Y.Color.TYPES.RGBA);
 
                 lum1 = this._getLuminanceFromCssColor(foreground);
                 lum2 = this._getLuminanceFromCssColor(background);
@@ -237,7 +240,7 @@ Y.namespace('M.atto_accessibilitychecker').Button = Y.Base.create('button', Y.M.
      * Generate the HTML that lists the found warnings.
      *
      * @method _addWarnings
-     * @param {Node} A Node to append the html to.
+     * @param {Node} list Node to append the html to.
      * @param {String} description Description of this failure.
      * @param {array} nodes An array of failing nodes.
      * @param {boolean} imagewarnings true if the warnings are related to images, false if text.
@@ -307,5 +310,43 @@ Y.namespace('M.atto_accessibilitychecker').Button = Y.Base.create('button', Y.M.
             b1 = part1(color[2]);
 
         return 0.2126 * r1 + 0.7152 * g1 + 0.0722 * b1;
+    },
+
+    /**
+     * Get the computed RGB converted to full alpha value, considering the node hierarchy.
+     *
+     * @method _getComputedBackgroundColor
+     * @param {Node} node
+     * @param {String} color The initial colour. If not specified, fetches the backgroundColor from the node.
+     * @return {Array} Colour in Array form (RGBA)
+     * @private
+     */
+    _getComputedBackgroundColor: function(node, color) {
+        color = color || node.getComputedStyle('backgroundColor');
+
+        if (color.toLowerCase() === 'transparent') {
+            // Y.Color doesn't handle 'transparent' properly.
+            color = 'rgba(1, 1, 1, 0)';
+        }
+
+        // Convert the colour to its constituent parts in RGBA format, then fetch the alpha.
+        var colorParts = Y.Color.toArray(color);
+        var alpha = colorParts[3];
+
+        if (alpha === 1) {
+            // If the alpha of the background is already 1, then the parent background colour does not change anything.
+            return colorParts;
+        }
+
+        // Fetch the computed background colour of the parent and use it to calculate the RGB of this item.
+        var parentColor = this._getComputedBackgroundColor(node.get('parentNode'));
+        return [
+            // RGB = (alpha * R|G|B) + (1 - alpha * solid parent colour).
+            (1 - alpha) * parentColor[0] + alpha * colorParts[0],
+            (1 - alpha) * parentColor[1] + alpha * colorParts[1],
+            (1 - alpha) * parentColor[2] + alpha * colorParts[2],
+            // We always return a colour with full alpha.
+            1
+        ];
     }
 });
index b734e7c..e37a08e 100644 (file)
@@ -793,7 +793,7 @@ if (CLI_SCRIPT) {
 
 // Start session and prepare global $SESSION, $USER.
 if (empty($CFG->sessiontimeout)) {
-    $CFG->sessiontimeout = 7200;
+    $CFG->sessiontimeout = 8 * 60 * 60;
 }
 \core\session\manager::start();
 
index 65cac74..dcb5e82 100644 (file)
@@ -11,6 +11,7 @@ information provided here is intended especially for developers.
   which means auto-detecting number of decimal points.
 * plagiarism_save_form_elements() has been deprecated. Please use {plugin name}_coursemodule_edit_post_actions() instead.
 * plagiarism_get_form_elements_module() has been deprecated. Please use {plugin name}_coursemodule_standard_elements() instead.
+* Changed default sessiontimeout to 8 hours to cover most normal working days
 
 === 3.8 ===
 * Add CLI option to notify all cron tasks to stop: admin/cli/cron.php --stop
index 8c64593..4ccb899 100644 (file)
Binary files a/lib/yui/build/moodle-core-chooserdialogue/moodle-core-chooserdialogue-debug.js and b/lib/yui/build/moodle-core-chooserdialogue/moodle-core-chooserdialogue-debug.js differ
index b07b223..9acc9d6 100644 (file)
Binary files a/lib/yui/build/moodle-core-chooserdialogue/moodle-core-chooserdialogue-min.js and b/lib/yui/build/moodle-core-chooserdialogue/moodle-core-chooserdialogue-min.js differ
index 8c64593..4ccb899 100644 (file)
Binary files a/lib/yui/build/moodle-core-chooserdialogue/moodle-core-chooserdialogue.js and b/lib/yui/build/moodle-core-chooserdialogue/moodle-core-chooserdialogue.js differ
index 020d7b0..a2df1f7 100644 (file)
@@ -244,10 +244,10 @@ Y.extend(CHOOSERDIALOGUE, Y.Base, {
             }
         }
 
-        // Take off 15px top and bottom for borders, plus 40px each for the title and button area before setting the
-        // new max-height
+        // Take off 15px top and bottom for borders, plus 69px for the title and 57px for the
+        // button area before setting the new max-height.
         totalheight = newheight;
-        newheight = newheight - (15 + 15 + 40 + 40);
+        newheight = newheight - (69 + 57 + 15 + 15);
         dialogue.setStyle('maxHeight', newheight + 'px');
 
         var dialogueheight = bb.getStyle('height');
@@ -260,6 +260,8 @@ Y.extend(CHOOSERDIALOGUE, Y.Base, {
         if (dialogueheight < this.get('baseheight')) {
             dialogueheight = this.get('baseheight');
             dialogue.setStyle('height', dialogueheight + 'px');
+        } else {
+            dialogue.setStyle('height', 'auto');
         }
 
         this.panel.centerDialogue();
index 0ba0a6c..f667b43 100644 (file)
@@ -2539,7 +2539,7 @@ class assign {
         // Only ever send a max of one days worth of updates.
         $yesterday = time() - (24 * 3600);
         $timenow   = time();
-        $lastcron = $DB->get_field('modules', 'lastcron', array('name' => 'assign'));
+        $lastruntime = $DB->get_field('task_scheduled', 'lastruntime', array('component' => 'mod_assign'));
 
         // Collect all submissions that require mailing.
         // Submissions are included if all are true:
@@ -2711,10 +2711,10 @@ class assign {
         $sql = 'SELECT id
                     FROM {assign}
                     WHERE
-                        allowsubmissionsfromdate >= :lastcron AND
+                        allowsubmissionsfromdate >= :lastruntime AND
                         allowsubmissionsfromdate <= :timenow AND
                         alwaysshowdescription = 0';
-        $params = array('lastcron' => $lastcron, 'timenow' => $timenow);
+        $params = array('lastruntime' => $lastruntime, 'timenow' => $timenow);
         $newlyavailable = $DB->get_records_sql($sql, $params);
         foreach ($newlyavailable as $record) {
             $cm = get_coursemodule_from_instance('assign', $record->id, 0, false, MUST_EXIST);
index a2b20e1..9484681 100644 (file)
@@ -291,7 +291,7 @@ class mod_forum_post_form extends moodleform {
                 // Additional attribs to handle collapsible div.
                 ['data-toggle' => 'collapse', 'data-target' => "#collapseAddForm"]);
             $buttonarray[] = &$mform->createElement('submit', 'advancedadddiscussion',
-                get_string('advanced'), null, null, ['customclassoverride' => 'btn-link']);
+                get_string('showadvancededitor'), null, null, ['customclassoverride' => 'btn-link']);
 
             $mform->addGroup($buttonarray, 'buttonar', '', array(' '), false);
             $mform->closeHeaderBefore('buttonar');
index 7ede4b8..df053be 100644 (file)
@@ -646,7 +646,7 @@ $string['sendstudentnotificationsdefault'] = 'Default setting for "Notify studen
 $string['sendstudentnotificationsdefault_help'] = 'Set the default value for the "Notify students" checkbox on the grading form.';
 $string['settings'] = 'Settings';
 $string['shortpost'] = 'Short post';
-$string['showingcountoftotaldiscussions'] = 'Showing {$a->count} of {$a->total} discussions';
+$string['showingcountoftotaldiscussions'] = 'List of discussions. Showing {$a->count} of {$a->total} discussions';
 $string['showgraderpanel'] = 'Show grader panel';
 $string['showpreviousrepliescount'] = 'Show previous replies ({$a})';
 $string['showsubscribers'] = 'Show/edit current subscribers';
index 74dc110..b72498f 100644 (file)
             {{{ pagination }}}
         {{/discussion_top_pagination}}
         {{$discussion_list_output}}
-            <span id="discussion-table-description-{{uniqid}}" class="sr-only">
-                {{#str}} showingcountoftotaldiscussions, mod_forum, {"count": "{{visiblediscussioncount}}", "total":"{{totaldiscussioncount}}"} {{/str}}
-            </span>
-            <table
-                class="table discussion-list"
-                aria-label='{{#str}} showingcountoftotaldiscussions, mod_forum, {"count": "{{visiblediscussioncount}}", "total":"{{totaldiscussioncount}}"} {{/str}}'
-                aria-describedby="discussion-table-description-{{uniqid}}"
-            >
+            <table class="table discussion-list">
+                <caption id="discussion-table-description-{{uniqid}}" class="sr-only">
+                    {{#str}} showingcountoftotaldiscussions, mod_forum, {"count": "{{visiblediscussioncount}}", "total":"{{totaldiscussioncount}}"} {{/str}}
+                </caption>
                 {{$discussion_list_header}}
                 <thead>
                     <tr>
index d167882..6dfdb7e 100644 (file)
@@ -435,7 +435,7 @@ class behat_mod_forum extends behat_base {
         // Navigate to forum.
         $this->execute('behat_general::click_link', $this->escape($forumname));
         $this->execute('behat_general::click_link', $buttonstr);
-        $this->execute('behat_forms::press_button', get_string('advanced'));
+        $this->execute('behat_forms::press_button', get_string('showadvancededitor'));
 
         $this->fill_new_discussion_form($table);
     }
index f65aabb..845fac2 100644 (file)
@@ -504,7 +504,14 @@ class report_log_table_log extends table_sql {
 
         if (!($this->filterparams->logreader instanceof logstore_legacy\log\store)) {
             // Filter out anonymous actions, this is N/A for legacy log because it never stores them.
-            $joins[] = "anonymous = 0";
+            if ($this->filterparams->modid) {
+                $context = context_module::instance($this->filterparams->modid);
+            } else {
+                $context = context_course::instance($this->filterparams->courseid);
+            }
+            if (!has_capability('moodle/site:viewanonymousevents', $context)) {
+                $joins[] = "anonymous = 0";
+            }
         }
 
         $selector = implode(' AND ', $joins);
index 2c72b9b..d122d07 100644 (file)
@@ -180,7 +180,11 @@ class report_loglive_renderable implements renderable {
         $filter->logreader = $readers[$this->selectedlogreader];
         $filter->date = $this->date;
         $filter->orderby = $this->order;
-        $filter->anonymous = 0;
+
+        $context = context_course::instance($filter->courseid);
+        if (!has_capability('moodle/site:viewanonymousevents', $context)) {
+            $filter->anonymous = 0;
+        }
 
         return $filter;
     }
index 710eac0..ec99292 100644 (file)
@@ -29,7 +29,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$version  = 2020010900.00;              // YYYYMMDD      = weekly release date of this DEV branch.
+$version  = 2020010900.01;              // YYYYMMDD      = weekly release date of this DEV branch.
                                         //         RR    = release increments - 00 in DEV branches.
                                         //           .XX = incremental changes.
 $release  = '3.9dev (Build: 20200109)'; // Human-friendly version name