admin/tool/usertours/amd/src/tour.js
admin/tool/usertours/amd/src/popper.js
auth/cas/CAS/
-auth/fc/fcFPP.php
enrol/lti/ims-blti/
filter/algebra/AlgParser.pm
filter/tex/mimetex.*
lib/editor/tinymce/plugins/pdw/tinymce/
lib/editor/tinymce/plugins/spellchecker/rpc.php
lib/editor/tinymce/tiny_mce/
+lib/mlbackend/php/phpml/
lib/adodb/
lib/bennu/
lib/evalmath/
lib/ltiprovider/
lib/amd/src/truncate.js
lib/fonts/
+lib/validateurlsyntax.php
media/player/videojs/amd/src/video-lazy.js
media/player/videojs/amd/src/Youtube-lazy.js
media/player/videojs/videojs/
admin/tool/usertours/amd/src/tour.js
admin/tool/usertours/amd/src/popper.js
auth/cas/CAS/
-auth/fc/fcFPP.php
enrol/lti/ims-blti/
filter/algebra/AlgParser.pm
filter/tex/mimetex.*
lib/editor/tinymce/plugins/pdw/tinymce/
lib/editor/tinymce/plugins/spellchecker/rpc.php
lib/editor/tinymce/tiny_mce/
+lib/mlbackend/php/phpml/
lib/adodb/
lib/bennu/
lib/evalmath/
lib/ltiprovider/
lib/amd/src/truncate.js
lib/fonts/
+lib/validateurlsyntax.php
media/player/videojs/amd/src/video-lazy.js
media/player/videojs/amd/src/Youtube-lazy.js
media/player/videojs/videojs/
{
+ "plugins": [
+ "stylelint-csstree-validator"
+ ],
"rules": {
+ "csstree/validator": true,
"at-rule-empty-line-before": [ "always",
- {"except": [ "blockless-group"], ignore: ["after-comment", "all-nested"]}
+ {"except": [ "blockless-after-blockless"], ignore: ["after-comment", "inside-block"]}
],
"at-rule-name-case": "lower",
"at-rule-name-space-after": "always-single-line",
"at-rule-no-unknown": null, # Enabled for non-scss in grunt.
"at-rule-semicolon-newline-after": "always",
+ "at-rule-semicolon-space-before": "never",
"block-closing-brace-newline-after": "always",
- "block-closing-brace-newline-before": "always-multi-line",
+ "block-closing-brace-newline-before": "always",
"block-closing-brace-space-before": "always-single-line",
"block-no-empty": true,
- "block-no-single-line": true,
- "block-opening-brace-newline-after": "always-multi-line",
+ "block-opening-brace-newline-after": "always",
"block-opening-brace-space-after": "always-single-line",
"block-opening-brace-space-before": "always",
"color-hex-case": ["lower", { "severity": "warning" }],
"declaration-bang-space-after": "never",
"declaration-bang-space-before": "always",
"declaration-block-no-duplicate-properties": true,
- "declaration-block-no-ignored-properties": true,
"declaration-block-no-shorthand-property-overrides": true,
"declaration-block-semicolon-newline-after": "always-multi-line",
"declaration-block-semicolon-space-after": "always-single-line",
"declaration-colon-space-after": "always-single-line",
"declaration-colon-space-before": "never",
"declaration-no-important": true,
+ "font-family-no-duplicate-names": true,
"function-calc-no-unspaced-operator": true,
"function-comma-newline-after": "always-multi-line",
"function-comma-space-after": "always-single-line",
"function-name-case": "lower",
"function-parentheses-newline-inside": "always-multi-line",
"function-parentheses-space-inside": "never-single-line",
- "function-url-data-uris": never,
+ "function-url-scheme-blacklist": ["data"],
"function-whitespace-after": "always",
"indentation": 4,
"keyframe-declaration-no-important": true,
"max-line-length": [132, { "severity": "warning" }],
"media-feature-colon-space-after": "always",
"media-feature-colon-space-before": "never",
- "media-feature-no-missing-punctuation": true,
"media-feature-parentheses-space-inside": "never",
"media-feature-range-operator-space-after": "always",
"media-feature-range-operator-space-before": "always",
"media-query-list-comma-newline-after": "always-multi-line",
"media-query-list-comma-space-after": "always-single-line",
"media-query-list-comma-space-before": "never",
- "no-browser-hacks": null, # Enabled for non-scss in grunt.
"no-empty-source": true,
"no-eol-whitespace": true,
"no-extra-semicolons": [true, { "severity": "warning" }],
"selector-pseudo-class-parentheses-space-inside": "never",
"selector-pseudo-element-case": "lower",
"selector-pseudo-element-no-unknown": true,
- "selector-root-no-composition": true,
"selector-type-case": "lower",
"selector-type-no-unknown": true,
"string-no-newline": true,
- "time-no-imperceptible": true,
+ "time-min-milliseconds": 100,
"unit-blacklist": ["pt"],
"unit-case": "lower",
"unit-no-unknown": true,
php:
# We only run the highest and lowest supported versions to reduce the load on travis-ci.org.
- 7.1
- - 5.6
+ - 7.0
addons:
postgresql: "9.3"
# Exclude it on all versions except for 7.1
- env: DB=mysqli TASK=PHPUNIT
- php: 5.6
-
- # Moodle 2.7 is not compatible with PHP 7 for the upgrade test.
- - env: DB=pgsql TASK=UPGRADE
- php: 7.1
+ php: 7.0
cache:
directories:
- $HOME/.npm
install:
- - sudo apt-get -y install haveged
- - sudo service haveged start
- >
if [ "$DB" = 'mysqli' ];
then
# We need the official upstream.
git remote add upstream https://github.com/moodle/moodle.git;
- # Checkout 27 STABLE branch.
- git fetch upstream MOODLE_27_STABLE;
- git checkout MOODLE_27_STABLE;
+ # Checkout 30 STABLE branch (the first version compatible with PHP 7.x)
+ git fetch upstream MOODLE_30_STABLE;
+ git checkout MOODLE_30_STABLE;
# Perform the upgrade
php admin/cli/install_database.php --agree-license --adminpass=Password --adminemail=admin@example.com --fullname="Upgrade test" --shortname=Upgrade;
rules: {
// These rules have to be disabled in .stylelintrc for scss compat.
"at-rule-no-unknown": true,
- "no-browser-hacks": [true, {"severity": "warning"}]
}
}
},
rules: {
// These rules have to be disabled in .stylelintrc for scss compat.
"at-rule-no-unknown": true,
- "no-browser-hacks": [true, {"severity": "warning"}]
}
}
}
define('IGNORE_COMPONENT_CACHE', true);
-// Check that PHP is of a sufficient version
-if (version_compare(phpversion(), "5.6.5") < 0) {
- $phpversion = phpversion();
- // do NOT localise - lang strings would not work here and we CAN NOT move it after installib
- fwrite(STDERR, "Moodle 3.2 or later requires at least PHP 5.6.5 (currently using version $phpversion).\n");
- fwrite(STDERR, "Please upgrade your server software or install older Moodle version.\n");
- exit(1);
-}
+// Check that PHP is of a sufficient version as soon as possible.
+require_once(__DIR__.'/../../lib/phpminimumversionlib.php');
+moodle_require_minimum_php_version();
// set up configuration
global $CFG;
if (!$options['skip-database']) {
install_cli_database($options, $interactive);
+ // This needs to happen at the end to ensure it occurs after all caches
+ // have been purged for the last time.
+ // This will build a cached version of the current theme for the user
+ // to immediately start browsing the site.
+ require_once($CFG->libdir.'/upgradelib.php');
+ upgrade_themes();
} else {
echo get_string('cliskipdatabase', 'install')."\n";
}
\$sudo -u www-data /usr/bin/php admin/cli/install_database.php --lang=cs --adminpass=soMePass123 --agree-license
";
-// Check that PHP is of a sufficient version
-if (version_compare(phpversion(), "5.6.5") < 0) {
- $phpversion = phpversion();
- // do NOT localise - lang strings would not work here and we CAN NOT move it after installib
- fwrite(STDERR, "Moodle 3.2 or later requires at least PHP 5.6.5 (currently using version $phpversion).\n");
- fwrite(STDERR, "Please upgrade your server software or install older Moodle version.\n");
- exit(1);
-}
+// Check that PHP is of a sufficient version as soon as possible.
+require_once(__DIR__.'/../../lib/phpminimumversionlib.php');
+moodle_require_minimum_php_version();
// Nothing to do if config.php does not exist
$configfile = __DIR__.'/../../config.php';
install_cli_database($options, true);
+// This needs to happen at the end to ensure it occurs after all caches
+// have been purged for the last time.
+// This will build a cached version of the current theme for the user
+// to immediately start browsing the site.
+require_once($CFG->libdir.'/upgradelib.php');
+upgrade_themes();
+
echo get_string('cliinstallfinished', 'install')."\n";
exit(0); // 0 means success
$DB->change_database_structure($sql);
} else {
echo "ERROR (unknown column type: $column->type)\n";
- $error++;
+ $errors++;
continue;
}
echo "CONVERTED\n";
admin_apply_default_settings(NULL, false);
admin_apply_default_settings(NULL, false);
+// This needs to happen at the end to ensure it occurs after all caches
+// have been purged for the last time.
+// This will build a cached version of the current theme for the user
+// to immediately start browsing the site.
+upgrade_themes();
+
echo get_string('cliupgradefinished', 'admin')."\n";
exit(0); // 0 means success
</CUSTOM_CHECK>
</CUSTOM_CHECKS>
</MOODLE>
+ <MOODLE version="3.4" requires="3.0">
+ <UNICODE level="required">
+ <FEEDBACK>
+ <ON_ERROR message="unicoderequired" />
+ </FEEDBACK>
+ </UNICODE>
+ <DATABASE level="required">
+ <VENDOR name="mariadb" version="5.5.31" />
+ <VENDOR name="mysql" version="5.5.31" />
+ <VENDOR name="postgres" version="9.3" />
+ <VENDOR name="mssql" version="10.0" />
+ <VENDOR name="oracle" version="10.2" />
+ </DATABASE>
+ <PHP version="7.0.0" level="required">
+ </PHP>
+ <PCREUNICODE level="optional">
+ <FEEDBACK>
+ <ON_CHECK message="pcreunicodewarning" />
+ </FEEDBACK>
+ </PCREUNICODE>
+ <PHP_EXTENSIONS>
+ <PHP_EXTENSION name="iconv" level="required">
+ <FEEDBACK>
+ <ON_ERROR message="iconvrequired" />
+ </FEEDBACK>
+ </PHP_EXTENSION>
+ <PHP_EXTENSION name="mbstring" level="optional">
+ <FEEDBACK>
+ <ON_CHECK message="mbstringrecommended" />
+ </FEEDBACK>
+ </PHP_EXTENSION>
+ <PHP_EXTENSION name="curl" level="required">
+ <FEEDBACK>
+ <ON_ERROR message="curlrequired" />
+ </FEEDBACK>
+ </PHP_EXTENSION>
+ <PHP_EXTENSION name="openssl" level="required">
+ <FEEDBACK>
+ <ON_ERROR message="opensslrequired" />
+ </FEEDBACK>
+ </PHP_EXTENSION>
+ <PHP_EXTENSION name="tokenizer" level="optional">
+ <FEEDBACK>
+ <ON_CHECK message="tokenizerrecommended" />
+ </FEEDBACK>
+ </PHP_EXTENSION>
+ <PHP_EXTENSION name="xmlrpc" level="optional">
+ <FEEDBACK>
+ <ON_CHECK message="xmlrpcrecommended" />
+ </FEEDBACK>
+ </PHP_EXTENSION>
+ <PHP_EXTENSION name="soap" level="optional">
+ <FEEDBACK>
+ <ON_CHECK message="soaprecommended" />
+ </FEEDBACK>
+ </PHP_EXTENSION>
+ <PHP_EXTENSION name="ctype" level="required">
+ <FEEDBACK>
+ <ON_ERROR message="ctyperequired" />
+ </FEEDBACK>
+ </PHP_EXTENSION>
+ <PHP_EXTENSION name="zip" level="required">
+ <FEEDBACK>
+ <ON_ERROR message="ziprequired" />
+ </FEEDBACK>
+ </PHP_EXTENSION>
+ <PHP_EXTENSION name="zlib" level="required">
+ </PHP_EXTENSION>
+ <PHP_EXTENSION name="gd" level="required">
+ <FEEDBACK>
+ <ON_ERROR message="gdrequired" />
+ </FEEDBACK>
+ </PHP_EXTENSION>
+ <PHP_EXTENSION name="simplexml" level="required">
+ <FEEDBACK>
+ <ON_ERROR message="simplexmlrequired" />
+ </FEEDBACK>
+ </PHP_EXTENSION>
+ <PHP_EXTENSION name="spl" level="required">
+ <FEEDBACK>
+ <ON_ERROR message="splrequired" />
+ </FEEDBACK>
+ </PHP_EXTENSION>
+ <PHP_EXTENSION name="pcre" level="required">
+ </PHP_EXTENSION>
+ <PHP_EXTENSION name="dom" level="required">
+ </PHP_EXTENSION>
+ <PHP_EXTENSION name="xml" level="required">
+ </PHP_EXTENSION>
+ <PHP_EXTENSION name="xmlreader" level="required">
+ </PHP_EXTENSION>
+ <PHP_EXTENSION name="intl" level="required">
+ <FEEDBACK>
+ <ON_ERROR message="intlrequired" />
+ </FEEDBACK>
+ </PHP_EXTENSION>
+ <PHP_EXTENSION name="json" level="required">
+ </PHP_EXTENSION>
+ <PHP_EXTENSION name="hash" level="required"/>
+ <PHP_EXTENSION name="fileinfo" level="required"/>
+ </PHP_EXTENSIONS>
+ <PHP_SETTINGS>
+ <PHP_SETTING name="memory_limit" value="96M" level="required">
+ <FEEDBACK>
+ <ON_ERROR message="settingmemorylimit" />
+ </FEEDBACK>
+ </PHP_SETTING>
+ <PHP_SETTING name="file_uploads" value="1" level="optional">
+ <FEEDBACK>
+ <ON_CHECK message="settingfileuploads" />
+ </FEEDBACK>
+ </PHP_SETTING>
+ <PHP_SETTING name="opcache.enable" value="1" level="optional">
+ <FEEDBACK>
+ <ON_CHECK message="opcacherecommended" />
+ </FEEDBACK>
+ </PHP_SETTING>
+ </PHP_SETTINGS>
+ <CUSTOM_CHECKS>
+ <CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_storage_engine" level="required">
+ <FEEDBACK>
+ <ON_ERROR message="unsupporteddbstorageengine" />
+ </FEEDBACK>
+ </CUSTOM_CHECK>
+ <CUSTOM_CHECK file="question/engine/upgrade/upgradelib.php" function="quiz_attempts_upgraded" level="required">
+ <FEEDBACK>
+ <ON_ERROR message="quizattemptsupgradedmessage" />
+ </FEEDBACK>
+ </CUSTOM_CHECK>
+ <CUSTOM_CHECK file="lib/upgradelib.php" function="check_slasharguments" level="optional">
+ <FEEDBACK>
+ <ON_CHECK message="slashargumentswarning" />
+ </FEEDBACK>
+ </CUSTOM_CHECK>
+ <CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_tables_row_format" level="optional">
+ <FEEDBACK>
+ <ON_CHECK message="unsupporteddbtablerowformat" />
+ </FEEDBACK>
+ </CUSTOM_CHECK>
+ <CUSTOM_CHECK file="lib/upgradelib.php" function="check_unoconv_version" level="optional">
+ <FEEDBACK>
+ <ON_CHECK message="unoconvwarning" />
+ </FEEDBACK>
+ </CUSTOM_CHECK>
+ <CUSTOM_CHECK file="lib/upgradelib.php" function="check_libcurl_version" level="optional">
+ <FEEDBACK>
+ <ON_CHECK message="libcurlwarning" />
+ </FEEDBACK>
+ </CUSTOM_CHECK>
+ <CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_file_format" level="required">
+ <FEEDBACK>
+ <ON_ERROR message="unsupporteddbfileformat" />
+ </FEEDBACK>
+ </CUSTOM_CHECK>
+ <CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_file_per_table" level="required">
+ <FEEDBACK>
+ <ON_ERROR message="unsupporteddbfilepertable" />
+ </FEEDBACK>
+ </CUSTOM_CHECK>
+ <CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_large_prefix" level="required">
+ <FEEDBACK>
+ <ON_ERROR message="unsupporteddblargeprefix" />
+ </FEEDBACK>
+ </CUSTOM_CHECK>
+ <CUSTOM_CHECK file="lib/upgradelib.php" function="check_is_https" level="optional">
+ <FEEDBACK>
+ <ON_CHECK message="ishttpswarning" />
+ </FEEDBACK>
+ </CUSTOM_CHECK>
+ <CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_incomplete_unicode_support" level="optional">
+ <FEEDBACK>
+ <ON_CHECK message="incompleteunicodesupport" />
+ </FEEDBACK>
+ </CUSTOM_CHECK>
+ </CUSTOM_CHECKS>
+ </MOODLE>
</COMPATIBILITY_MATRIX>
die();
}
-// Check that PHP is of a sufficient version as soon as possible
-if (version_compare(phpversion(), '5.6.5') < 0) {
- $phpversion = phpversion();
- // do NOT localise - lang strings would not work here and we CAN NOT move it to later place
- echo "Moodle 3.2 or later requires at least PHP 5.6.5 (currently using version $phpversion).<br />";
- echo "Please upgrade your server software or install older Moodle version.";
- die();
-}
+// Check that PHP is of a sufficient version as soon as possible.
+require_once(__DIR__.'/../lib/phpminimumversionlib.php');
+moodle_require_minimum_php_version();
// make sure iconv is available and actually works
if (!function_exists('iconv')) {
//remove moodle.org from the hub list
foreach ($hubs as $key => $hub) {
- if ($hub['url'] == HUB_MOODLEORGHUBURL) {
+ if ($hub['url'] == HUB_MOODLEORGHUBURL || $hub['url'] == HUB_OLDMOODLEORGHUBURL) {
unset($hubs[$key]);
}
}
$imageurl = get_config('hub', 'site_imageurl_' . $cleanhuburl);
$privacy = get_config('hub', 'site_privacy_' . $cleanhuburl);
$address = get_config('hub', 'site_address_' . $cleanhuburl);
+ if ($address === false) {
+ $address = '';
+ }
$region = get_config('hub', 'site_region_' . $cleanhuburl);
$country = get_config('hub', 'site_country_' . $cleanhuburl);
- if ($country === false) {
- $country = $admin->country;
+ if (empty($country)) {
+ $country = $admin->country ?: $CFG->country;
}
$language = get_config('hub', 'site_language_' . $cleanhuburl);
if ($language === false) {
$language = explode('_', current_language())[0];
}
$geolocation = get_config('hub', 'site_geolocation_' . $cleanhuburl);
+ if ($geolocation === false) {
+ $geolocation = '';
+ }
$contactable = get_config('hub', 'site_contactable_' . $cleanhuburl);
$emailalert = get_config('hub', 'site_emailalert_' . $cleanhuburl);
- $emailalert = ($emailalert === 0) ? 0 : 1;
+ $emailalert = ($emailalert === false || $emailalert) ? 1 : 0;
$coursesnumber = get_config('hub', 'site_coursesnumber_' . $cleanhuburl);
$usersnumber = get_config('hub', 'site_usersnumber_' . $cleanhuburl);
$roleassignmentsnumber = get_config('hub', 'site_roleassignmentsnumber_' . $cleanhuburl);
$mform->addElement('hidden', 'regioncode', '-');
$mform->setType('regioncode', PARAM_ALPHANUMEXT);
- $countries = get_string_manager()->get_list_of_countries();
+ $countries = ['' => ''] + get_string_manager()->get_list_of_countries();
$mform->addElement('select', 'countrycode', get_string('sitecountry', 'hub'), $countries);
$mform->setDefault('countrycode', $country);
$mform->setType('countrycode', PARAM_ALPHANUMEXT);
$mform->addHelpButton('countrycode', 'sitecountry', 'hub');
+ $mform->addRule('countrycode', $strrequired, 'required', null, 'client');
$mform->addElement('text', 'geolocation', get_string('sitegeolocation', 'hub'),
array('class' => 'registration_textfield'));
$mform->addElement('text', 'contactphone', get_string('sitephone', 'hub'),
array('class' => 'registration_textfield'));
$mform->setType('contactphone', PARAM_TEXT);
+ $mform->setDefault('contactphone', $contactphone);
$mform->addHelpButton('contactphone', 'sitephone', 'hub');
$mform->setForceLtr('contactphone');
echo $OUTPUT->header();
//check if the site is registered on Moodle.org and display a message about registering on MOOCH
- $registered = $DB->count_records('registration_hubs', array('huburl' => HUB_MOODLEORGHUBURL, 'confirmed' => 1));
- if (empty($registered)) {
- $warningmsg = get_string('registermoochtips', 'hub');
- $warningmsg .= $renderer->single_button(new moodle_url('register.php', array('huburl' => HUB_MOODLEORGHUBURL
- , 'hubname' => 'Moodle.org')), get_string('register', 'admin'));
- echo $renderer->box($warningmsg, 'buttons mdl-align generalbox adminwarning');
- }
+ $adminrenderer = $PAGE->get_renderer('core', 'admin');
+ echo $adminrenderer->warn_if_not_registered();
//do not check sesskey if confirm = false because this script is linked into email message
if (!empty($errormessage)) {
// Some Moodle.org registration explanation.
if ($huburl == HUB_MOODLEORGHUBURL) {
+ $notificationtype = \core\output\notification::NOTIFY_ERROR;
if (!empty($registeredhub->token)) {
if ($registeredhub->timemodified == 0) {
$registrationmessage = get_string('pleaserefreshregistrationunknown', 'admin');
} else {
$lastupdated = userdate($registeredhub->timemodified, get_string('strftimedate', 'langconfig'));
$registrationmessage = get_string('pleaserefreshregistration', 'admin', $lastupdated);
+ $notificationtype = \core\output\notification::NOTIFY_INFO;
}
} else {
$registrationmessage = get_string('registrationwarning', 'admin');
}
- echo $OUTPUT->notification($registrationmessage);
+ echo $OUTPUT->notification($registrationmessage, $notificationtype);
echo $OUTPUT->heading(get_string('registerwithmoodleorg', 'admin'));
$renderer = $PAGE->get_renderer('core', 'register');
if (!$registered) {
- $registerbutton = $this->single_button(new moodle_url('/admin/registration/register.php',
- array('huburl' => HUB_MOODLEORGHUBURL, 'hubname' => 'Moodle.org')),
+ if (has_capability('moodle/site:config', context_system::instance())) {
+ $registerbutton = $this->single_button(new moodle_url('/admin/registration/register.php',
+ array('huburl' => HUB_MOODLEORGHUBURL, 'hubname' => 'Moodle.net')),
get_string('register', 'admin'));
+ $str = 'registrationwarning';
+ } else {
+ $registerbutton = '';
+ $str = 'registrationwarningcontactadmin';
+ }
- return $this->warning( get_string('registrationwarning', 'admin')
- . ' ' . $this->help_icon('registration', 'admin') . $registerbutton );
+ return $this->warning( get_string($str, 'admin')
+ . ' ' . $this->help_icon('registration', 'admin') . $registerbutton ,
+ 'error alert alert-danger');
}
return '';
}
+ /**
+ * Return an admin page warning if site is not registered with moodle.org
+ *
+ * @return string
+ */
+ public function warn_if_not_registered() {
+ global $CFG;
+ require_once($CFG->dirroot . '/' . $CFG->admin . '/registration/lib.php');
+ $registrationmanager = new registration_manager();
+ return $this->registration_warning($registrationmanager->get_registeredhub(HUB_MOODLEORGHUBURL) ? true : false);
+ }
+
/**
* Helper method to render the information about the available Moodle update
*
// to modify them
echo $OUTPUT->header($focus);
+// Display a warning if site is not registered.
+if (empty($query)) {
+ $adminrenderer = $PAGE->get_renderer('core', 'admin');
+ echo $adminrenderer->warn_if_not_registered();
+}
+
echo $OUTPUT->heading(get_string('administrationsite'));
if ($errormsg !== '') {
$areasconfig[$areaid]->docsprocessed . ' , ' .
$areasconfig[$areaid]->recordsprocessed . ' , ' .
$areasconfig[$areaid]->docsignored;
+ if ($areasconfig[$areaid]->partial) {
+ $laststatus .= ' ' . get_string('searchpartial', 'admin');
+ }
} else {
$laststatus = '';
}
--- /dev/null
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Adds settings links to admin tree.
+ *
+ * @package core_analytics
+ * @copyright 2016 David Monllao {@link http://www.davidmonllao.com}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+if ($hassiteconfig) {
+ $settings = new admin_settingpage('analyticssettings', new lang_string('analyticssettings', 'analytics'));
+ $ADMIN->add('appearance', $settings);
+
+ if ($ADMIN->fulltree) {
+ // Select the site prediction's processor.
+ $predictionprocessors = \core_analytics\manager::get_all_prediction_processors();
+ $predictors = array();
+ foreach ($predictionprocessors as $fullclassname => $predictor) {
+ $pluginname = substr($fullclassname, 1, strpos($fullclassname, '\\', 1) - 1);
+ $predictors[$fullclassname] = new lang_string('pluginname', $pluginname);
+ }
+ $settings->add(new \core_analytics\admin_setting_predictor('analytics/predictionsprocessor',
+ new lang_string('predictionsprocessor', 'analytics'), new lang_string('predictionsprocessor_help', 'analytics'),
+ '\mlbackend_php\processor', $predictors)
+ );
+
+ // Log store.
+ $logmanager = get_log_manager();
+ $readers = $logmanager->get_readers('core\log\sql_reader');
+ $options = array();
+ $defaultreader = null;
+ foreach ($readers as $plugin => $reader) {
+ if (!$reader->is_logging()) {
+ continue;
+ }
+ if (!isset($defaultreader)) {
+ // The top one as default reader.
+ $defaultreader = $plugin;
+ }
+ $options[$plugin] = $reader->get_name();
+ }
+
+ if (empty($defaultreader)) {
+ // We fall here during initial site installation because log stores are not
+ // enabled until admin/tool/log/db/install.php is executed and get_readers
+ // return nothing.
+
+ if ($enabledlogstores = get_config('tool_log', 'enabled_stores')) {
+ $enabledlogstores = explode(',', $enabledlogstores);
+ $defaultreader = reset($enabledlogstores);
+
+ // No need to set the correct name, just the value, this will not be displayed.
+ $options[$defaultreader] = $defaultreader;
+ }
+ }
+ $settings->add(new admin_setting_configselect('analytics/logstore',
+ new lang_string('analyticslogstore', 'analytics'), new lang_string('analyticslogstore_help', 'analytics'),
+ $defaultreader, $options));
+
+ // Enable/disable time splitting methods.
+ $alltimesplittings = \core_analytics\manager::get_all_time_splittings();
+
+ $timesplittingoptions = array();
+ $timesplittingdefaults = array('\core\analytics\time_splitting\quarters_accum',
+ '\core\analytics\time_splitting\quarters', '\core\analytics\time_splitting\no_splitting');
+ foreach ($alltimesplittings as $key => $timesplitting) {
+ $timesplittingoptions[$key] = $timesplitting->get_name();
+ }
+ $settings->add(new admin_setting_configmultiselect('analytics/timesplittings',
+ new lang_string('enabledtimesplittings', 'analytics'), new lang_string('timesplittingmethod_help', 'analytics'),
+ $timesplittingdefaults, $timesplittingoptions)
+ );
+
+ // Predictions processor output dir.
+ $defaultmodeloutputdir = rtrim($CFG->dataroot, '/') . DIRECTORY_SEPARATOR . 'models';
+ if (empty(get_config('analytics', 'modeloutputdir')) && !file_exists($defaultmodeloutputdir) &&
+ is_writable($defaultmodeloutputdir)) {
+ // Automatically create the dir for them so users don't see the invalid value red cross.
+ mkdir($defaultmodeloutputdir, $CFG->directorypermissions, true);
+ }
+ $settings->add(new admin_setting_configdirectory('analytics/modeloutputdir', new lang_string('modeloutputdir', 'analytics'),
+ new lang_string('modeloutputdirinfo', 'analytics'), $defaultmodeloutputdir));
+ }
+}
$temp->add(new admin_setting_heading('searchengineheading', new lang_string('searchengine', 'admin'), ''));
$temp->add(new admin_setting_configselect('searchengine',
new lang_string('selectsearchengine', 'admin'), '', 'solr', $engines));
+ $temp->add(new admin_setting_heading('searchindexingheading', new lang_string('searchoptions', 'admin'), ''));
+ $temp->add(new admin_setting_configcheckbox('searchindexwhendisabled',
+ new lang_string('searchindexwhendisabled', 'admin'), new lang_string('searchindexwhendisabled_desc', 'admin'),
+ 0));
+ $temp->add(new admin_setting_configduration('searchindextime',
+ new lang_string('searchindextime', 'admin'), new lang_string('searchindextime_desc', 'admin'),
+ 600));
$ADMIN->add('searchplugins', $temp);
$ADMIN->add('searchplugins', new admin_externalpage('searchareas', new lang_string('searchareas', 'admin'),
new lang_string('passwordchangetokendeletion', 'admin'),
new lang_string('passwordchangetokendeletion_desc', 'admin'), 0));
+ $temp->add(new admin_setting_configduration('tokenduration',
+ new lang_string('tokenduration', 'admin'),
+ new lang_string('tokenduration_desc', 'admin'), 12 * WEEKSECS, WEEKSECS));
+
$temp->add(new admin_setting_configcheckbox('groupenrolmentkeypolicy', new lang_string('groupenrolmentkeypolicy', 'admin'), new lang_string('groupenrolmentkeypolicy_desc', 'admin'), 1));
$temp->add(new admin_setting_configcheckbox('disableuserimages', new lang_string('disableuserimages', 'admin'), new lang_string('configdisableuserimages', 'admin'), 0));
$temp->add(new admin_setting_configcheckbox('emailchangeconfirmation', new lang_string('emailchangeconfirmation', 'admin'), new lang_string('configemailchangeconfirmation', 'admin'), 1));
$ADMIN->add('root', new admin_externalpage('adminnotifications', new lang_string('notifications'), "$CFG->wwwroot/$CFG->admin/index.php"));
$ADMIN->add('root', new admin_externalpage('registrationmoodleorg', new lang_string('registration', 'admin'),
- "$CFG->wwwroot/$CFG->admin/registration/register.php?huburl=" . HUB_MOODLEORGHUBURL . "&hubname=Moodle.org&sesskey=" . sesskey()));
+ "$CFG->wwwroot/$CFG->admin/registration/register.php?huburl=" . HUB_MOODLEORGHUBURL . "&hubname=Moodle.net&sesskey=" . sesskey()));
$ADMIN->add('root', new admin_externalpage('registrationhub', new lang_string('registerwith', 'hub'),
"$CFG->wwwroot/$CFG->admin/registration/register.php", 'moodle/site:config', true));
$ADMIN->add('root', new admin_externalpage('registrationhubs', new lang_string('hubs', 'admin'),
'phone2' => new lang_string('phone2'),
'department' => new lang_string('department'),
'institution' => new lang_string('institution'),
+ 'city' => new lang_string('city'),
+ 'country' => new lang_string('country'),
)));
$setting = new admin_setting_configtext('fullnamedisplay', new lang_string('fullnamedisplay', 'admin'),
new lang_string('configfullnamedisplay', 'admin'), 'language', PARAM_TEXT, 50);
--- /dev/null
+@core @core_admin
+Feature: Manage tokens
+ In order to manage webservice usage
+ As an admin
+ I need to be able to create and delete tokens
+
+ Background:
+ Given the following "users" exist:
+ | username | password | firstname | lastname |
+ | testuser | testuser | Joe | Bloggs |
+ | testuser2 | testuser2 | TestFirstname | TestLastname |
+ And I log in as "admin"
+ And I am on site homepage
+
+ @javascript
+ Scenario: Add & delete a token
+ Given I navigate to "Plugins > Web services > Manage tokens" in site administration
+ And I follow "Add"
+ And I set the field "User" to "Joe Bloggs"
+ And I set the field "IP restriction" to "127.0.0.1"
+ When I press "Save changes"
+ Then I should see "Joe Bloggs"
+ And I should see "127.0.0.1"
+ And I follow "Delete"
+ And I press "Delete"
+ And I should not see "Joe Bloggs"
--- /dev/null
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Shows a dialogue with info about this logs.
+ *
+ * @module tool_analytics/log_info
+ * @class log_info
+ * @package tool_analytics
+ * @copyright 2017 David Monllao {@link http://www.davidmonllao.com}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+define(['jquery', 'core/str', 'core/modal_factory', 'core/notification'], function($, str, ModalFactory, Notification) {
+
+ return /** @alias module:tool_analytics/log_info */ {
+
+ /**
+ * Prepares a modal info for a log's results.
+ *
+ * @method loadInfo
+ * @param {int} id
+ * @param {string[]} info
+ */
+ loadInfo: function(id, info) {
+
+ var link = $('[data-model-log-id="' + id + '"]');
+ str.get_string('loginfo', 'tool_analytics').then(function(langString) {
+
+ var bodyInfo = $("<ul>");
+ info.forEach(function(item) {
+ bodyInfo.append('<li>' + item + '</li>');
+ });
+ bodyInfo.append("</ul>");
+
+ return ModalFactory.create({
+ title: langString,
+ body: bodyInfo.html(),
+ large: true,
+ }, link);
+
+ }).catch(Notification.exception);
+ }
+ };
+});
--- /dev/null
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Model edit form.
+ *
+ * @package tool_analytics
+ * @copyright 2017 David Monllao {@link http://www.davidmonllao.com}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace tool_analytics\output\form;
+
+defined('MOODLE_INTERNAL') || die();
+
+require_once($CFG->dirroot.'/lib/formslib.php');
+
+/**
+ * Model edit form.
+ *
+ * @package tool_analytics
+ * @copyright 2017 David Monllao {@link http://www.davidmonllao.com}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class edit_model extends \moodleform {
+
+ /**
+ * Form definition
+ */
+ public function definition() {
+ global $OUTPUT;
+
+ $mform = $this->_form;
+
+ if ($this->_customdata['model']->get_model_obj()->trained == 1) {
+ $message = get_string('edittrainedwarning', 'tool_analytics');
+ $mform->addElement('html', $OUTPUT->notification($message, \core\output\notification::NOTIFY_WARNING));
+ }
+
+ $mform->addElement('advcheckbox', 'enabled', get_string('enabled', 'tool_analytics'));
+
+ $indicators = array();
+ foreach ($this->_customdata['indicators'] as $classname => $indicator) {
+ $optionname = \tool_analytics\output\helper::class_to_option($classname);
+ $indicators[$optionname] = $indicator->get_name();
+ }
+ $options = array(
+ 'multiple' => true
+ );
+ $mform->addElement('autocomplete', 'indicators', get_string('indicators', 'tool_analytics'), $indicators, $options);
+ $mform->setType('indicators', PARAM_ALPHANUMEXT);
+
+ $timesplittings = array('' => '');
+ foreach ($this->_customdata['timesplittings'] as $classname => $timesplitting) {
+ $optionname = \tool_analytics\output\helper::class_to_option($classname);
+ $timesplittings[$optionname] = $timesplitting->get_name();
+ }
+
+ $mform->addElement('select', 'timesplitting', get_string('timesplittingmethod', 'analytics'), $timesplittings);
+ $mform->addHelpButton('timesplitting', 'timesplittingmethod', 'analytics');
+
+ $mform->addElement('hidden', 'id', $this->_customdata['id']);
+ $mform->setType('id', PARAM_INT);
+
+ $mform->addElement('hidden', 'action', 'edit');
+ $mform->setType('action', PARAM_ALPHANUMEXT);
+
+ $this->add_action_buttons();
+ }
+
+ /**
+ * Form validation
+ *
+ * @param array $data data from the form.
+ * @param array $files files uploaded.
+ *
+ * @return array of errors.
+ */
+ public function validation($data, $files) {
+ $errors = parent::validation($data, $files);
+
+ if (!empty($data['timesplitting'])) {
+ $realtimesplitting = \tool_analytics\output\helper::option_to_class($data['timesplitting']);
+ if (\core_analytics\manager::is_valid($realtimesplitting, '\core_analytics\local\time_splitting\base') === false) {
+ $errors['timesplitting'] = get_string('errorinvalidtimesplitting', 'analytics');
+ }
+ }
+
+ if (empty($data['indicators'])) {
+ $errors['indicators'] = get_string('errornoindicators', 'analytics');
+ } else {
+ foreach ($data['indicators'] as $indicator) {
+ $realindicatorname = \tool_analytics\output\helper::option_to_class($indicator);
+ if (\core_analytics\manager::is_valid($realindicatorname, '\core_analytics\local\indicator\base') === false) {
+ $errors['indicators'] = get_string('errorinvalidindicator', 'analytics', $realindicatorname);
+ }
+ }
+ }
+
+ if (!empty($data['enabled']) && empty($data['timesplitting'])) {
+ $errors['enabled'] = get_string('errorcantenablenotimesplitting', 'tool_analytics');
+ }
+
+ return $errors;
+ }
+}
--- /dev/null
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Typical crappy helper class with tiny functions.
+ *
+ * @package tool_analytics
+ * @copyright 2017 David Monllao {@link http://www.davidmonllao.com}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace tool_analytics\output;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Helper class with general purpose tiny functions.
+ *
+ * @package tool_analytics
+ * @copyright 2017 David Monllao {@link http://www.davidmonllao.com}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class helper {
+
+ /**
+ * Converts a class full name to a select option key
+ *
+ * @param string $class
+ * @return string
+ */
+ public static function class_to_option($class) {
+ // Form field is PARAM_ALPHANUMEXT and we are sending fully qualified class names
+ // as option names, but replacing the backslash for a string that is really unlikely
+ // to ever be part of a class name.
+ return str_replace('\\', '2015102400ouuu', $class);
+ }
+
+ /**
+ * option_to_class
+ *
+ * @param string $option
+ * @return string
+ */
+ public static function option_to_class($option) {
+ // Really unlikely but yeah, I'm a bad booyyy.
+ return str_replace('2015102400ouuu', '\\', $option);
+ }
+}
--- /dev/null
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Model logs table class.
+ *
+ * @package tool_analytics
+ * @copyright 2017 David Monllao {@link http://www.davidmonllao.com}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace tool_analytics\output;
+
+defined('MOODLE_INTERNAL') || die;
+require_once($CFG->libdir . '/tablelib.php');
+
+/**
+ * Model logs table class.
+ *
+ * @package tool_analytics
+ * @copyright 2017 David Monllao {@link http://www.davidmonllao.com}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class model_logs extends \table_sql {
+
+ /**
+ * @var \core_analytics\model
+ */
+ protected $model = null;
+
+ /**
+ * Sets up the table_log parameters.
+ *
+ * @param string $uniqueid unique id of form.
+ * @param \core_analytics\model $model
+ */
+ public function __construct($uniqueid, $model) {
+ global $PAGE;
+
+ parent::__construct($uniqueid);
+
+ $this->model = $model;
+
+ $this->set_attribute('class', 'modellog generaltable generalbox');
+ $this->set_attribute('aria-live', 'polite');
+
+ $this->define_columns(array('time', 'version', 'indicators', 'timesplitting', 'accuracy', 'info', 'usermodified'));
+ $this->define_headers(array(
+ get_string('time'),
+ get_string('version'),
+ get_string('indicators', 'tool_analytics'),
+ get_string('timesplittingmethod', 'analytics'),
+ get_string('accuracy', 'tool_analytics'),
+ get_string('info', 'tool_analytics'),
+ get_string('fullnameuser'),
+ ));
+ $this->pageable(true);
+ $this->collapsible(false);
+ $this->sortable(false);
+ $this->is_downloadable(false);
+
+ $this->define_baseurl($PAGE->url);
+ }
+
+ /**
+ * Generate the version column.
+ *
+ * @param \stdClass $log log data.
+ * @return string HTML for the version column
+ */
+ public function col_version($log) {
+ $recenttimestr = get_string('strftimerecent', 'core_langconfig');
+ return userdate($log->version, $recenttimestr);
+ }
+
+ /**
+ * Generate the time column.
+ *
+ * @param \stdClass $log log data.
+ * @return string HTML for the time column
+ */
+ public function col_time($log) {
+ $recenttimestr = get_string('strftimerecent', 'core_langconfig');
+ return userdate($log->timecreated, $recenttimestr);
+ }
+
+ /**
+ * Generate the indicators column.
+ *
+ * @param \stdClass $log log data.
+ * @return string HTML for the indicators column
+ */
+ public function col_indicators($log) {
+ $indicatorclasses = json_decode($log->indicators);
+ $indicators = array();
+ foreach ($indicatorclasses as $indicatorclass) {
+ $indicator = \core_analytics\manager::get_indicator($indicatorclass);
+ if ($indicator) {
+ $indicators[] = $indicator->get_name();
+ } else {
+ debugging('Can\'t load ' . $indicatorclass . ' indicator', DEBUG_DEVELOPER);
+ }
+ }
+ return '<ul><li>' . implode('</li><li>', $indicators) . '</li></ul>';
+ }
+
+ /**
+ * Generate the context column.
+ *
+ * @param \stdClass $log log data.
+ * @return string HTML for the context column
+ */
+ public function col_timesplitting($log) {
+ $timesplitting = \core_analytics\manager::get_time_splitting($log->timesplitting);
+ return $timesplitting->get_name();
+ }
+
+ /**
+ * Generate the accuracy column.
+ *
+ * @param \stdClass $log log data.
+ * @return string HTML for the accuracy column
+ */
+ public function col_accuracy($log) {
+ return strval(round($log->score * 100, 2)) . '%';
+ }
+
+ /**
+ * Generate the info column.
+ *
+ * @param \stdClass $log log data.
+ * @return string HTML for the score column
+ */
+ public function col_info($log) {
+ global $PAGE;
+
+ if (empty($log->info) && empty($log->dir)) {
+ return '';
+ }
+
+ $info = array();
+ if (!empty($log->info)) {
+ $info = json_decode($log->info);
+ }
+ if (!empty($log->dir)) {
+ $info[] = get_string('predictorresultsin', 'tool_analytics', $log->dir);
+ }
+ $PAGE->requires->js_call_amd('tool_analytics/log_info', 'loadInfo', array($log->id, $info));
+ return \html_writer::link('#', get_string('view'), array('data-model-log-id' => $log->id));
+ }
+
+ /**
+ * Generate the usermodified column.
+ *
+ * @param \stdClass $log log data.
+ * @return string HTML for the usermodified column
+ */
+ public function col_usermodified($log) {
+ $user = \core_user::get_user($log->usermodified);
+ return fullname($user);
+ }
+
+ /**
+ * Query the logs table. Store results in the object for use by build_table.
+ *
+ * @param int $pagesize size of page for paginated displayed table.
+ * @param bool $useinitialsbar do you want to use the initials bar.
+ */
+ public function query_db($pagesize, $useinitialsbar = true) {
+ $total = count($this->model->get_logs());
+ $this->pagesize($pagesize, $total);
+ $this->rawdata = $this->model->get_logs($this->get_page_start(), $this->get_page_size());
+
+ // Set initial bars.
+ if ($useinitialsbar) {
+ $this->initialbars($total > $pagesize);
+ }
+ }
+}
--- /dev/null
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Prediction models list page.
+ *
+ * @package tool_analytics
+ * @copyright 2016 David Monllao {@link http://www.davidmonllao.com}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace tool_analytics\output;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Shows tool_analytics models list.
+ *
+ * @package tool_analytics
+ * @copyright 2016 David Monllao {@link http://www.davidmonllao.com}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class models_list implements \renderable, \templatable {
+
+ /**
+ * models
+ *
+ * @var \core_analytics\model[]
+ */
+ protected $models = array();
+
+ /**
+ * __construct
+ *
+ * @param \core_analytics\model[] $models
+ * @return void
+ */
+ public function __construct($models) {
+ $this->models = $models;
+ }
+
+ /**
+ * Exports the data.
+ *
+ * @param \renderer_base $output
+ * @return \stdClass
+ */
+ public function export_for_template(\renderer_base $output) {
+
+ $data = new \stdClass();
+
+ $data->models = array();
+ foreach ($this->models as $model) {
+ $modeldata = $model->export();
+
+ // Model predictions list.
+ if ($model->uses_insights()) {
+ $predictioncontexts = $model->get_predictions_contexts();
+ if ($predictioncontexts) {
+
+ foreach ($predictioncontexts as $contextid => $unused) {
+ // We prepare this to be used as single_select template options.
+ $context = \context::instance_by_id($contextid);
+
+ // Special name for system level predictions as showing "System is not visually nice".
+ if ($contextid == SYSCONTEXTID) {
+ $contextname = get_string('allpredictions', 'tool_analytics');
+ } else {
+ $contextname = shorten_text($context->get_context_name(true, true), 90);
+ }
+ $predictioncontexts[$contextid] = $contextname;
+ }
+ \core_collator::asort($predictioncontexts);
+
+ if (!empty($predictioncontexts)) {
+ $url = new \moodle_url('/report/insights/insights.php', array('modelid' => $model->get_id()));
+ $singleselect = new \single_select($url, 'contextid', $predictioncontexts);
+ $modeldata->insights = $singleselect->export_for_template($output);
+ }
+ }
+
+ if (empty($modeldata->insights)) {
+ if ($model->any_prediction_obtained()) {
+ $modeldata->noinsights = get_string('noinsights', 'analytics');
+ } else {
+ $modeldata->noinsights = get_string('nopredictionsyet', 'analytics');
+ }
+ }
+
+ } else {
+ $modeldata->noinsights = get_string('noinsightsmodel', 'analytics');
+ }
+
+ // Actions.
+ $actionsmenu = new \action_menu();
+ $actionsmenu->set_menu_trigger(get_string('actions'));
+ $actionsmenu->set_owner_selector('model-actions-' . $model->get_id());
+ $actionsmenu->set_alignment(\action_menu::TL, \action_menu::BL);
+
+ // Edit model.
+ if (!$model->is_static()) {
+ $url = new \moodle_url('model.php', array('action' => 'edit', 'id' => $model->get_id()));
+ $icon = new \action_menu_link_secondary($url, new \pix_icon('t/edit', get_string('edit')), get_string('edit'));
+ $actionsmenu->add($icon);
+ }
+
+ // Enable / disable.
+ if ($model->is_enabled()) {
+ $action = 'disable';
+ $text = get_string('disable');
+ $icontype = 't/block';
+ } else {
+ $action = 'enable';
+ $text = get_string('enable');
+ $icontype = 'i/checked';
+ }
+ $url = new \moodle_url('model.php', array('action' => $action, 'id' => $model->get_id()));
+ $icon = new \action_menu_link_secondary($url, new \pix_icon($icontype, $text), $text);
+ $actionsmenu->add($icon);
+
+ // Evaluate machine-learning-based models.
+ if ($model->get_indicators() && !$model->is_static()) {
+ $url = new \moodle_url('model.php', array('action' => 'evaluate', 'id' => $model->get_id()));
+ $icon = new \action_menu_link_secondary($url, new \pix_icon('i/calc', get_string('evaluate', 'tool_analytics')),
+ get_string('evaluate', 'tool_analytics'));
+ $actionsmenu->add($icon);
+ }
+
+ if ($modeldata->enabled && !empty($modeldata->timesplitting)) {
+ $url = new \moodle_url('model.php', array('action' => 'getpredictions', 'id' => $model->get_id()));
+ $icon = new \action_menu_link_secondary($url, new \pix_icon('i/notifications',
+ get_string('getpredictions', 'tool_analytics')), get_string('getpredictions', 'tool_analytics'));
+ $actionsmenu->add($icon);
+ }
+
+ // Machine-learning-based models evaluation log.
+ if (!$model->is_static()) {
+ $url = new \moodle_url('model.php', array('action' => 'log', 'id' => $model->get_id()));
+ $icon = new \action_menu_link_secondary($url, new \pix_icon('i/report', get_string('viewlog', 'tool_analytics')),
+ get_string('viewlog', 'tool_analytics'));
+ $actionsmenu->add($icon);
+ }
+
+ $modeldata->actions = $actionsmenu->export_for_template($output);
+
+ $data->models[] = $modeldata;
+ }
+
+ $data->warnings = array(
+ (object)array('message' => get_string('bettercli', 'tool_analytics'), 'closebutton' => true)
+ );
+
+ return $data;
+ }
+}
--- /dev/null
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Renderer.
+ *
+ * @package tool_analytics
+ * @copyright 2016 David Monllao {@link http://www.davidmonllao.com}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace tool_analytics\output;
+
+defined('MOODLE_INTERNAL') || die();
+
+use plugin_renderer_base;
+use templatable;
+use renderable;
+
+/**
+ * Renderer class.
+ *
+ * @package tool_analytics
+ * @copyright 2016 David Monllao {@link http://www.davidmonllao.com}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class renderer extends plugin_renderer_base {
+
+ /**
+ * Defer to template.
+ *
+ * @param \tool_analytics\output\models_list $modelslist
+ * @return string HTML
+ */
+ protected function render_models_list(\tool_analytics\output\models_list $modelslist) {
+ $data = $modelslist->export_for_template($this);
+ return parent::render_from_template('tool_analytics/models_list', $data);
+ }
+
+ /**
+ * Renders a table.
+ *
+ * @param \table_sql $table
+ * @return string HTML
+ */
+ public function render_table(\table_sql $table) {
+
+ ob_start();
+ $table->out(10, true);
+ $output = ob_get_contents();
+ ob_end_clean();
+
+ return $output;
+ }
+
+ /**
+ * Web interface evaluate results.
+ *
+ * @param \stdClass[] $results
+ * @param string[] $logs
+ * @return string HTML
+ */
+ public function render_evaluate_results($results, $logs = array()) {
+ global $OUTPUT;
+
+ $output = '';
+
+ foreach ($results as $timesplittingid => $result) {
+
+ if (!CLI_SCRIPT) {
+ $output .= $OUTPUT->box_start('generalbox m-b-3');
+ }
+
+ // Check that the array key is a string, not all results depend on time splitting methods (e.g. general errors).
+ if (!is_numeric($timesplittingid)) {
+ $timesplitting = \core_analytics\manager::get_time_splitting($timesplittingid);
+ $langstrdata = (object)array('name' => $timesplitting->get_name(), 'id' => $timesplittingid);
+
+ if (CLI_SCRIPT) {
+ $output .= $OUTPUT->heading(get_string('getpredictionsresultscli', 'tool_analytics', $langstrdata), 3);
+ } else {
+ $output .= $OUTPUT->heading(get_string('getpredictionsresults', 'tool_analytics', $langstrdata), 3);
+ }
+ }
+
+ if ($result->status == 0) {
+ $output .= $OUTPUT->notification(get_string('goodmodel', 'tool_analytics'),
+ \core\output\notification::NOTIFY_SUCCESS);
+ } else if ($result->status === \core_analytics\model::NO_DATASET) {
+ $output .= $OUTPUT->notification(get_string('nodatatoevaluate', 'tool_analytics'),
+ \core\output\notification::NOTIFY_WARNING);
+ }
+
+ if (isset($result->score)) {
+ // Score.
+ $output .= $OUTPUT->heading(get_string('accuracy', 'tool_analytics') . ': ' .
+ round(floatval($result->score), 4) * 100 . '%', 4);
+ }
+
+ if (!empty($result->info)) {
+ foreach ($result->info as $message) {
+ $output .= $OUTPUT->notification($message, \core\output\notification::NOTIFY_WARNING);
+ }
+ }
+
+ if (!CLI_SCRIPT) {
+ $output .= $OUTPUT->box_end();
+ }
+ }
+
+ // Info logged during evaluation.
+ if (!empty($logs) && debugging()) {
+ $output .= $OUTPUT->heading(get_string('extrainfo', 'tool_analytics'), 3);
+ foreach ($logs as $log) {
+ $output .= $OUTPUT->notification($log, \core\output\notification::NOTIFY_WARNING);
+ }
+ }
+
+ if (!CLI_SCRIPT) {
+ $output .= $OUTPUT->single_button(new \moodle_url('/admin/tool/analytics/index.php'), get_string('continue'));
+ }
+
+ return $output;
+ }
+
+
+ /**
+ * Web interface training & prediction results.
+ *
+ * @param \stdClass|false $trainresults
+ * @param string[] $trainlogs
+ * @param \stdClass|false $predictresults
+ * @param string[] $predictlogs
+ * @return string HTML
+ */
+ public function render_get_predictions_results($trainresults = false, $trainlogs = array(), $predictresults = false, $predictlogs = array()) {
+ global $OUTPUT;
+
+ $output = '';
+
+ if ($trainresults || (!empty($trainlogs) && debugging())) {
+ $output .= $OUTPUT->heading(get_string('trainingresults', 'tool_analytics'), 3);
+ }
+
+ if ($trainresults) {
+ if ($trainresults->status == 0) {
+ $output .= $OUTPUT->notification(get_string('trainingprocessfinished', 'tool_analytics'),
+ \core\output\notification::NOTIFY_SUCCESS);
+ } else if ($trainresults->status === \core_analytics\model::NO_DATASET) {
+ $output .= $OUTPUT->notification(get_string('nodatatotrain', 'tool_analytics'),
+ \core\output\notification::NOTIFY_WARNING);
+ } else {
+ $output .= $OUTPUT->notification(get_string('generalerror', 'analytics', $trainresults->status),
+ \core\output\notification::NOTIFY_ERROR);
+ }
+ }
+
+ if (!empty($trainlogs) && debugging()) {
+ $output .= $OUTPUT->heading(get_string('extrainfo', 'tool_analytics'), 4);
+ foreach ($trainlogs as $log) {
+ $output .= $OUTPUT->notification($log, \core\output\notification::NOTIFY_WARNING);
+ }
+ }
+
+ if ($predictresults || (!empty($predictlogs) && debugging())) {
+ $output .= $OUTPUT->heading(get_string('predictionresults', 'tool_analytics'), 3, 'main m-t-3');
+ }
+
+ if ($predictresults) {
+ if ($predictresults->status == 0) {
+ $output .= $OUTPUT->notification(get_string('predictionprocessfinished', 'tool_analytics'),
+ \core\output\notification::NOTIFY_SUCCESS);
+ } else if ($predictresults->status === \core_analytics\model::NO_DATASET) {
+ $output .= $OUTPUT->notification(get_string('nodatatopredict', 'tool_analytics'),
+ \core\output\notification::NOTIFY_WARNING);
+ } else {
+ $output .= $OUTPUT->notification(get_string('generalerror', 'analytics', $predictresults->status),
+ \core\output\notification::NOTIFY_ERROR);
+ }
+ }
+
+ if (!empty($predictlogs) && debugging()) {
+ $output .= $OUTPUT->heading(get_string('extrainfo', 'tool_analytics'), 4);
+ foreach ($predictlogs as $log) {
+ $output .= $OUTPUT->notification($log, \core\output\notification::NOTIFY_WARNING);
+ }
+ }
+
+ if (!CLI_SCRIPT) {
+ $output .= $OUTPUT->single_button(new \moodle_url('/admin/tool/analytics/i