Compare commits
239 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 237f4ccada | |||
| f674b77d34 | |||
| 9215f9d294 | |||
| b72be5f142 | |||
| 5ed11926a6 | |||
| e4274d80a4 | |||
| 87883bb43c | |||
| cd83b3732e | |||
| c6ec73b12e | |||
| 3c23c78500 | |||
| 1b22f24666 | |||
| 0656fb0d19 | |||
| d13532e364 | |||
| 0e077d9b68 | |||
| 35fbf2b4af | |||
| 3938b91363 | |||
| d87d0973f5 | |||
| c5298a3d9a | |||
| 83dda7ae04 | |||
| 2561b61d81 | |||
| 119c201a10 | |||
| 3cdb182a70 | |||
| 5e6e118a2e | |||
| cd0b5a63fa | |||
| afc3b1dd3d | |||
| d1983c3ce1 | |||
| 0094d8e66e | |||
| b34246ca19 | |||
| 5e29bd67e6 | |||
| ad7c296dc9 | |||
| 9aad1581bc | |||
| 56882a76d1 | |||
| 14c8b8bd56 | |||
| e66bf8a5c1 | |||
| 01aee79df0 | |||
| e3b4f6d3fd | |||
| 73d36ebafa | |||
| d73d9dd99f | |||
| 301f78c282 | |||
| 373c263482 | |||
| ac7cd6c603 | |||
| 62b4ebab51 | |||
| abbda5d025 | |||
| 0debb3cac0 | |||
| 9f4404e80d | |||
| d9af87d70a | |||
| 804f1f5ac7 | |||
| 23f0d09ec7 | |||
| 641b678d4b | |||
| 5183181f94 | |||
| b74abdbea1 | |||
| a11c2cb391 | |||
| 204748856a | |||
| 8962bd76c3 | |||
| 8a07e2f53d | |||
| 3de329785d | |||
| 63a4a88dd1 | |||
| 4f46b8449b | |||
| 72c300facf | |||
| c96074aafd | |||
| 7f507d94d9 | |||
| 6211bc0be5 | |||
| 6dc0b43072 | |||
| 502076cde6 | |||
| 79368aaa6a | |||
| 5431063238 | |||
| 36764c36c0 | |||
| f902e75bae | |||
| 8fd5eb7be5 | |||
| 8399b45fd0 | |||
| dc783d3d5e | |||
| aaaf3abc4d | |||
| 9a36fe6886 | |||
| 1b8ccba1f2 | |||
| 723ffea626 | |||
| 0c57ffc2b5 | |||
| f3ae9f9d45 | |||
| 3bffbfabb5 | |||
| 3afeaed3ff | |||
| c05862dc9a | |||
| 9cd78a8b4f | |||
| 8f630db213 | |||
| 689d10b02b | |||
| 71f40d0018 | |||
| b9f9758f5e | |||
| 9e19f3c1f5 | |||
| 8f0daf43b7 | |||
| fa72038987 | |||
| 6679c41c89 | |||
| 1ed97439dd | |||
| 17625bd5b2 | |||
| 475ea093b4 | |||
| 40d45ede41 | |||
| 6651b3f940 | |||
| e1ac84a458 | |||
| ff833a08de | |||
| d426ee3ccc | |||
| 813338182c | |||
| 5e7f937481 | |||
| 1bbfbd7444 | |||
| 0f308b0df1 | |||
| fea40706b1 | |||
| eb60ece090 | |||
| 062dc30ffd | |||
| a834862ce4 | |||
| e148629f48 | |||
| 8e750158a0 | |||
| 78ea26ad7b | |||
| b58a1b9e34 | |||
| 298a70eba1 | |||
| 0e301e88a5 | |||
| 4b9b0839b6 | |||
| d7d94cf30f | |||
| 72b6d0be84 | |||
| fa2d1ab5d3 | |||
| 78aabd1e28 | |||
| 72e7b87b92 | |||
| 3a83f57043 | |||
| 2a706c3e5c | |||
| faaa25b5cc | |||
| 6b5a1b02fe | |||
| 96ddfecda3 | |||
| 94259f8a7d | |||
| 855e7e9ede | |||
| e6725b8cbb | |||
| bd80f68c11 | |||
| dbcfda9641 | |||
| b62526d0ad | |||
| d9293c77bc | |||
| 6f9415fea0 | |||
| 647020f584 | |||
| afc20e7caa | |||
| 6d82a01438 | |||
| 3e47cdda94 | |||
| 7ccaf08d5a | |||
| 5d309ef2a8 | |||
| ce023afec9 | |||
| fdb9a664f6 | |||
| 79d705df64 | |||
| 73e9259c10 | |||
| 785cf4fb22 | |||
| c30923d77d | |||
| ea388d74ab | |||
| 61d1af0818 | |||
| 93960101e9 | |||
| 26e8b4a0fa | |||
| a1523774bc | |||
| 7c1feb97b2 | |||
| 26e00f4640 | |||
| bf4038a971 | |||
| 10c4a67760 | |||
| def3f4a074 | |||
| 71613b1055 | |||
| db374d6a80 | |||
| 6958a078a6 | |||
| 5566bfe436 | |||
| 40cdfc58fc | |||
| 416b25fc77 | |||
| ae88411798 | |||
| 909c977e00 | |||
| 3306411314 | |||
| 4203a0389e | |||
| 2d308243f4 | |||
| 6a7baaced0 | |||
| 0c611e0a13 | |||
| 905511e816 | |||
| d883536e6f | |||
| 653d6f0229 | |||
| 4ab41d6090 | |||
| c50d68cfd9 | |||
| 33d6929e1f | |||
| f4a604e4e2 | |||
| 0ecc30eb85 | |||
| 4de37cf603 | |||
| dda7890857 | |||
| b470f7b246 | |||
| f5087ef548 | |||
| 7e146f752a | |||
| ece30526dd | |||
| a3fa31fa21 | |||
| 06b3ac6ca1 | |||
| 4c8c9a4c4b | |||
| 538c8eddb5 | |||
| fafed9dc90 | |||
| 1611b30b1c | |||
| 69455d835c | |||
| c33060d008 | |||
| 10f934e300 | |||
| 9d63efed82 | |||
| da5111e321 | |||
| ebfe1d5945 | |||
| 359cc7e787 | |||
| 981784000d | |||
| 542a7490f2 | |||
| e44ae4df58 | |||
| e89432fb19 | |||
| 3e30dffa31 | |||
| e084f4c0b4 | |||
| 215851c4c0 | |||
| f751383a15 | |||
| ab1207e8eb | |||
| 5ef3241ae3 | |||
| eebc6ba6a8 | |||
| 6cd746cb4d | |||
| 6877043d8c | |||
| 2c249dbee1 | |||
| 6c14348b41 | |||
| c7b4cf91f8 | |||
| 3bc49b14bf | |||
| f4e28ca6c2 | |||
| ed1ce9cf9b | |||
| 31530a2730 | |||
| 82babe08ea | |||
| 76e39a9c2a | |||
| f41360dd50 | |||
| 838190a43a | |||
| e2b34c37bd | |||
| 250afa688f | |||
| 325915ef34 | |||
| fec16e68c9 | |||
| c906a33e1e | |||
| e8a5efe835 | |||
| aa07315267 | |||
| d4de6e594d | |||
| 14138237ee | |||
| 0e74a6c0c5 | |||
| 06c9de6b05 | |||
| a8d18f88a1 | |||
| a87f5b6e8c | |||
| 9e52a6a0e1 | |||
| e21872130d | |||
| 3567998cfd | |||
| 0820e24c18 | |||
| 35f368a1b4 | |||
| 31aedd4c1c | |||
| 147a25d87f | |||
| 7eb9ddc5ae | |||
| 3afc0edaf9 | |||
| e1fcbc9d3d |
+1
-1
@@ -92,4 +92,4 @@ theme/boost/amd/src/bootstrap/tab.js
|
||||
theme/boost/amd/src/bootstrap/toast.js
|
||||
theme/boost/amd/src/bootstrap/tooltip.js
|
||||
theme/boost/amd/src/bootstrap/util.js
|
||||
theme/boost/scss/fontawesome/
|
||||
theme/boost/scss/fontawesome/
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
name: Core
|
||||
|
||||
on: [push]
|
||||
on:
|
||||
push:
|
||||
branches-ignore:
|
||||
- master
|
||||
- MOODLE_[0-9]+_STABLE
|
||||
tags-ignore:
|
||||
- v[0-9]+.[0-9]+.[0-9]+*
|
||||
|
||||
env:
|
||||
php: 7.4
|
||||
|
||||
@@ -46,3 +46,4 @@ composer.phar
|
||||
atlassian-ide-plugin.xml
|
||||
/node_modules/
|
||||
/.vscode/
|
||||
moodle-plugin-ci.phar
|
||||
|
||||
+1
-1
@@ -93,4 +93,4 @@ theme/boost/amd/src/bootstrap/tab.js
|
||||
theme/boost/amd/src/bootstrap/toast.js
|
||||
theme/boost/amd/src/bootstrap/tooltip.js
|
||||
theme/boost/amd/src/bootstrap/util.js
|
||||
theme/boost/scss/fontawesome/
|
||||
theme/boost/scss/fontawesome/
|
||||
|
||||
@@ -19,6 +19,12 @@ services:
|
||||
addons:
|
||||
postgresql: "9.6"
|
||||
|
||||
branches:
|
||||
except:
|
||||
- master
|
||||
- /MOODLE_[0-9]+_STABLE/
|
||||
- /^v[0-9]+\.[0-9]+\.[0-9]+.*/
|
||||
|
||||
jobs:
|
||||
# Enable fast finish.
|
||||
# This will fail the build if a single job fails (except those in allow_failures).
|
||||
|
||||
+2
-2
@@ -424,7 +424,7 @@ module.exports = function(grunt) {
|
||||
'*/**/yui/src/*/meta/',
|
||||
'*/**/build/',
|
||||
].concat(thirdPartyPaths);
|
||||
grunt.file.write('.eslintignore', eslintIgnores.join('\n'));
|
||||
grunt.file.write('.eslintignore', eslintIgnores.join('\n') + '\n');
|
||||
|
||||
// Generate .stylelintignore.
|
||||
const stylelintIgnores = [
|
||||
@@ -433,7 +433,7 @@ module.exports = function(grunt) {
|
||||
'theme/boost/style/moodle.css',
|
||||
'theme/classic/style/moodle.css',
|
||||
].concat(thirdPartyPaths);
|
||||
grunt.file.write('.stylelintignore', stylelintIgnores.join('\n'));
|
||||
grunt.file.write('.stylelintignore', stylelintIgnores.join('\n') + '\n');
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Fix orphaned calendar events that were broken by MDL-67494.
|
||||
*
|
||||
* This script will look for all the calendar events which userids
|
||||
* where broken by a wrong upgrade step, affecting to Moodle 3.9.5
|
||||
* and up.
|
||||
*
|
||||
* It performs checks to both:
|
||||
* a) Detect if the site was affected (ran the wrong upgrade step).
|
||||
* b) Look for orphaned calendar events, categorising them as:
|
||||
* - standard: site / category / course / group / user events
|
||||
* - subscription: events created via subscriptions.
|
||||
* - action: normal action events, created to show common important dates.
|
||||
* - override: user and group override events, particular, that some activities support.
|
||||
* - custom: other events, not being any of the above, common or particular.
|
||||
* By specifying it (--fix) try to recover as many broken events (missing userid) as
|
||||
* possible. Standard, subscription, action, override events in core are fully supported but
|
||||
* override or custom events should be fixed by each plugin as far as there isn't any standard
|
||||
* API (plugin-wise) to launch a rebuild of the calendar events.
|
||||
*
|
||||
* @package core
|
||||
* @copyright 2021 onwards Simey Lameze <simey@moodle.com>
|
||||
* @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
define('CLI_SCRIPT', true);
|
||||
|
||||
require_once(__DIR__ . '/../../config.php');
|
||||
require_once($CFG->libdir . "/clilib.php");
|
||||
require_once($CFG->libdir . '/db/upgradelib.php');
|
||||
|
||||
// Supported options.
|
||||
$long = ['fix' => false, 'help' => false];
|
||||
$short = ['f' => 'fix', 'h' => 'help'];
|
||||
|
||||
// CLI options.
|
||||
[$options, $unrecognized] = cli_get_params($long, $short);
|
||||
|
||||
if ($unrecognized) {
|
||||
$unrecognized = implode("\n ", $unrecognized);
|
||||
cli_error(get_string('cliunknowoption', 'admin', $unrecognized));
|
||||
}
|
||||
|
||||
if ($options['help']) {
|
||||
$help = <<<EOT
|
||||
Fix orphaned calendar events.
|
||||
|
||||
This script detects calendar events that have had their
|
||||
userid lost. By default it will perform various checks
|
||||
and report them, showing the site status in an easy way.
|
||||
|
||||
Also, optionally (--fix), it wil try to recover as many
|
||||
lost userids as possible from different sources. Note that
|
||||
this script aims to process well-know events in core,
|
||||
leaving custom events in 3rd part plugins mostly unmodified
|
||||
because there isn't any consistent way to regenerate them.
|
||||
|
||||
For more details: https://tracker.moodle.org/browse/MDL-71156
|
||||
|
||||
Options:
|
||||
-h, --help Print out this help.
|
||||
-f, --fix Fix the orphaned calendar events in the DB.
|
||||
If not specified only check and report problems to STDERR.
|
||||
|
||||
Usage:
|
||||
- Only report: \$ sudo -u www-data /usr/bin/php admin/cli/fix_orphaned_calendar_events.php
|
||||
- Report and fix: \$ sudo -u www-data /usr/bin/php admin/cli/fix_orphaned_calendar_events.php -f
|
||||
EOT;
|
||||
|
||||
cli_writeln($help);
|
||||
die;
|
||||
}
|
||||
|
||||
// Check various usual pre-requisites.
|
||||
if (empty($CFG->version)) {
|
||||
cli_error('Database is not yet installed.');
|
||||
}
|
||||
|
||||
$admin = get_admin();
|
||||
if (!$admin) {
|
||||
cli_error('Error: No admin account was found.');
|
||||
}
|
||||
|
||||
if (moodle_needs_upgrading()) {
|
||||
cli_error('Moodle upgrade pending, script execution suspended.');
|
||||
}
|
||||
|
||||
// Do everything as admin by default.
|
||||
\core\session\manager::set_user($admin);
|
||||
|
||||
// Report current site status.
|
||||
cli_heading('Checking the site status');
|
||||
$needsfix = upgrade_calendar_site_status();
|
||||
|
||||
// Report current calendar events status.
|
||||
cli_heading('Checking the calendar events status');
|
||||
$info = upgrade_calendar_events_status();
|
||||
$hasbadevents = $info['total']->bad > 0 || $info['total']->bad != $info['other']->bad;
|
||||
$needsfix = $needsfix || $hasbadevents;
|
||||
|
||||
// If, selected, fix as many calendar events as possible.
|
||||
if ($options['fix']) {
|
||||
|
||||
// If the report has told us that the fix was not needed... ask for confirmation!
|
||||
if (!$needsfix) {
|
||||
cli_writeln("This site DOES NOT NEED to run the calendar events fix.");
|
||||
$input = cli_input('Are you completely sure that you want to run the fix? (y/N)', 'N', ['y', 'Y', 'n', 'N']);
|
||||
if (strtolower($input) != 'y') {
|
||||
exit(0);
|
||||
}
|
||||
cli_writeln("");
|
||||
}
|
||||
cli_heading('Fixing as many as possible calendar events');
|
||||
upgrade_calendar_events_fix_remaining($info);
|
||||
// Report current (after fix) calendar events status.
|
||||
cli_heading('Checking the calendar events status (after fix)');
|
||||
upgrade_calendar_events_status();
|
||||
} else if ($needsfix) {
|
||||
// Fix option was not provided but problem events have been found. Notify the user and provide info how to fix these events.
|
||||
cli_writeln("This site NEEDS to run the calendar events fix!");
|
||||
cli_writeln("To fix the calendar events, re-run this script with the --fix option.");
|
||||
}
|
||||
@@ -119,7 +119,7 @@ if (!empty($options['collation'])) {
|
||||
if ($dbcollation->value !== $collation || $dbcharset->value !== $charset) {
|
||||
// Try to convert the DB.
|
||||
echo "Converting database to '$collation' for $CFG->wwwroot:\n";
|
||||
$sql = "ALTER DATABASE $CFG->dbname DEFAULT CHARACTER SET $charset DEFAULT COLLATE = $collation";
|
||||
$sql = "ALTER DATABASE `$CFG->dbname` DEFAULT CHARACTER SET $charset DEFAULT COLLATE = $collation";
|
||||
try {
|
||||
$DB->change_database_structure($sql);
|
||||
} catch (exception $e) {
|
||||
@@ -146,7 +146,7 @@ if (!empty($options['collation'])) {
|
||||
|
||||
} else {
|
||||
try {
|
||||
$DB->change_database_structure("ALTER TABLE $table->name CONVERT TO CHARACTER SET $charset COLLATE $collation");
|
||||
$DB->change_database_structure("ALTER TABLE `$table->name` CONVERT TO CHARACTER SET $charset COLLATE $collation");
|
||||
echo "CONVERTED\n";
|
||||
$converted++;
|
||||
} catch (ddl_exception $e) {
|
||||
@@ -163,7 +163,7 @@ if (!empty($options['collation'])) {
|
||||
}
|
||||
}
|
||||
|
||||
$sql = "SHOW FULL COLUMNS FROM $table->name WHERE collation IS NOT NULL";
|
||||
$sql = "SHOW FULL COLUMNS FROM `$table->name` WHERE collation IS NOT NULL";
|
||||
$rs2 = $DB->get_recordset_sql($sql);
|
||||
foreach ($rs2 as $column) {
|
||||
$column = (object)array_change_key_case((array)$column, CASE_LOWER);
|
||||
@@ -181,7 +181,7 @@ if (!empty($options['collation'])) {
|
||||
$notnull = ($column->null === 'NO') ? 'NOT NULL' : 'NULL';
|
||||
$default = (!is_null($column->default) and $column->default !== '') ? "DEFAULT '$column->default'" : '';
|
||||
// primary, unique and inc are not supported for texts
|
||||
$sql = "ALTER TABLE $table->name
|
||||
$sql = "ALTER TABLE `$table->name`
|
||||
MODIFY COLUMN $column->field $column->type
|
||||
CHARACTER SET $charset
|
||||
COLLATE $collation $notnull $default";
|
||||
@@ -192,11 +192,11 @@ if (!empty($options['collation'])) {
|
||||
$default = !is_null($column->default) ? "DEFAULT '$column->default'" : '';
|
||||
|
||||
if ($rowformat != '') {
|
||||
$sql = "ALTER TABLE $table->name $rowformat";
|
||||
$sql = "ALTER TABLE `$table->name` $rowformat";
|
||||
$DB->change_database_structure($sql);
|
||||
}
|
||||
|
||||
$sql = "ALTER TABLE $table->name
|
||||
$sql = "ALTER TABLE `$table->name`
|
||||
MODIFY COLUMN $column->field $column->type
|
||||
CHARACTER SET $charset
|
||||
COLLATE $collation $notnull $default";
|
||||
@@ -315,8 +315,8 @@ function mysql_set_row_format($tablename, $charset, $collation, $engine) {
|
||||
if ($rs->row_format == 'Compact' || $rs->row_format == 'Redundant') {
|
||||
$rowformat = $DB->get_row_format_sql($engine, $collation);
|
||||
// Try to convert to compressed format and then try updating the collation again.
|
||||
$DB->change_database_structure("ALTER TABLE $tablename $rowformat");
|
||||
$DB->change_database_structure("ALTER TABLE $tablename CONVERT TO CHARACTER SET $charset COLLATE $collation");
|
||||
$DB->change_database_structure("ALTER TABLE `$tablename` $rowformat");
|
||||
$DB->change_database_structure("ALTER TABLE `$tablename` CONVERT TO CHARACTER SET $charset COLLATE $collation");
|
||||
} else {
|
||||
// Row format may not be the problem. Can not diagnose problem. Send fail reply.
|
||||
return false;
|
||||
|
||||
@@ -158,7 +158,7 @@ if (!empty($options['info'])) {
|
||||
}
|
||||
|
||||
foreach ($fixtables as $table) {
|
||||
$DB->change_database_structure("ALTER TABLE {$prefix}$table ROW_FORMAT=Compressed");
|
||||
$DB->change_database_structure("ALTER TABLE `{$prefix}$table` ROW_FORMAT=Compressed");
|
||||
echo str_pad($prefix . $table, 32, ' ', STR_PAD_RIGHT) . " ... Compressed\n";
|
||||
}
|
||||
|
||||
@@ -189,7 +189,7 @@ if (!empty($options['info'])) {
|
||||
echo "SET GLOBAL innodb_file_per_table=1;\n";
|
||||
echo "SET GLOBAL innodb_file_format=Barracuda;\n";
|
||||
foreach ($fixtables as $table) {
|
||||
echo "ALTER TABLE {$prefix}$table ROW_FORMAT=Compressed;\n";
|
||||
echo "ALTER TABLE `{$prefix}$table` ROW_FORMAT=Compressed;\n";
|
||||
}
|
||||
echo "\n";
|
||||
exit(0);
|
||||
|
||||
@@ -3447,7 +3447,7 @@
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="hash" level="required"/>
|
||||
<PHP_EXTENSION name="fileinfo" level="required"/>
|
||||
<PHP_EXTENSION name="sodium" level="required"/>
|
||||
<PHP_EXTENSION name="sodium" level="optional"/>
|
||||
</PHP_EXTENSIONS>
|
||||
<PHP_SETTINGS>
|
||||
<PHP_SETTING name="memory_limit" value="96M" level="required">
|
||||
@@ -3527,6 +3527,8 @@
|
||||
<ON_CHECK message="sixtyfourbitswarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_max_input_vars" level="optional">
|
||||
</CUSTOM_CHECK>
|
||||
</CUSTOM_CHECKS>
|
||||
</MOODLE>
|
||||
</COMPATIBILITY_MATRIX>
|
||||
|
||||
@@ -45,7 +45,7 @@ list($options, $unrecognised) = cli_get_params(
|
||||
array(
|
||||
'stop-on-failure' => 0,
|
||||
'verbose' => false,
|
||||
'replace' => false,
|
||||
'replace' => '',
|
||||
'help' => false,
|
||||
'tags' => '',
|
||||
'profile' => '',
|
||||
@@ -70,7 +70,7 @@ $help = "
|
||||
Behat utilities to run behat tests in parallel
|
||||
|
||||
Usage:
|
||||
php run.php [--BEHAT_OPTION=\"value\"] [--feature=\"value\"] [--replace] [--fromrun=value --torun=value] [--help]
|
||||
php run.php [--BEHAT_OPTION=\"value\"] [--feature=\"value\"] [--replace=\"{run}\"] [--fromrun=value --torun=value] [--help]
|
||||
|
||||
Options:
|
||||
--BEHAT_OPTION Any combination of behat option specified in http://behat.readthedocs.org/en/v2.5/guides/6.cli.html
|
||||
@@ -144,9 +144,10 @@ $extraopts = $unrecognised;
|
||||
if ($options['profile']) {
|
||||
$profile = $options['profile'];
|
||||
|
||||
// If profile passed is not set, then exit.
|
||||
// If profile passed is not set, then exit (note we skip if the 'replace' option is found within the 'profile' value).
|
||||
if (!isset($CFG->behat_config[$profile]) && !isset($CFG->behat_profiles[$profile]) &&
|
||||
!(isset($options['replace']) && (strpos($options['profile'], $options['replace']) >= 0 ))) {
|
||||
!($options['replace'] && (strpos($profile, (string) $options['replace']) !== false))) {
|
||||
|
||||
echo "Invalid profile passed: " . $profile . PHP_EOL;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -189,7 +189,12 @@ class cohort_role_assignments_table extends table_sql {
|
||||
FROM {tool_cohortroles} uca
|
||||
JOIN {user} u ON u.id = uca.userid
|
||||
JOIN {cohort} c ON c.id = uca.cohortid";
|
||||
$params = array();
|
||||
|
||||
// Check if any additional filtering is required.
|
||||
[$sqlwhere, $params] = $this->get_sql_where();
|
||||
if ($sqlwhere) {
|
||||
$sql .= " WHERE {$sqlwhere}";
|
||||
}
|
||||
|
||||
// Add order by if needed.
|
||||
if (!$count && $sqlsort = $this->get_sql_sort()) {
|
||||
|
||||
@@ -86,8 +86,8 @@ if ($removeid) {
|
||||
|
||||
$title = get_string('existingcohortroles', 'tool_cohortroles');
|
||||
echo $output->heading($title);
|
||||
$url = new moodle_url('/admin/tool/cohortroles/index.php');
|
||||
$table = new tool_cohortroles\output\cohort_role_assignments_table(uniqid(), $url);
|
||||
|
||||
$table = new tool_cohortroles\output\cohort_role_assignments_table('cohort-role-assignments', $pageurl);
|
||||
echo $table->out(50, true);
|
||||
|
||||
echo $output->spacer();
|
||||
|
||||
@@ -37,67 +37,68 @@
|
||||
This template does not have an example context because it includes ajax functionality.
|
||||
}}
|
||||
<div data-region="user-competency-full-info" data-node="user-competency" data-competencyid="{{usercompetency.competencyid}}" data-userid="{{usercompetency.userid}}" data-region-id="{{uniqid}}">
|
||||
<div data-region="competency-summary">
|
||||
{{#competency}}
|
||||
{{> tool_lp/competency_summary }}
|
||||
{{/competency}}
|
||||
<dl>
|
||||
{{#usercompetency}}
|
||||
<dt>{{#str}}reviewstatus, tool_lp{{/str}}</dt>
|
||||
<dd data-region="user-competency-status">{{statusname}}
|
||||
<div data-region="competency-summary">
|
||||
{{#competency}}
|
||||
{{> tool_lp/competency_summary }}
|
||||
{{/competency}}
|
||||
<dl>
|
||||
{{#usercompetency}}
|
||||
<dt>{{#str}}reviewstatus, tool_lp{{/str}}</dt>
|
||||
<dd data-region="user-competency-status">{{statusname}}
|
||||
|
||||
{{#isstatusinreview}}
|
||||
- {{reviewer.fullname}}
|
||||
{{/isstatusinreview}}
|
||||
{{#isstatusinreview}}
|
||||
- {{reviewer.fullname}}
|
||||
{{/isstatusinreview}}
|
||||
|
||||
{{#isrequestreviewallowed}}<button class="btn btn-secondary" data-action="request-review">{{#str}}requestreview, tool_lp{{/str}}</button>{{/isrequestreviewallowed}}
|
||||
{{#iscancelreviewrequestallowed}}<button class="btn btn-secondary" data-action="cancel-review-request">{{#str}}cancelreviewrequest, tool_lp{{/str}}</button>{{/iscancelreviewrequestallowed}}
|
||||
{{#isstartreviewallowed}}<button class="btn btn-secondary" data-action="start-review">{{#str}}startreview, tool_lp{{/str}}</button>{{/isstartreviewallowed}}
|
||||
{{#isstopreviewallowed}}<button class="btn btn-secondary" data-action="stop-review">{{#str}}stopreview, tool_lp{{/str}}</button>{{/isstopreviewallowed}}
|
||||
</dd>
|
||||
<dt>{{#str}}proficient, tool_lp{{/str}}</dt>
|
||||
<dd>
|
||||
<span class="badge {{#proficiency}}badge-success{{/proficiency}}{{^proficiency}}badge-danger{{/proficiency}} float-left">
|
||||
{{proficiencyname}}
|
||||
</span>
|
||||
</dd>
|
||||
<dt>{{#str}}rating, tool_lp{{/str}}</dt>
|
||||
<dd>{{gradename}}
|
||||
{{#cangrade}}
|
||||
<button class="btn btn-secondary" id="rate_{{uniqid}}">{{#str}}rate, tool_lp{{/str}}</button>
|
||||
{{/cangrade}}
|
||||
</dd>
|
||||
{{#js}}
|
||||
require(['jquery', 'tool_lp/grade_user_competency_inline', 'tool_lp/user_competency_info', 'tool_lp/user_competency_workflow'], function($, mod, info, UserCompWorkflow) {
|
||||
{{#isrequestreviewallowed}}<button class="btn btn-secondary" data-action="request-review">{{#str}}requestreview, tool_lp{{/str}}</button>{{/isrequestreviewallowed}}
|
||||
{{#iscancelreviewrequestallowed}}<button class="btn btn-secondary" data-action="cancel-review-request">{{#str}}cancelreviewrequest, tool_lp{{/str}}</button>{{/iscancelreviewrequestallowed}}
|
||||
{{#isstartreviewallowed}}<button class="btn btn-secondary" data-action="start-review">{{#str}}startreview, tool_lp{{/str}}</button>{{/isstartreviewallowed}}
|
||||
{{#isstopreviewallowed}}<button class="btn btn-secondary" data-action="stop-review">{{#str}}stopreview, tool_lp{{/str}}</button>{{/isstopreviewallowed}}
|
||||
</dd>
|
||||
<dt>{{#str}}proficient, tool_lp{{/str}}</dt>
|
||||
<dd>
|
||||
<span class="badge {{#proficiency}}badge-success{{/proficiency}}{{^proficiency}}badge-danger{{/proficiency}} float-left">
|
||||
{{proficiencyname}}
|
||||
</span>
|
||||
</dd>
|
||||
<dt>{{#str}}rating, tool_lp{{/str}}</dt>
|
||||
<dd>{{gradename}}
|
||||
{{#cangrade}}
|
||||
<button class="btn btn-secondary" id="rate_{{uniqid}}">{{#str}}rate, tool_lp{{/str}}</button>
|
||||
{{/cangrade}}
|
||||
</dd>
|
||||
{{#js}}
|
||||
require(['jquery', 'tool_lp/grade_user_competency_inline', 'tool_lp/user_competency_info', 'tool_lp/user_competency_workflow'], function($, mod, info, UserCompWorkflow) {
|
||||
|
||||
var competencyElement = $('[data-region-id="{{uniqid}}"]');
|
||||
var infoReloader = new info(competencyElement, '{{competency.competency.id}}', '{{user.id}}');
|
||||
var competencyElement = $('[data-region-id="{{uniqid}}"]');
|
||||
var infoReloader = new info(competencyElement, '{{competency.competency.id}}', '{{user.id}}');
|
||||
|
||||
var ucw = new UserCompWorkflow();
|
||||
ucw.registerEvents('[data-region="user-competency-status"]');
|
||||
ucw.on('status-changed', infoReloader.reload.bind(infoReloader));
|
||||
ucw.on('error-occured', infoReloader.reload.bind(infoReloader));
|
||||
var ucw = new UserCompWorkflow();
|
||||
ucw.registerEvents('[data-region="user-competency-status"]');
|
||||
ucw.on('status-changed', infoReloader.reload.bind(infoReloader));
|
||||
ucw.on('error-occured', infoReloader.reload.bind(infoReloader));
|
||||
|
||||
var inlineGrader = new mod('#rate_{{uniqid}}', '{{competency.scaleid}}', '{{competency.competency.id}}', '{{user.id}}', '{{plan.id}}', '', '{{#str}}chooserating, tool_lp{{/str}}');
|
||||
inlineGrader.on('competencyupdated', infoReloader.reload.bind(infoReloader));
|
||||
});
|
||||
{{/js}}
|
||||
{{/usercompetency}}
|
||||
</dl>
|
||||
{{#commentarea}}
|
||||
{{#canpostorhascomments}}
|
||||
{{>tool_lp/comment_area}}
|
||||
{{/canpostorhascomments}}
|
||||
{{/commentarea}}
|
||||
<dl data-region="evidence-listing">
|
||||
<dt>{{#str}}evidence, tool_lp{{/str}}</dt>
|
||||
<dd>
|
||||
{{#evidence}}
|
||||
{{> tool_lp/evidence_summary }}
|
||||
{{/evidence}}
|
||||
{{^evidence}}
|
||||
<p>{{#str}}noevidence, tool_lp{{/str}}</p>
|
||||
{{/evidence}}
|
||||
</dd>
|
||||
</dl>
|
||||
var inlineGrader = new mod('#rate_{{uniqid}}', '{{competency.scaleid}}', '{{competency.competency.id}}', '{{user.id}}', '{{plan.id}}', '', '{{#str}}chooserating, tool_lp{{/str}}');
|
||||
inlineGrader.on('competencyupdated', infoReloader.reload.bind(infoReloader));
|
||||
});
|
||||
{{/js}}
|
||||
{{/usercompetency}}
|
||||
</dl>
|
||||
{{#commentarea}}
|
||||
{{#canpostorhascomments}}
|
||||
{{>tool_lp/comment_area}}
|
||||
{{/canpostorhascomments}}
|
||||
{{/commentarea}}
|
||||
<dl data-region="evidence-listing">
|
||||
<dt>{{#str}}evidence, tool_lp{{/str}}</dt>
|
||||
<dd>
|
||||
{{#evidence}}
|
||||
{{> tool_lp/evidence_summary }}
|
||||
{{/evidence}}
|
||||
{{^evidence}}
|
||||
<p>{{#str}}noevidence, tool_lp{{/str}}</p>
|
||||
{{/evidence}}
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+24
-22
@@ -170,32 +170,34 @@ function tool_mobile_myprofile_navigation(\core_user\output\myprofile\tree $tree
|
||||
}
|
||||
|
||||
// Check if the user is using the app, encouraging him to use it otherwise.
|
||||
$usertoken = tool_mobile_get_token($user->id);
|
||||
$mobilestrconnected = null;
|
||||
$mobilelastaccess = null;
|
||||
if ($iscurrentuser || is_siteadmin()) {
|
||||
$usertoken = tool_mobile_get_token($user->id);
|
||||
$mobilestrconnected = null;
|
||||
$mobilelastaccess = null;
|
||||
|
||||
if ($usertoken) {
|
||||
$mobilestrconnected = get_string('lastsiteaccess');
|
||||
if ($usertoken->lastaccess) {
|
||||
$mobilelastaccess = userdate($usertoken->lastaccess) . " (" . format_time(time() - $usertoken->lastaccess) . ")";
|
||||
// Logout link.
|
||||
$validtoken = empty($usertoken->validuntil) || time() < $usertoken->validuntil;
|
||||
if ($iscurrentuser && $validtoken) {
|
||||
$url = new moodle_url('/'.$CFG->admin.'/tool/mobile/logout.php', ['sesskey' => sesskey()]);
|
||||
$logoutlink = html_writer::link($url, get_string('logout'));
|
||||
$mobilelastaccess .= " ($logoutlink)";
|
||||
if ($usertoken) {
|
||||
$mobilestrconnected = get_string('lastsiteaccess');
|
||||
if ($usertoken->lastaccess) {
|
||||
$mobilelastaccess = userdate($usertoken->lastaccess) . " (" . format_time(time() - $usertoken->lastaccess) . ")";
|
||||
// Logout link.
|
||||
$validtoken = empty($usertoken->validuntil) || time() < $usertoken->validuntil;
|
||||
if ($iscurrentuser && $validtoken) {
|
||||
$url = new moodle_url('/'.$CFG->admin.'/tool/mobile/logout.php', ['sesskey' => sesskey()]);
|
||||
$logoutlink = html_writer::link($url, get_string('logout'));
|
||||
$mobilelastaccess .= " ($logoutlink)";
|
||||
}
|
||||
} else {
|
||||
// We should not reach this point.
|
||||
$mobilelastaccess = get_string("never");
|
||||
}
|
||||
} else {
|
||||
// We should not reach this point.
|
||||
$mobilelastaccess = get_string("never");
|
||||
} else if ($url = tool_mobile_create_app_download_url()) {
|
||||
$mobilestrconnected = get_string('mobileappenabled', 'tool_mobile', $url->out());
|
||||
}
|
||||
} else if ($url = tool_mobile_create_app_download_url()) {
|
||||
$mobilestrconnected = get_string('mobileappenabled', 'tool_mobile', $url->out());
|
||||
}
|
||||
|
||||
if ($mobilestrconnected) {
|
||||
$newnodes[] = new core_user\output\myprofile\node('mobile', 'mobileappnode', $mobilestrconnected, null, null,
|
||||
$mobilelastaccess);
|
||||
if ($mobilestrconnected) {
|
||||
$newnodes[] = new core_user\output\myprofile\node('mobile', 'mobileappnode', $mobilestrconnected, null, null,
|
||||
$mobilelastaccess);
|
||||
}
|
||||
}
|
||||
|
||||
// Add nodes, if any.
|
||||
|
||||
@@ -310,11 +310,10 @@ class profile_manager {
|
||||
'CURLOPT_HEADER' => 0,
|
||||
];
|
||||
$content = $curl->get($url, null, $options);
|
||||
$errno = $curl->get_errno();
|
||||
$info = $curl->get_info();
|
||||
|
||||
// The base cURL seems fine, let's press on.
|
||||
if (!$errno) {
|
||||
if (!$curl->get_errno() && !$curl->error) {
|
||||
// WebFinger gave us a 404 back so the user has no droids here.
|
||||
if ($info['http_code'] >= 400) {
|
||||
if ($info['http_code'] === 404) {
|
||||
|
||||
@@ -438,17 +438,7 @@ class manager {
|
||||
$filename = 'tour_export_' . $tour->get_id() . '_' . time() . '.json';
|
||||
|
||||
// Force download.
|
||||
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', time()) . ' GMT');
|
||||
header('Cache-Control: private, must-revalidate, pre-check=0, post-check=0, max-age=0');
|
||||
header('Expires: ' . gmdate('D, d M Y H:i:s', 0) . 'GMT');
|
||||
header('Pragma: no-cache');
|
||||
header('Accept-Ranges: none');
|
||||
header('Content-disposition: attachment; filename=' . $filename);
|
||||
header('Content-length: ' . strlen($exportstring));
|
||||
header('Content-type: text/calendar; charset=utf-8');
|
||||
|
||||
echo $exportstring;
|
||||
die;
|
||||
send_file($exportstring, $filename, 0, 0, true, true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -178,6 +178,33 @@ class prediction {
|
||||
\core\event\prediction_action_started::create($eventdata)->trigger();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the executed actions.
|
||||
*
|
||||
* Actions could be filtered by actionname.
|
||||
*
|
||||
* @param array $actionnamefilter Limit the results obtained to this list of action names.
|
||||
* @param int $userid the user id. Current user by default.
|
||||
* @return array of actions.
|
||||
*/
|
||||
public function get_executed_actions(array $actionnamefilter = null, int $userid = 0): array {
|
||||
global $USER, $DB;
|
||||
|
||||
$conditions[] = "predictionid = :predictionid";
|
||||
$params['predictionid'] = $this->get_prediction_data()->id;
|
||||
if (!$userid) {
|
||||
$userid = $USER->id;
|
||||
}
|
||||
$conditions[] = "userid = :userid";
|
||||
$params['userid'] = $userid;
|
||||
if ($actionnamefilter) {
|
||||
list($actionsql, $actionparams) = $DB->get_in_or_equal($actionnamefilter, SQL_PARAMS_NAMED);
|
||||
$conditions[] = "actionname $actionsql";
|
||||
$params = $params + $actionparams;
|
||||
}
|
||||
return $DB->get_records_select('analytics_prediction_actions', implode(' AND ', $conditions), $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* format_calculations
|
||||
*
|
||||
|
||||
@@ -112,6 +112,86 @@ class analytics_prediction_actions_testcase extends advanced_testcase {
|
||||
$this->assertEquals(2, $DB->count_records('analytics_prediction_actions'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for test_get_executed_actions.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function execute_actions_provider(): array {
|
||||
return [
|
||||
'Empty actions with no filter' => [
|
||||
[],
|
||||
[],
|
||||
0
|
||||
],
|
||||
'Empty actions with filter' => [
|
||||
[],
|
||||
[\core_analytics\prediction::ACTION_FIXED],
|
||||
0
|
||||
],
|
||||
'Multiple actions with no filter' => [
|
||||
[
|
||||
\core_analytics\prediction::ACTION_FIXED,
|
||||
\core_analytics\prediction::ACTION_FIXED,
|
||||
\core_analytics\prediction::ACTION_INCORRECTLY_FLAGGED
|
||||
],
|
||||
[],
|
||||
3
|
||||
],
|
||||
'Multiple actions applying filter' => [
|
||||
[
|
||||
\core_analytics\prediction::ACTION_FIXED,
|
||||
\core_analytics\prediction::ACTION_FIXED,
|
||||
\core_analytics\prediction::ACTION_INCORRECTLY_FLAGGED
|
||||
],
|
||||
[\core_analytics\prediction::ACTION_FIXED],
|
||||
2
|
||||
],
|
||||
'Multiple actions not applying filter' => [
|
||||
[
|
||||
\core_analytics\prediction::ACTION_FIXED,
|
||||
\core_analytics\prediction::ACTION_FIXED,
|
||||
\core_analytics\prediction::ACTION_INCORRECTLY_FLAGGED
|
||||
],
|
||||
[\core_analytics\prediction::ACTION_NOT_APPLICABLE],
|
||||
0
|
||||
],
|
||||
'Multiple actions with multiple filter' => [
|
||||
[
|
||||
\core_analytics\prediction::ACTION_FIXED,
|
||||
\core_analytics\prediction::ACTION_FIXED,
|
||||
\core_analytics\prediction::ACTION_INCORRECTLY_FLAGGED
|
||||
],
|
||||
[\core_analytics\prediction::ACTION_FIXED, \core_analytics\prediction::ACTION_INCORRECTLY_FLAGGED],
|
||||
3
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests for get_executed_actions() function.
|
||||
*
|
||||
* @dataProvider execute_actions_provider
|
||||
* @param array $actionstoexecute An array of actions to execute
|
||||
* @param array $actionnamefilter Actions to filter
|
||||
* @param int $returned Number of actions returned
|
||||
*
|
||||
* @covers \core_analytics\prediction::get_executed_actions
|
||||
*/
|
||||
public function test_get_executed_actions(array $actionstoexecute, array $actionnamefilter, int $returned) {
|
||||
|
||||
$this->setUser($this->teacher2);
|
||||
list($ignored, $predictions) = $this->model->get_predictions($this->context, true);
|
||||
$prediction = reset($predictions);
|
||||
$target = $this->model->get_target();
|
||||
foreach($actionstoexecute as $action) {
|
||||
$prediction->action_executed($action, $target);
|
||||
}
|
||||
|
||||
$filteredactions = $prediction->get_executed_actions($actionnamefilter);
|
||||
$this->assertCount($returned, $filteredactions);
|
||||
}
|
||||
|
||||
/**
|
||||
* test_get_predictions
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
This files describes API changes in analytics sub system,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
=== 3.10.4 ===
|
||||
|
||||
* A new function get_executed_actions() has been added to \core_analytics\prediction class
|
||||
to get all (or filtered by action name) executed actions of a prediction
|
||||
|
||||
=== 3.8 ===
|
||||
|
||||
* "Time-splitting method" have been replaced by "Analysis interval" for the language strings that are
|
||||
|
||||
@@ -45,7 +45,7 @@ $string['auth_dbname'] = 'Name of the database itself. Leave empty if using an O
|
||||
$string['auth_dbname_key'] = 'DB name';
|
||||
$string['auth_dbpass'] = 'Password matching the above username';
|
||||
$string['auth_dbpass_key'] = 'Password';
|
||||
$string['auth_dbpasstype'] = '<p>Specify the format that the password field is using.</p> <p>Use \'internal\' if you want the external database to manage usernames and email addresses, but Moodle to manage passwords. If you use \'internal\', you <i>must</i> provide a populated email address field in the external database, and you must execute both admin/cron.php and auth/db/cli/sync_users.php regularly. Moodle will send an email to new users with a temporary password.</p>';
|
||||
$string['auth_dbpasstype'] = '<p>Specify the format that the password field is using.</p> <p>Use \'internal\' if you want the external database to manage usernames and email addresses, but Moodle to manage passwords. If you use \'internal\', you must provide a populated email address field in the external database, and you must enable the \auth_db\task\sync_users scheduled task. Moodle will send an email to new users with a temporary password.</p>';
|
||||
$string['auth_dbpasstype_key'] = 'Password format';
|
||||
$string['auth_dbreviveduser'] = 'Revived user {$a->name} id {$a->id}';
|
||||
$string['auth_dbrevivedusererror'] = 'Error reviving user {$a}';
|
||||
|
||||
@@ -75,7 +75,7 @@ $string['auth_ldap_passwdexpire_settings'] = 'LDAP password expiry settings';
|
||||
$string['auth_ldap_preventpassindb'] = 'Select yes to prevent passwords from being stored in Moodle\'s DB.';
|
||||
$string['auth_ldap_preventpassindb_key'] = 'Prevent password caching';
|
||||
$string['auth_ldap_rolecontext'] = '{$a->localname} context';
|
||||
$string['auth_ldap_rolecontext_help'] = 'LDAP context used to select for <i>{$a->localname}</i> mapping. Separate multiple groups with \';\'. Usually something like "cn={$a->shortname},ou=staff,o=myorg".';
|
||||
$string['auth_ldap_rolecontext_help'] = 'LDAP context used to select for <i>{$a->localname}</i> mapping. Separate multiple groups with \';\'. Usually something like "cn={$a->shortname},ou=first-ou-with-role-groups,o=myorg; cn={$a->shortname},ou=second-ou-with-role-groups,o=myorg".';
|
||||
$string['auth_ldap_search_sub'] = 'Search users from subcontexts.';
|
||||
$string['auth_ldap_search_sub_key'] = 'Search subcontexts';
|
||||
$string['auth_ldap_server_settings'] = 'LDAP server settings';
|
||||
|
||||
+1
-3
@@ -710,9 +710,7 @@ class auth_plugin_mnet extends auth_plugin_base {
|
||||
|
||||
foreach($superArray as $subArray) {
|
||||
$subArray = array_values($subArray);
|
||||
$instring = "('".implode("', '",$subArray)."')";
|
||||
$query = "select id, session_id, username from {mnet_session} where username in $instring";
|
||||
$results = $DB->get_records_sql($query);
|
||||
$results = $DB->get_records_list('mnet_session', 'username', $subArray, '', 'id, session_id, username');
|
||||
|
||||
if ($results == false) {
|
||||
// We seem to have a username that breaks our query:
|
||||
|
||||
@@ -290,9 +290,9 @@ abstract class info {
|
||||
*/
|
||||
protected function warn_about_invalid_availability(\coding_exception $e) {
|
||||
$name = $this->get_thing_name();
|
||||
// If it occurs while building modinfo based on somebody calling $cm->name,
|
||||
// we can't get $cm->name, and this line will cause a warning.
|
||||
$htmlname = @$this->format_info($name, $this->course);
|
||||
$htmlname = $this->format_info($name, $this->course);
|
||||
// Because we call format_info here, likely in the middle of building dynamic data for the
|
||||
// activity, there could be a chance that the name might not be available.
|
||||
if ($htmlname === '') {
|
||||
// So instead use the numbers (cmid) from the tag.
|
||||
$htmlname = preg_replace('~[^0-9]~', '', $name);
|
||||
@@ -739,11 +739,11 @@ abstract class info {
|
||||
$info = preg_replace_callback('~<AVAILABILITY_CMNAME_([0-9]+)/>~',
|
||||
function($matches) use($modinfo, $context) {
|
||||
$cm = $modinfo->get_cm($matches[1]);
|
||||
if ($cm->has_view() and $cm->uservisible) {
|
||||
if ($cm->has_view() and $cm->get_user_visible()) {
|
||||
// Help student by providing a link to the module which is preventing availability.
|
||||
return \html_writer::link($cm->url, format_string($cm->name, true, array('context' => $context)));
|
||||
return \html_writer::link($cm->get_url(), format_string($cm->get_name(), true, ['context' => $context]));
|
||||
} else {
|
||||
return format_string($cm->name, true, array('context' => $context));
|
||||
return format_string($cm->get_name(), true, ['context' => $context]);
|
||||
}
|
||||
}, $info);
|
||||
|
||||
|
||||
@@ -511,4 +511,33 @@ class info_testcase extends advanced_testcase {
|
||||
sort($result);
|
||||
$this->assertEquals($expected, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the info_module class when involved in a recursive call to $cm->name.
|
||||
*/
|
||||
public function test_info_recursive_name_call() {
|
||||
global $DB;
|
||||
|
||||
$this->resetAfterTest();
|
||||
|
||||
// Create a course and page.
|
||||
$generator = $this->getDataGenerator();
|
||||
$course = $generator->create_course();
|
||||
$page1 = $generator->create_module('page', ['course' => $course->id, 'name' => 'Page1']);
|
||||
|
||||
// Set invalid availability.
|
||||
$DB->set_field('course_modules', 'availability', 'not valid', ['id' => $page1->cmid]);
|
||||
|
||||
// Get the cm_info object.
|
||||
$this->setAdminUser();
|
||||
$modinfo = get_fast_modinfo($course);
|
||||
$cm1 = $modinfo->get_cm($page1->cmid);
|
||||
|
||||
// At this point we will generate dynamic data for $cm1, which will cause the debugging
|
||||
// call below.
|
||||
$this->assertEquals('Page1', $cm1->name);
|
||||
|
||||
$this->assertDebuggingCalled('Error processing availability data for ' .
|
||||
'‘Page1’: Invalid availability text');
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+17
-8
@@ -198,8 +198,11 @@ M.core_availability.form = {
|
||||
// If the groupmode and grouping id aren't set, disable it.
|
||||
var groupmode = Y.one('#id_groupmode');
|
||||
var groupingid = Y.one('#id_groupingid');
|
||||
if ((!groupmode || Number(groupmode.get('value')) === 0) &&
|
||||
(!groupingid || Number(groupingid.get('value')) === 0)) {
|
||||
var groupavailability = Number(this.restrictByGroup.getData('groupavailability')) === 1;
|
||||
var groupingavailability = Number(this.restrictByGroup.getData('groupingavailability')) === 1;
|
||||
|
||||
if ((!groupmode || Number(groupmode.get('value')) === 0 || !groupavailability) &&
|
||||
(!groupingid || Number(groupingid.get('value')) === 0 || !groupingavailability)) {
|
||||
this.restrictByGroup.set('disabled', true);
|
||||
return;
|
||||
}
|
||||
@@ -220,22 +223,28 @@ M.core_availability.form = {
|
||||
e.preventDefault();
|
||||
|
||||
// Add the condition.
|
||||
var groupmode = Y.one('#id_groupmode');
|
||||
var groupingid = Y.one('#id_groupingid');
|
||||
var groupavailability = Number(this.restrictByGroup.getData('groupavailability')) === 1;
|
||||
var groupingavailability = Number(this.restrictByGroup.getData('groupingavailability')) === 1;
|
||||
|
||||
var newChild;
|
||||
if (groupingid && Number(groupingid.get('value')) !== 0) {
|
||||
if (groupingid && Number(groupingid.get('value')) !== 0 && groupingavailability) {
|
||||
// Add a grouping restriction if one is specified.
|
||||
newChild = new M.core_availability.Item(
|
||||
{type: 'grouping', id: Number(groupingid.get('value'))}, true);
|
||||
} else {
|
||||
} else if (groupmode && groupavailability) {
|
||||
// Otherwise just add a group restriction.
|
||||
newChild = new M.core_availability.Item({type: 'group'}, true);
|
||||
}
|
||||
|
||||
// Refresh HTML.
|
||||
this.rootList.addChild(newChild);
|
||||
this.update();
|
||||
this.rootList.renumber();
|
||||
this.rootList.updateHtml();
|
||||
if (newChild !== null) {
|
||||
this.rootList.addChild(newChild);
|
||||
this.update();
|
||||
this.rootList.renumber();
|
||||
this.rootList.updateHtml();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+3
-3
File diff suppressed because one or more lines are too long
+17
-8
@@ -198,8 +198,11 @@ M.core_availability.form = {
|
||||
// If the groupmode and grouping id aren't set, disable it.
|
||||
var groupmode = Y.one('#id_groupmode');
|
||||
var groupingid = Y.one('#id_groupingid');
|
||||
if ((!groupmode || Number(groupmode.get('value')) === 0) &&
|
||||
(!groupingid || Number(groupingid.get('value')) === 0)) {
|
||||
var groupavailability = Number(this.restrictByGroup.getData('groupavailability')) === 1;
|
||||
var groupingavailability = Number(this.restrictByGroup.getData('groupingavailability')) === 1;
|
||||
|
||||
if ((!groupmode || Number(groupmode.get('value')) === 0 || !groupavailability) &&
|
||||
(!groupingid || Number(groupingid.get('value')) === 0 || !groupingavailability)) {
|
||||
this.restrictByGroup.set('disabled', true);
|
||||
return;
|
||||
}
|
||||
@@ -220,22 +223,28 @@ M.core_availability.form = {
|
||||
e.preventDefault();
|
||||
|
||||
// Add the condition.
|
||||
var groupmode = Y.one('#id_groupmode');
|
||||
var groupingid = Y.one('#id_groupingid');
|
||||
var groupavailability = Number(this.restrictByGroup.getData('groupavailability')) === 1;
|
||||
var groupingavailability = Number(this.restrictByGroup.getData('groupingavailability')) === 1;
|
||||
|
||||
var newChild;
|
||||
if (groupingid && Number(groupingid.get('value')) !== 0) {
|
||||
if (groupingid && Number(groupingid.get('value')) !== 0 && groupingavailability) {
|
||||
// Add a grouping restriction if one is specified.
|
||||
newChild = new M.core_availability.Item(
|
||||
{type: 'grouping', id: Number(groupingid.get('value'))}, true);
|
||||
} else {
|
||||
} else if (groupmode && groupavailability) {
|
||||
// Otherwise just add a group restriction.
|
||||
newChild = new M.core_availability.Item({type: 'group'}, true);
|
||||
}
|
||||
|
||||
// Refresh HTML.
|
||||
this.rootList.addChild(newChild);
|
||||
this.update();
|
||||
this.rootList.renumber();
|
||||
this.rootList.updateHtml();
|
||||
if (newChild !== null) {
|
||||
this.rootList.addChild(newChild);
|
||||
this.update();
|
||||
this.rootList.renumber();
|
||||
this.rootList.updateHtml();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Vendored
+17
-8
@@ -196,8 +196,11 @@ M.core_availability.form = {
|
||||
// If the groupmode and grouping id aren't set, disable it.
|
||||
var groupmode = Y.one('#id_groupmode');
|
||||
var groupingid = Y.one('#id_groupingid');
|
||||
if ((!groupmode || Number(groupmode.get('value')) === 0) &&
|
||||
(!groupingid || Number(groupingid.get('value')) === 0)) {
|
||||
var groupavailability = Number(this.restrictByGroup.getData('groupavailability')) === 1;
|
||||
var groupingavailability = Number(this.restrictByGroup.getData('groupingavailability')) === 1;
|
||||
|
||||
if ((!groupmode || Number(groupmode.get('value')) === 0 || !groupavailability) &&
|
||||
(!groupingid || Number(groupingid.get('value')) === 0 || !groupingavailability)) {
|
||||
this.restrictByGroup.set('disabled', true);
|
||||
return;
|
||||
}
|
||||
@@ -218,22 +221,28 @@ M.core_availability.form = {
|
||||
e.preventDefault();
|
||||
|
||||
// Add the condition.
|
||||
var groupmode = Y.one('#id_groupmode');
|
||||
var groupingid = Y.one('#id_groupingid');
|
||||
var groupavailability = Number(this.restrictByGroup.getData('groupavailability')) === 1;
|
||||
var groupingavailability = Number(this.restrictByGroup.getData('groupingavailability')) === 1;
|
||||
|
||||
var newChild;
|
||||
if (groupingid && Number(groupingid.get('value')) !== 0) {
|
||||
if (groupingid && Number(groupingid.get('value')) !== 0 && groupingavailability) {
|
||||
// Add a grouping restriction if one is specified.
|
||||
newChild = new M.core_availability.Item(
|
||||
{type: 'grouping', id: Number(groupingid.get('value'))}, true);
|
||||
} else {
|
||||
} else if (groupmode && groupavailability) {
|
||||
// Otherwise just add a group restriction.
|
||||
newChild = new M.core_availability.Item({type: 'group'}, true);
|
||||
}
|
||||
|
||||
// Refresh HTML.
|
||||
this.rootList.addChild(newChild);
|
||||
this.update();
|
||||
this.rootList.renumber();
|
||||
this.rootList.updateHtml();
|
||||
if (newChild !== null) {
|
||||
this.rootList.addChild(newChild);
|
||||
this.update();
|
||||
this.rootList.renumber();
|
||||
this.rootList.updateHtml();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -4055,9 +4055,30 @@ class restore_contentbankcontent_structure_step extends restore_structure_step {
|
||||
$exists = $DB->record_exists('contentbank_content', $params);
|
||||
if (!$exists) {
|
||||
$params['configdata'] = $data->configdata;
|
||||
$params['usercreated'] = $this->get_mappingid('user', $data->usercreated);
|
||||
$params['usermodified'] = $this->get_mappingid('user', $data->usermodified);
|
||||
$params['timemodified'] = time();
|
||||
|
||||
// Trying to map users. Users cannot always be mapped, e.g. when copying.
|
||||
$params['usercreated'] = $this->get_mappingid('user', $data->usercreated);
|
||||
if (!$params['usercreated']) {
|
||||
// Leave the content creator unchanged when we are restoring the same site.
|
||||
// Otherwise use current user id.
|
||||
if ($this->task->is_samesite()) {
|
||||
$params['usercreated'] = $data->usercreated;
|
||||
} else {
|
||||
$params['usercreated'] = $this->task->get_userid();
|
||||
}
|
||||
}
|
||||
$params['usermodified'] = $this->get_mappingid('user', $data->usermodified);
|
||||
if (!$params['usermodified']) {
|
||||
// Leave the content modifier unchanged when we are restoring the same site.
|
||||
// Otherwise use current user id.
|
||||
if ($this->task->is_samesite()) {
|
||||
$params['usermodified'] = $data->usermodified;
|
||||
} else {
|
||||
$params['usermodified'] = $this->task->get_userid();
|
||||
}
|
||||
}
|
||||
|
||||
$newitemid = $DB->insert_record('contentbank_content', $params);
|
||||
$this->set_mapping('contentbank_content', $oldid, $newitemid, true);
|
||||
}
|
||||
|
||||
@@ -278,6 +278,73 @@ class core_backup_automated_backup_testcase extends advanced_testcase {
|
||||
$this->assertTrue($skipped);
|
||||
$this->expectOutputRegex("/Skipping $course->fullname \(Not modified since previous backup\)/");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the task completes when coureid is missing.
|
||||
*/
|
||||
public function test_task_complete_when_courseid_is_missing() {
|
||||
global $DB;
|
||||
$admin = get_admin();
|
||||
$classobject = $this->backupcronautomatedhelper->return_this();
|
||||
|
||||
// Create this backup course.
|
||||
$backupcourse = new stdClass;
|
||||
$backupcourse->courseid = $this->course->id;
|
||||
$backupcourse->laststatus = backup_cron_automated_helper::BACKUP_STATUS_NOTYETRUN;
|
||||
$DB->insert_record('backup_courses', $backupcourse);
|
||||
$backupcourse = $DB->get_record('backup_courses', ['courseid' => $this->course->id]);
|
||||
|
||||
// Create a backup task.
|
||||
$method = new ReflectionMethod('\backup_cron_automated_helper', 'push_course_backup_adhoc_task');
|
||||
$method->setAccessible(true); // Allow accessing of private method.
|
||||
$method->invokeArgs($classobject, [$backupcourse, $admin]);
|
||||
|
||||
// Delete course for this test.
|
||||
delete_course($this->course->id, false);
|
||||
|
||||
$task = core\task\manager::get_next_adhoc_task(time());
|
||||
|
||||
ob_start();
|
||||
$task->execute();
|
||||
$output = ob_get_clean();
|
||||
|
||||
$this->assertStringContainsString('Invalid course id: ' . $this->course->id . ', task aborted.', $output);
|
||||
core\task\manager::adhoc_task_complete($task);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the task completes when backup course is missing.
|
||||
*/
|
||||
public function test_task_complete_when_backup_course_is_missing() {
|
||||
global $DB;
|
||||
$admin = get_admin();
|
||||
$classobject = $this->backupcronautomatedhelper->return_this();
|
||||
|
||||
// Create this backup course.
|
||||
$backupcourse = new stdClass;
|
||||
$backupcourse->courseid = $this->course->id;
|
||||
$backupcourse->laststatus = backup_cron_automated_helper::BACKUP_STATUS_NOTYETRUN;
|
||||
$DB->insert_record('backup_courses', $backupcourse);
|
||||
$backupcourse = $DB->get_record('backup_courses', ['courseid' => $this->course->id]);
|
||||
|
||||
// Create a backup task.
|
||||
$method = new ReflectionMethod('\backup_cron_automated_helper', 'push_course_backup_adhoc_task');
|
||||
$method->setAccessible(true); // Allow accessing of private method.
|
||||
$method->invokeArgs($classobject, [$backupcourse, $admin]);
|
||||
|
||||
// Delete backup course for this test.
|
||||
$DB->delete_records('backup_courses', ['courseid' => $this->course->id]);
|
||||
|
||||
$task = core\task\manager::get_next_adhoc_task(time());
|
||||
|
||||
ob_start();
|
||||
$task->execute();
|
||||
$output = ob_get_clean();
|
||||
|
||||
$this->assertStringContainsString('Automated backup for course: ' . $this->course->fullname . ' encounters an error.',
|
||||
$output);
|
||||
core\task\manager::adhoc_task_complete($task);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
This files describes API changes in /backup/*,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
=== 4.0 ===
|
||||
=== 3.10 ===
|
||||
* Local plugins can now hook into a backup and restore process of grade items by
|
||||
using define_grade_item_plugin_structure method (See MDL-69418).
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ if (!is_null($action)) {
|
||||
} else { // Revoked badge.
|
||||
header("HTTP/1.0 410 Gone");
|
||||
$assertion = array();
|
||||
if ($obversion == OPEN_BADGES_V2) {
|
||||
if ($obversion >= OPEN_BADGES_V2) {
|
||||
$assertionurl = new moodle_url('/badges/assertion.php', array('b' => $hash));
|
||||
$assertion['id'] = $assertionurl->out();
|
||||
}
|
||||
|
||||
@@ -43,6 +43,10 @@ if ($persistedissuer) {
|
||||
$returnurl = new moodle_url('/badges/backpack-connect.php',
|
||||
['action' => 'authorization', 'sesskey' => sesskey(), 'backpackid' => $backpackid]);
|
||||
|
||||
// If scope is not passed as parameter, use the issuer supported scopes.
|
||||
if (empty($scope)) {
|
||||
$scope = $issuer->get('scopessupported');
|
||||
}
|
||||
$client = new core_badges\oauth2\client($issuer, $returnurl, $scope, $externalbackpack);
|
||||
if ($client) {
|
||||
if (!$client->is_logged_in()) {
|
||||
|
||||
@@ -128,7 +128,7 @@ class core_badges_assertion {
|
||||
$email = empty($this->_data->backpackemail) ? $this->_data->email : $this->_data->backpackemail;
|
||||
$assertionurl = new moodle_url('/badges/assertion.php', array('b' => $hash, 'obversion' => $this->_obversion));
|
||||
|
||||
if ($this->_obversion == OPEN_BADGES_V2) {
|
||||
if ($this->_obversion >= OPEN_BADGES_V2) {
|
||||
$classurl = new moodle_url('/badges/badge_json.php', array('id' => $this->get_badge_id()));
|
||||
} else {
|
||||
$classurl = new moodle_url('/badges/assertion.php', array('b' => $hash, 'action' => 1));
|
||||
@@ -325,7 +325,7 @@ class core_badges_assertion {
|
||||
*/
|
||||
protected function embed_data_badge_version2 (&$json, $type = OPEN_BADGES_V2_TYPE_ASSERTION) {
|
||||
// Specification Version 2.0.
|
||||
if ($this->_obversion == OPEN_BADGES_V2) {
|
||||
if ($this->_obversion >= OPEN_BADGES_V2) {
|
||||
$badge = new badge($this->_data->id);
|
||||
if (empty($this->_data->courseid)) {
|
||||
$context = context_system::instance();
|
||||
|
||||
@@ -56,12 +56,12 @@ class external_backpack extends \moodleform {
|
||||
$mform->addElement('text', 'backpackapiurl', get_string('backpackapiurl', 'core_badges'));
|
||||
$mform->setType('backpackapiurl', PARAM_URL);
|
||||
$mform->addRule('backpackapiurl', null, 'required', null, 'client');
|
||||
$mform->addRule('backpackapiurl', get_string('maximumchars', '', 255), 'maxlength', 50, 'client');
|
||||
$mform->addRule('backpackapiurl', get_string('maximumchars', '', 255), 'maxlength', 255, 'client');
|
||||
|
||||
$mform->addElement('text', 'backpackweburl', get_string('backpackweburl', 'core_badges'));
|
||||
$mform->setType('backpackweburl', PARAM_URL);
|
||||
$mform->addRule('backpackweburl', null, 'required', null, 'client');
|
||||
$mform->addRule('backpackweburl', get_string('maximumchars', '', 255), 'maxlength', 50, 'client');
|
||||
$mform->addRule('backpackweburl', get_string('maximumchars', '', 255), 'maxlength', 255, 'client');
|
||||
|
||||
$apiversions = badges_get_badge_api_versions();
|
||||
$mform->addElement('select', 'apiversion', get_string('apiversion', 'core_badges'), $apiversions);
|
||||
|
||||
@@ -222,6 +222,7 @@ class client extends \core\oauth2\client {
|
||||
$callbackurl = self::callback_url();
|
||||
|
||||
if ($granttype == 'authorization_code') {
|
||||
$this->basicauth = true;
|
||||
$params = array('code' => $code,
|
||||
'grant_type' => $granttype,
|
||||
'redirect_uri' => $callbackurl->out(false),
|
||||
@@ -236,7 +237,7 @@ class client extends \core\oauth2\client {
|
||||
);
|
||||
}
|
||||
if ($this->basicauth) {
|
||||
$idsecret = urlencode($this->clientid) . ':' . urlencode($this->clientsecret);
|
||||
$idsecret = $this->clientid . ':' . $this->clientsecret;
|
||||
$this->setHeader('Authorization: Basic ' . base64_encode($idsecret));
|
||||
} else {
|
||||
$params['client_id'] = $this->clientid;
|
||||
@@ -244,11 +245,13 @@ class client extends \core\oauth2\client {
|
||||
}
|
||||
// Requests can either use http GET or POST.
|
||||
$response = $this->post($this->token_url(), $this->build_post_data($params));
|
||||
$r = json_decode($response);
|
||||
if ($this->info['http_code'] !== 200) {
|
||||
throw new moodle_exception('Could not upgrade oauth token');
|
||||
$debuginfo = !empty($this->error) ? $this->error : $response;
|
||||
throw new moodle_exception('oauth2refreshtokenerror', 'core_error', '', $this->info['http_code'], $debuginfo);
|
||||
}
|
||||
|
||||
$r = json_decode($response);
|
||||
|
||||
if (is_null($r)) {
|
||||
throw new moodle_exception("Could not decode JSON token response");
|
||||
}
|
||||
|
||||
@@ -240,13 +240,23 @@ class award_criteria_cohort extends award_criteria {
|
||||
return array($join, $where, $params);
|
||||
} else {
|
||||
// User is a member of ALL of the specified cohorts.
|
||||
$join = " LEFT JOIN {cohort_members} cm ON cm.userid = u.id";
|
||||
$join = ' LEFT JOIN {cohort_members} cm ON cm.userid = u.id';
|
||||
$where = ' AND (';
|
||||
$i = 0;
|
||||
foreach ($this->params as $param) {
|
||||
$i++;
|
||||
$where = ' AND cm.cohortid = :cohortid'.$i;
|
||||
if ($i == 0) {
|
||||
$where .= 'cm.cohortid = :cohortid'.$i;
|
||||
} else {
|
||||
$where .= ' OR cm.cohortid = :cohortid'.$i;
|
||||
}
|
||||
$params['cohortid'.$i] = $param['cohort'];
|
||||
$i++;
|
||||
}
|
||||
$where .= ')
|
||||
GROUP BY u.id, bi.badgeid
|
||||
HAVING COUNT(cm.cohortid) = :cohortcount';
|
||||
$params['cohortcount'] = $i;
|
||||
|
||||
return array($join, $where, $params);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -624,35 +624,127 @@ class core_badges_badgeslib_testcase extends advanced_testcase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test badges observer when cohort_member_added event is fired.
|
||||
* Test badges observer when cohort_member_added event is fired and user required to belong to any cohort.
|
||||
*
|
||||
* @covers award_criteria_cohort
|
||||
*/
|
||||
public function test_badges_observer_cohort_criteria_review() {
|
||||
public function test_badges_observer_any_cohort_criteria_review() {
|
||||
global $CFG;
|
||||
|
||||
require_once("$CFG->dirroot/cohort/lib.php");
|
||||
|
||||
$cohort = $this->getDataGenerator()->create_cohort();
|
||||
$cohort1 = $this->getDataGenerator()->create_cohort();
|
||||
$cohort2 = $this->getDataGenerator()->create_cohort();
|
||||
|
||||
$this->preventResetByRollback(); // Messaging is not compatible with transactions.
|
||||
|
||||
$badge = new badge($this->badgeid);
|
||||
$this->assertFalse($badge->is_issued($this->user->id));
|
||||
$this->assertSame(0, $badge->review_all_criteria()); // Verify award_criteria_cohort->get_completed_criteria_sql().
|
||||
|
||||
// Set up the badge criteria.
|
||||
$criteriaoverall = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_OVERALL, 'badgeid' => $badge->id));
|
||||
$criteriaoverall->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ANY));
|
||||
$criteriaoverall1 = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_COHORT, 'badgeid' => $badge->id));
|
||||
$criteriaoverall1->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ANY, 'cohort_cohorts' => array('0' => $cohort->id)));
|
||||
|
||||
// Make the badge active.
|
||||
$criteriaoverall1->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ANY,
|
||||
'cohort_cohorts' => array('0' => $cohort1->id, '1' => $cohort2->id)));
|
||||
$badge->set_status(BADGE_STATUS_ACTIVE);
|
||||
|
||||
// Reload it to contain criteria.
|
||||
$badge = new badge($this->badgeid);
|
||||
$this->assertFalse($badge->is_issued($this->user->id));
|
||||
$this->assertSame(0, $badge->review_all_criteria()); // Verify award_criteria_cohort->get_completed_criteria_sql().
|
||||
|
||||
// Add the user to the cohort.
|
||||
cohort_add_member($cohort->id, $this->user->id);
|
||||
cohort_add_member($cohort2->id, $this->user->id);
|
||||
$this->assertDebuggingCalled();
|
||||
|
||||
// Verify that the badge was awarded.
|
||||
$this->assertDebuggingCalled();
|
||||
$this->assertTrue($badge->is_issued($this->user->id));
|
||||
// As the badge has been awarded to user because core_badges_observer been called when the member has been added to the
|
||||
// cohort, there are no other users that can award this badge.
|
||||
$this->assertSame(0, $badge->review_all_criteria()); // Verify award_criteria_cohort->get_completed_criteria_sql().
|
||||
}
|
||||
|
||||
/**
|
||||
* Test badges observer when cohort_member_added event is fired and user required to belong to multiple (all) cohorts.
|
||||
*
|
||||
* @covers award_criteria_cohort
|
||||
*/
|
||||
public function test_badges_observer_all_cohort_criteria_review() {
|
||||
global $CFG;
|
||||
|
||||
require_once("$CFG->dirroot/cohort/lib.php");
|
||||
|
||||
$cohort1 = $this->getDataGenerator()->create_cohort();
|
||||
$cohort2 = $this->getDataGenerator()->create_cohort();
|
||||
$cohort3 = $this->getDataGenerator()->create_cohort();
|
||||
|
||||
// Add user2 to cohort1 and cohort3.
|
||||
$user2 = $this->getDataGenerator()->create_user();
|
||||
cohort_add_member($cohort3->id, $user2->id);
|
||||
cohort_add_member($cohort1->id, $user2->id);
|
||||
|
||||
// Add user3 to cohort1, cohort2 and cohort3.
|
||||
$user3 = $this->getDataGenerator()->create_user();
|
||||
cohort_add_member($cohort1->id, $user3->id);
|
||||
cohort_add_member($cohort2->id, $user3->id);
|
||||
cohort_add_member($cohort3->id, $user3->id);
|
||||
|
||||
$this->preventResetByRollback(); // Messaging is not compatible with transactions.
|
||||
|
||||
// Cohort criteria are used in site badges.
|
||||
$badge = new badge($this->badgeid);
|
||||
|
||||
$this->assertFalse($badge->is_issued($this->user->id));
|
||||
$this->assertSame(0, $badge->review_all_criteria()); // Verify award_criteria_cohort->get_completed_criteria_sql().
|
||||
|
||||
// Set up the badge criteria.
|
||||
$criteriaoverall = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_OVERALL, 'badgeid' => $badge->id));
|
||||
$criteriaoverall->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ANY));
|
||||
$criteriaoverall1 = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_COHORT, 'badgeid' => $badge->id));
|
||||
$criteriaoverall1->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ALL,
|
||||
'cohort_cohorts' => array('0' => $cohort1->id, '1' => $cohort2->id, '2' => $cohort3->id)));
|
||||
$badge->set_status(BADGE_STATUS_ACTIVE);
|
||||
|
||||
// Reload it to contain criteria.
|
||||
$badge = new badge($this->badgeid);
|
||||
|
||||
// Verify that the badge was not awarded yet (ALL cohorts are needed and review_all_criteria has to be called).
|
||||
$this->assertFalse($badge->is_issued($this->user->id));
|
||||
$this->assertFalse($badge->is_issued($user2->id));
|
||||
$this->assertFalse($badge->is_issued($user3->id));
|
||||
|
||||
// Verify that after calling review_all_criteria, users with the criteria (user3) award the badge instantly.
|
||||
$this->assertSame(1, $badge->review_all_criteria()); // Verify award_criteria_cohort->get_completed_criteria_sql().
|
||||
$this->assertFalse($badge->is_issued($this->user->id));
|
||||
$this->assertFalse($badge->is_issued($user2->id));
|
||||
$this->assertTrue($badge->is_issued($user3->id));
|
||||
$this->assertDebuggingCalled();
|
||||
|
||||
// Add the user to the cohort1.
|
||||
cohort_add_member($cohort1->id, $this->user->id);
|
||||
|
||||
// Verify that the badge was not awarded yet (ALL cohorts are needed).
|
||||
$this->assertFalse($badge->is_issued($this->user->id));
|
||||
$this->assertSame(0, $badge->review_all_criteria()); // Verify award_criteria_cohort->get_completed_criteria_sql().
|
||||
|
||||
// Add the user to the cohort3.
|
||||
cohort_add_member($cohort3->id, $this->user->id);
|
||||
|
||||
// Verify that the badge was not awarded yet (ALL cohorts are needed).
|
||||
$this->assertFalse($badge->is_issued($this->user->id));
|
||||
$this->assertSame(0, $badge->review_all_criteria()); // Verify award_criteria_cohort->get_completed_criteria_sql().
|
||||
|
||||
// Add user to cohort2.
|
||||
cohort_add_member($cohort2->id, $this->user->id);
|
||||
$this->assertDebuggingCalled();
|
||||
|
||||
// Verify that the badge was awarded (ALL cohorts).
|
||||
$this->assertTrue($badge->is_issued($this->user->id));
|
||||
// As the badge has been awarded to user because core_badges_observer been called when the member has been added to the
|
||||
// cohort, there are no other users that can award this badge.
|
||||
$this->assertSame(0, $badge->review_all_criteria()); // Verify award_criteria_cohort->get_completed_criteria_sql().
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -698,6 +790,16 @@ class core_badges_badgeslib_testcase extends advanced_testcase {
|
||||
$this->assertStringMatchesFormat($testassertion2->badge, json_encode($assertion2->get_badge_assertion()));
|
||||
$this->assertStringMatchesFormat($testassertion2->class, json_encode($assertion2->get_badge_class()));
|
||||
$this->assertStringMatchesFormat($testassertion2->issuer, json_encode($assertion2->get_issuer()));
|
||||
|
||||
// Test Openbadge specification version 2.1. It has the same format as OBv2.0.
|
||||
// Get assertion version 2.1.
|
||||
$award = reset($awards);
|
||||
$assertion2 = new core_badges_assertion($award->uniquehash, OPEN_BADGES_V2P1);
|
||||
|
||||
// Make sure JSON strings have the same structure.
|
||||
$this->assertStringMatchesFormat($testassertion2->badge, json_encode($assertion2->get_badge_assertion()));
|
||||
$this->assertStringMatchesFormat($testassertion2->class, json_encode($assertion2->get_badge_class()));
|
||||
$this->assertStringMatchesFormat($testassertion2->issuer, json_encode($assertion2->get_issuer()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
$string['otherusers'] = 'Other Users ({$a})';
|
||||
$string['otherusers'] = 'Other users ({$a})';
|
||||
$string['onlinestatushiding_desc'] = 'If enabled, users have the option to hide their online status from other users.';
|
||||
$string['configtimetosee'] = 'Number of minutes determining the period of inactivity after which a user is no longer considered to be online.';
|
||||
$string['onlinestatushiding'] = 'Online status hiding';
|
||||
|
||||
@@ -37,7 +37,7 @@ Feature: The online users block allow you to see who is currently online on fron
|
||||
When I log in as "student1"
|
||||
And I am on site homepage
|
||||
Then I should not see "Admin User" in the "Online users" "block"
|
||||
And I should see "Other Users (1)" in the "Online users" "block"
|
||||
And I should see "Other users (1)" in the "Online users" "block"
|
||||
And I should see "Student 1" in the "Online users" "block"
|
||||
And I should see "Student 2" in the "Online users" "block"
|
||||
And I should see "3 online users" in the "Online users" "block"
|
||||
@@ -79,7 +79,7 @@ Feature: The online users block allow you to see who is currently online on fron
|
||||
And I am on site homepage
|
||||
Then I should see "2 online user" in the "Online users" "block"
|
||||
And I should not see "Admin" in the "Online users" "block"
|
||||
And I should see "Other Users (1)" in the "Online users" "block"
|
||||
And I should see "Other users (1)" in the "Online users" "block"
|
||||
And I should see "Student 2" in the "Online users" "block"
|
||||
And I should not see "Student 1" in the "Online users" "block"
|
||||
And I log out
|
||||
@@ -94,7 +94,7 @@ Feature: The online users block allow you to see who is currently online on fron
|
||||
And I am on site homepage
|
||||
Then I should see "3 online users" in the "Online users" "block"
|
||||
And I should not see "Admin" in the "Online users" "block"
|
||||
And I should see "Other Users (1)" in the "Online users" "block"
|
||||
And I should see "Other users (1)" in the "Online users" "block"
|
||||
And I should see "Student 2" in the "Online users" "block"
|
||||
And I should see "Student 1" in the "Online users" "block"
|
||||
|
||||
@@ -138,7 +138,7 @@ Feature: The online users block allow you to see who is currently online on fron
|
||||
And I am on site homepage
|
||||
And I should see "2 online user" in the "Online users" "block"
|
||||
And I should not see "Admin" in the "Online users" "block"
|
||||
And I should see "Other Users (1)" in the "Online users" "block"
|
||||
And I should see "Other users (1)" in the "Online users" "block"
|
||||
And I should see "Student 2" in the "Online users" "block"
|
||||
And I should not see "Student 1" in the "Online users" "block"
|
||||
And I log out
|
||||
@@ -148,6 +148,6 @@ Feature: The online users block allow you to see who is currently online on fron
|
||||
When I am on site homepage
|
||||
Then I should see "3 online users" in the "Online users" "block"
|
||||
And I should not see "Admin" in the "Online users" "block"
|
||||
And I should see "Other Users (1)" in the "Online users" "block"
|
||||
And I should see "Other users (1)" in the "Online users" "block"
|
||||
And I should see "Student 2" in the "Online users" "block"
|
||||
And I should see "Student 1" in the "Online users" "block"
|
||||
|
||||
@@ -42,19 +42,21 @@ class block_tag_youtube_edit_form extends block_edit_form {
|
||||
|
||||
// Category setting.
|
||||
$categorychoices = ['0' => get_string('anycategory', 'block_tag_youtube')];
|
||||
$hascategoryerror = false;
|
||||
$categoryerror = '';
|
||||
|
||||
try {
|
||||
// Get all video categories through an API call and add them to the category list.
|
||||
$categorychoices += $this->block->get_categories();
|
||||
} catch (Exception $e) {
|
||||
$hascategoryerror = true;
|
||||
$categoryerror = $e->getMessage();
|
||||
}
|
||||
$mform->addElement('select', 'config_category', get_string('category', 'block_tag_youtube'),
|
||||
$categorychoices);
|
||||
$mform->setDefault('config_category', 0);
|
||||
|
||||
if ($categoryerror) {
|
||||
if ($hascategoryerror) {
|
||||
$notification = $OUTPUT->notification(get_string('categoryerror', 'block_tag_youtube', $categoryerror),
|
||||
'error');
|
||||
$mform->addElement('static', 'config_category_error', '', $notification);
|
||||
|
||||
@@ -66,6 +66,102 @@ function create_event($properties) {
|
||||
return $event->create($record);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to create a x number of events for each event type.
|
||||
*
|
||||
* @param int $quantity The quantity of events to be created.
|
||||
* @return array List of created events.
|
||||
*/
|
||||
function create_standard_events(int $quantity): array {
|
||||
$types = ['site', 'category', 'course', 'group', 'user'];
|
||||
|
||||
$events = [];
|
||||
foreach ($types as $eventtype) {
|
||||
// Create five events of each event type.
|
||||
for ($i = 0; $i < $quantity; $i++) {
|
||||
$events[] = create_event(['eventtype' => $eventtype]);
|
||||
}
|
||||
}
|
||||
|
||||
return $events;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to create an action event.
|
||||
*
|
||||
* @param array $data The event data.
|
||||
* @return bool|calendar_event
|
||||
*/
|
||||
function create_action_event(array $data) {
|
||||
global $CFG;
|
||||
|
||||
require_once($CFG->dirroot . '/calendar/lib.php');
|
||||
|
||||
if (!isset($data['modulename']) || !isset($data['instance'])) {
|
||||
throw new coding_exception('Module and instance should be specified when creating an action event.');
|
||||
}
|
||||
|
||||
$isuseroverride = isset($data->priority) && $data->priority == CALENDAR_EVENT_USER_OVERRIDE_PRIORITY;
|
||||
if ($isuseroverride) {
|
||||
if (!in_array($data['modulename'], ['assign', 'lesson', 'quiz'])) {
|
||||
throw new coding_exception('Only assign, lesson and quiz modules supports overrides');
|
||||
}
|
||||
}
|
||||
|
||||
$event = array_merge($data, [
|
||||
'eventtype' => isset($data['eventtype']) ? $data['eventtype'] : 'open',
|
||||
'courseid' => isset($data['courseid']) ? $data['courseid'] : 0,
|
||||
'instance' => $data['instance'],
|
||||
'modulename' => $data['modulename'],
|
||||
'type' => CALENDAR_EVENT_TYPE_ACTION,
|
||||
]);
|
||||
|
||||
return create_event($event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to create an user override calendar event.
|
||||
*
|
||||
* @param string $modulename The modulename.
|
||||
* @param int $instanceid The instance id.
|
||||
* @param int $userid The user id.
|
||||
* @return calendar_event|false
|
||||
*/
|
||||
function create_user_override_event(string $modulename, int $instanceid, int $userid) {
|
||||
if (!isset($userid)) {
|
||||
throw new coding_exception('Must specify userid when creating a user override.');
|
||||
}
|
||||
|
||||
return create_action_event([
|
||||
'modulename' => $modulename,
|
||||
'instance' => $instanceid,
|
||||
'userid' => $userid,
|
||||
'priority' => CALENDAR_EVENT_USER_OVERRIDE_PRIORITY,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to create an group override calendar event.
|
||||
*
|
||||
* @param string $modulename The modulename.
|
||||
* @param int $instanceid The instance id.
|
||||
* @param int $courseid The course id.
|
||||
* @param int $groupid The group id.
|
||||
* @return calendar_event|false
|
||||
*/
|
||||
function create_group_override_event(string $modulename, int $instanceid, int $courseid, int $groupid) {
|
||||
if (!isset($groupid)) {
|
||||
throw new coding_exception('Must specify groupid when creating a group override.');
|
||||
}
|
||||
|
||||
return create_action_event([
|
||||
'groupid' => $groupid,
|
||||
'courseid' => $courseid,
|
||||
'modulename' => $modulename,
|
||||
'instance' => $instanceid,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* A test factory that will create action events.
|
||||
*
|
||||
|
||||
@@ -159,3 +159,37 @@ Feature: Content bank use editor feature
|
||||
And I click on "Content bank" "link"
|
||||
And I follow "filltheblanks.h5p"
|
||||
Then "Edit" "link" should not exist in the "region-main" "region"
|
||||
|
||||
Scenario: Teachers keep their content authoring in copied courses
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| teacher1 | Teacher | 1 | teacher1@example.com |
|
||||
And the following "courses" exist:
|
||||
| fullname | shortname | category |
|
||||
| Course 1 | C1 | 0 |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
And the following "contentbank content" exist:
|
||||
| contextlevel | reference | contenttype | user | contentname | filepath |
|
||||
| Course | C1 | contenttype_h5p | admin | filltheblanks.h5p | /h5p/tests/fixtures/filltheblanks.h5p |
|
||||
| Course | C1 | contenttype_h5p | teacher1 | ipsums.h5p | /h5p/tests/fixtures/ipsums.h5p |
|
||||
And I am on "Course 1" course homepage
|
||||
And I navigate to "Copy course" in current page administration
|
||||
And I set the following fields to these values:
|
||||
| Course full name | Copy |
|
||||
| Course short name | Copy |
|
||||
| Teacher | 1 |
|
||||
When I press "Copy and view"
|
||||
And I trigger cron
|
||||
And I am on homepage
|
||||
And I log out
|
||||
And I log in as "teacher1"
|
||||
And I am on "Copy" course homepage
|
||||
And I expand "Site pages" node
|
||||
And I click on "Content bank" "link"
|
||||
And I follow "ipsums.h5p"
|
||||
Then "Edit" "link" should exist in the "region-main" "region"
|
||||
And I click on "Content bank" "link"
|
||||
And I follow "filltheblanks.h5p"
|
||||
Then "Edit" "link" should not exist in the "region-main" "region"
|
||||
|
||||
@@ -103,6 +103,10 @@ class no_recent_accesses extends course_enrolments {
|
||||
return get_string('nocoursestudents', 'course');
|
||||
}
|
||||
|
||||
if (!$fortraining && !$course->get_course_data()->visible) {
|
||||
return get_string('hiddenfromstudents');
|
||||
}
|
||||
|
||||
if ($course->get_end() && $course->get_end() < $course->get_start()) {
|
||||
return get_string('errorendbeforestart', 'course');
|
||||
}
|
||||
|
||||
+24
-25
@@ -57,8 +57,6 @@ M.course_dndupload = {
|
||||
// The selector identifying the list of modules within a section (note changing this may require
|
||||
// changes to the get_mods_element function)
|
||||
modslistselector: 'ul.section',
|
||||
// Original onbeforeunload event.
|
||||
originalUnloadEvent: null,
|
||||
|
||||
/**
|
||||
* Initalise the drag and drop upload interface
|
||||
@@ -765,7 +763,10 @@ M.course_dndupload = {
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState == 1) {
|
||||
this.originalUnloadEvent = window.onbeforeunload;
|
||||
self.reportUploadDirtyState(true);
|
||||
// Trigger form upload start events.
|
||||
require(['core_form/events'], function(FormEvent) {
|
||||
FormEvent.triggerUploadStarted(section.get('id'));
|
||||
});
|
||||
}
|
||||
if (xhr.readyState == 4) {
|
||||
if (xhr.status == 200) {
|
||||
@@ -793,7 +794,10 @@ M.course_dndupload = {
|
||||
} else {
|
||||
new M.core.alert({message: M.util.get_string('servererror', 'moodle')});
|
||||
}
|
||||
self.reportUploadDirtyState(false);
|
||||
// Trigger form upload complete events.
|
||||
require(['core_form/events'], function(FormEvent) {
|
||||
FormEvent.triggerUploadCompleted(section.get('id'));
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1025,7 +1029,10 @@ M.course_dndupload = {
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState == 1) {
|
||||
this.originalUnloadEvent = window.onbeforeunload;
|
||||
self.reportUploadDirtyState(true);
|
||||
// Trigger form upload start events.
|
||||
require(['core_form/events'], function(FormEvent) {
|
||||
FormEvent.triggerUploadStarted(section.get('id'));
|
||||
});
|
||||
}
|
||||
if (xhr.readyState == 4) {
|
||||
if (xhr.status == 200) {
|
||||
@@ -1043,13 +1050,24 @@ M.course_dndupload = {
|
||||
} else {
|
||||
// Error - remove the dummy element
|
||||
resel.parent.removeChild(resel.li);
|
||||
// Trigger form upload complete events.
|
||||
require(['core_form/events'], function(FormEvent) {
|
||||
FormEvent.triggerUploadCompleted(section.get('id'));
|
||||
});
|
||||
new M.core.alert({message: result.error});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Trigger form upload complete events.
|
||||
require(['core_form/events'], function(FormEvent) {
|
||||
FormEvent.triggerUploadCompleted(section.get('id'));
|
||||
});
|
||||
new M.core.alert({message: M.util.get_string('servererror', 'moodle')});
|
||||
}
|
||||
self.reportUploadDirtyState(false);
|
||||
// Trigger form upload complete events.
|
||||
require(['core_form/events'], function(FormEvent) {
|
||||
FormEvent.triggerUploadCompleted(section.get('id'));
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1083,24 +1101,5 @@ M.course_dndupload = {
|
||||
if (M.core.actionmenu && M.core.actionmenu.newDOMNode) {
|
||||
M.core.actionmenu.newDOMNode(node);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Set the event to prevent user navigate away when upload progress still running.
|
||||
*
|
||||
* @param {bool} enable true if upload progress is running, false otherwise
|
||||
*/
|
||||
reportUploadDirtyState: function(enable) {
|
||||
if (!enable) {
|
||||
window.onbeforeunload = this.originalUnloadEvent;
|
||||
} else {
|
||||
window.onbeforeunload = function(e) {
|
||||
var warningMessage = M.util.get_string('changesmadereallygoaway', 'moodle');
|
||||
if (e) {
|
||||
e.returnValue = warningMessage;
|
||||
}
|
||||
return warningMessage;
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -621,10 +621,23 @@ abstract class moodleform_mod extends moodleform {
|
||||
if (!empty($CFG->enableavailability)) {
|
||||
// Add special button to end of previous section if groups/groupings
|
||||
// are enabled.
|
||||
if ($this->_features->groups || $this->_features->groupings) {
|
||||
|
||||
$availabilityplugins = \core\plugininfo\availability::get_enabled_plugins();
|
||||
$groupavailability = $this->_features->groups && array_key_exists('group', $availabilityplugins);
|
||||
$groupingavailability = $this->_features->groupings && array_key_exists('grouping', $availabilityplugins);
|
||||
|
||||
if ($groupavailability || $groupingavailability) {
|
||||
// When creating the button, we need to set type=button to prevent it behaving as a submit.
|
||||
$mform->addElement('static', 'restrictgroupbutton', '',
|
||||
html_writer::tag('button', get_string('restrictbygroup', 'availability'),
|
||||
array('id' => 'restrictbygroup', 'disabled' => 'disabled', 'class' => 'btn btn-secondary')));
|
||||
html_writer::tag('button', get_string('restrictbygroup', 'availability'), [
|
||||
'id' => 'restrictbygroup',
|
||||
'type' => 'button',
|
||||
'disabled' => 'disabled',
|
||||
'class' => 'btn btn-secondary',
|
||||
'data-groupavailability' => $groupavailability,
|
||||
'data-groupingavailability' => $groupingavailability
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
// Availability field. This is just a textarea; the user interface
|
||||
|
||||
@@ -55,12 +55,16 @@ class field_controller extends \core_customfield\field_controller {
|
||||
|
||||
$mform->addElement('text', 'configdata[displaysize]', get_string('displaysize', 'customfield_text'), ['size' => 6]);
|
||||
$mform->setType('configdata[displaysize]', PARAM_INT);
|
||||
$mform->setDefault('configdata[displaysize]', 50);
|
||||
if (!$this->get_configdata_property('displaysize')) {
|
||||
$mform->setDefault('configdata[displaysize]', 50);
|
||||
}
|
||||
$mform->addRule('configdata[displaysize]', null, 'numeric', null, 'client');
|
||||
|
||||
$mform->addElement('text', 'configdata[maxlength]', get_string('maxlength', 'customfield_text'), ['size' => 6]);
|
||||
$mform->setType('configdata[maxlength]', PARAM_INT);
|
||||
$mform->setDefault('configdata[maxlength]', 1333);
|
||||
if (!$this->get_configdata_property('maxlength')) {
|
||||
$mform->setDefault('configdata[maxlength]', 1333);
|
||||
}
|
||||
$mform->addRule('configdata[maxlength]', null, 'numeric', null, 'client');
|
||||
|
||||
$mform->addElement('selectyesno', 'configdata[ispassword]', get_string('ispassword', 'customfield_text'));
|
||||
@@ -113,7 +117,7 @@ class field_controller extends \core_customfield\field_controller {
|
||||
$errors['configdata[link]'] = get_string('errorconfiglinkplaceholder', 'customfield_text');
|
||||
} else if (!validateUrlSyntax(str_replace('$$', 'XYZ', $link), 's+H?S?F-E-u-P-a?I?p?f?q?r?')) {
|
||||
// This validation is more strict than PARAM_URL - it requires the protocol and it must be either http or https.
|
||||
$errors['configdata[link]'] = get_string('errorconfigdisplaysize', 'customfield_text');
|
||||
$errors['configdata[link]'] = get_string('errorconfiglinksyntax', 'customfield_text');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,7 +188,9 @@ $removeenabled = $canunenrol ? '' : 'disabled="disabled"';
|
||||
</td>
|
||||
<td id="buttonscell">
|
||||
<div id="addcontrols">
|
||||
<input name="add" <?php echo $addenabled; ?> id="add" type="submit" value="<?php echo $OUTPUT->larrow().' '.get_string('add'); ?>" title="<?php print_string('add'); ?>" /><br />
|
||||
<input class="btn btn-secondary" name="add" <?php echo $addenabled; ?> id="add" type="submit"
|
||||
value="<?php echo $OUTPUT->larrow() . ' ' . get_string('add'); ?>"
|
||||
title="<?php print_string('add'); ?>" /><br />
|
||||
|
||||
<div class="enroloptions">
|
||||
|
||||
@@ -205,7 +207,9 @@ $removeenabled = $canunenrol ? '' : 'disabled="disabled"';
|
||||
</div>
|
||||
|
||||
<div id="removecontrols">
|
||||
<input name="remove" id="remove" <?php echo $removeenabled; ?> type="submit" value="<?php echo get_string('remove').' '.$OUTPUT->rarrow(); ?>" title="<?php print_string('remove'); ?>" />
|
||||
<input class="btn btn-secondary" name="remove" id="remove" <?php echo $removeenabled; ?> type="submit"
|
||||
value="<?php echo get_string('remove') . ' ' . $OUTPUT->rarrow(); ?>"
|
||||
title="<?php print_string('remove'); ?>" />
|
||||
</div>
|
||||
</td>
|
||||
<td id="potentialcell">
|
||||
|
||||
@@ -98,6 +98,7 @@ Feature: Users can auto-enrol themself in courses where self enrolment is allowe
|
||||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I press "Enrol me"
|
||||
And I should see "You are enrolled in the course"
|
||||
And I log out
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
@@ -118,6 +119,7 @@ Feature: Users can auto-enrol themself in courses where self enrolment is allowe
|
||||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I press "Enrol me"
|
||||
And I should see "You are enrolled in the course"
|
||||
And I log out
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
|
||||
@@ -1036,6 +1036,59 @@ class core_enrollib_testcase extends advanced_testcase {
|
||||
$this->assertEquals([$course1->id, $course2->id, $course3->id, $course4->id], array_keys($courses));
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for {@see test_enrol_get_my_courses_by_time}
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function enrol_get_my_courses_by_time_provider(): array {
|
||||
return [
|
||||
'No start or end time' =>
|
||||
[null, null, true],
|
||||
'Start time now, no end time' =>
|
||||
[0, null, true],
|
||||
'Start time now, end time in the future' =>
|
||||
[0, MINSECS, true],
|
||||
'Start time in the past, no end time' =>
|
||||
[-MINSECS, null, true],
|
||||
'Start time in the past, end time in the future' =>
|
||||
[-MINSECS, MINSECS, true],
|
||||
'Start time in the past, end time in the past' =>
|
||||
[-DAYSECS, -HOURSECS, false],
|
||||
'Start time in the future' =>
|
||||
[MINSECS, null, false],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that expected course enrolments are returned when they have timestart / timeend specified
|
||||
*
|
||||
* @param int|null $timestartoffset Null for 0, otherwise offset from current time
|
||||
* @param int|null $timeendoffset Null for 0, otherwise offset from current time
|
||||
* @param bool $expectreturn
|
||||
*
|
||||
* @dataProvider enrol_get_my_courses_by_time_provider
|
||||
*/
|
||||
public function test_enrol_get_my_courses_by_time(?int $timestartoffset, ?int $timeendoffset, bool $expectreturn): void {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$time = time();
|
||||
$timestart = $timestartoffset === null ? 0 : $time + $timestartoffset;
|
||||
$timeend = $timeendoffset === null ? 0 : $time + $timeendoffset;
|
||||
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
$user = $this->getDataGenerator()->create_and_enrol($course, 'student', null, 'manual', $timestart, $timeend);
|
||||
$this->setUser($user);
|
||||
|
||||
$courses = enrol_get_my_courses();
|
||||
if ($expectreturn) {
|
||||
$this->assertCount(1, $courses);
|
||||
$this->assertEquals($course->id, reset($courses)->id);
|
||||
} else {
|
||||
$this->assertEmpty($courses);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* test_course_users
|
||||
*
|
||||
@@ -1362,4 +1415,77 @@ class core_enrollib_testcase extends advanced_testcase {
|
||||
$durationinday = $duration / DAYSECS;
|
||||
$this->assertEquals(9, $durationinday);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test get_enrolled_with_capabilities_join cannotmatchanyrows attribute.
|
||||
*
|
||||
* @dataProvider get_enrolled_with_capabilities_join_cannotmatchanyrows_data()
|
||||
* @param string $capability the tested capability
|
||||
* @param bool $useprohibit if the capability must be assigned to prohibit
|
||||
* @param int $expectedmatch expected cannotmatchanyrows value
|
||||
* @param int $expectedcount expceted count value
|
||||
*/
|
||||
public function test_get_enrolled_with_capabilities_join_cannotmatchanyrows(
|
||||
string $capability,
|
||||
bool $useprohibit,
|
||||
int $expectedmatch,
|
||||
int $expectedcount
|
||||
) {
|
||||
global $DB, $CFG;
|
||||
|
||||
$this->resetAfterTest();
|
||||
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
$context = context_course::instance($course->id);
|
||||
|
||||
$roleid = $CFG->defaultuserroleid;
|
||||
|
||||
// Override capability if necessary.
|
||||
if ($useprohibit && $capability) {
|
||||
assign_capability($capability, CAP_PROHIBIT, $roleid, $context);
|
||||
}
|
||||
|
||||
// Check if we must enrol or not.
|
||||
$this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
|
||||
|
||||
$join = get_enrolled_with_capabilities_join($context, '', $capability);
|
||||
|
||||
// Execute query.
|
||||
$sql = "SELECT COUNT(DISTINCT u.id)
|
||||
FROM {user} u {$join->joins}
|
||||
WHERE {$join->wheres}";
|
||||
$countrecords = $DB->count_records_sql($sql, $join->params);
|
||||
|
||||
// Validate cannotmatchanyrows.
|
||||
$this->assertEquals($expectedmatch, $join->cannotmatchanyrows);
|
||||
$this->assertEquals($expectedcount, $countrecords);
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for test_get_enrolled_with_capabilities_join_cannotmatchanyrows
|
||||
*
|
||||
* @return @array of testing scenarios
|
||||
*/
|
||||
public function get_enrolled_with_capabilities_join_cannotmatchanyrows_data() {
|
||||
return [
|
||||
'no prohibits, no capability' => [
|
||||
'capability' => '',
|
||||
'useprohibit' => false,
|
||||
'expectedmatch' => 0,
|
||||
'expectedcount' => 1,
|
||||
],
|
||||
'no prohibits with capability' => [
|
||||
'capability' => 'moodle/course:manageactivities',
|
||||
'useprohibit' => false,
|
||||
'expectedmatch' => 0,
|
||||
'expectedcount' => 1,
|
||||
],
|
||||
'prohibits with capability' => [
|
||||
'capability' => 'moodle/course:manageactivities',
|
||||
'useprohibit' => true,
|
||||
'expectedmatch' => 1,
|
||||
'expectedcount' => 0,
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,16 @@ class grade_export_xml extends grade_export {
|
||||
public $plugin = 'xml';
|
||||
public $updatedgradesonly = false; // default to export ALL grades
|
||||
|
||||
/**
|
||||
* Ensure we produce correctly formed XML content by encoding idnumbers appropriately
|
||||
*
|
||||
* @param string $idnumber
|
||||
* @return string
|
||||
*/
|
||||
private static function xml_export_idnumber(string $idnumber): string {
|
||||
return htmlspecialchars($idnumber, ENT_QUOTES | ENT_XML1);
|
||||
}
|
||||
|
||||
/**
|
||||
* To be implemented by child classes
|
||||
* @param boolean $feedback
|
||||
@@ -84,9 +94,11 @@ class grade_export_xml extends grade_export {
|
||||
}
|
||||
|
||||
// only need id number
|
||||
fwrite($handle, "\t\t<assignment>{$grade_item->idnumber}</assignment>\n");
|
||||
$gradeitemidnumber = self::xml_export_idnumber($grade_item->idnumber);
|
||||
fwrite($handle, "\t\t<assignment>{$gradeitemidnumber}</assignment>\n");
|
||||
// this column should be customizable to use either student id, idnumber, uesrname or email.
|
||||
fwrite($handle, "\t\t<student>{$user->idnumber}</student>\n");
|
||||
$useridnumber = self::xml_export_idnumber($user->idnumber);
|
||||
fwrite($handle, "\t\t<student>{$useridnumber}</student>\n");
|
||||
// Format and display the grade in the selected display type (real, letter, percentage).
|
||||
if (is_array($this->displaytype)) {
|
||||
// Grades display type came from the return of export_bulk_export_data() on grade publishing.
|
||||
|
||||
@@ -12,10 +12,12 @@ Feature: I need to export grades as xml
|
||||
| username | firstname | lastname | email | idnumber |
|
||||
| teacher1 | Teacher | 1 | teacher1@example.com | t1 |
|
||||
| student1 | Student | 1 | student1@example.com | s1 |
|
||||
| student2 | Student | 2 | student2@example.com | 'Bill'&"Ben"<tag>Hello</tag> |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
| student1 | C1 | student |
|
||||
| student2 | C1 | student |
|
||||
And the following "activities" exist:
|
||||
| activity | course | idnumber | name | intro |
|
||||
| assign | C1 | a1 | Test assignment name | Submit something! |
|
||||
@@ -24,15 +26,21 @@ Feature: I need to export grades as xml
|
||||
And I navigate to "View > Grader report" in the course gradebook
|
||||
And I turn editing mode on
|
||||
And I give the grade "80.00" to the user "Student 1" for the grade item "Test assignment name"
|
||||
And I give the grade "42.00" to the user "Student 2" for the grade item "Test assignment name"
|
||||
And I press "Save changes"
|
||||
|
||||
@javascript
|
||||
Scenario: Export grades as text
|
||||
Scenario: Export grades as XML
|
||||
When I navigate to "Export > XML file" in the course gradebook
|
||||
And I expand all fieldsets
|
||||
And I set the field "Grade export decimal places" to "1"
|
||||
And I press "Download"
|
||||
Then I should see "s1"
|
||||
And I should see "a1"
|
||||
And I should see "80.0"
|
||||
And I should not see "80.00"
|
||||
Then I should see "s1" in the "//results//result[1]//student" "xpath_element"
|
||||
And I should see "a1" in the "//results//result[1]//assignment" "xpath_element"
|
||||
And I should see "80.0" in the "//results//result[1]//score" "xpath_element"
|
||||
And I should not see "80.00" in the "//results//result[1]//score" "xpath_element"
|
||||
# Ensure we have the encoded ID number of student 2.
|
||||
And I should see "'Bill'&\"Ben\"<tag>Hello</tag>" in the "//results//result[2]//student" "xpath_element"
|
||||
And I should see "a1" in the "//results//result[2]//assignment" "xpath_element"
|
||||
And I should see "42.0" in the "//results//result[2]//score" "xpath_element"
|
||||
And I should not see "42.00" in the "//results//result[2]//score" "xpath_element"
|
||||
|
||||
+3
@@ -156,6 +156,9 @@ class fetch extends external_api {
|
||||
$hasgrade = $gradeitem->user_has_grade($gradeduser);
|
||||
$grade = $gradeitem->get_grade_for_user($gradeduser, $USER);
|
||||
$instance = $gradeitem->get_advanced_grading_instance($USER, $grade);
|
||||
if (!$instance) {
|
||||
throw new moodle_exception('error:gradingunavailable', 'grading');
|
||||
}
|
||||
$controller = $instance->get_controller();
|
||||
$definition = $controller->get_definition();
|
||||
$fillings = $instance->get_guide_filling();
|
||||
|
||||
+4
@@ -149,6 +149,10 @@ class fetch extends external_api {
|
||||
$hasgrade = $gradeitem->user_has_grade($gradeduser);
|
||||
$grade = $gradeitem->get_grade_for_user($gradeduser, $USER);
|
||||
$instance = $gradeitem->get_advanced_grading_instance($USER, $grade);
|
||||
if (!$instance) {
|
||||
throw new moodle_exception('error:gradingunavailable', 'grading');
|
||||
}
|
||||
|
||||
$controller = $instance->get_controller();
|
||||
$definition = $controller->get_definition();
|
||||
$fillings = $instance->get_rubric_filling();
|
||||
|
||||
@@ -231,7 +231,7 @@ if (!empty($method)) {
|
||||
} else {
|
||||
$tag = html_writer::tag('span', get_string('statusdraft', 'core_grading'), array('class' => 'status draft'));
|
||||
}
|
||||
echo $output->heading(s($definition->name) . ' ' . $tag, 3, 'definition-name');
|
||||
echo $output->heading(format_string($definition->name) . ' ' . $tag, 3, 'definition-name');
|
||||
echo $output->box($controller->render_preview($PAGE), 'definition-preview');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -240,6 +240,10 @@ class gradeimport_csv_load_data {
|
||||
$select = "{$field} = :{$field}";
|
||||
}
|
||||
|
||||
// Validate if the user id value is numerical.
|
||||
if ($field === 'id' && !is_numeric($value)) {
|
||||
$errorkey = 'usermappingerror';
|
||||
}
|
||||
// Make sure the record exists and that there's only one matching record found.
|
||||
$user = $DB->get_record_select('user', $select, array($userfields['field'] => $value), '*', MUST_EXIST);
|
||||
} catch (dml_missing_record_exception $missingex) {
|
||||
|
||||
@@ -87,7 +87,7 @@ class provider implements
|
||||
* @param int $userid The userid of the user whose data is to be exported.
|
||||
*/
|
||||
public static function export_user_preferences(int $userid) {
|
||||
$preferences = get_user_preferences();
|
||||
$preferences = get_user_preferences(null, null, $userid);
|
||||
foreach ($preferences as $name => $value) {
|
||||
$prefname = null;
|
||||
$prefdescription = null;
|
||||
|
||||
@@ -63,14 +63,18 @@ class gradereport_grader_privacy_testcase extends \core_privacy\tests\provider_t
|
||||
* These preferences can be set on each course, but the value is shared in the whole site.
|
||||
*/
|
||||
public function test_export_user_preferences_single() {
|
||||
// Add some user preferences.
|
||||
// Create test user, add some preferences.
|
||||
$user = $this->getDataGenerator()->create_user();
|
||||
$this->setUser($user);
|
||||
|
||||
set_user_preference('grade_report_showcalculations', 1, $user);
|
||||
set_user_preference('grade_report_meanselection', GRADE_REPORT_MEAN_GRADED, $user);
|
||||
set_user_preference('grade_report_studentsperpage', 50, $user);
|
||||
|
||||
// Validate exported data.
|
||||
// Switch to admin user (so we can validate preferences of our test user are still exported).
|
||||
$this->setAdminUser();
|
||||
|
||||
// Validate exported data for our test user.
|
||||
provider::export_user_preferences($user->id);
|
||||
$context = context_user::instance($user->id);
|
||||
$writer = writer::with_context($context);
|
||||
|
||||
@@ -13,4 +13,4 @@ Feature: We can use the user report
|
||||
And I am on "Course 1" course homepage
|
||||
And I navigate to "View > User report" in the course gradebook
|
||||
And I select "All users (0)" from the "Select all or one user" singleselect
|
||||
Then I should see "No students enrolled in this course yet"
|
||||
Then I should see "There are no students enrolled in this course."
|
||||
|
||||
+1
-1
@@ -232,7 +232,7 @@ if ($editform->is_cancelled()) {
|
||||
$newgroup = new stdClass();
|
||||
$newgroup->courseid = $data->courseid;
|
||||
$newgroup->name = $group['name'];
|
||||
$newgroup->enablemessaging = $data->enablemessaging;
|
||||
$newgroup->enablemessaging = $data->enablemessaging ?? 0;
|
||||
$groupid = groups_create_group($newgroup);
|
||||
$createdgroups[] = $groupid;
|
||||
foreach($group['members'] as $user) {
|
||||
|
||||
@@ -421,6 +421,8 @@ class helper {
|
||||
* @return array The JS array converted to PHP array.
|
||||
*/
|
||||
public static function parse_js_array(string $jscontent): array {
|
||||
// Convert all line-endings to UNIX format first.
|
||||
$jscontent = str_replace(array("\r\n", "\r"), "\n", $jscontent);
|
||||
$jsarray = preg_split('/,\n\s+/', substr($jscontent, 0, -1));
|
||||
$jsarray = preg_replace('~{?\\n~', '', $jsarray);
|
||||
|
||||
|
||||
@@ -79,7 +79,9 @@ abstract class handler {
|
||||
* Register the H5P autoloader.
|
||||
*/
|
||||
public static function register(): void {
|
||||
spl_autoload_register([static::class, 'autoload']);
|
||||
// Prepend H5P libraries in order to guarantee they are loaded first. Plugins using same libraries will need to use a
|
||||
// different namespace if they want to use a different version.
|
||||
spl_autoload_register([static::class, 'autoload'], true, true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Binary file not shown.
@@ -5,52 +5,52 @@
|
||||
<json>
|
||||
<![CDATA[
|
||||
{
|
||||
"fontFamily": "h5p-core-21",
|
||||
"fontFamily": "h5p-core",
|
||||
"description": "Font generated by IcoMoon.",
|
||||
"majorVersion": 1,
|
||||
"minorVersion": 1,
|
||||
"version": "Version 1.1",
|
||||
"fontId": "h5p-core-21",
|
||||
"psName": "h5p-core-21",
|
||||
"fontId": "h5p-core",
|
||||
"psName": "h5p-core",
|
||||
"subFamily": "Regular",
|
||||
"fullName": "h5p-core-21"
|
||||
"fullName": "h5p-core"
|
||||
}
|
||||
]]>
|
||||
</json>
|
||||
</metadata>
|
||||
<defs>
|
||||
<font id="h5p-core-21" horiz-adv-x="1024">
|
||||
<font id="h5p-core" horiz-adv-x="1024">
|
||||
<font-face units-per-em="1024" ascent="960" descent="-64" />
|
||||
<missing-glyph horiz-adv-x="1024" />
|
||||
<glyph unicode=" " horiz-adv-x="512" d="" />
|
||||
<glyph unicode="" glyph-name="arrow-down" data-tags="arrow-down" d="M234 389.669h556l-278-278z" />
|
||||
<glyph unicode="" glyph-name="arrow-left" data-tags="arrow-left" d="M381-11.331v524l262-262z" />
|
||||
<glyph unicode="" glyph-name="colapse" data-tags="colapse" d="M512 447.336l256-256-60-60-196 196-196-196-60 60z" />
|
||||
<glyph unicode="" glyph-name="expand" data-tags="expand" d="M708 423.336l60-60-256-256-256 256 60 60 196-196z" />
|
||||
<glyph unicode="" glyph-name="move" data-tags="move" d="M386.662 725.063h71.27v-71.27h-71.27v71.27zM566.067 725.063h71.27v-71.27h-71.27v71.27zM386.662 568.8h71.27v-71.27h-71.27v71.27zM566.067 568.8h71.27v-71.27h-71.27v71.27zM386.662 412.435h71.27v-71.27h-71.27v71.27zM566.067 412.435h71.27v-71.27h-71.27v71.27zM386.662 256.173h71.27v-71.27h-71.27v71.27zM566.067 256.173h71.27v-71.27h-71.27v71.27zM386.662 99.808h71.27v-71.27h-71.27v71.27zM566.067 99.808h71.27v-71.27h-71.27v71.27zM386.662-56.454h71.27v-71.27h-71.27v71.27zM566.067-56.454h71.27v-71.27h-71.27v71.27z" />
|
||||
<glyph unicode="" glyph-name="check-mark" data-tags="check-mark" d="M454.299 245.924l-116.917 116.917-84.781-84.707 201.696-201.697 317.097 317.097-84.781 84.706z" />
|
||||
<glyph unicode="" glyph-name="arrow-up-circle" data-tags="arrow-up-circle" d="M512 606.057c-148.616 0-264.722-120.75-260.077-269.367 0-125.395 88.241-232.212 208.991-255.434v213.636h-92.885c-13.933 0-13.933 9.288-9.288 18.577l139.327 171.838c4.645 9.288 13.933 9.288 23.221 4.645 0 0 4.645-4.645 4.645-4.645l139.327-171.838c9.288-9.288 4.645-18.577-9.288-18.577h-92.885v-213.636c143.972 32.51 232.212 171.838 199.703 315.808-23.221 120.75-130.039 204.347-250.789 208.991z" />
|
||||
<glyph unicode="" glyph-name="info-circle" data-tags="info-circle" d="M512 601.601c-144.077 0-260.266-116.191-260.266-260.266s116.191-260.266 260.266-260.266 260.266 116.191 260.266 260.266v0c0 139.429-116.191 255.619-260.266 260.266zM470.171 550.478h88.305v-69.714h-88.305v69.714zM600.305 160.078h-181.257v51.123h51.123v162.666h-51.123v51.123h139.429v-218.438h46.477l-4.648-46.477z" />
|
||||
<glyph unicode="" glyph-name="search" data-tags="search" d="M772.098 125.51l-110.68 110.68c71.943 99.612 49.806 243.494-49.806 315.437s-243.494 44.27-315.437-55.339c-71.943-99.612-49.806-243.494 49.806-315.437 77.475-55.339 182.623-55.339 260.098 0l110.68-110.68c5.533-5.533 11.068-5.533 16.601 0 0 0 0 0 0 0l33.205 33.205c11.068 5.533 11.068 16.601 5.533 22.137 0 0 0 0 0 0zM478.795 202.985c-88.544 0-160.486 71.943-160.486 160.486s71.943 160.486 160.486 160.486 160.486-71.943 160.486-160.486-71.943-160.486-160.486-160.486v0z" />
|
||||
<glyph unicode="" glyph-name="fullscreen" data-tags="fullscreen" d="M368.55 490.521c5.737 5.737 0 5.737-5.737 5.737l-103.284 11.476c-5.737 5.737-11.476 0-11.476-5.737l11.476-109.021c0-5.737 5.737-5.737 5.737-5.737l103.284 103.284zM293.959 427.403l63.118-63.118c5.737-5.737 11.476-5.737 17.213 0l22.953 22.953c5.737 5.737 5.737 11.476 0 17.213l-63.118 57.379-40.166-34.429zM787.42 387.237c5.737-5.737 5.737 0 5.737 5.737l11.476 109.021c0 5.737-5.737 11.476-11.476 11.476l-109.021-11.476c-5.737 0-5.737-5.737-5.737-5.737l109.021-109.021zM724.305 461.832l-63.118-63.118c-5.737-5.737-5.737-11.476 0-17.213l22.953-22.953c5.737-5.737 11.476-5.737 17.213 0l63.118 63.118-40.166 40.166zM689.876 180.672c-5.737-5.737 0-5.737 5.737-5.737l109.021-11.476c5.737 0 11.476 5.737 11.476 11.476l-17.213 103.284c0 5.737-5.737 5.737-5.737 5.737l-103.284-103.284zM758.731 249.527l-63.118 63.118c-5.737 5.737-11.476 5.737-17.213 0l-22.953-22.953c-5.737-5.737-5.737-11.476 0-17.213l63.118-63.118 40.166 40.166zM265.269 283.956c-5.737 5.737-5.737 0-5.737-5.737l-11.476-109.021c0-5.737 5.737-11.476 11.476-11.476l109.021 11.476c5.737 0 5.737 5.737 5.737 5.737l-109.021 109.021zM334.124 209.362l63.118 63.118c5.737 5.737 5.737 11.476 0 17.213l-22.953 22.953c-5.737 5.737-11.476 5.737-17.213 0l-63.118-63.118 40.166-40.166zM161.985 593.805v-499.201h722.979v499.201h-722.979zM844.799 134.77h-636.911v413.13h636.911v-413.13z" />
|
||||
<glyph unicode="" glyph-name="h5p" data-tags="h5p" d="M934.072 489.192c-22.319 16.738-50.216 27.897-89.273 27.897h-139.487v-66.954h-156.225l-11.159-55.795c11.159 5.579 27.897 11.159 39.057 11.159s22.319 0 33.476 0c33.476 0 66.954-11.159 89.273-33.476s33.476-50.216 33.476-83.692c0-22.319-5.579-44.635-16.738-66.954s-27.897-39.057-50.216-50.216c-5.579-5.579-16.738 0-22.319-11.159h117.17v133.908h66.954c44.635 0 78.113 11.159 100.43 27.897 22.319 22.319 33.476 50.216 33.476 83.692 0 39.057-11.159 66.954-27.897 83.692v0zM839.221 377.603c-11.159-5.579-22.319-11.159-44.635-11.159h-33.476v83.692h39.057c22.319 0 33.476-5.579 44.635-11.159 5.579-5.579 11.159-16.738 11.159-27.897 0-16.738-5.579-27.897-16.738-33.476v0zM565.826 338.546c-16.738 0-33.476-11.159-44.635-27.897l-94.851 16.738 44.635 195.281h-94.851v-150.646h-117.17v150.646h-111.589v-362.667h111.589v133.908h117.17v-133.908h139.487c-16.738 11.159-33.476 11.159-44.635 22.319s-22.319 22.319-27.897 33.476c-5.579 11.159-11.159 22.319-16.738 39.057l94.851 16.738c5.579-16.738 22.319-27.897 44.635-27.897 27.897 0 50.216 22.319 50.216 50.216 0 22.319-22.319 44.635-50.216 44.635v0z" />
|
||||
<glyph unicode="" glyph-name="rights-of-use" data-tags="rights-of-use" d="M899.611 329.519c0-5.907 0-5.907 0-5.907-23.631-23.631-47.261-35.448-76.799-41.355-11.813 0-23.631-5.907-35.448-5.907s-17.724 0-29.537 0c0 0-5.907 0-5.907 5.907-64.985 59.079-135.877 118.153-200.863 183.139 0 0-5.907 0-5.907 0-23.631-5.907-47.261-11.813-70.892-17.724s-53.168 0-76.799 11.813c-17.724 11.813-23.631 17.724-29.537 35.448-5.907 5.907 0 23.631 11.813 23.631 41.355 11.813 88.616 29.537 129.971 47.261 11.813 5.907 29.537 5.907 41.355 5.907 5.907 0 11.813-5.907 11.813-5.907 41.355-17.724 82.709-29.537 124.060-47.261 0 0 5.907 0 5.907 0 29.537 5.907 64.985 17.724 94.523 23.631 5.907 0 5.907 0 5.907 0l106.34-212.676zM291.12 335.429c17.724 11.813 35.448 5.907 53.168-11.813 11.813-11.813 11.813-29.537 5.907-47.261 17.724 5.907 35.448-5.907 41.355-17.724 11.813-17.724 5.907-35.448-5.907-47.261 5.907 0 11.813 0 17.724 0 11.813-5.907 23.631-11.813 29.537-29.537s0-29.537-5.907-35.448c-5.907-5.907-11.813-11.813-17.724-17.724s-11.813-11.813-17.724-17.724-35.448-17.724-53.168 0c-29.537 29.537-53.168 64.985-82.709 94.523-17.724 23.631-35.448 41.355-47.261 64.985-5.907 11.813-11.813 17.724-11.813 29.537 0 5.907 0 17.724 5.907 23.631 11.813 11.813 17.724 17.724 29.537 29.537 17.724 17.724 47.261 11.813 64.985-5.907-5.907 0-5.907-5.907-5.907-11.813v0zM438.811 128.66l29.537-29.537c17.724-17.724 47.261-11.813 59.079 5.907l-5.907 5.907c-23.631 23.631-47.261 47.261-70.892 70.892-5.907 5.907-5.907 5.907-5.907 11.813s5.907 5.907 11.813 11.813c5.907 0 11.813 0 11.813-5.907 11.813-11.813 29.537-29.537 47.261-47.261 11.813-11.813 29.537-29.537 47.261-47.261 5.907-11.813 17.724-11.813 29.537-11.813 11.813 5.907 23.631 11.813 29.537 23.631 0 5.907 0 5.907 0 5.907-41.355 41.355-88.616 82.709-129.971 129.971-5.907 5.907-5.907 5.907-5.907 11.813 0 11.813 11.813 11.813 23.631 5.907 0 0 5.907 0 5.907-5.907 41.355-41.355 88.616-88.616 129.971-129.971 5.907-5.907 5.907-5.907 5.907-5.907 17.724 0 35.448 17.724 35.448 35.448 0 5.907 0 5.907 0 5.907-47.261 47.261-100.429 100.429-147.691 147.691-5.907 5.907-5.907 5.907-5.907 11.813s5.907 11.813 5.907 11.813c5.907 0 11.813 0 11.813-5.907 5.907-5.907 5.907-5.907 11.813-11.813 35.448-35.448 70.892-70.892 106.34-106.34 11.813-11.813 23.631-23.631 29.537-29.537 0 0 5.907-5.907 5.907 0 23.631 5.907 35.448 29.537 29.537 53.168h35.448c0 0 0 0 0 0 0-5.907 0-17.724 0-23.631-5.907-29.537-23.631-47.261-53.168-59.079 0 0-5.907 0-5.907-5.907-11.813-29.537-35.448-53.168-64.985-53.168-5.907 0-5.907 0-5.907-5.907-17.724-35.448-59.079-47.261-88.616-35.448-5.907 0-11.813 5.907-11.813 5.907-5.907-5.907-11.813-11.813-23.631-17.724-29.537-11.813-59.079-5.907-76.799 11.813-11.813 11.813-17.724 17.724-29.537 29.537 17.724 23.631 23.631 29.537 29.537 41.355v0 0zM273.396 642.628c29.537-11.813 64.985-23.631 94.523-29.537 35.448-11.813 64.985-23.631 100.429-29.537 0 0 0 0 5.907 0-17.724-5.907-35.448-11.813-47.261-17.724 0 0-5.907 0-5.907 0-47.261 11.813-94.523 23.631-135.877 41.355-5.907 0-5.907 0-5.907 0l-76.799-183.139c0-11.813 5.907-17.724 11.813-23.631s5.907-5.907 5.907-11.813c-5.907-5.907-11.813-17.724-23.631-23.631-17.724 17.724-29.537 35.448-29.537 64.985l88.616 212.676c-5.907-11.813 5.907 5.907 17.724 0v0z" />
|
||||
<glyph unicode="" glyph-name="delete-circle" data-tags="delete-circle" d="M512 601.601c-147.107 0-260.266-118.817-260.266-260.266s118.817-260.266 260.266-260.266 260.266 118.817 260.266 260.266-113.158 260.266-260.266 260.266zM653.449 262.123c5.659-5.659 5.659-16.973 0-28.29l-33.949-33.949c-5.659-5.659-16.973-5.659-28.29 0l-79.212 79.212-79.212-79.212c-5.659-5.659-16.973-5.659-28.29 0l-33.949 33.949c-5.659 5.659-5.659 16.973 0 28.29l84.871 79.212-79.212 79.212c-5.659 5.659-5.659 16.973 0 28.29l33.949 33.949c5.659 5.659 16.973 5.659 28.29 0l73.554-84.871 79.212 79.212c5.659 5.659 16.973 5.659 28.29 0l33.949-33.949c5.659-5.659 5.659-16.973 0-28.29l-79.212-73.554 79.212-79.212z" />
|
||||
<glyph unicode="" glyph-name="window" data-tags="window" d="M203.936 461.136c-5.704-5.704 0-5.704 5.704-5.704l108.394-11.41c5.704 0 11.41 5.704 11.41 11.41l-17.114 102.687c0 5.704-5.704 5.704-5.704 5.704l-102.687-102.687zM272.395 523.891l-62.752 62.752c-5.704 5.704-11.41 5.704-17.114 0l-17.114-22.821c-5.704-5.704-5.704-11.41 0-17.114l62.752-62.752 34.228 39.935zM751.605 558.119c-5.704 5.704-5.704 0-5.704-5.704l-11.41-108.394c0-5.704 5.704-11.41 11.41-11.41l108.394 11.41c5.704 0 5.704 5.704 5.704 5.704l-108.394 108.394zM814.357 483.957l62.752 62.752c5.704 5.704 5.704 11.41 0 17.114l-22.821 22.821c-5.704 5.704-11.41 5.704-17.114 0l-62.752-62.752 39.935-39.935zM848.588 221.534c5.704 5.704 0 5.704-5.704 5.704l-102.687 17.114c-5.704 0-11.41-5.704-11.41-11.41l11.41-108.394c0-5.704 5.704-5.704 5.704-5.704l102.687 102.687zM780.129 158.779l62.752-62.752c5.704-5.704 11.41-5.704 17.114 0l22.821 22.821c5.704 5.704 5.704 11.41 0 17.114l-62.752 62.752-39.935-39.935zM300.919 124.551c5.704-5.704 5.704 0 5.704 5.704l11.41 108.394c0 5.704-5.704 11.41-11.41 11.41l-108.394-11.41c-5.704 0-5.704-5.704-5.704-5.704l108.394-108.394zM238.167 193.010l-62.752-62.752c-5.704-5.704-5.704-11.41 0-17.114l22.821-22.821c5.704-5.704 11.41-5.704 17.114 0l62.752 62.752-39.935 39.935zM352.264 466.843v-239.605h347.998v239.605h-347.998zM654.622 267.172h-262.424v154.032h262.424v-154.032z" />
|
||||
<glyph unicode="" glyph-name="code" data-tags="code" d="M449.641 235.325c6.235-6.235 6.235-12.472 6.235-18.707v-62.359c0-6.235-6.235-6.235-6.235-6.235l-230.728 155.897c-6.235 6.235-6.235 12.472-6.235 18.707v49.886c0 6.235 6.235 12.472 6.235 18.707l230.728 155.897c6.235 6.235 6.235 0 6.235-6.235v-62.359c0-6.235-6.235-12.472-6.235-18.707l-162.134-112.245c-6.235-6.235-6.235-6.235 0-12.472l162.134-99.776zM736.493 341.335c6.235 6.235 6.235 6.235 0 12.472l-155.897 112.245c-6.235 6.235-6.235 12.472-6.235 18.707v62.359c0 6.235 6.235 6.235 6.235 6.235l230.728-155.897c6.235-6.235 6.235-12.472 6.235-18.707v-49.886c0-6.235-6.235-12.472-6.235-18.707l-230.728-155.897c-6.235-6.235-6.235 0-6.235 6.235v62.359c0 6.235 6.235 12.472 6.235 18.707l155.897 99.776z" />
|
||||
<glyph unicode="" glyph-name="download" data-tags="download" d="M358.941 435.525c-11.773 0-17.66-5.887-5.887-17.66l153.059-188.382c5.887-11.773 23.547-11.773 29.433 0l153.059 188.382c5.887 11.773 5.887 17.66-5.887 17.66h-323.782zM576.756 423.751v135.399c0 11.773-11.773 23.547-23.547 23.547h-70.643c-11.773 0-23.547-11.773-23.547-23.547v-141.286h117.739zM653.286 288.352c-5.887 0-17.66-5.887-23.547-11.773l-76.53-94.19c-5.887-5.887-17.66-17.66-23.547-23.547 0 0-5.887-5.887-11.773-5.887s-17.66 11.773-17.66 11.773c-5.887 5.887-17.66 17.66-23.547 23.547l-76.53 94.19c-5.887 5.887-17.66 11.773-23.547 11.773h-123.626c-5.887 0-17.66-5.887-17.66-17.66v-141.286c0-5.887 5.887-17.66 17.66-17.66h529.824c5.887 0 17.66 5.887 17.66 17.66v141.286c0 5.887-5.887 17.66-17.66 17.66l-129.513-5.887zM305.958 176.502c-17.66 0-29.433 11.773-29.433 29.433s11.773 29.433 29.433 29.433c17.66 0 29.433-11.773 29.433-29.433s-11.773-29.433-29.433-29.433v0z" />
|
||||
<glyph unicode="" glyph-name="delete" data-tags="delete" d="M620.266 341.335l134.045 134.045c10.311 10.311 10.311 30.934 0 41.245l-61.866 61.866c-10.311 10.311-30.934 10.311-41.245 0l-134.045-134.045-134.045 134.045c-10.311 10.311-30.934 10.311-41.245 0l-61.866-61.866c-10.311-10.311-10.311-30.934 0-41.245l134.045-134.045-134.045-134.045c-10.311-10.311-10.311-30.934 0-41.245l61.866-61.866c10.311-10.311 30.934-10.311 41.245 0l134.045 134.045 134.045-134.045c10.311-10.311 30.934-10.311 41.245 0l61.866 61.866c10.311 10.311 10.311 30.934 0 41.245l-134.045 134.045z" />
|
||||
<glyph unicode="" glyph-name="edit-image" data-tags="edit-image" d="M300.237 621.639c69.018 23.142 133.325 14.234 189.133-33.28 56.627-48.128 77.619-110.592 63.181-183.808-2.355-12.186 0.307-19.456 8.704-27.853 93.901-93.389 156.774-156.467 250.47-250.163 5.427-5.427 10.957-10.854 15.667-16.896 39.424-50.278 16.794-124.006-44.237-142.029-36.966-10.957-68.403 0-95.334 27.034-95.642 96.051-160.973 160.973-256.614 257.024-6.963 6.963-12.8 8.909-22.63 6.758-117.76-26.317-229.171 60.826-231.731 181.453-0.614 26.419 3.584 52.326 15.974 77.926 34.816-34.816 68.506-67.789 101.274-101.786 10.445-10.752 20.992-15.36 36.045-15.36 14.643 0 25.19 3.891 34.816 14.848 10.752 12.39 23.040 23.347 34.611 35.021 14.336 14.438 14.336 46.080-0.205 60.518-35.123 35.226-70.349 70.349-106.598 106.496 3.891 2.253 5.632 3.482 7.475 4.096zM703.386 63.559c-0.41-24.269 20.685-45.466 44.851-45.158 23.757 0.41 44.032 20.992 43.93 44.544-0.102 23.757-20.275 44.032-44.237 44.134-23.859 0.307-44.237-19.661-44.544-43.52z" />
|
||||
<glyph unicode="" glyph-name="hourglass" data-tags="hourglass" d="M733.286-10.579c-147.763 0-295.526 0-443.29 0 0 2.048 0.102 4.096 0 6.144-0.307 13.824-1.024 32.666-0.922 46.49 0.41 39.731 6.861 78.131 19.046 115.2 17.203 52.224 43.725 96.256 81.306 130.355 4.506 4.096 9.216 7.885 13.722 11.776-0.205 0.717-0.307 1.126-0.41 1.229-1.331 1.229-2.765 2.355-4.198 3.584-28.058 22.63-50.688 51.405-68.403 85.606-30.618 59.085-43.52 123.597-41.165 192.614 0.205 7.168 0.614 18.33 0.922 25.498 147.763 0 295.526 0 443.29 0 0.205-1.331 0.512-2.662 0.614-3.994 2.662-36.966 1.229-77.722-5.939-113.869-14.336-72.909-44.544-133.837-95.027-179.405-4.096-3.686-8.294-7.066-12.39-10.547 0.205-0.717 0.307-1.126 0.512-1.331 0.819-0.717 1.638-1.434 2.458-2.15 42.189-33.894 71.68-79.872 90.931-135.782 11.776-34.202 18.637-69.837 20.070-106.701 0.819-19.763-0.614-44.851-1.126-64.717zM687.309 32.634c0 6.554 0.205 12.493 0 18.432-1.331 37.581-7.27 74.138-19.866 108.749-17.92 49.562-45.568 88.269-88.678 108.646-2.458 1.126-2.97 3.072-2.97 5.837 0.102 16.691 0.102 33.485 0 50.176 0 3.994 1.331 5.427 4.096 6.963 9.114 5.325 18.432 10.24 26.829 16.896 29.696 23.552 49.152 56.934 62.362 95.744 10.342 30.413 15.77 62.259 17.818 94.822 0.614 9.114 0.102 18.227 0.102 27.546-116.634 0-233.574 0-351.027 0 0.307-8.704 0.614-16.998 1.024-25.395 1.946-37.274 8.499-73.216 21.504-107.213 18.125-47.104 45.261-83.558 86.528-103.117 2.253-1.024 2.867-2.662 2.867-5.427-0.102-17.203-0.102-34.509 0-51.712 0-3.072-1.024-4.506-3.277-5.632-5.632-2.867-11.366-5.734-16.691-9.216-34.304-22.733-56.832-57.754-71.987-100.147-12.493-35.123-18.125-71.987-19.661-109.875-0.205-5.325 0-10.752 0-16.282 117.35 0.205 234.189 0.205 351.027 0.205zM410.214 451.962c68.096 0 135.373 0 203.674 0-3.789-6.554-7.168-12.595-10.752-18.227-10.957-16.998-24.269-30.618-39.731-41.472s-27.75-25.293-32.768-46.592c-1.638-6.963-2.765-14.336-2.867-21.606-0.307-17.203-0.205-34.406 0.307-51.712 0.717-28.058 12.493-48.947 32.154-62.566 43.008-30.003 65.843-75.878 75.776-132.506 0.307-1.638 0.307-3.379 0.614-5.53-83.149 0-166.093 0-249.242 0 2.662 20.685 7.885 40.346 15.462 59.085 13.312 32.973 32.768 59.187 59.494 77.722 16.589 11.469 28.365 27.955 32.358 50.995 0.819 4.813 1.331 9.83 1.434 14.746 0.102 18.637 0.614 37.274-0.205 55.808-1.126 24.678-11.981 43.213-28.57 57.139-9.216 7.782-18.944 14.746-27.648 23.142-11.981 11.162-21.197 25.395-29.491 41.574z" />
|
||||
<glyph unicode="" glyph-name="plus-icon" data-tags="plus-icon" d="M768 285.015c0-19.323-15.664-34.987-34.987-34.987h-151.040v-151.467c0-19.323-15.664-34.987-34.987-34.987h-69.547c-19.323 0-34.987 15.664-34.987 34.987v151.467h-151.467c-19.323 0-34.987 15.664-34.987 34.987v69.547c0 19.323 15.664 34.987 34.987 34.987h151.467v151.467c0 19.323 15.664 34.987 34.987 34.987h69.547c19.323 0 34.987-15.664 34.987-34.987v-151.467h151.467c19.323 0 34.987-15.664 34.987-34.987z" />
|
||||
<glyph unicode="" glyph-name="video-upload-icon" data-tags="video-upload-icon" d="M384 328.535v-128c0-21.333 21.333-42.667 42.667-42.667h128c21.333 0 42.667 17.067 42.667 42.667v128c0 21.333-17.067 42.667-42.667 42.667h-128c-21.333 0-42.667-17.067-42.667-42.667zM785.067 499.201l-102.4 106.667c-12.8 12.8-38.4 21.333-55.467 21.333h-140.8l21.333-42.667h89.6v-136.533c0-17.067 12.8-29.867 29.867-29.867h140.8v-341.333h-426.667v328.533h-42.667v-341.333c0-17.067 12.8-29.867 29.867-29.867h448c17.067 0 29.867 12.8 29.867 29.867v384c4.267 17.067-8.533 38.4-21.333 51.2zM640 456.535v123.733c4.267 0 12.8-4.267 12.8-8.533l102.4-102.4c4.267-4.267 4.267-8.533 8.533-12.8h-123.733zM725.333 166.401v196.267c0 4.267-4.267 8.533-8.533 8.533s-8.533 0-12.8-4.267l-89.6-89.6v-29.867l89.6-89.6c8.533-4.267 8.533 0 12.8 0 4.267 4.267 8.533 4.267 8.533 8.533zM349.867 473.601v136.533l59.733-59.733c8.533-8.533 17.067-4.267 25.6 0l12.8 12.8c8.533 8.533 8.533 17.067 0 25.6l-115.2 106.667c-8.533 8.533-17.067 8.533-21.333 0l-115.2-110.933c-4.267-8.533-4.267-17.067 0-25.6l12.8-12.8c8.533-8.533 17.067-8.533 21.333 0l59.733 59.733v-136.533c0-8.533 8.533-17.067 17.067-17.067h25.6c0 0 17.067 8.533 17.067 21.333z" />
|
||||
<glyph unicode="" glyph-name="play-icon" data-tags="play-icon" d="M392.533 597.335c81.067 46.933 187.733 46.933 273.067 0 42.667-25.6 72.533-55.467 98.133-98.133 72.533-128 29.867-294.4-98.133-371.2-128-72.533-294.4-29.867-371.2 98.133-46.933 81.067-46.933 187.733 0 273.067 21.333 42.667 55.467 72.533 98.133 98.133zM661.333 345.601c12.8 8.533 12.8 29.867 0 38.4l-192 110.933c-8.533 4.267-12.8 4.267-21.333 0s-12.8-12.8-12.8-21.333v-226.133c0-8.533 4.267-17.067 12.8-21.333s17.067-4.267 21.333 0l192 119.467z" />
|
||||
<glyph unicode="" glyph-name="copy" data-tags="copy" d="M722.133 561.201h-247.733c-65.867 0-119.2-53.333-119.2-119.2v-288.533c0-65.867 53.333-119.2 119.2-119.2h247.867c65.867 0 119.2 53.333 119.2 119.2v288.533c-0.267 65.867-53.467 119.2-119.333 119.2zM778.533 156.534c0-31.333-25.067-56.4-56.4-56.4h-247.867c-31.333 0-56.4 25.067-56.4 56.4v285.467c0 31.333 25.067 56.4 56.4 56.4h247.733c31.333 0 56.4-25.067 56.4-56.4v-285.467zM245.2 326.001v288.533c0 31.333 25.067 56.4 56.4 56.4h247.733c31.333 0 56.4-25.067 56.4-56.4v-18.8h62.667v18.8c0 65.867-53.333 119.2-119.2 119.2h-247.467c-65.867 0-119.2-53.333-119.2-119.2v-288.533c0-65.867 53.333-119.2 119.2-119.2h18.8v62.667h-18.8c-31.467-3.067-56.533 22-56.533 56.533zM681.2 360.534h-163.067c-18.8 0-31.333 12.533-31.333 31.333s12.533 31.333 31.333 31.333h163.067c18.8 0 31.333-12.533 31.333-31.333s-15.6-31.333-31.333-31.333zM681.2 266.401h-163.067c-18.8 0-31.333 12.533-31.333 31.333s12.533 31.333 31.333 31.333h163.067c18.8 0 31.333-12.533 31.333-31.333s-15.6-31.333-31.333-31.333zM681.2 172.268h-163.067c-18.8 0-31.333 12.533-31.333 31.333s12.533 31.333 31.333 31.333h163.067c18.8 0 31.333-12.533 31.333-31.333s-15.6-31.333-31.333-31.333z" />
|
||||
<glyph unicode="" glyph-name="examples-icon" data-tags="examples-icon" d="M213.333 166.402c89.6 38.4 183.467 68.267 273.067 17.067v281.6c-68.267 46.933-157.867 55.467-234.667 12.8l-38.4-311.467zM810.667 166.402l-42.667 315.733c-72.533 38.4-166.4 34.133-234.667-17.067v-285.867c93.867 51.2 187.733 21.333 277.333-12.8zM832 520.535c-51.2 29.867-110.933 46.933-170.667 55.467-51.2 0-102.4-8.533-149.333-29.867-46.933 21.333-98.133 29.867-149.333 29.867-59.733-4.267-119.467-25.6-170.667-55.467l-64-452.267c0 0 29.867-17.067 110.933 21.333 46.933 25.6 102.4 34.133 157.867 25.6 42.667-4.267 85.333-21.333 115.2-55.467v0c29.867 34.133 72.533 51.2 115.2 55.467 55.467 4.267 106.667-4.267 157.867-29.867 81.067-38.4 110.933-21.333 110.933-21.333l-64 456.533zM793.6 115.202c-42.667 21.333-89.6 34.133-140.8 34.133-8.533 0-21.333 0-29.867 0-42.667-4.267-81.067-17.067-115.2-42.667-34.133 25.6-72.533 38.4-115.2 42.667-12.8 0-21.333 0-34.133 0-46.933 0-93.867-8.533-136.533-29.867-21.333-12.8-46.933-21.333-72.533-25.6l64 413.867c46.933 25.6 98.133 38.4 149.333 42.667 46.933 0 93.867-8.533 136.533-25.6l12.8-8.533 12.8 4.267c42.667 17.067 89.6 25.6 136.533 25.6 51.2-4.267 102.4-17.067 149.333-42.667l59.733-418.133c-29.867 8.533-51.2 17.067-76.8 29.867z" />
|
||||
<glyph unicode="" glyph-name="tutorials-icon" data-tags="tutorials-icon" d="M887.467 430.935l-375.467-110.933h-4.267l-217.6 68.267c-21.333-25.6-34.133-59.733-34.133-98.133 21.333-12.8 25.6-38.4 12.8-59.733-4.267-4.267-8.533-8.533-12.8-12.8l17.067-145.067c0-4.267 0-4.267-4.267-8.533 0 0 0 0-4.267 0h-64c-4.267 0-4.267 0-8.533 4.267 0 4.267-4.267 4.267-4.267 8.533l17.067 145.067c-12.8 8.533-17.067 21.333-17.067 34.133 0 17.067 8.533 29.867 21.333 38.4 0 38.4 12.8 76.8 34.133 110.933l-106.667 29.867c-8.533 4.267-8.533 8.533-8.533 17.067 0 4.267 4.267 4.267 4.267 4.267l375.467 119.467h4.267l375.467-123.733c4.267 0 8.533-4.267 8.533-8.533s-4.267-8.533-8.533-12.8zM725.333 234.669c4.267-46.933-93.867-85.333-213.333-85.333s-213.333 38.4-213.333 85.333l4.267 106.667 192-64c4.267 0 12.8 0 17.067 0s12.8 0 17.067 4.267l192 59.733 4.267-106.667z" />
|
||||
<glyph unicode="" glyph-name="info-important-description" data-tags="info-important-description" d="M512 697.368c-188.5 0-341.3-152.8-341.3-341.3s152.8-341.4 341.3-341.4 341.3 152.8 341.3 341.3-152.8 341.4-341.3 341.4v0zM512 43.268c-172.7 0-312.7 140-312.7 312.7s140 312.7 312.7 312.7c172.7 0 312.7-140 312.7-312.7-0.2-172.6-140.1-312.5-312.7-312.7v0zM512 605.568c-137.9 0-249.6-111.8-249.6-249.6s111.7-249.6 249.6-249.6 249.6 111.8 249.6 249.6-111.8 249.6-249.6 249.6v0z" />
|
||||
<glyph unicode="" glyph-name="icon-info" data-tags="icon-info" d="M467.2 459.522h87.467c0.028 0 0.062 0 0.095 0 6.056 0 11.499 2.629 15.248 6.808 3.979 4.15 6.419 9.769 6.419 15.957 0 0.097-0.001 0.194-0.002 0.29v70.385c0.001 0.082 0.002 0.179 0.002 0.276 0 6.188-2.44 11.806-6.409 15.946-3.759 4.19-9.201 6.819-15.257 6.819-0.033 0-0.067 0-0.1 0h-87.462c-0.028 0-0.062 0-0.095 0-6.056 0-11.499-2.629-15.248-6.808-3.979-4.15-6.419-9.769-6.419-15.957 0-0.097 0.001-0.194 0.002-0.29v-69.959c-0.001-0.082-0.002-0.179-0.002-0.276 0-6.188 2.44-11.806 6.409-15.946 3.715-4.373 9.2-7.159 15.338-7.245zM597.333 156.589h-22.187v209.92c0.001 0.082 0.002 0.179 0.002 0.276 0 6.188-2.44 11.806-6.409 15.946-3.759 4.19-9.201 6.819-15.257 6.819-0.033 0-0.067 0-0.1 0h-130.128c-0.028 0-0.062 0-0.095 0-6.056 0-11.499-2.629-15.248-6.808-3.979-4.15-6.419-9.769-6.419-15.957 0-0.097 0.001-0.194 0.002-0.29v-46.492c-0.001-0.082-0.002-0.179-0.002-0.276 0-6.188 2.44-11.806 6.409-15.946 3.759-4.19 9.201-6.819 15.257-6.819 0.033 0 0.067 0 0.1 0h22.182v-139.947h-22.187c-0.028 0-0.062 0-0.095 0-6.056 0-11.499-2.629-15.248-6.808-3.979-4.15-6.419-9.769-6.419-15.957 0-0.097 0.001-0.194 0.002-0.29v-46.492c-0.001-0.082-0.002-0.179-0.002-0.276 0-6.188 2.44-11.806 6.409-15.946 3.759-4.19 9.201-6.819 15.257-6.819 0.033 0 0.067 0 0.1 0h174.075c0.028 0 0.062 0 0.095 0 6.056 0 11.499 2.629 15.248 6.808 3.979 4.15 6.419 9.769 6.419 15.957 0 0.097-0.001 0.194-0.002 0.29v46.065c0.043 0.527 0.067 1.141 0.067 1.761 0 5.302-1.791 10.185-4.8 14.079-3.742 4.424-9.36 7.247-15.636 7.247-0.489 0-0.975-0.017-1.456-0.051z" />
|
||||
<glyph unicode="" glyph-name="paste" data-tags="paste" d="M394.402 702.4h-75.333c-65.867 0-119.2-53.333-119.2-119.2v-288.533c0-56.4 37.6-100.4 87.867-116v69.067c-15.733 9.467-25.067 25.067-25.067 47.067v288.4c0 31.333 25.067 56.4 56.4 56.4h131.733c0 0 0 0 3.2 3.2v0c0 31.333-28.267 59.6-59.6 59.6zM704.802 592.533c0 0-28.267 0-40.8 0-12.533 34.533-43.867 59.6-84.667 59.6s-69.067-25.067-81.6-59.6c-12.533 0-40.8 0-40.8 0-65.867 0-119.2-53.333-119.2-119.2v-288.533c0-65.867 53.333-119.2 119.2-119.2h247.867c65.867 0 119.2 53.333 119.2 119.2v285.467c3.2 65.867-53.2 122.267-119.2 122.267zM582.535 605.2c22 0 40.8-18.8 40.8-40.8s-18.8-40.8-40.8-40.8c-22 0-40.8 18.8-40.8 40.8s15.733 40.8 40.8 40.8zM764.402 181.733c0-31.333-25.067-56.4-56.4-56.4h-250.933c-31.333 0-56.4 25.067-56.4 56.4v288.533c0 18.8 9.467 37.6 25.067 47.067v0c0-43.867 34.533-78.4 78.4-78.4h160c43.867 0 78.4 34.533 78.4 78.4v0c12.533-9.467 22-28.267 22-47.067v-288.533z" />
|
||||
<glyph unicode="" glyph-name="arrow-down" data-tags="arrow-down" d="M234 565.667h556l-278-278z" />
|
||||
<glyph unicode="" glyph-name="arrow-left" data-tags="arrow-left" d="M381 164.667v524l262-262z" />
|
||||
<glyph unicode="" glyph-name="colapse" data-tags="colapse" d="M512 584.667l256-256-60-60-196 196-196-196-60 60z" />
|
||||
<glyph unicode="" glyph-name="expand" data-tags="expand" d="M708 584.667l60-60-256-256-256 256 60 60 196-196z" />
|
||||
<glyph unicode="" glyph-name="move" data-tags="move" d="M386.662 853.061h71.27v-71.27h-71.27v71.27zM566.067 853.061h71.27v-71.27h-71.27v71.27zM386.662 696.798h71.27v-71.27h-71.27v71.27zM566.067 696.798h71.27v-71.27h-71.27v71.27zM386.662 540.433h71.27v-71.27h-71.27v71.27zM566.067 540.433h71.27v-71.27h-71.27v71.27zM386.662 384.171h71.27v-71.27h-71.27v71.27zM566.067 384.171h71.27v-71.27h-71.27v71.27zM386.662 227.806h71.27v-71.27h-71.27v71.27zM566.067 227.806h71.27v-71.27h-71.27v71.27zM386.662 71.544h71.27v-71.27h-71.27v71.27zM566.067 71.544h71.27v-71.27h-71.27v71.27z" />
|
||||
<glyph unicode="" glyph-name="check-mark" data-tags="check-mark" d="M454.301 395.253l-116.917 116.917-84.781-84.707 201.696-201.697 317.097 317.097-84.781 84.706z" />
|
||||
<glyph unicode="" glyph-name="arrow-up-circle" data-tags="arrow-up-circle" d="M513.344 689.068c-148.616 0-264.722-120.75-260.077-269.367 0-125.395 88.241-232.212 208.991-255.434v213.636h-92.885c-13.933 0-13.933 9.288-9.288 18.577l139.327 171.838c4.645 9.288 13.933 9.288 23.221 4.645 0 0 4.645-4.645 4.645-4.645l139.327-171.838c9.288-9.288 4.645-18.577-9.288-18.577h-92.885v-213.636c143.972 32.51 232.212 171.838 199.703 315.808-23.221 120.75-130.039 204.347-250.789 208.991z" />
|
||||
<glyph unicode="" glyph-name="info-circle" data-tags="info-circle" d="M512 686.933c-144.077 0-260.266-116.191-260.266-260.266s116.191-260.266 260.266-260.266 260.266 116.191 260.266 260.266v0c0 139.429-116.191 255.619-260.266 260.266zM470.171 635.81h88.305v-69.714h-88.305v69.714zM600.305 245.41h-181.257v51.123h51.123v162.666h-51.123v51.123h139.429v-218.438h46.477l-4.648-46.477z" />
|
||||
<glyph unicode="" glyph-name="search" data-tags="search" d="M769.263 223.163l-110.68 110.68c71.943 99.612 49.806 243.494-49.806 315.437s-243.494 44.27-315.437-55.339c-71.943-99.612-49.806-243.494 49.806-315.437 77.475-55.339 182.623-55.339 260.098 0l110.68-110.68c5.533-5.533 11.068-5.533 16.601 0 0 0 0 0 0 0l33.205 33.205c11.068 5.533 11.068 16.601 5.533 22.137 0 0 0 0 0 0zM475.96 300.638c-88.544 0-160.486 71.943-160.486 160.486s71.943 160.486 160.486 160.486 160.486-71.943 160.486-160.486-71.943-160.486-160.486-160.486v0z" />
|
||||
<glyph unicode="" glyph-name="fullscreen" data-tags="fullscreen" d="M357.075 572.983c5.737 5.737 0 5.737-5.737 5.737l-103.284 11.476c-5.737 5.737-11.476 0-11.476-5.737l11.476-109.021c0-5.737 5.737-5.737 5.737-5.737l103.284 103.284zM282.484 509.865l63.118-63.118c5.737-5.737 11.476-5.737 17.213 0l22.953 22.953c5.737 5.737 5.737 11.476 0 17.213l-63.118 57.379-40.166-34.429zM775.945 469.699c5.737-5.737 5.737 0 5.737 5.737l11.476 109.021c0 5.737-5.737 11.476-11.476 11.476l-109.021-11.476c-5.737 0-5.737-5.737-5.737-5.737l109.021-109.021zM712.83 544.294l-63.118-63.118c-5.737-5.737-5.737-11.476 0-17.213l22.953-22.953c5.737-5.737 11.476-5.737 17.213 0l63.118 63.118-40.166 40.166zM678.401 263.134c-5.737-5.737 0-5.737 5.737-5.737l109.021-11.476c5.737 0 11.476 5.737 11.476 11.476l-17.213 103.284c0 5.737-5.737 5.737-5.737 5.737l-103.284-103.284zM747.256 331.989l-63.118 63.118c-5.737 5.737-11.476 5.737-17.213 0l-22.953-22.953c-5.737-5.737-5.737-11.476 0-17.213l63.118-63.118 40.166 40.166zM253.794 366.418c-5.737 5.737-5.737 0-5.737-5.737l-11.476-109.021c0-5.737 5.737-11.476 11.476-11.476l109.021 11.476c5.737 0 5.737 5.737 5.737 5.737l-109.021 109.021zM322.649 291.824l63.118 63.118c5.737 5.737 5.737 11.476 0 17.213l-22.953 22.953c-5.737 5.737-11.476 5.737-17.213 0l-63.118-63.118 40.166-40.166zM150.51 676.267v-499.201h722.979v499.201h-722.979zM833.324 217.232h-636.911v413.13h636.911v-413.13z" />
|
||||
<glyph unicode="" glyph-name="h5p" data-tags="h5p" d="M891.406 574.524c-22.319 16.738-50.216 27.897-89.273 27.897h-139.487v-66.954h-156.225l-11.159-55.795c11.159 5.579 27.897 11.159 39.057 11.159s22.319 0 33.476 0c33.476 0 66.954-11.159 89.273-33.476s33.476-50.216 33.476-83.692c0-22.319-5.579-44.635-16.738-66.954s-27.897-39.057-50.216-50.216c-5.579-5.579-16.738 0-22.319-11.159h117.17v133.908h66.954c44.635 0 78.113 11.159 100.43 27.897 22.319 22.319 33.476 50.216 33.476 83.692 0 39.057-11.159 66.954-27.897 83.692v0zM796.555 462.935c-11.159-5.579-22.319-11.159-44.635-11.159h-33.476v83.692h39.057c22.319 0 33.476-5.579 44.635-11.159 5.579-5.579 11.159-16.738 11.159-27.897 0-16.738-5.579-27.897-16.738-33.476v0zM523.16 423.878c-16.738 0-33.476-11.159-44.635-27.897l-94.851 16.738 44.635 195.281h-94.851v-150.646h-117.17v150.646h-111.589v-362.667h111.589v133.908h117.17v-133.908h139.487c-16.738 11.159-33.476 11.159-44.635 22.319s-22.319 22.319-27.897 33.476c-5.579 11.159-11.159 22.319-16.738 39.057l94.851 16.738c5.579-16.738 22.319-27.897 44.635-27.897 27.897 0 50.216 22.319 50.216 50.216 0 22.319-22.319 44.635-50.216 44.635v0z" />
|
||||
<glyph unicode="" glyph-name="rights-of-use" data-tags="rights-of-use" d="M878.277 414.35c0-5.907 0-5.907 0-5.907-23.631-23.631-47.261-35.448-76.799-41.355-11.813 0-23.631-5.907-35.448-5.907s-17.724 0-29.537 0c0 0-5.907 0-5.907 5.907-64.985 59.079-135.877 118.153-200.863 183.139 0 0-5.907 0-5.907 0-23.631-5.907-47.261-11.813-70.892-17.724s-53.168 0-76.799 11.813c-17.724 11.813-23.631 17.724-29.537 35.448-5.907 5.907 0 23.631 11.813 23.631 41.355 11.813 88.616 29.537 129.971 47.261 11.813 5.907 29.537 5.907 41.355 5.907 5.907 0 11.813-5.907 11.813-5.907 41.355-17.724 82.709-29.537 124.060-47.261 0 0 5.907 0 5.907 0 29.537 5.907 64.985 17.724 94.523 23.631 5.907 0 5.907 0 5.907 0l106.34-212.676zM269.786 420.26c17.724 11.813 35.448 5.907 53.168-11.813 11.813-11.813 11.813-29.537 5.907-47.261 17.724 5.907 35.448-5.907 41.355-17.724 11.813-17.724 5.907-35.448-5.907-47.261 5.907 0 11.813 0 17.724 0 11.813-5.907 23.631-11.813 29.537-29.537s0-29.537-5.907-35.448c-5.907-5.907-11.813-11.813-17.724-17.724s-11.813-11.813-17.724-17.724-35.448-17.724-53.168 0c-29.537 29.537-53.168 64.985-82.709 94.523-17.724 23.631-35.448 41.355-47.261 64.985-5.907 11.813-11.813 17.724-11.813 29.537 0 5.907 0 17.724 5.907 23.631 11.813 11.813 17.724 17.724 29.537 29.537 17.724 17.724 47.261 11.813 64.985-5.907-5.907 0-5.907-5.907-5.907-11.813v0zM417.477 213.491l29.537-29.537c17.724-17.724 47.261-11.813 59.079 5.907l-5.907 5.907c-23.631 23.631-47.261 47.261-70.892 70.892-5.907 5.907-5.907 5.907-5.907 11.813s5.907 5.907 11.813 11.813c5.907 0 11.813 0 11.813-5.907 11.813-11.813 29.537-29.537 47.261-47.261 11.813-11.813 29.537-29.537 47.261-47.261 5.907-11.813 17.724-11.813 29.537-11.813 11.813 5.907 23.631 11.813 29.537 23.631 0 5.907 0 5.907 0 5.907-41.355 41.355-88.616 82.709-129.971 129.971-5.907 5.907-5.907 5.907-5.907 11.813 0 11.813 11.813 11.813 23.631 5.907 0 0 5.907 0 5.907-5.907 41.355-41.355 88.616-88.616 129.971-129.971 5.907-5.907 5.907-5.907 5.907-5.907 17.724 0 35.448 17.724 35.448 35.448 0 5.907 0 5.907 0 5.907-47.261 47.261-100.429 100.429-147.691 147.691-5.907 5.907-5.907 5.907-5.907 11.813s5.907 11.813 5.907 11.813c5.907 0 11.813 0 11.813-5.907 5.907-5.907 5.907-5.907 11.813-11.813 35.448-35.448 70.892-70.892 106.34-106.34 11.813-11.813 23.631-23.631 29.537-29.537 0 0 5.907-5.907 5.907 0 23.631 5.907 35.448 29.537 29.537 53.168h35.448c0 0 0 0 0 0 0-5.907 0-17.724 0-23.631-5.907-29.537-23.631-47.261-53.168-59.079 0 0-5.907 0-5.907-5.907-11.813-29.537-35.448-53.168-64.985-53.168-5.907 0-5.907 0-5.907-5.907-17.724-35.448-59.079-47.261-88.616-35.448-5.907 0-11.813 5.907-11.813 5.907-5.907-5.907-11.813-11.813-23.631-17.724-29.537-11.813-59.079-5.907-76.799 11.813-11.813 11.813-17.724 17.724-29.537 29.537 17.724 23.631 23.631 29.537 29.537 41.355v0 0zM252.062 727.459c29.537-11.813 64.985-23.631 94.523-29.537 35.448-11.813 64.985-23.631 100.429-29.537 0 0 0 0 5.907 0-17.724-5.907-35.448-11.813-47.261-17.724 0 0-5.907 0-5.907 0-47.261 11.813-94.523 23.631-135.877 41.355-5.907 0-5.907 0-5.907 0l-76.799-183.139c0-11.813 5.907-17.724 11.813-23.631s5.907-5.907 5.907-11.813c-5.907-5.907-11.813-17.724-23.631-23.631-17.724 17.724-29.537 35.448-29.537 64.985l88.616 212.676c-5.907-11.813 5.907 5.907 17.724 0v0z" />
|
||||
<glyph unicode="" glyph-name="delete-circle" data-tags="delete-circle" d="M512 686.933c-147.107 0-260.266-118.817-260.266-260.266s118.817-260.266 260.266-260.266 260.266 118.817 260.266 260.266-113.158 260.266-260.266 260.266zM653.449 347.455c5.659-5.659 5.659-16.973 0-28.29l-33.949-33.949c-5.659-5.659-16.973-5.659-28.29 0l-79.212 79.212-79.212-79.212c-5.659-5.659-16.973-5.659-28.29 0l-33.949 33.949c-5.659 5.659-5.659 16.973 0 28.29l84.871 79.212-79.212 79.212c-5.659 5.659-5.659 16.973 0 28.29l33.949 33.949c5.659 5.659 16.973 5.659 28.29 0l73.554-84.871 79.212 79.212c5.659 5.659 16.973 5.659 28.29 0l33.949-33.949c5.659-5.659 5.659-16.973 0-28.29l-79.212-73.554 79.212-79.212z" />
|
||||
<glyph unicode="" glyph-name="window" data-tags="window" d="M186.821 549.319c-5.704-5.704 0-5.704 5.704-5.704l108.394-11.41c5.704 0 11.41 5.704 11.41 11.41l-17.114 102.687c0 5.704-5.704 5.704-5.704 5.704l-102.687-102.687zM255.28 612.074l-62.752 62.752c-5.704 5.704-11.41 5.704-17.114 0l-17.114-22.821c-5.704-5.704-5.704-11.41 0-17.114l62.752-62.752 34.228 39.935zM734.49 646.302c-5.704 5.704-5.704 0-5.704-5.704l-11.41-108.394c0-5.704 5.704-11.41 11.41-11.41l108.394 11.41c5.704 0 5.704 5.704 5.704 5.704l-108.394 108.394zM797.242 572.14l62.752 62.752c5.704 5.704 5.704 11.41 0 17.114l-22.821 22.821c-5.704 5.704-11.41 5.704-17.114 0l-62.752-62.752 39.935-39.935zM831.473 309.717c5.704 5.704 0 5.704-5.704 5.704l-102.687 17.114c-5.704 0-11.41-5.704-11.41-11.41l11.41-108.394c0-5.704 5.704-5.704 5.704-5.704l102.687 102.687zM763.014 246.962l62.752-62.752c5.704-5.704 11.41-5.704 17.114 0l22.821 22.821c5.704 5.704 5.704 11.41 0 17.114l-62.752 62.752-39.935-39.935zM283.804 212.734c5.704-5.704 5.704 0 5.704 5.704l11.41 108.394c0 5.704-5.704 11.41-11.41 11.41l-108.394-11.41c-5.704 0-5.704-5.704-5.704-5.704l108.394-108.394zM221.052 281.193l-62.752-62.752c-5.704-5.704-5.704-11.41 0-17.114l22.821-22.821c5.704-5.704 11.41-5.704 17.114 0l62.752 62.752-39.935 39.935zM335.149 555.026v-239.605h347.998v239.605h-347.998zM637.507 355.355h-262.424v154.032h262.424v-154.032z" />
|
||||
<glyph unicode="" glyph-name="code" data-tags="code" d="M446.523 311.303c6.235-6.235 6.235-12.472 6.235-18.707v-62.359c0-6.235-6.235-6.235-6.235-6.235l-230.728 155.897c-6.235 6.235-6.235 12.472-6.235 18.707v49.886c0 6.235 6.235 12.472 6.235 18.707l230.728 155.897c6.235 6.235 6.235 0 6.235-6.235v-62.359c0-6.235-6.235-12.472-6.235-18.707l-162.134-112.245c-6.235-6.235-6.235-6.235 0-12.472l162.134-99.776zM733.375 417.313c6.235 6.235 6.235 6.235 0 12.472l-155.897 112.245c-6.235 6.235-6.235 12.472-6.235 18.707v62.359c0 6.235 6.235 6.235 6.235 6.235l230.728-155.897c6.235-6.235 6.235-12.472 6.235-18.707v-49.886c0-6.235-6.235-12.472-6.235-18.707l-230.728-155.897c-6.235-6.235-6.235 0-6.235 6.235v62.359c0 6.235 6.235 12.472 6.235 18.707l155.897 99.776z" />
|
||||
<glyph unicode="" glyph-name="download" data-tags="download" d="M353.050 512.027c-11.773 0-17.66-5.887-5.887-17.66l153.059-188.382c5.887-11.773 23.547-11.773 29.433 0l153.059 188.382c5.887 11.773 5.887 17.66-5.887 17.66h-323.782zM570.865 500.253v135.399c0 11.773-11.773 23.547-23.547 23.547h-70.643c-11.773 0-23.547-11.773-23.547-23.547v-141.286h117.739zM647.395 364.854c-5.887 0-17.66-5.887-23.547-11.773l-76.53-94.19c-5.887-5.887-17.66-17.66-23.547-23.547 0 0-5.887-5.887-11.773-5.887s-17.66 11.773-17.66 11.773c-5.887 5.887-17.66 17.66-23.547 23.547l-76.53 94.19c-5.887 5.887-17.66 11.773-23.547 11.773h-123.626c-5.887 0-17.66-5.887-17.66-17.66v-141.286c0-5.887 5.887-17.66 17.66-17.66h529.824c5.887 0 17.66 5.887 17.66 17.66v141.286c0 5.887-5.887 17.66-17.66 17.66l-129.513-5.887zM300.067 253.004c-17.66 0-29.433 11.773-29.433 29.433s11.773 29.433 29.433 29.433c17.66 0 29.433-11.773 29.433-29.433s-11.773-29.433-29.433-29.433v0z" />
|
||||
<glyph unicode="" glyph-name="delete" data-tags="delete" d="M615.111 426.667l134.045 134.045c10.311 10.311 10.311 30.934 0 41.245l-61.866 61.866c-10.311 10.311-30.934 10.311-41.245 0l-134.045-134.045-134.045 134.045c-10.311 10.311-30.934 10.311-41.245 0l-61.866-61.866c-10.311-10.311-10.311-30.934 0-41.245l134.045-134.045-134.045-134.045c-10.311-10.311-10.311-30.934 0-41.245l61.866-61.866c10.311-10.311 30.934-10.311 41.245 0l134.045 134.045 134.045-134.045c10.311-10.311 30.934-10.311 41.245 0l61.866 61.866c10.311 10.311 10.311 30.934 0 41.245l-134.045 134.045z" />
|
||||
<glyph unicode="" glyph-name="edit-image" data-tags="edit-image" d="M300.336 749.664c69.018 23.142 133.325 14.234 189.133-33.28 56.627-48.128 77.619-110.592 63.181-183.808-2.355-12.186 0.307-19.456 8.704-27.853 93.901-93.389 156.774-156.467 250.47-250.163 5.427-5.427 10.957-10.854 15.667-16.896 39.424-50.278 16.794-124.006-44.237-142.029-36.966-10.957-68.403 0-95.334 27.034-95.642 96.051-160.973 160.973-256.614 257.024-6.963 6.963-12.8 8.909-22.63 6.758-117.76-26.317-229.171 60.826-231.731 181.453-0.614 26.419 3.584 52.326 15.974 77.926 34.816-34.816 68.506-67.789 101.274-101.786 10.445-10.752 20.992-15.36 36.045-15.36 14.643 0 25.19 3.891 34.816 14.848 10.752 12.39 23.040 23.347 34.611 35.021 14.336 14.438 14.336 46.080-0.205 60.518-35.123 35.226-70.349 70.349-106.598 106.496 3.891 2.253 5.632 3.482 7.475 4.096zM703.485 191.584c-0.41-24.269 20.685-45.466 44.851-45.158 23.757 0.41 44.032 20.992 43.93 44.544-0.102 23.757-20.275 44.032-44.237 44.134-23.859 0.307-44.237-19.661-44.544-43.52z" />
|
||||
<glyph unicode="" glyph-name="hourglass" data-tags="hourglass" d="M733.414 117.419c-147.763 0-295.526 0-443.29 0 0 2.048 0.102 4.096 0 6.144-0.307 13.824-1.024 32.666-0.922 46.49 0.41 39.731 6.861 78.131 19.046 115.2 17.203 52.224 43.725 96.256 81.306 130.355 4.506 4.096 9.216 7.885 13.722 11.776-0.205 0.717-0.307 1.126-0.41 1.229-1.331 1.229-2.765 2.355-4.198 3.584-28.058 22.63-50.688 51.405-68.403 85.606-30.618 59.085-43.52 123.597-41.165 192.614 0.205 7.168 0.614 18.33 0.922 25.498 147.763 0 295.526 0 443.29 0 0.205-1.331 0.512-2.662 0.614-3.994 2.662-36.966 1.229-77.722-5.939-113.869-14.336-72.909-44.544-133.837-95.027-179.405-4.096-3.686-8.294-7.066-12.39-10.547 0.205-0.717 0.307-1.126 0.512-1.331 0.819-0.717 1.638-1.434 2.458-2.15 42.189-33.894 71.68-79.872 90.931-135.782 11.776-34.202 18.637-69.837 20.070-106.701 0.819-19.763-0.614-44.851-1.126-64.717zM687.437 160.632c0 6.554 0.205 12.493 0 18.432-1.331 37.581-7.27 74.138-19.866 108.749-17.92 49.562-45.568 88.269-88.678 108.646-2.458 1.126-2.97 3.072-2.97 5.837 0.102 16.691 0.102 33.485 0 50.176 0 3.994 1.331 5.427 4.096 6.963 9.114 5.325 18.432 10.24 26.829 16.896 29.696 23.552 49.152 56.934 62.362 95.744 10.342 30.413 15.77 62.259 17.818 94.822 0.614 9.114 0.102 18.227 0.102 27.546-116.634 0-233.574 0-351.027 0 0.307-8.704 0.614-16.998 1.024-25.395 1.946-37.274 8.499-73.216 21.504-107.213 18.125-47.104 45.261-83.558 86.528-103.117 2.253-1.024 2.867-2.662 2.867-5.427-0.102-17.203-0.102-34.509 0-51.712 0-3.072-1.024-4.506-3.277-5.632-5.632-2.867-11.366-5.734-16.691-9.216-34.304-22.733-56.832-57.754-71.987-100.147-12.493-35.123-18.125-71.987-19.661-109.875-0.205-5.325 0-10.752 0-16.282 117.35 0.205 234.189 0.205 351.027 0.205zM410.342 579.96c68.096 0 135.373 0 203.674 0-3.789-6.554-7.168-12.595-10.752-18.227-10.957-16.998-24.269-30.618-39.731-41.472s-27.75-25.293-32.768-46.592c-1.638-6.963-2.765-14.336-2.867-21.606-0.307-17.203-0.205-34.406 0.307-51.712 0.717-28.058 12.493-48.947 32.154-62.566 43.008-30.003 65.843-75.878 75.776-132.506 0.307-1.638 0.307-3.379 0.614-5.53-83.149 0-166.093 0-249.242 0 2.662 20.685 7.885 40.346 15.462 59.085 13.312 32.973 32.768 59.187 59.494 77.722 16.589 11.469 28.365 27.955 32.358 50.995 0.819 4.813 1.331 9.83 1.434 14.746 0.102 18.637 0.614 37.274-0.205 55.808-1.126 24.678-11.981 43.213-28.57 57.139-9.216 7.782-18.944 14.746-27.648 23.142-11.981 11.162-21.197 25.395-29.491 41.574z" />
|
||||
<glyph unicode="" glyph-name="plus-icon" data-tags="plus-icon" d="M767.787 391.893c0-19.323-15.664-34.987-34.987-34.987h-151.040v-151.467c0-19.323-15.664-34.987-34.987-34.987h-69.547c-19.323 0-34.987 15.664-34.987 34.987v151.467h-151.467c-19.323 0-34.987 15.664-34.987 34.987v69.547c0 19.323 15.664 34.987 34.987 34.987h151.467v151.467c0 19.323 15.664 34.987 34.987 34.987h69.547c19.323 0 34.987-15.664 34.987-34.987v-151.467h151.467c19.323 0 34.987-15.664 34.987-34.987z" />
|
||||
<glyph unicode="" glyph-name="video-upload-icon" data-tags="video-upload-icon" d="M395.848 387.201v-128c0-21.333 21.333-42.667 42.667-42.667h128c21.333 0 42.667 17.067 42.667 42.667v128c0 21.333-17.067 42.667-42.667 42.667h-128c-21.333 0-42.667-17.067-42.667-42.667zM796.915 557.867l-102.4 106.667c-12.8 12.8-38.4 21.333-55.467 21.333h-140.8l21.333-42.667h89.6v-136.533c0-17.067 12.8-29.867 29.867-29.867h140.8v-341.333h-426.667v328.533h-42.667v-341.333c0-17.067 12.8-29.867 29.867-29.867h448c17.067 0 29.867 12.8 29.867 29.867v384c4.267 17.067-8.533 38.4-21.333 51.2zM651.848 515.201v123.733c4.267 0 12.8-4.267 12.8-8.533l102.4-102.4c4.267-4.267 4.267-8.533 8.533-12.8h-123.733zM737.181 225.067v196.267c0 4.267-4.267 8.533-8.533 8.533s-8.533 0-12.8-4.267l-89.6-89.6v-29.867l89.6-89.6c8.533-4.267 8.533 0 12.8 0 4.267 4.267 8.533 4.267 8.533 8.533zM361.715 532.267v136.533l59.733-59.733c8.533-8.533 17.067-4.267 25.6 0l12.8 12.8c8.533 8.533 8.533 17.067 0 25.6l-115.2 106.667c-8.533 8.533-17.067 8.533-21.333 0l-115.2-110.933c-4.267-8.533-4.267-17.067 0-25.6l12.8-12.8c8.533-8.533 17.067-8.533 21.333 0l59.733 59.733v-136.533c0-8.533 8.533-17.067 17.067-17.067h25.6c0 0 17.067 8.533 17.067 21.333z" />
|
||||
<glyph unicode="" glyph-name="play-icon" data-tags="play-icon" d="M375.444 661.357c81.067 46.933 187.733 46.933 273.067 0 42.667-25.6 72.533-55.467 98.133-98.133 72.533-128 29.867-294.4-98.133-371.2-128-72.533-294.4-29.867-371.2 98.133-46.933 81.067-46.933 187.733 0 273.067 21.333 42.667 55.467 72.533 98.133 98.133zM644.244 409.623c12.8 8.533 12.8 29.867 0 38.4l-192 110.933c-8.533 4.267-12.8 4.267-21.333 0s-12.8-12.8-12.8-21.333v-226.133c0-8.533 4.267-17.067 12.8-21.333s17.067-4.267 21.333 0l192 119.467z" />
|
||||
<glyph unicode="" glyph-name="copy" data-tags="copy" d="M722.133 603.867h-247.733c-65.867 0-119.2-53.333-119.2-119.2v-288.533c0-65.867 53.333-119.2 119.2-119.2h247.867c65.867 0 119.2 53.333 119.2 119.2v288.533c-0.267 65.867-53.467 119.2-119.333 119.2zM778.533 199.2c0-31.333-25.067-56.4-56.4-56.4h-247.867c-31.333 0-56.4 25.067-56.4 56.4v285.467c0 31.333 25.067 56.4 56.4 56.4h247.733c31.333 0 56.4-25.067 56.4-56.4v-285.467zM245.2 368.667v288.533c0 31.333 25.067 56.4 56.4 56.4h247.733c31.333 0 56.4-25.067 56.4-56.4v-18.8h62.667v18.8c0 65.867-53.333 119.2-119.2 119.2h-247.467c-65.867 0-119.2-53.333-119.2-119.2v-288.533c0-65.867 53.333-119.2 119.2-119.2h18.8v62.667h-18.8c-31.467-3.067-56.533 22-56.533 56.533zM681.2 403.2h-163.067c-18.8 0-31.333 12.533-31.333 31.333s12.533 31.333 31.333 31.333h163.067c18.8 0 31.333-12.533 31.333-31.333s-15.6-31.333-31.333-31.333zM681.2 309.067h-163.067c-18.8 0-31.333 12.533-31.333 31.333s12.533 31.333 31.333 31.333h163.067c18.8 0 31.333-12.533 31.333-31.333s-15.6-31.333-31.333-31.333zM681.2 214.934h-163.067c-18.8 0-31.333 12.533-31.333 31.333s12.533 31.333 31.333 31.333h163.067c18.8 0 31.333-12.533 31.333-31.333s-15.6-31.333-31.333-31.333z" />
|
||||
<glyph unicode="" glyph-name="examples-icon" data-tags="examples-icon" d="M213.333 275.201c89.6 38.4 183.467 68.267 273.067 17.067v281.6c-68.267 46.933-157.867 55.467-234.667 12.8l-38.4-311.467zM810.667 275.201l-42.667 315.733c-72.533 38.4-166.4 34.133-234.667-17.067v-285.867c93.867 51.2 187.733 21.333 277.333-12.8zM832 629.334c-51.2 29.867-110.933 46.933-170.667 55.467-51.2 0-102.4-8.533-149.333-29.867-46.933 21.333-98.133 29.867-149.333 29.867-59.733-4.267-119.467-25.6-170.667-55.467l-64-452.267c0 0 29.867-17.067 110.933 21.333 46.933 25.6 102.4 34.133 157.867 25.6 42.667-4.267 85.333-21.333 115.2-55.467v0c29.867 34.133 72.533 51.2 115.2 55.467 55.467 4.267 106.667-4.267 157.867-29.867 81.067-38.4 110.933-21.333 110.933-21.333l-64 456.533zM793.6 224.001c-42.667 21.333-89.6 34.133-140.8 34.133-8.533 0-21.333 0-29.867 0-42.667-4.267-81.067-17.067-115.2-42.667-34.133 25.6-72.533 38.4-115.2 42.667-12.8 0-21.333 0-34.133 0-46.933 0-93.867-8.533-136.533-29.867-21.333-12.8-46.933-21.333-72.533-25.6l64 413.867c46.933 25.6 98.133 38.4 149.333 42.667 46.933 0 93.867-8.533 136.533-25.6l12.8-8.533 12.8 4.267c42.667 17.067 89.6 25.6 136.533 25.6 51.2-4.267 102.4-17.067 149.333-42.667l59.733-418.133c-29.867 8.533-51.2 17.067-76.8 29.867z" />
|
||||
<glyph unicode="" glyph-name="tutorials-icon" data-tags="tutorials-icon" d="M887.468 537.598l-375.467-110.933h-4.267l-217.6 68.267c-21.333-25.6-34.133-59.733-34.133-98.133 21.333-12.8 25.6-38.4 12.8-59.733-4.267-4.267-8.533-8.533-12.8-12.8l17.067-145.067c0-4.267 0-4.267-4.267-8.533 0 0 0 0-4.267 0h-64c-4.267 0-4.267 0-8.533 4.267 0 4.267-4.267 4.267-4.267 8.533l17.067 145.067c-12.8 8.533-17.067 21.333-17.067 34.133 0 17.067 8.533 29.867 21.333 38.4 0 38.4 12.8 76.8 34.133 110.933l-106.667 29.867c-8.533 4.267-8.533 8.533-8.533 17.067 0 4.267 4.267 4.267 4.267 4.267l375.467 119.467h4.267l375.467-123.733c4.267 0 8.533-4.267 8.533-8.533s-4.267-8.533-8.533-12.8zM725.334 341.332c4.267-46.933-93.867-85.333-213.333-85.333s-213.333 38.4-213.333 85.333l4.267 106.667 192-64c4.267 0 12.8 0 17.067 0s12.8 0 17.067 4.267l192 59.733 4.267-106.667z" />
|
||||
<glyph unicode="" glyph-name="info-important-description" data-tags="info-important-description" d="M512 768.017c-188.5 0-341.3-152.8-341.3-341.3s152.8-341.4 341.3-341.4 341.3 152.8 341.3 341.3-152.8 341.4-341.3 341.4v0zM512 113.917c-172.7 0-312.7 140-312.7 312.7s140 312.7 312.7 312.7c172.7 0 312.7-140 312.7-312.7-0.2-172.6-140.1-312.5-312.7-312.7v0zM512 676.217c-137.9 0-249.6-111.8-249.6-249.6s111.7-249.6 249.6-249.6 249.6 111.8 249.6 249.6-111.8 249.6-249.6 249.6v0z" />
|
||||
<glyph unicode="" glyph-name="icon-info" data-tags="icon-info" d="M468.875 565.974h87.467c0.028 0 0.062 0 0.095 0 6.056 0 11.499 2.629 15.248 6.808 3.979 4.15 6.419 9.769 6.419 15.957 0 0.097-0.001 0.194-0.002 0.29v70.385c0.001 0.082 0.002 0.179 0.002 0.276 0 6.188-2.44 11.806-6.409 15.946-3.759 4.19-9.201 6.819-15.257 6.819-0.033 0-0.067 0-0.1 0h-87.462c-0.028 0-0.062 0-0.095 0-6.056 0-11.499-2.629-15.248-6.808-3.979-4.15-6.419-9.769-6.419-15.957 0-0.097 0.001-0.194 0.002-0.29v-69.959c-0.001-0.082-0.002-0.179-0.002-0.276 0-6.188 2.44-11.806 6.409-15.946 3.715-4.373 9.2-7.159 15.338-7.245zM599.008 263.041h-22.187v209.92c0.001 0.082 0.002 0.179 0.002 0.276 0 6.188-2.44 11.806-6.409 15.946-3.759 4.19-9.201 6.819-15.257 6.819-0.033 0-0.067 0-0.1 0h-130.128c-0.028 0-0.062 0-0.095 0-6.056 0-11.499-2.629-15.248-6.808-3.979-4.15-6.419-9.769-6.419-15.957 0-0.097 0.001-0.194 0.002-0.29v-46.492c-0.001-0.082-0.002-0.179-0.002-0.276 0-6.188 2.44-11.806 6.409-15.946 3.759-4.19 9.201-6.819 15.257-6.819 0.033 0 0.067 0 0.1 0h22.182v-139.947h-22.187c-0.028 0-0.062 0-0.095 0-6.056 0-11.499-2.629-15.248-6.808-3.979-4.15-6.419-9.769-6.419-15.957 0-0.097 0.001-0.194 0.002-0.29v-46.492c-0.001-0.082-0.002-0.179-0.002-0.276 0-6.188 2.44-11.806 6.409-15.946 3.759-4.19 9.201-6.819 15.257-6.819 0.033 0 0.067 0 0.1 0h174.075c0.028 0 0.062 0 0.095 0 6.056 0 11.499 2.629 15.248 6.808 3.979 4.15 6.419 9.769 6.419 15.957 0 0.097-0.001 0.194-0.002 0.29v46.065c0.043 0.527 0.067 1.141 0.067 1.761 0 5.302-1.791 10.185-4.8 14.079-3.742 4.424-9.36 7.247-15.636 7.247-0.489 0-0.975-0.017-1.456-0.051z" />
|
||||
<glyph unicode="" glyph-name="paste" data-tags="paste" d="M394.402 745.067h-75.333c-65.867 0-119.2-53.333-119.2-119.2v-288.533c0-56.4 37.6-100.4 87.867-116v69.067c-15.733 9.467-25.067 25.067-25.067 47.067v288.4c0 31.333 25.067 56.4 56.4 56.4h131.733c0 0 0 0 3.2 3.2v0c0 31.333-28.267 59.6-59.6 59.6zM704.802 635.2c0 0-28.267 0-40.8 0-12.533 34.533-43.867 59.6-84.667 59.6s-69.067-25.067-81.6-59.6c-12.533 0-40.8 0-40.8 0-65.867 0-119.2-53.333-119.2-119.2v-288.533c0-65.867 53.333-119.2 119.2-119.2h247.867c65.867 0 119.2 53.333 119.2 119.2v285.467c3.2 65.867-53.2 122.267-119.2 122.267zM582.535 647.867c22 0 40.8-18.8 40.8-40.8s-18.8-40.8-40.8-40.8c-22 0-40.8 18.8-40.8 40.8s15.733 40.8 40.8 40.8zM764.402 224.4c0-31.333-25.067-56.4-56.4-56.4h-250.933c-31.333 0-56.4 25.067-56.4 56.4v288.533c0 18.8 9.467 37.6 25.067 47.067v0c0-43.867 34.533-78.4 78.4-78.4h160c43.867 0 78.4 34.533 78.4 78.4v0c12.533-9.467 22-28.267 22-47.067v-288.533z" />
|
||||
<glyph unicode="" glyph-name="reuse" data-tags="reuse" d="M734.974 624.751c-54.605 61.619-134.123 100.573-222.977 100.573-164.936 0-298.661-133.724-298.661-298.661h74.667c0 123.721 100.272 223.993 223.993 223.993 68.214 0 128.747-30.96 169.766-79.119l-70.213-70.213h199.109v199.109l-75.689-75.689zM511.999 202.671c-68.214 0-128.747 30.96-169.766 79.119l70.213 70.213h-199.109v-199.109l75.689 75.689c54.605-61.619 134.123-100.573 222.977-100.573 164.936 0 298.661 133.724 298.661 298.661h-74.667c0-123.721-100.272-223.993-223.993-223.993z" />
|
||||
<glyph unicode="" glyph-name="info-outlined" data-tags="info-outlined" d="M467.199 181.336h89.599v268.8h-89.599v-268.8zM512 853.335c-247.296 0-448.001-200.705-448.001-448.001s200.705-448.001 448.001-448.001 448.001 200.705 448.001 448.001-200.705 448.001-448.001 448.001zM512 46.936c-197.568 0-358.398 160.83-358.398 358.398s160.83 358.398 358.398 358.398 358.398-160.83 358.398-358.398-160.83-358.398-358.398-358.398zM467.199 539.734h89.599v89.599h-89.599v-89.599z" />
|
||||
<glyph unicode="" glyph-name="spinner" data-tags="spinner" d="M600 808.001c0-48.602-39.398-88-88-88s-88 39.398-88 88 39.398 88 88 88 88-39.398 88-88zM512 133.333c-48.602 0-88-39.398-88-88s39.398-88 88-88 88 39.398 88 88-39.398 88-88 88zM893.334 514.667c-48.602 0-88-39.398-88-88s39.398-88 88-88 88 39.398 88 88-39.398 88-88 88zM218.666 426.667c0 48.602-39.398 88-88 88s-88-39.398-88-88 39.398-88 88-88 88 39.398 88 88zM242.357 245.024c-48.602 0-88-39.398-88-88s39.398-88 88-88 88 39.398 88 88c0 48.6-39.4 88-88 88zM781.643 245.024c-48.602 0-88-39.398-88-88s39.398-88 88-88 88 39.398 88 88c0 48.6-39.398 88-88 88zM242.357 784.31c-48.602 0-88-39.398-88-88s39.398-88 88-88 88 39.398 88 88-39.4 88-88 88z" />
|
||||
|
||||
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
Binary file not shown.
Binary file not shown.
@@ -107,7 +107,7 @@ abstract class H5PMetadata {
|
||||
switch ($config['type']) {
|
||||
case 'text':
|
||||
if ($value !== null && strlen($value) > $config['maxLength']) {
|
||||
$value = \core_text::substr($value, 0, $config['maxLength']);
|
||||
$value = mb_substr($value, 0, $config['maxLength']);
|
||||
}
|
||||
$types[] = '%s';
|
||||
break;
|
||||
|
||||
@@ -758,14 +758,11 @@ class H5PValidator {
|
||||
unlink($tmpPath);
|
||||
return FALSE;
|
||||
}
|
||||
// Moodle: the extension mbstring is optional.
|
||||
/*
|
||||
if (!extension_loaded('mbstring')) {
|
||||
$this->h5pF->setErrorMessage($this->h5pF->t('The mbstring PHP extension is not loaded. H5P need this to function properly'), 'mbstring-unsupported');
|
||||
unlink($tmpPath);
|
||||
return FALSE;
|
||||
}
|
||||
*/
|
||||
|
||||
// Create a temporary dir to extract package in.
|
||||
$tmpDir = $this->h5pF->getUploadedH5pFolderPath();
|
||||
@@ -812,7 +809,7 @@ class H5PValidator {
|
||||
}
|
||||
$totalSize += $fileStat['size'];
|
||||
|
||||
$fileName = \core_text::strtolower($fileStat['name']);
|
||||
$fileName = mb_strtolower($fileStat['name']);
|
||||
if (preg_match('/(^[\._]|\/[\._])/', $fileName) !== 0) {
|
||||
continue; // Skip any file or folder starting with a . or _
|
||||
}
|
||||
@@ -3318,15 +3315,12 @@ class H5PCore {
|
||||
$setup->disable_hub = TRUE;
|
||||
}
|
||||
|
||||
// Moodle: the extension mbstring is optional.
|
||||
/*
|
||||
if (!extension_loaded('mbstring')) {
|
||||
$setup->errors[] = $this->h5pF->t(
|
||||
'The mbstring PHP extension is not loaded. H5P needs this to function properly'
|
||||
);
|
||||
$setup->disable_hub = TRUE;
|
||||
}
|
||||
*/
|
||||
|
||||
// Check php version >= 5.2
|
||||
$php_version = explode('.', phpversion());
|
||||
@@ -3674,13 +3668,12 @@ class H5PContentValidator {
|
||||
|
||||
// Check if string is within allowed length
|
||||
if (isset($semantics->maxLength)) {
|
||||
// Moodle: the extension mbstring is optional.
|
||||
/*
|
||||
if (!extension_loaded('mbstring')) {
|
||||
$this->h5pF->setErrorMessage($this->h5pF->t('The mbstring PHP extension is not loaded. H5P need this to function properly'), 'mbstring-unsupported');
|
||||
}
|
||||
*/
|
||||
$text = \core_text::substr($text, 0, $semantics->maxLength);
|
||||
else {
|
||||
$text = mb_substr($text, 0, $semantics->maxLength);
|
||||
}
|
||||
}
|
||||
|
||||
// Check if string is according to optional regexp in semantics
|
||||
@@ -3730,14 +3723,11 @@ class H5PContentValidator {
|
||||
// file name, 2. testing against a returned error array that could
|
||||
// never be more than 1 element long anyway, 3. recreating the regex
|
||||
// for every file.
|
||||
// Moodle: the extension mbstring is optional.
|
||||
/*
|
||||
if (!extension_loaded('mbstring')) {
|
||||
$this->h5pF->setErrorMessage($this->h5pF->t('The mbstring PHP extension is not loaded. H5P need this to function properly'), 'mbstring-unsupported');
|
||||
$valid = FALSE;
|
||||
}
|
||||
*/
|
||||
if (!preg_match($wl_regex, \core_text::strtolower($file))) {
|
||||
else if (!preg_match($wl_regex, mb_strtolower($file))) {
|
||||
$this->h5pF->setErrorMessage($this->h5pF->t('File "%filename" not allowed. Only files with the following extensions are allowed: %files-allowed.', array('%filename' => $file, '%files-allowed' => $whitelist)), 'not-in-whitelist');
|
||||
$valid = FALSE;
|
||||
}
|
||||
@@ -4279,7 +4269,7 @@ class H5PContentValidator {
|
||||
return '<';
|
||||
}
|
||||
|
||||
if (!preg_match('%^<\s*(/\s*)?([a-zA-Z0-9\-]+)([^>]*)>?|(<!--.*?-->)$%', $string, $matches)) {
|
||||
if (!preg_match('%^<\s*(/\s*)?([a-zA-Z0-9\-]+)\s*([^>]*)>?|(<!--.*?-->)$%', $string, $matches)) {
|
||||
// Seriously malformed.
|
||||
return '';
|
||||
}
|
||||
@@ -4341,7 +4331,13 @@ class H5PContentValidator {
|
||||
// Attribute name, href for instance.
|
||||
if (preg_match('/^([-a-zA-Z]+)/', $attr, $match)) {
|
||||
$attrName = strtolower($match[1]);
|
||||
$skip = ($attrName == 'style' || substr($attrName, 0, 2) == 'on');
|
||||
$skip = (
|
||||
$attrName == 'style' ||
|
||||
substr($attrName, 0, 2) == 'on' ||
|
||||
substr($attrName, 0, 1) == '-' ||
|
||||
// Ignore long attributes to avoid unnecessary processing overhead.
|
||||
strlen($attrName) > 96
|
||||
);
|
||||
$working = $mode = 1;
|
||||
$attr = preg_replace('/^[-a-zA-Z]+/', '', $attr);
|
||||
}
|
||||
|
||||
@@ -1030,7 +1030,7 @@ H5P.t = function (key, vars, ns) {
|
||||
H5P.Dialog = function (name, title, content, $element) {
|
||||
/** @alias H5P.Dialog# */
|
||||
var self = this;
|
||||
var $dialog = H5P.jQuery('<div class="h5p-popup-dialog h5p-' + name + '-dialog">\
|
||||
var $dialog = H5P.jQuery('<div class="h5p-popup-dialog h5p-' + name + '-dialog" role="dialog" tabindex="-1">\
|
||||
<div class="h5p-inner">\
|
||||
<h2>' + title + '</h2>\
|
||||
<div class="h5p-scroll-content">' + content + '</div>\
|
||||
@@ -1053,6 +1053,12 @@ H5P.Dialog = function (name, title, content, $element) {
|
||||
.click(function () {
|
||||
self.close();
|
||||
})
|
||||
.keypress(function (e) {
|
||||
if (e.which === 13 || e.which === 32) {
|
||||
self.close();
|
||||
return false;
|
||||
}
|
||||
})
|
||||
.end()
|
||||
.find('a')
|
||||
.click(function (e) {
|
||||
@@ -1072,6 +1078,7 @@ H5P.Dialog = function (name, title, content, $element) {
|
||||
$dialog.addClass('h5p-open'); // Fade in
|
||||
// Triggering an event, in case something has to be done after dialog has been opened.
|
||||
H5P.jQuery(self).trigger('dialog-opened', [$dialog]);
|
||||
$dialog.focus();
|
||||
}, 1);
|
||||
};
|
||||
|
||||
@@ -1083,6 +1090,8 @@ H5P.Dialog = function (name, title, content, $element) {
|
||||
setTimeout(function () {
|
||||
$dialog.remove();
|
||||
H5P.jQuery(self).trigger('dialog-closed', [$dialog]);
|
||||
$element.attr('tabindex', '-1');
|
||||
$element.focus();
|
||||
}, 200);
|
||||
};
|
||||
};
|
||||
@@ -1363,11 +1372,11 @@ H5P.openEmbedDialog = function ($element, embedCode, resizeCode, size, instance)
|
||||
var $expander = H5P.jQuery(this);
|
||||
var $content = $expander.next();
|
||||
if ($content.is(':visible')) {
|
||||
$expander.removeClass('h5p-open').text(H5P.t('showAdvanced'));
|
||||
$expander.removeClass('h5p-open').text(H5P.t('showAdvanced')).attr('aria-expanded', 'true');
|
||||
$content.hide();
|
||||
}
|
||||
else {
|
||||
$expander.addClass('h5p-open').text(H5P.t('hideAdvanced'));
|
||||
$expander.addClass('h5p-open').text(H5P.t('hideAdvanced')).attr('aria-expanded', 'false');
|
||||
$content.show();
|
||||
}
|
||||
$dialog.find('.h5p-embed-code-container').each(function () {
|
||||
@@ -1378,6 +1387,7 @@ H5P.openEmbedDialog = function ($element, embedCode, resizeCode, size, instance)
|
||||
$dialog.find('.h5p-expander').click(expand).keypress(function (event) {
|
||||
if (event.keyCode === 32) {
|
||||
expand.apply(this);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}).on('dialog-closed', function () {
|
||||
|
||||
@@ -14,7 +14,7 @@ Removed:
|
||||
Added:
|
||||
* readme_moodle.txt
|
||||
|
||||
Downloaded version: 1.24 release
|
||||
Downloaded version: 1.24.2 release
|
||||
|
||||
Changes:
|
||||
1. In order to allow the dependency path to be overridden by child H5PCore classes, a couple of minor changes have been added to the
|
||||
@@ -31,33 +31,21 @@ https://github.com/h5p/h5p-php-library/compare/master...andrewnicols:libraryPath
|
||||
Hopefully, when upgrading, these patch won't be needed because it will be included in the H5P library by default.
|
||||
|
||||
|
||||
2. As the mbstring extension is optional in Moodle, the following changes have been hardcoded to the library:
|
||||
2.1. Comment the following methods in h5p.classes.php file where the extension_loaded('mbstring') is called:
|
||||
* isValidPackage
|
||||
* checkSetupErrorMessage
|
||||
* validateText
|
||||
* validateContentFiles
|
||||
2. Replace the $_SESSION references to $SESSION. That implies that the information is saved to backends, so only the Moodle one
|
||||
should be used by core (core should be free from $_SESSION and always use $SESSION).
|
||||
|
||||
2.2. Change all the mb_uses straight to the core_text() alternatives. Version 1.24 has 3 ocurrences in h5p.classes.php
|
||||
and 1 ocurrence in h5p-metadata.class.php.
|
||||
|
||||
3. Another PR has been sent to H5P library (https://github.com/h5p/h5p-php-library/pull/69) to fix some php74 minor problems. The same fix is being applied locally by MDL-67077. Once we import a new version, if it includes de fix, this won't be needed to reapply and can be removed.
|
||||
|
||||
4. Replace the $_SESSION references to $SESSION. That implies that the information is saved to backends, so only the Moodle one should be used by core (core should be free from $_SESSION and always use $SESSION).
|
||||
h5p.classes.php file:
|
||||
- Into hashToken method:
|
||||
Declare the global $SESSION.
|
||||
Change all the $_SESSION by $SESSION.
|
||||
A script for testing this part can be found in MDL-68068
|
||||
|
||||
The point 2 from above won't be needed once the mbstring extension becomes mandatory in Moodle. A request has been
|
||||
sent to MDL-65809.
|
||||
|
||||
5. Upgrade and patch JQuery library.
|
||||
3. Upgrade and patch JQuery library.
|
||||
Once https://github.com/h5p/h5p-php-library/issues/83 gets integrated in
|
||||
H5P PHP Library (upgrading the JQuery version), this change won't be needed.
|
||||
|
||||
5.1. Prepare the patched JQuery 1.12.4 library following these steps:
|
||||
3.1. Prepare the patched JQuery 1.12.4 library following these steps:
|
||||
a) Download the uncompressed JQuery Core 1.12.4 from https://code.jquery.com/jquery-1.12.4.js
|
||||
b) Add the patch in https://snyk.io/vuln/SNYK-JS-JQUERY-174006 to the downloaded file.
|
||||
You'll need to replace this code (line 212):
|
||||
@@ -75,15 +63,14 @@ H5P PHP Library (upgrading the JQuery version), this change won't be needed.
|
||||
}
|
||||
c) Minify the patched jquery-1-12.4.js.
|
||||
|
||||
5.2. Edit h5p/h5plib/v124/joubel/core/js/jquery.js and replace the JQuery piece of code
|
||||
3.2. Edit h5p/h5plib/v124/joubel/core/js/jquery.js and replace the JQuery piece of code
|
||||
(at the beginning of the file, above the comment "// Snap this specific version of jQuery into H5P. jQuery.noConflict will")
|
||||
with the previous patched and minified JQuery version.
|
||||
|
||||
5.3. Remove the following comment in h5p/h5plib/v124/joubel/core/js/jquery.js:
|
||||
3.3. Remove the following comment in h5p/h5plib/v124/joubel/core/js/jquery.js:
|
||||
|
||||
/**
|
||||
* jQuery v1.9.1
|
||||
*
|
||||
* @member
|
||||
*/
|
||||
|
||||
|
||||
@@ -202,7 +202,7 @@ div.h5p-fullscreen {
|
||||
color: #999;
|
||||
text-decoration: none;
|
||||
outline: none;
|
||||
line-height: 23px;
|
||||
line-height: 22px;
|
||||
}
|
||||
.h5p-actions > .h5p-button:hover {
|
||||
color: #666;
|
||||
@@ -223,8 +223,8 @@ div.h5p-fullscreen {
|
||||
.h5p-actions > .h5p-button:before {
|
||||
font-family: 'H5P';
|
||||
font-size: 20px;
|
||||
line-height: 20px;
|
||||
vertical-align: top;
|
||||
line-height: 23px;
|
||||
vertical-align: bottom;
|
||||
padding-right: 0;
|
||||
}
|
||||
.h5p-actions > .h5p-button.h5p-export:before {
|
||||
@@ -367,10 +367,6 @@ div.h5p-fullscreen {
|
||||
}
|
||||
.h5p-popup-dialog .h5p-close {
|
||||
cursor: pointer;
|
||||
}
|
||||
.h5p-popup-dialog .h5p-close:after {
|
||||
font-family: 'H5P';
|
||||
content: "\e894";
|
||||
font-size: 2em;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
@@ -383,6 +379,10 @@ div.h5p-fullscreen {
|
||||
text-indent: -0.065em;
|
||||
z-index: 3
|
||||
}
|
||||
.h5p-popup-dialog .h5p-close:after {
|
||||
font-family: 'H5P';
|
||||
content: "\e894";
|
||||
}
|
||||
.h5p-popup-dialog .h5p-close:hover:after,
|
||||
.h5p-popup-dialog .h5p-close:focus:after {
|
||||
color: #454545;
|
||||
@@ -412,7 +412,6 @@ div.h5p-fullscreen {
|
||||
.h5p-expander {
|
||||
cursor: pointer;
|
||||
font-size: 1.125em;
|
||||
outline: none;
|
||||
margin: 0.5em 0 0;
|
||||
display: inline-block;
|
||||
}
|
||||
@@ -543,6 +542,25 @@ div.h5p-fullscreen {
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
}
|
||||
.h5p-content code,
|
||||
.h5peditor code {
|
||||
color: #3d3d3d;
|
||||
background: #e0e0e0;
|
||||
border-radius: 2px;
|
||||
padding: 0 5px;
|
||||
}
|
||||
.h5p-content pre > code,
|
||||
.h5peditor pre > code {
|
||||
background-color: #fafafa;
|
||||
padding: 5px;
|
||||
display: block;
|
||||
line-height: normal;
|
||||
border: 1px solid #c7c7c7;
|
||||
border-left-width: 4px;
|
||||
max-width: 100%;
|
||||
white-space: pre;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
|
||||
/* This is loaded as part of Core and not Editor since this needs to be outside the editor iframe */
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<location>joubel/core</location>
|
||||
<name>h5p-php-library</name>
|
||||
<license>GPL-3.0</license>
|
||||
<version>1.24</version>
|
||||
<version>1.24.2</version>
|
||||
</library>
|
||||
<library>
|
||||
<location>joubel/editor</location>
|
||||
|
||||
@@ -36,7 +36,7 @@ use advanced_testcase;
|
||||
* @copyright 2019 Sara Arjona <sara@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class helper_testcase extends \advanced_testcase {
|
||||
class helper_test extends \advanced_testcase {
|
||||
|
||||
/**
|
||||
* Test the behaviour of get_display_options().
|
||||
@@ -379,4 +379,49 @@ class helper_testcase extends \advanced_testcase {
|
||||
$helperfile = helper::get_export_info('nofileexist.h5p', $url);
|
||||
$this->assertNull($helperfile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the parse_js_array function with a range of content.
|
||||
*
|
||||
* @dataProvider parse_js_array_provider
|
||||
* @param string $content
|
||||
* @param array $expected
|
||||
*/
|
||||
public function test_parse_js_array(string $content, array $expected): void {
|
||||
$this->assertEquals($expected, helper::parse_js_array($content));
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for test_parse_js_array().
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function parse_js_array_provider(): array {
|
||||
$lines = [
|
||||
"{",
|
||||
" missingTranslation: '[Missing translation :key]',",
|
||||
" loading: 'Loading, please wait...',",
|
||||
" selectLibrary: 'Select the library you wish to use for your content.',",
|
||||
"}",
|
||||
];
|
||||
$expected = [
|
||||
'missingTranslation' => '[Missing translation :key]',
|
||||
'loading' => 'Loading, please wait...',
|
||||
'selectLibrary' => 'Select the library you wish to use for your content.',
|
||||
];
|
||||
return [
|
||||
'Strings with \n' => [
|
||||
implode("\n", $lines),
|
||||
$expected,
|
||||
],
|
||||
'Strings with \r\n' => [
|
||||
implode("\r\n", $lines),
|
||||
$expected,
|
||||
],
|
||||
'Strings with \r' => [
|
||||
implode("\r", $lines),
|
||||
$expected,
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
This files describes API changes in core libraries and APIs,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
=== 3.10.4 ===
|
||||
* The third-party library h5p/h5plib/v124/core has been updated to version 1.24.2.
|
||||
|
||||
=== 3.10 ===
|
||||
* Added a new cache for h5p_library_files (MDL-69207)
|
||||
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
// This file is part of Moodle - https://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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Automatically generated strings for Moodle installer
|
||||
*
|
||||
* Do not edit this file manually! It contains just a subset of strings
|
||||
* needed during the very first steps of installation. This file was
|
||||
* generated automatically by export-installer.php (which is part of AMOS
|
||||
* {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
|
||||
* list of strings defined in /install/stringnames.txt.
|
||||
*
|
||||
* @package installer
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$string['parentlanguage'] = 'da';
|
||||
$string['thislanguage'] = 'Dansk til Workplace';
|
||||
@@ -31,4 +31,13 @@ defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$string['clianswerno'] = 'n';
|
||||
$string['cliansweryes'] = 'w';
|
||||
$string['cliincorrectvalueerror'] = 'Erè, valè kòrèk "{$ a-> valè}" pou "{$ a-> opsyon}"';
|
||||
$string['cliincorrectvalueretry'] = 'Valè ki pa kòrèk, tanpri eseye ankò';
|
||||
$string['clitypevalue'] = 'valè kalite';
|
||||
$string['clitypevaluedefault'] = 'tape valè, peze Antre pou itilize valè default ({$ a})';
|
||||
$string['cliunknowoption'] = 'Opsyon ki pa rekonèt:
|
||||
{$ a}
|
||||
Tanpri itilize opsyon --help.';
|
||||
$string['cliyesnoprompt'] = 'Tape w (pou wi) oswa n (pou non)';
|
||||
$string['environmentrequireinstall'] = 'dwe enstale ak pèmèt';
|
||||
$string['environmentrequireversion'] = 'vèsyon {$ a-> bezwen} obligatwa epi w ap kouri {$ a-> current}';
|
||||
|
||||
@@ -29,6 +29,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$string['parentlanguage'] = 'he';
|
||||
$string['parentlanguage'] = '';
|
||||
$string['thisdirection'] = 'rtl';
|
||||
$string['thislanguage'] = 'עברית';
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
// This file is part of Moodle - https://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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Automatically generated strings for Moodle installer
|
||||
*
|
||||
* Do not edit this file manually! It contains just a subset of strings
|
||||
* needed during the very first steps of installation. This file was
|
||||
* generated automatically by export-installer.php (which is part of AMOS
|
||||
* {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
|
||||
* list of strings defined in /install/stringnames.txt.
|
||||
*
|
||||
* @package installer
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$string['cannotcreatedboninstall'] = '<p> Tidak dapat membuat basis data. </p> <p> Basis data yang ditentukan tidak ada dan pengguna yang diberikan tidak memiliki izin untuk membuat basis data. </p> <p> Administrator situs harus memverifikasi konfigurasi basis data. < / p>';
|
||||
$string['cannotcreatelangdir'] = 'Tidak dapat membuat direktori lang';
|
||||
$string['cannotcreatetempdir'] = 'Tidak dapat membuat direktori temp';
|
||||
$string['cannotdownloadcomponents'] = 'Tidak dapat mengunduh komponen';
|
||||
$string['cannotdownloadzipfile'] = 'Tidak dapat mengunduh berkas ZIP';
|
||||
$string['cannotfindcomponent'] = 'Tidak dapat menemukan komponen';
|
||||
$string['cannotsavemd5file'] = 'Tidak dapat menyimpan berkas md5';
|
||||
$string['cannotsavezipfile'] = 'Tidak dapat menyimpan berkas ZIP';
|
||||
$string['cannotunzipfile'] = 'Tidak dapat mengekstrak berkas';
|
||||
$string['componentisuptodate'] = 'Komponen sudah mutakhir';
|
||||
$string['dmlexceptiononinstall'] = '<p>Terjadi kesalahan basis data [{$a->errorcode}].<br />{$a->debuginfo}</p>';
|
||||
$string['downloadedfilecheckfailed'] = 'Pemeriksaan berkas yang diunduh gagal';
|
||||
$string['invalidmd5'] = 'Variabel periksa salah - coba lagi';
|
||||
$string['missingrequiredfield'] = 'Beberapa ruas wajib tidak ada';
|
||||
$string['remotedownloaderror'] = '<p> Pengunduhan komponen ke peladen Anda gagal. Harap verifikasi setelan proksi; ekstensi PHP cURL sangat direkomendasikan. </p> <p> Anda harus mengunduh berkas <a href="{$a->url} ">{$a->url} </a> secara manual, menyalinnya ke"{$a->dest} "di peladen Anda dan uraikan di sana. </p>';
|
||||
$string['wrongdestpath'] = 'Jalur tujuan salah';
|
||||
$string['wrongsourcebase'] = 'Basis URL sumber salah';
|
||||
$string['wrongzipfilename'] = 'Nama file ZIP salah';
|
||||
@@ -70,12 +70,12 @@ $string['pathsroparentdataroot'] = 'La cartella genitore ({$a->parent}) non è s
|
||||
$string['pathssubadmindir'] = 'Alcuni web host utilizzano la cartella /admin come URL di accesso a pannelli di controllo od altre funzioni particolari. Tuttavia questo nome coincide con il nome della cartella che Moodle utilizza per i propri file di amministrazione. Per evitare conflitti, è possibile specificare un nome alternativo per la cartella Admin di Moodle. Ad esempio:<p><b>moodleadmin</b></p>
|
||||
Tutti i link che puntano ai file di amministrazione di Moodle terranno conto di questa variazione.';
|
||||
$string['pathssubdataroot'] = '<p>La cartella dove Moodle memorizzerà i file caricati dagli utenti.</p>
|
||||
<p>L\'utente con il qule gira il processo del web server (in genere \'www-data\' o \'apache\') deve avere i permessi di lettura e di scrittura su questa cartella.</p>
|
||||
<p>L\'utente con il quale gira il processo del web server (in genere \'www-data\' o \'apache\') deve avere i permessi di lettura e di scrittura su questa cartella.</p>
|
||||
<p>La cartella inoltre non deve essere direttamente accessibile via web.</p>
|
||||
<p>Qualora la cartella non esista, lo script di installazione tenterà di crearla.</p>';
|
||||
$string['pathssubdirroot'] = '<p>Percorso assoluto della cartella dove si trova il codice di Moodle.</p>';
|
||||
$string['pathssubwwwroot'] = '<p>L\'iIndirizzo web per raggiungere a Moodle, in altre parole l\'indirizzo che gli utenti inseriranno nella barra degli indirizzi del proprio browser per accedere a questa installazione.</p>
|
||||
<p>Non è possibile accedere alla stessa installazione Moodle usando più di un indirizzi web. Se il tuo sito usa più indirizzi web, devi configurare dei re-indirizzamenti permanenti per tutti gli altri indirizzi web.</p>
|
||||
$string['pathssubwwwroot'] = '<p>L\'indirizzo web per raggiungere a Moodle, in altre parole l\'indirizzo che gli utenti inseriranno nella barra degli indirizzi del proprio browser per accedere a questa installazione.</p>
|
||||
<p>Non è possibile accedere alla stessa installazione Moodle usando più di un indirizzo web. Se il tuo sito usa più indirizzi web, devi configurare dei re-indirizzamenti permanenti per tutti gli altri indirizzi web.</p>
|
||||
<p>Se il tuo sito è raggiungibile sia dalla Internet sia dalla rete interna (a volte chiamata Intranet), allora usa l\'indirizzo Internet pubblico.</p>
|
||||
<p>Se l\'indirizzo utilizzato è errato, per favore correggilo nella barra degli indirizzi del browser e avvia nuovamente l\'installazione.</p>';
|
||||
$string['pathsunsecuredataroot'] = 'La posizione della Cartella dati non è sicura';
|
||||
@@ -89,7 +89,7 @@ $string['welcomep10'] = '{$a->installername} ({$a->installerversion})';
|
||||
$string['welcomep20'] = 'Se vedi questa pagina hai installato correttamente e lanciato il pacchetto <strong>{$a->packname} {$a->packversion}</strong>. Complimenti!';
|
||||
$string['welcomep30'] = 'La release di <strong>{$a->installername}</strong> include l\'applicazione per creare l\'ambiente necessario a far girare <strong>Moodle</strong>:';
|
||||
$string['welcomep40'] = 'Il pacchetto include anche <strong>Moodle {$a->moodlerelease} ({$a->moodleversion})</strong>.';
|
||||
$string['welcomep50'] = 'L\'utilizzo delle applicazioni incluse in questo pacchetto è regolato dalle rispettive licenze. L\'intero pacchetto <strong>{$a->installername}</strong> è <a href="http://www.opensource.org/docs/definition_plain.html">open source</a> ed è distribuito in accordo alla licenza <a href="http://www.gnu.org/copyleft/gpl.html">GPL</a>.';
|
||||
$string['welcomep50'] = 'L\'utilizzo delle applicazioni incluse in questo pacchetto è regolato dalle rispettive licenze. L\'intero pacchetto <strong>{$a->installername}</strong> è <a href="https://www.opensource.org/docs/definition_plain.html">open source</a> ed è distribuito in accordo alla licenza <a href="https://www.gnu.org/copyleft/gpl.html">GPL</a>.';
|
||||
$string['welcomep60'] = 'Le prossime pagine ti guideranno attraverso semplici passi per installare e configurare <strong>Moodle</strong> nel tuo computer. Puoi utilizzare le impostazioni di default oppure modificarle per adeguarle alle tue esigenze.';
|
||||
$string['welcomep70'] = 'Fai click sul pulsante "Avanti" per continuare l\'installazione di <strong>Moodle</strong>.';
|
||||
$string['wwwroot'] = 'Indirizzo web';
|
||||
|
||||
@@ -45,7 +45,7 @@ $string['dbprefix'] = 'Префикс на табели';
|
||||
$string['dirroot'] = 'Moodle директориум';
|
||||
$string['environmenthead'] = 'Ја проверувам околината...';
|
||||
$string['installation'] = 'Инсталација';
|
||||
$string['langdownloaderror'] = 'За жал, јазикот "{$a}" не беше инсталиран. Инсталацискиот процес ќе продолжи на англиски.';
|
||||
$string['langdownloaderror'] = 'За жал, јазикот "{$a}" не е преземен. Инсталацискиот процес ќе продолжи на англиски.';
|
||||
$string['memorylimithelp'] = '<p>Прагот на меморијата кај PHP за Вашиот компјутер моментално е подесена на {$a}. </p>
|
||||
|
||||
<p>Ова може да предизвика проблеми со меморијата подоцна,
|
||||
@@ -64,6 +64,12 @@ $string['memorylimithelp'] = '<p>Прагот на меморијата кај P
|
||||
<p><blockquote>php_value memory_limit 40M</blockquote></p>
|
||||
<p>Како и да е, на некои компјутери, ова може да ги спречи <b>сите </b> PHP страници да работат (ќе забележите грешки на страниците) па ќе треба да ја преместите датотеката .htaccess.</p></li>
|
||||
</ol>';
|
||||
$string['paths'] = 'Патеки';
|
||||
$string['pathshead'] = 'Потврди патеки';
|
||||
$string['pathsroparentdataroot'] = 'Неможе да се запишува во предходниот директориум ({$a->parent}). Процесот на инсталација неможе да го создаде директориумот ({$a->dataroot}).';
|
||||
$string['pathssubdataroot'] = '<p>Директориум каде што Moodle ќе ја зачува целата содржина на датотеки прикачена од корисниците.</p> <p>Овој директориум треба да биде има дозвола за читање и запишување од веб-серверот (најлесто \'www-data\', \'nobody\', или \'apache\').</p> <p>Не смее да биде директно достапен преку Интернет.</p> <p>Ако директориумот во моментов не постои, процесот на инсталација ќе се обиде да го создаде.</p>';
|
||||
$string['pathssubdirroot'] = '<p>Целосна патека до директориумот каде што е кодот на Moodle.</p>';
|
||||
$string['pathssubwwwroot'] = '<p>Целосната адреса каде што ќе се пристапува до Moodle, т.е. адресата што корисниците треба да ја внесат во лентата за адреси на нивниот прелистувач за пристап до Moodle.</p> <p>Не е можно да се пристапи до Moodle со користење на повеќе адреси. Ако вашата страница е достапна преку повеќе адреси, тогаш изберете ја најлесната и поставете трајно пренасочување за секоја од другите адреси.</p> <p>Ако вашата страница е достапна и од Интернет, и од внатрешна мрежа (понекогаш наречена Интранет), тогаш користете ја јавната адреса тука.</p> <p>Ако тековната адреса не е точна, променете ја URL-адресата во лентата за адреси на прелистувачот и повторно стартувајте ја инсталацијата.</p>';
|
||||
$string['pathswrongadmindir'] = 'Администраторскиот директориум не постои';
|
||||
$string['phpversion'] = 'Верзија на PHP';
|
||||
$string['phpversionhelp'] = '<p>На Moodle му е потребна верзија на PHP, и тоа најмалку 4.1.0. </p>
|
||||
|
||||
@@ -29,5 +29,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$string['parentlanguage'] = 'en';
|
||||
$string['thisdirection'] = 'ltr';
|
||||
$string['thislanguage'] = 'Македонски';
|
||||
|
||||
@@ -40,7 +40,7 @@ $string['databasehost'] = 'Servidor da base de dados';
|
||||
$string['databasename'] = 'Nome da base de dados';
|
||||
$string['databasetypehead'] = 'Escolha o <i>driver</i> da base de dados';
|
||||
$string['dataroot'] = 'Pasta de dados';
|
||||
$string['datarootpermission'] = 'Permissões da diretoria de dados';
|
||||
$string['datarootpermission'] = 'Permissões da pasta de dados';
|
||||
$string['dbprefix'] = 'Prefixo das tabelas';
|
||||
$string['dirroot'] = 'Pasta do Moodle';
|
||||
$string['environmenthead'] = 'A verificar sistema...';
|
||||
@@ -55,11 +55,11 @@ $string['pathshead'] = 'Confirmar caminhos';
|
||||
$string['pathsrodataroot'] = 'A pasta de dados não tem permissões de escrita.';
|
||||
$string['pathsroparentdataroot'] = 'A pasta ascendente <b>{$a->parent}</b> não tem permissões de escrita. O programa de instalação não conseguiu criar a pasta <b>{$a->dataroot}</b>.';
|
||||
$string['pathssubadmindir'] = 'Alguns servidores Web utilizam a pasta <strong>admin</strong> em URLs especiais de acesso a funcionalidades especiais, como é o caso de painéis de controlo. Algumas situações podem criar conflitos com a localização normal das páginas de administração do Moodle. Estes problemas podem ser resolvidos renomeando a pasta <strong>admin</strong> na instalação do Moodle e indicando aqui o novo nome a utilizar. Por exemplo:<br /><br /><b>moodleadmin</b><br /><br />Esta ação resolverá os problemas de acesso das hiperligações para as funcionalidades de administração do Moodle.';
|
||||
$string['pathssubdataroot'] = '<p>Diretoria onde o Moodle irá armazenar todo o conteúdo de ficheiros enviados pelos utilizadores.</p>
|
||||
<p>Esta diretoria deve ser legível e gravável pelo utilizador do servidor web (geralmente \'www-data\', \'nobody\', ou \'apache\').</p>
|
||||
$string['pathssubdataroot'] = '<p>Pasta onde o Moodle irá armazenar todo o conteúdo de ficheiros enviados pelos utilizadores.</p>
|
||||
<p>Esta pasta deve ser legível e gravável pelo utilizador do servidor web (geralmente \'www-data\', \'nobody\', ou \'apache\').</p>
|
||||
<p>Não deve ser acessível diretamente através da web.</p>
|
||||
<p>Se a diretoria não existir, o processo de instalação tentará criá-la.</p>';
|
||||
$string['pathssubdirroot'] = 'Caminho completo para a diretoria que contém o código Moodle.';
|
||||
<p>Se a pasta não existir, o processo de instalação tentará criá-la.</p>';
|
||||
$string['pathssubdirroot'] = 'Caminho completo para a pasta que contém o código Moodle.';
|
||||
$string['pathssubwwwroot'] = 'Endereço web completo de acesso ao Moodle. Não é possível aceder ao Moodle usando mais do que um endereço. Se o site tiver mais do que um endereço público, devem ser configurados redirecionamentos permanentes em todos eles, à exceção deste. Se o site pode ser acedido a partir da Internet e de Intranet, use o endereço público aqui. Se o endereço atual não está correto, altere o endereço indicado na barra de endereço do seu navegador e reinicie a instalação.';
|
||||
$string['pathsunsecuredataroot'] = 'A localização da pasta de dados não é segura';
|
||||
$string['pathswrongadmindir'] = 'A pasta <b>admin</b> não existe';
|
||||
|
||||
@@ -75,7 +75,7 @@ $string['pathssubwwwroot'] = '<p>Пуна адреса путем које ће
|
||||
<p>Није могуће приступати Moodleu коришћењем више адреса. Ако се вашем сајту може приступити са више адреса, онда изаберите најлакшу, а за све остале адресе подесите перманентну редирекцију.</p>
|
||||
<p>Ако се вашем сајту може приступити како са интернета, тако и из интерне мреже (која се понекад назив интранет), онда овде употребите јавну адресу.</p>
|
||||
<p>Ако је текућа адреса нетачна, молимо вас, промените URL адресу у адресној траци свог веб читача и поново покрените инсталацију.</p>';
|
||||
$string['pathsunsecuredataroot'] = 'Dataroot локација није безбедна';
|
||||
$string['pathsunsecuredataroot'] = 'Локација директоријума са подацима није безбедна';
|
||||
$string['pathswrongadmindir'] = 'Админ директоријум не постоји';
|
||||
$string['phpextension'] = '{$a} PHP екстензија';
|
||||
$string['phpversion'] = 'PHP верзија';
|
||||
|
||||
@@ -72,7 +72,7 @@ $string['pathssubdataroot'] = '<p>Direktorijum gde će Moodle čuvati datoteke i
|
||||
<p>Ukoliko ovaj direktorijum ne postoji proces instalacije će pokušati da ga kreira.</p>';
|
||||
$string['pathssubdirroot'] = '<p>Puna putanja do direktorijuma koji sadrži kôd Moodlea.</p>';
|
||||
$string['pathssubwwwroot'] = '<p>Puna adresa putem koje će se pristupati Moodleu, tj. adresa koju će korisnici uneti u adresnu traku svojih veb čitača kako bi pristupili Moodleu.</p> <p>Nije moguće pristupati Moodleu korišćenjem više adresa. Ako se vašem sajtu može pristupiti sa više adresa, onda izaberite najlakšu, a za sve ostale adrese podesite permanentnu redirekciju.</p> <p>Ako se vašem sajtu može pristupiti kako sa interneta, tako i iz interne mreže (koja se ponekad naziv intranet), onda ovde upotrebite javnu adresu.</p> <p>Ako je tekuća adresa netačna, molimo vas, promenite URL adresu u adresnoj traci svog veb čitača i ponovo pokrenite instalaciju.</p>';
|
||||
$string['pathsunsecuredataroot'] = 'Dataroot lokacija nije bezbedna';
|
||||
$string['pathsunsecuredataroot'] = 'Lokacija direktorijuma sa podacima nije bezbedna';
|
||||
$string['pathswrongadmindir'] = 'Admin direktorijum ne postoji';
|
||||
$string['phpextension'] = '{$a} PHP ekstenѕija';
|
||||
$string['phpversion'] = 'PHP verzija';
|
||||
|
||||
@@ -37,9 +37,9 @@ $string['cannotcreatetempdir'] = 'Det går inte att skapa temp-katalogen';
|
||||
$string['cannotdownloadcomponents'] = 'Kan inte ladda ned komponenter';
|
||||
$string['cannotdownloadzipfile'] = 'Kan inte ladda ned ZIP-fil';
|
||||
$string['cannotfindcomponent'] = 'Hittar inte komponenten';
|
||||
$string['cannotsavemd5file'] = 'Det går inte att spara md5-fil';
|
||||
$string['cannotsavezipfile'] = 'Det går inte att spara ZIP-fil';
|
||||
$string['cannotunzipfile'] = 'Det går inte att packa upp fil';
|
||||
$string['cannotsavemd5file'] = 'Kan inte spara md5-fil';
|
||||
$string['cannotsavezipfile'] = 'Kan inte spara ZIP-fil';
|
||||
$string['cannotunzipfile'] = 'Det går inte att packa upp filen';
|
||||
$string['componentisuptodate'] = 'Komponenten är aktuell';
|
||||
$string['dmlexceptiononinstall'] = '<p>Ett databasfel har inträffat [{$a->errorcode}].<br />{$a->debuginfo}</p>';
|
||||
$string['downloadedfilecheckfailed'] = 'Kontrollen av den nedladdade filen misslyckades';
|
||||
@@ -47,5 +47,5 @@ $string['invalidmd5'] = 'Kontrollvariabeln var felaktig - försök igen';
|
||||
$string['missingrequiredfield'] = 'Det saknas några obligatoriska fält';
|
||||
$string['remotedownloaderror'] = 'Nedladdningen av en komponent till din server misslyckades. Vänligen verifiera inställningar för proxy. <br /><br />Du måste ladda ner <a href="{$a->url}">{$a->url}</a> filen manuellt, kopiera den till "{$a->dest}" på din server och packa upp den där.';
|
||||
$string['wrongdestpath'] = 'Fel målsökväg';
|
||||
$string['wrongsourcebase'] = 'Fel bas-URL till källan';
|
||||
$string['wrongsourcebase'] = 'Felaktig käll- URL rot';
|
||||
$string['wrongzipfilename'] = 'Fel namn på ZIP-filen';
|
||||
|
||||
@@ -29,5 +29,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$string['parentlanguage'] = '';
|
||||
$string['thisdirection'] = 'ltr';
|
||||
$string['thislanguage'] = 'Svenska';
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$string['language'] = 'Ngôn ngữ';
|
||||
$string['moodlelogo'] = 'Logo Moodle';
|
||||
$string['next'] = 'Tiếp theo';
|
||||
$string['previous'] = 'Trước';
|
||||
$string['reload'] = 'Nạp lại';
|
||||
|
||||
+8
-5
@@ -302,8 +302,8 @@ $string['configmycoursesperpage'] = 'Maximum number of courses to display in any
|
||||
$string['configmymoodleredirect'] = 'This setting forces redirects to /my on login for non-admins and replaces the top level site navigation with /my';
|
||||
$string['configmypagelocked'] = 'This setting prevents the default page from being edited by any non-admins';
|
||||
$string['confignavcourselimit'] = 'Limits the number of courses shown to the user in the navigation.';
|
||||
$string['confignavshowallcourses'] = 'This setting determines whether users who are enrolled in courses can see Courses (listing all courses) in the navigation, in addition to My Courses (listing courses in which they are enrolled).';
|
||||
$string['confignavshowcategories'] = 'Show course categories in the navigation bar and navigation blocks. This does not occur with courses the user is currently enrolled in, they will still be listed under mycourses without categories.';
|
||||
$string['confignavshowallcourses'] = 'This setting determines whether users who are enrolled in courses can see Courses (listing all courses) in the navigation, in addition to My courses (listing courses in which they are enrolled).';
|
||||
$string['confignavshowcategories'] = 'Show course categories in the navigation bar and navigation blocks. This does not occur with courses the user is currently enrolled in; they will still be listed under My courses without categories.';
|
||||
$string['confignoreplyaddress'] = 'Emails are sometimes sent out on behalf of a user (eg forum posts). The email address you specify here will be used as the "From" address in those cases when the recipients should not be able to reply directly to the user (eg when a user chooses to keep their address private). This setting will also be used as the envelope sender when sending email.';
|
||||
$string['confignotifyloginfailures'] = 'Send login failure notification messages to these selected users. This requires an internal logstore (eg Standard Logstore) to be enabled.';
|
||||
$string['confignotifyloginthreshold'] = 'If notifications about failed logins are active, how many failed login attempts by one user or one IP address is it worth notifying about?';
|
||||
@@ -383,7 +383,7 @@ For example: standard,orangewhite.';
|
||||
$string['configtimezone'] = 'This is the default timezone for displaying dates - each user can override this setting in their profile. Cron tasks and other server settings are specified in this timezone. You should change the setting if it shows as "Invalid timezone"';
|
||||
$string['configuseblogassociations'] = 'Should users be able to organize their blog by associating entries with courses and course modules?';
|
||||
$string['configuseexternalyui'] = 'Instead of using local files, use online files available on Yahoo‘s servers. WARNING: This requires an internet connection, or no AJAX will work on your site. This setting is not compatible with sites using https.';
|
||||
$string['configusesitenameforsitepages'] = 'If enabled the site\'s shortname will be used for the site pages node in the navigation rather than the string \'Site pages\'';
|
||||
$string['configusesitenameforsitepages'] = 'If enabled the site\'s short name will be used for the site pages node in the navigation rather than the string \'Site pages\'.';
|
||||
$string['configusetags'] = 'Should tags functionality across the site be enabled?';
|
||||
$string['configvariables'] = 'Variables';
|
||||
$string['configverifychangedemail'] = 'Enables verification of changed email addresses using allowed and denied email domains settings. If this setting is disabled the domains are enforced only when creating new users.';
|
||||
@@ -871,7 +871,7 @@ $string['navshowfrontpagemods_help'] = 'If enabled, front page activities will b
|
||||
$string['navshowallcourses'] = 'Show all courses';
|
||||
$string['navshowcategories'] = 'Show course categories';
|
||||
$string['navshowmycoursecategories'] = 'Show my course categories';
|
||||
$string['navshowmycoursecategories_help'] = 'If enabled courses in the users my courses branch will be shown in categories.';
|
||||
$string['navshowmycoursecategories_help'] = 'If enabled, courses in the user\'s My courses branch will be shown in categories in the navigation block (Classic-based themes only).';
|
||||
$string['navsortmycourseshiddenlast'] = 'Sort my hidden courses last';
|
||||
$string['navsortmycourseshiddenlast_help'] = 'If enabled, any hidden courses will be listed after visible courses (for users who can view hidden courses). Otherwise, all courses, regardless of their visibility, will be listed according to the \'Sort my courses\' setting.';
|
||||
$string['navsortmycoursessort'] = 'Sort my courses';
|
||||
@@ -1023,7 +1023,8 @@ $string['profilesignup'] = 'Display on signup page?';
|
||||
$string['profilespecificsettings'] = 'Specific settings';
|
||||
$string['profilevisible'] = 'Who is this field visible to?';
|
||||
$string['profilevisible_help'] = '* Not visible - For private data only viewable by administrators
|
||||
* Visible to user - For private data only viewable by the user and by administrators
|
||||
* Visible to user - For private data only viewable by the user and administrators
|
||||
* Visible to user, teachers and admins - For private data only viewable by the user, administrators and teachers (on course profile)
|
||||
* Visible to everyone';
|
||||
$string['profilevisibleall'] = 'Visible to everyone';
|
||||
$string['profilevisiblenone'] = 'Not visible';
|
||||
@@ -1191,6 +1192,8 @@ $string['sessionhandling'] = 'Session handling';
|
||||
$string['sessiontimeout'] = 'Timeout';
|
||||
$string['settingdependenton'] = 'This setting may be hidden, based on the value of <strong>{$a}</strong>.';
|
||||
$string['settingfileuploads'] = 'File uploading is required for normal operation, please enable it in PHP configuration.';
|
||||
$string['settingmaxinputvars'] = 'PHP setting max_input_vars is recommended to be at least 5000.';
|
||||
$string['settingmaxinputvarsrequired'] = 'PHP setting max_input_vars must be at least 5000.';
|
||||
$string['settingmemorylimit'] = 'Insufficient memory detected, please set higher memory limit in PHP settings.';
|
||||
$string['settingsafemode'] = 'Moodle is not fully compatible with safe mode, please ask server administrator to turn it off. Running Moodle under safe mode is not supported, please expect various problems if you do so.';
|
||||
$string['setupsearchengine'] = 'Setup search engine';
|
||||
|
||||
@@ -391,6 +391,7 @@ $string['loginasnoenrol'] = 'You cannot use enrol or unenrol when in course "Log
|
||||
$string['loginasonecourse'] = 'You cannot enter this course.<br /> You have to terminate the "Login as" session before entering any other course.';
|
||||
$string['maxbytesfile'] = 'The file {$a->file} is too large. The maximum size you can upload is {$a->size}.';
|
||||
$string['maxareabytes'] = 'The file is larger than the space remaining in this area.';
|
||||
$string['maxdraftitemids'] = 'Due to uploading a high volume of files, your file uploads are temporarily limited. Please try again after a few seconds.';
|
||||
$string['messageundeliveredbynotificationsettings'] = 'The message could not be sent because personal messages between users (in Notification settings) has been disabled by a site administrator.';
|
||||
$string['messagingdisable'] = 'Messaging is disabled on this site';
|
||||
$string['mimetexisnotexist'] = 'Your system is not configured to run mimeTeX. You need to obtain the C source from <a href="https://www.forkosh.com/mimetex.zip">https://www.forkosh.com/mimetex.zip</a>, compile it and put the executable into your moodle/filter/tex/ directory.';
|
||||
@@ -468,6 +469,7 @@ $string['notownerofkey'] = 'You are not owner of this key';
|
||||
$string['nousers'] = 'No such user!';
|
||||
$string['oauth1accesstoken'] = 'OAuth 1.0 error: We did not obtain the access token.';
|
||||
$string['oauth1requesttoken'] = 'OAuth 1.0 error: We did not obtain the request token - the service provider may be temporarily down.';
|
||||
$string['oauth2refreshtokenerror'] = 'Could not refresh OAuth 2 token. HTTP status for remote endpoint: {$a}';
|
||||
$string['onlyadmins'] = 'Only administrators can do that';
|
||||
$string['onlyeditingteachers'] = 'Only editing teachers can do that';
|
||||
$string['onlyeditown'] = 'You can only edit your own information';
|
||||
|
||||
@@ -95,3 +95,4 @@ $string['templatetypeown'] = 'Own form';
|
||||
$string['templatetypeshared'] = 'Shared template';
|
||||
$string['templatesource'] = 'Location: {$a->component} ({$a->area})';
|
||||
$string['error:notinrange'] = 'Invalid grade \'{$a->grade}\' provided. Grades must be between 0 and {$a->maxgrade}.';
|
||||
$string['error:gradingunavailable'] = 'The advanced grading method is not correctly set. Please check the whole forum grading options in the forum settings.';
|
||||
|
||||
+1
-1
@@ -120,7 +120,7 @@ $string['roleassignmentsnumber'] = 'Number of role assignments ({$a})';
|
||||
$string['search'] = 'Search';
|
||||
$string['sendingsize'] = 'Please wait the course file is uploading ({$a->total}Mb)...';
|
||||
$string['sendfollowinginfo'] = 'More information';
|
||||
$string['sendfollowinginfo_help'] = 'The following information will be sent to contribute to overall statistics only. It will not be made public on any site listing.';
|
||||
$string['sendfollowinginfo_help'] = 'The following information will be sent to Moodle each time your site registration is updated (by default weekly, when the \'Site registration\' scheduled task is run). The information contributes to overall statistics only and will not be made public on any site listing.';
|
||||
$string['sent'] = '...finished';
|
||||
$string['siteadmin'] = 'Administrator';
|
||||
$string['siteadmin_help'] = 'The full name of the site administrator.';
|
||||
|
||||
+1
-1
@@ -1472,7 +1472,7 @@ $string['normalfilter'] = 'Normal search';
|
||||
$string['nosite'] = 'Could not find site-level course';
|
||||
$string['nostudentsfound'] = 'No {$a} found';
|
||||
$string['nostudentsingroup'] = 'There are no students in this group yet';
|
||||
$string['nostudentsyet'] = 'No students enrolled in this course yet';
|
||||
$string['nostudentsyet'] = 'There are no students enrolled in this course.';
|
||||
$string['nosuchemail'] = 'No such email address';
|
||||
$string['notavailable'] = 'Not available';
|
||||
$string['notavailablecourse'] = '{$a} is not available';
|
||||
|
||||
+36
-11
@@ -5525,9 +5525,11 @@ abstract class context extends stdClass implements IteratorAggregate {
|
||||
* type of context, e.g. User, Course, Forum, etc.
|
||||
* @param boolean $short whether to use the short name of the thing. Only applies
|
||||
* to course contexts
|
||||
* @param boolean $escape Whether the returned name of the thing is to be
|
||||
* HTML escaped or not.
|
||||
* @return string the human readable context name.
|
||||
*/
|
||||
public function get_context_name($withprefix = true, $short = false) {
|
||||
public function get_context_name($withprefix = true, $short = false, $escape = true) {
|
||||
// must be implemented in all context levels
|
||||
throw new coding_exception('can not get name of abstract context');
|
||||
}
|
||||
@@ -6229,9 +6231,10 @@ class context_system extends context {
|
||||
*
|
||||
* @param boolean $withprefix does not apply to system context
|
||||
* @param boolean $short does not apply to system context
|
||||
* @param boolean $escape does not apply to system context
|
||||
* @return string the human readable context name.
|
||||
*/
|
||||
public function get_context_name($withprefix = true, $short = false) {
|
||||
public function get_context_name($withprefix = true, $short = false, $escape = true) {
|
||||
return self::get_level_name();
|
||||
}
|
||||
|
||||
@@ -6488,9 +6491,10 @@ class context_user extends context {
|
||||
*
|
||||
* @param boolean $withprefix whether to prefix the name of the context with User
|
||||
* @param boolean $short does not apply to user context
|
||||
* @param boolean $escape does not apply to user context
|
||||
* @return string the human readable context name.
|
||||
*/
|
||||
public function get_context_name($withprefix = true, $short = false) {
|
||||
public function get_context_name($withprefix = true, $short = false, $escape = true) {
|
||||
global $DB;
|
||||
|
||||
$name = '';
|
||||
@@ -6675,9 +6679,10 @@ class context_coursecat extends context {
|
||||
*
|
||||
* @param boolean $withprefix whether to prefix the name of the context with Category
|
||||
* @param boolean $short does not apply to course categories
|
||||
* @param boolean $escape Whether the returned name of the context is to be HTML escaped or not.
|
||||
* @return string the human readable context name.
|
||||
*/
|
||||
public function get_context_name($withprefix = true, $short = false) {
|
||||
public function get_context_name($withprefix = true, $short = false, $escape = true) {
|
||||
global $DB;
|
||||
|
||||
$name = '';
|
||||
@@ -6685,7 +6690,11 @@ class context_coursecat extends context {
|
||||
if ($withprefix){
|
||||
$name = get_string('category').': ';
|
||||
}
|
||||
$name .= format_string($category->name, true, array('context' => $this));
|
||||
if (!$escape) {
|
||||
$name .= format_string($category->name, true, array('context' => $this, 'escape' => false));
|
||||
} else {
|
||||
$name .= format_string($category->name, true, array('context' => $this));
|
||||
}
|
||||
}
|
||||
return $name;
|
||||
}
|
||||
@@ -6907,9 +6916,10 @@ class context_course extends context {
|
||||
*
|
||||
* @param boolean $withprefix whether to prefix the name of the context with Course
|
||||
* @param boolean $short whether to use the short name of the thing.
|
||||
* @param bool $escape Whether the returned category name is to be HTML escaped or not.
|
||||
* @return string the human readable context name.
|
||||
*/
|
||||
public function get_context_name($withprefix = true, $short = false) {
|
||||
public function get_context_name($withprefix = true, $short = false, $escape = true) {
|
||||
global $DB;
|
||||
|
||||
$name = '';
|
||||
@@ -6921,9 +6931,18 @@ class context_course extends context {
|
||||
$name = get_string('course').': ';
|
||||
}
|
||||
if ($short){
|
||||
$name .= format_string($course->shortname, true, array('context' => $this));
|
||||
if (!$escape) {
|
||||
$name .= format_string($course->shortname, true, array('context' => $this, 'escape' => false));
|
||||
} else {
|
||||
$name .= format_string($course->shortname, true, array('context' => $this));
|
||||
}
|
||||
} else {
|
||||
$name .= format_string(get_course_display_name_for_list($course));
|
||||
if (!$escape) {
|
||||
$name .= format_string(get_course_display_name_for_list($course), true, array('context' => $this,
|
||||
'escape' => false));
|
||||
} else {
|
||||
$name .= format_string(get_course_display_name_for_list($course), true, array('context' => $this));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7130,9 +7149,10 @@ class context_module extends context {
|
||||
* @param boolean $withprefix whether to prefix the name of the context with the
|
||||
* module name, e.g. Forum, Glossary, etc.
|
||||
* @param boolean $short does not apply to module context
|
||||
* @param boolean $escape Whether the returned name of the context is to be HTML escaped or not.
|
||||
* @return string the human readable context name.
|
||||
*/
|
||||
public function get_context_name($withprefix = true, $short = false) {
|
||||
public function get_context_name($withprefix = true, $short = false, $escape = true) {
|
||||
global $DB;
|
||||
|
||||
$name = '';
|
||||
@@ -7144,7 +7164,11 @@ class context_module extends context {
|
||||
if ($withprefix){
|
||||
$name = get_string('modulename', $cm->modname).': ';
|
||||
}
|
||||
$name .= format_string($mod->name, true, array('context' => $this));
|
||||
if (!$escape) {
|
||||
$name .= format_string($mod->name, true, array('context' => $this, 'escape' => false));
|
||||
} else {
|
||||
$name .= format_string($mod->name, true, array('context' => $this));
|
||||
}
|
||||
}
|
||||
}
|
||||
return $name;
|
||||
@@ -7405,9 +7429,10 @@ class context_block extends context {
|
||||
*
|
||||
* @param boolean $withprefix whether to prefix the name of the context with Block
|
||||
* @param boolean $short does not apply to block context
|
||||
* @param boolean $escape does not apply to block context
|
||||
* @return string the human readable context name.
|
||||
*/
|
||||
public function get_context_name($withprefix = true, $short = false) {
|
||||
public function get_context_name($withprefix = true, $short = false, $escape = true) {
|
||||
global $DB, $CFG;
|
||||
|
||||
$name = '';
|
||||
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+48
-13
@@ -68,6 +68,22 @@ define([
|
||||
/** @var {Array} disallowedNestedHelpers - List of helpers that can't be called within other helpers */
|
||||
var disallowedNestedHelpers = ['js'];
|
||||
|
||||
/**
|
||||
* Normalise the provided component such that '', 'moodle', and 'core' are treated consistently.
|
||||
*
|
||||
* @param {String} component
|
||||
* @returns {String}
|
||||
*/
|
||||
var getNormalisedComponent = function(component) {
|
||||
if (component) {
|
||||
if (component !== 'moodle' && component !== 'core') {
|
||||
return component;
|
||||
}
|
||||
}
|
||||
|
||||
return 'core';
|
||||
};
|
||||
|
||||
/**
|
||||
* Search the various caches for a template promise for the given search key.
|
||||
* The search key should be in the format <theme>/<component>/<template> e.g. boost/core/modal.
|
||||
@@ -133,7 +149,7 @@ define([
|
||||
var requests = [];
|
||||
// Get a list of promises for each of the templates we need to load.
|
||||
var templatePromises = templatesToLoad.map(function(templateData) {
|
||||
var component = templateData.component;
|
||||
var component = getNormalisedComponent(templateData.component);
|
||||
var name = templateData.name;
|
||||
var searchKey = templateData.searchKey;
|
||||
var theme = templateData.theme;
|
||||
@@ -177,6 +193,7 @@ define([
|
||||
// Process all of the template dependencies for this template and add
|
||||
// them to the caches so that we don't request them again later.
|
||||
response.templates.forEach(function(data) {
|
||||
data.component = getNormalisedComponent(data.component);
|
||||
// Generate the search key for this template in the response so that we
|
||||
// can add it to the caches.
|
||||
var tempSearchKey = [theme, data.component, data.name].join('/');
|
||||
@@ -200,7 +217,7 @@ define([
|
||||
// with them now so that we don't need to re-fetch them.
|
||||
str.cache_strings(response.strings.map(function(data) {
|
||||
return {
|
||||
component: data.component,
|
||||
component: getNormalisedComponent(data.component),
|
||||
key: data.name,
|
||||
value: data.value
|
||||
};
|
||||
@@ -315,7 +332,7 @@ define([
|
||||
// This is the first time this has been requested so let's add it to the buffer
|
||||
// to be loaded.
|
||||
var parts = templateName.split('/');
|
||||
var component = parts.shift();
|
||||
var component = getNormalisedComponent(parts.shift());
|
||||
var name = parts.join('/');
|
||||
var deferred = $.Deferred();
|
||||
|
||||
@@ -361,7 +378,7 @@ define([
|
||||
|
||||
// This is the first time this has been requested so let's add it to the buffer to be loaded.
|
||||
var parts = templateName.split('/');
|
||||
var component = parts.shift();
|
||||
var component = getNormalisedComponent(parts.shift());
|
||||
var name = parts.join('/');
|
||||
|
||||
// Add this template to the buffer to be loaded.
|
||||
@@ -409,6 +426,7 @@ define([
|
||||
Renderer.prototype.renderIcon = function(key, component, title) {
|
||||
// Preload the module to do the icon rendering based on the theme iconsystem.
|
||||
var modulename = config.iconsystemmodule;
|
||||
component = getNormalisedComponent(component);
|
||||
|
||||
// RequireJS does not return a promise.
|
||||
var ready = $.Deferred();
|
||||
@@ -425,7 +443,12 @@ define([
|
||||
return ready.then(function(iconSystem) {
|
||||
return this.getTemplate(iconSystem.getTemplateName());
|
||||
}.bind(this)).then(function(template) {
|
||||
return iconSystem.renderIcon(key, component, title, template);
|
||||
return iconSystem.renderIcon(
|
||||
key,
|
||||
component,
|
||||
title,
|
||||
template
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -456,15 +479,21 @@ define([
|
||||
}
|
||||
|
||||
var templateName = iconSystem.getTemplateName();
|
||||
|
||||
var searchKey = this.currentThemeName + '/' + templateName;
|
||||
var template = templateCache[searchKey];
|
||||
|
||||
component = getNormalisedComponent(component);
|
||||
|
||||
// The key might have been escaped by the JS Mustache engine which
|
||||
// converts forward slashes to HTML entities. Let us undo that here.
|
||||
key = key.replace(///gi, '/');
|
||||
|
||||
return iconSystem.renderIcon(key, component, text, template);
|
||||
return iconSystem.renderIcon(
|
||||
key,
|
||||
component,
|
||||
text,
|
||||
template
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -508,9 +537,7 @@ define([
|
||||
param = parts.join(',').trim();
|
||||
}
|
||||
|
||||
if (!component || component === 'moodle') {
|
||||
component = 'core';
|
||||
}
|
||||
component = getNormalisedComponent(component);
|
||||
|
||||
if (param !== '') {
|
||||
// Allow variable expansion in the param part only.
|
||||
@@ -522,7 +549,11 @@ define([
|
||||
}
|
||||
|
||||
var index = this.requiredStrings.length;
|
||||
this.requiredStrings.push({key: key, component: component, param: param});
|
||||
this.requiredStrings.push({
|
||||
key: key,
|
||||
component: component,
|
||||
param: param
|
||||
});
|
||||
|
||||
// The placeholder must not use {{}} as those can be misinterpreted by the engine.
|
||||
return '[[_s' + index + ']]';
|
||||
@@ -545,7 +576,7 @@ define([
|
||||
// This involves wrapping {{, and }} in change delimeter tags.
|
||||
content = content
|
||||
.replace(/"/g, '\\"')
|
||||
.replace(/([\{\}]{2,3})/g, '{{=<% %>=}}$1<%={{ }}=%>')
|
||||
.replace(/([{}]{2,3})/g, '{{=<% %>=}}$1<%={{ }}=%>')
|
||||
.replace(/(\r\n|\r|\n)/g, '
')
|
||||
;
|
||||
return '"' + content + '"';
|
||||
@@ -1173,7 +1204,11 @@ define([
|
||||
*/
|
||||
renderPix: function(key, component, title) {
|
||||
var renderer = new Renderer();
|
||||
return renderer.renderIcon(key, component, title);
|
||||
return renderer.renderIcon(
|
||||
key,
|
||||
getNormalisedComponent(component),
|
||||
title
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -731,17 +731,28 @@ class behat_config_util {
|
||||
}
|
||||
$installedversion = $package->version;
|
||||
} else if (!empty($CFG->behat_ionic_wwwroot)) {
|
||||
// Get app version from config.json inside wwwroot.
|
||||
$jsonurl = $CFG->behat_ionic_wwwroot . '/config.json';
|
||||
$json = @download_file_content($jsonurl);
|
||||
// Get app version from env.json inside wwwroot.
|
||||
$jsonurl = $CFG->behat_ionic_wwwroot . '/assets/env.json';
|
||||
$json = @file_get_contents($jsonurl);
|
||||
if (!$json) {
|
||||
throw new coding_exception('Unable to load app version from ' . $jsonurl);
|
||||
// Fall back to ionic 3 config file.
|
||||
$jsonurl = $CFG->behat_ionic_wwwroot . '/config.json';
|
||||
$json = @file_get_contents($jsonurl);
|
||||
if (!$json) {
|
||||
throw new coding_exception('Unable to load app version from ' . $jsonurl);
|
||||
}
|
||||
$config = json_decode($json);
|
||||
if ($config === null || empty($config->versionname)) {
|
||||
throw new coding_exception('Invalid app config data in ' . $jsonurl);
|
||||
}
|
||||
$installedversion = str_replace('-dev', '', $config->versionname);
|
||||
} else {
|
||||
$env = json_decode($json);
|
||||
if (empty($env->build->version ?? null)) {
|
||||
throw new coding_exception('Invalid app config data in ' . $jsonurl);
|
||||
}
|
||||
$installedversion = $env->build->version;
|
||||
}
|
||||
$config = json_decode($json);
|
||||
if ($config === null || empty($config->versionname)) {
|
||||
throw new coding_exception('Invalid app config data in ' . $jsonurl);
|
||||
}
|
||||
$installedversion = str_replace('-dev', '', $config->versionname);
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
|
||||
@@ -25,10 +25,11 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once(__DIR__ . '/../../behat/behat_base.php');
|
||||
|
||||
use Behat\Gherkin\Node\TableNode as TableNode;
|
||||
use Behat\Behat\Tester\Exception\PendingException as PendingException;
|
||||
|
||||
|
||||
/**
|
||||
* Class to quickly create Behat test data using component data generators.
|
||||
*
|
||||
@@ -480,53 +481,7 @@ abstract class behat_generator_base {
|
||||
* @return context
|
||||
*/
|
||||
protected function get_context($levelname, $contextref) {
|
||||
global $DB;
|
||||
|
||||
// Getting context levels and names (we will be using the English ones as it is the test site language).
|
||||
$contextlevels = context_helper::get_all_levels();
|
||||
$contextnames = array();
|
||||
foreach ($contextlevels as $level => $classname) {
|
||||
$contextnames[context_helper::get_level_name($level)] = $level;
|
||||
}
|
||||
|
||||
if (empty($contextnames[$levelname])) {
|
||||
throw new Exception('The specified "' . $levelname . '" context level does not exist');
|
||||
}
|
||||
$contextlevel = $contextnames[$levelname];
|
||||
|
||||
// Return it, we don't need to look for other internal ids.
|
||||
if ($contextlevel == CONTEXT_SYSTEM) {
|
||||
return context_system::instance();
|
||||
}
|
||||
|
||||
switch ($contextlevel) {
|
||||
|
||||
case CONTEXT_USER:
|
||||
$instanceid = $DB->get_field('user', 'id', array('username' => $contextref));
|
||||
break;
|
||||
|
||||
case CONTEXT_COURSECAT:
|
||||
$instanceid = $DB->get_field('course_categories', 'id', array('idnumber' => $contextref));
|
||||
break;
|
||||
|
||||
case CONTEXT_COURSE:
|
||||
$instanceid = $DB->get_field('course', 'id', array('shortname' => $contextref));
|
||||
break;
|
||||
|
||||
case CONTEXT_MODULE:
|
||||
$instanceid = $DB->get_field('course_modules', 'id', array('idnumber' => $contextref));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
$contextclass = $contextlevels[$contextlevel];
|
||||
if (!$context = $contextclass::instance($instanceid, IGNORE_MISSING)) {
|
||||
throw new Exception('The specified "' . $contextref . '" context reference does not exist');
|
||||
}
|
||||
|
||||
return $context;
|
||||
return behat_base::get_context($levelname, $contextref);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1068,6 +1068,69 @@ EOF;
|
||||
|
||||
\core\session\manager::set_user($user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the internal moodle context id from the context reference.
|
||||
*
|
||||
* The context reference changes depending on the context
|
||||
* level, it can be the system, a user, a category, a course or
|
||||
* a module.
|
||||
*
|
||||
* @throws Exception
|
||||
* @param string $levelname The context level string introduced by the test writer
|
||||
* @param string $contextref The context reference introduced by the test writer
|
||||
* @return context
|
||||
*/
|
||||
public static function get_context(string $levelname, string $contextref): context {
|
||||
global $DB;
|
||||
|
||||
// Getting context levels and names (we will be using the English ones as it is the test site language).
|
||||
$contextlevels = context_helper::get_all_levels();
|
||||
$contextnames = array();
|
||||
foreach ($contextlevels as $level => $classname) {
|
||||
$contextnames[context_helper::get_level_name($level)] = $level;
|
||||
}
|
||||
|
||||
if (empty($contextnames[$levelname])) {
|
||||
throw new Exception('The specified "' . $levelname . '" context level does not exist');
|
||||
}
|
||||
$contextlevel = $contextnames[$levelname];
|
||||
|
||||
// Return it, we don't need to look for other internal ids.
|
||||
if ($contextlevel == CONTEXT_SYSTEM) {
|
||||
return context_system::instance();
|
||||
}
|
||||
|
||||
switch ($contextlevel) {
|
||||
|
||||
case CONTEXT_USER:
|
||||
$instanceid = $DB->get_field('user', 'id', array('username' => $contextref));
|
||||
break;
|
||||
|
||||
case CONTEXT_COURSECAT:
|
||||
$instanceid = $DB->get_field('course_categories', 'id', array('idnumber' => $contextref));
|
||||
break;
|
||||
|
||||
case CONTEXT_COURSE:
|
||||
$instanceid = $DB->get_field('course', 'id', array('shortname' => $contextref));
|
||||
break;
|
||||
|
||||
case CONTEXT_MODULE:
|
||||
$instanceid = $DB->get_field('course_modules', 'id', array('idnumber' => $contextref));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
$contextclass = $contextlevels[$contextlevel];
|
||||
if (!$context = $contextclass::instance($instanceid, IGNORE_MISSING)) {
|
||||
throw new Exception('The specified "' . $contextref . '" context reference does not exist');
|
||||
}
|
||||
|
||||
return $context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger click on node via javascript instead of actually clicking on it via pointer.
|
||||
*
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user