Compare commits
341 Commits
v3.4.0-rc3
..
v3.4.1
| Author | SHA1 | Date | |
|---|---|---|---|
| c9236c6860 | |||
| 5dcd9c53e3 | |||
| 758066eda4 | |||
| 6a12f2de83 | |||
| fe8663110a | |||
| 0f6761962a | |||
| bc066df1f6 | |||
| 246b39cba9 | |||
| facd24b4c7 | |||
| b7b3b75b2c | |||
| 98ac97e2a0 | |||
| 9aa6e8bfa4 | |||
| 03a65d8916 | |||
| 5e430e98cb | |||
| 068f22aee0 | |||
| 99d570fef4 | |||
| 4a2bc331fb | |||
| 3fef39fc68 | |||
| 5d434d4d19 | |||
| 440113b457 | |||
| 41ff45a7a7 | |||
| fa4274319d | |||
| 06c5a9e6ff | |||
| ca3605500e | |||
| 6beb56ba1f | |||
| f83fc14e4d | |||
| 844eae52fb | |||
| cf304a8870 | |||
| 8ec36b0fe2 | |||
| 31a9ee8172 | |||
| d0308d8d76 | |||
| 144c240841 | |||
| 434c5f8a56 | |||
| 0ce4a24888 | |||
| bfd1dd07d8 | |||
| 51e05c09c3 | |||
| 02990bd6b9 | |||
| a66195b8b9 | |||
| ae7953ff01 | |||
| e5dc80a10c | |||
| f080964380 | |||
| 2ea79c66cf | |||
| 36b738c185 | |||
| 1a89875c36 | |||
| c29b6e8c15 | |||
| ff710b83c3 | |||
| c619279f5e | |||
| 5772b0fba2 | |||
| c89d473133 | |||
| 0e540897e6 | |||
| 27e2fe6981 | |||
| e35bc644de | |||
| 5d7d6cb52b | |||
| 913abd448b | |||
| dfe9aa213b | |||
| dc24b81fef | |||
| cff1f1943e | |||
| fe5d17b166 | |||
| cdda22dad7 | |||
| 641a281bef | |||
| e70b33b720 | |||
| 8578d28631 | |||
| c7a1ecd9f6 | |||
| 829adb5f21 | |||
| b6e79ab8d8 | |||
| 2ba2d02202 | |||
| 2d117605b8 | |||
| 237e1a85ce | |||
| 5cb64c1faa | |||
| e714f3cee9 | |||
| 16deaa8611 | |||
| ffa36a4bbe | |||
| 5ed65e12e1 | |||
| d1c15a50c9 | |||
| bc121625c3 | |||
| 251a824d8e | |||
| efde049bdf | |||
| 88498220a1 | |||
| dfdadbdbe2 | |||
| fb8b947963 | |||
| b844baf8be | |||
| 0c794fc199 | |||
| 2f4feacac7 | |||
| 7d7edc8820 | |||
| 18c838f586 | |||
| 21c63124ab | |||
| 350cefe41e | |||
| 47c56f3475 | |||
| 4b5ac4ceae | |||
| 8ed193c3ee | |||
| 40e430e634 | |||
| aaf94b8f75 | |||
| 18e6878f5a | |||
| 1041ccaf2e | |||
| fb7b0157c1 | |||
| 8827e7fc3f | |||
| b85ec901dd | |||
| 2faa795209 | |||
| ca5a9de8c5 | |||
| b9287872eb | |||
| 8b448de4b0 | |||
| 06588b2cc0 | |||
| e8e4566aaa | |||
| 94ccf35860 | |||
| cf0386e763 | |||
| a603f86d65 | |||
| 265e374204 | |||
| e62e93aa0d | |||
| d00a6f52b4 | |||
| 0c75121648 | |||
| 5681222a0b | |||
| a45b7aa7ee | |||
| 3093cc28f1 | |||
| 0ff581cece | |||
| b93a787b3e | |||
| 4ab37af070 | |||
| f85f002b37 | |||
| f7bdcf959f | |||
| 64abea941e | |||
| b9bebd0e36 | |||
| de703e70e7 | |||
| b35acd2249 | |||
| a45c466000 | |||
| 3b7f331372 | |||
| 3145f21de1 | |||
| f8550e7982 | |||
| ab0847d328 | |||
| 54339683ac | |||
| 65e260281b | |||
| f29bd28d6a | |||
| 9654f2cd71 | |||
| 2337078a30 | |||
| 29d9535277 | |||
| 4b162c766d | |||
| 606c17e6ef | |||
| daf44482e9 | |||
| 7da0e04ca3 | |||
| 45c42e01a3 | |||
| 74af3b176d | |||
| 7e9f55f138 | |||
| 7354b4ea0e | |||
| 9f6edf2171 | |||
| 511c9addfa | |||
| 8616e10e89 | |||
| 91406c9103 | |||
| aa383f1b47 | |||
| 8bb22c4544 | |||
| ff383cdd57 | |||
| 23e190ead5 | |||
| d997069c62 | |||
| 96cc77d435 | |||
| 1daf3fafc0 | |||
| 7522b6a2e3 | |||
| ece94bb4e2 | |||
| cd44d4e463 | |||
| 395c985759 | |||
| 684d866e20 | |||
| 3b2e8b4a0a | |||
| 816e06e809 | |||
| 6924954471 | |||
| 2875ff2934 | |||
| b1ddacfc8e | |||
| 6d353a7918 | |||
| f9e09bd963 | |||
| 4f657eeed9 | |||
| 60e57b8448 | |||
| 628f99bf45 | |||
| 68e670d8ea | |||
| af9b21a388 | |||
| de08d71fc8 | |||
| 4846674f5c | |||
| ac66136751 | |||
| 5617f26568 | |||
| ad81f22148 | |||
| aabf264460 | |||
| c22d3a30a1 | |||
| 64d3271039 | |||
| c83c2c0f47 | |||
| 5fdb912a82 | |||
| 7a06e15952 | |||
| b64f314662 | |||
| e5994e8c04 | |||
| 1fb4f49cca | |||
| 32b4b57b26 | |||
| fd7e75a8a5 | |||
| abd7d4394b | |||
| e4256cd769 | |||
| 5a6a4cef8b | |||
| 8721afb2c6 | |||
| 0e199a5aec | |||
| 320947908b | |||
| 2e55209603 | |||
| f8979fac97 | |||
| 6a33a850fc | |||
| 9164ab6e39 | |||
| 2af1421e34 | |||
| 5a9fa0fe57 | |||
| c1db07d55b | |||
| c5b7a25ee6 | |||
| 7cc665e9c7 | |||
| 05fd85142e | |||
| e62ea2b803 | |||
| 972142a9af | |||
| b25f3693bb | |||
| 369caa6183 | |||
| 00268741c2 | |||
| 605b0547de | |||
| eea1aff443 | |||
| 1bc5a5abe9 | |||
| be4ea98f29 | |||
| 845215d826 | |||
| 2a9c11965b | |||
| 8c3d8a68f7 | |||
| 969010296d | |||
| 87186b9710 | |||
| 539ad434cb | |||
| af4fa2a55b | |||
| 15aec0b054 | |||
| 7974bbcaf7 | |||
| b4cbad15de | |||
| fe1eb00c0f | |||
| 03df75c0de | |||
| 21c6513a7c | |||
| 8938d826d9 | |||
| e71a526011 | |||
| f3f6960d3e | |||
| 8952d3f100 | |||
| 0bb9e2d8d7 | |||
| 07b6c89868 | |||
| ffba0168b1 | |||
| 26a276cea1 | |||
| 3e2eb62931 | |||
| 62104652c8 | |||
| c950c91696 | |||
| 73e4f14d1b | |||
| 87d3c32f2e | |||
| b8e0488c90 | |||
| 6c23087aa7 | |||
| a6d9966786 | |||
| 1a8167e781 | |||
| 47dd1d85aa | |||
| c29edc7551 | |||
| fdddb80b70 | |||
| 70a804d98e | |||
| c12caea3d4 | |||
| 191a7fd205 | |||
| b0cb0168f4 | |||
| fb762d4e5c | |||
| ed0e988020 | |||
| 20cb5f4086 | |||
| de5d2667ab | |||
| 4a54efd42a | |||
| 5769d5fc86 | |||
| 0225f34969 | |||
| 23c69f1ef0 | |||
| 6e6b38e0b5 | |||
| 2e3892e951 | |||
| abe62e33e6 | |||
| 78731d0b96 | |||
| 56a58d538c | |||
| ef1c918973 | |||
| 3b9fce4e1c | |||
| 7b9e9eb98d | |||
| 0456d880f0 | |||
| 705776211a | |||
| 94b8228ba1 | |||
| 0b7d0d0f79 | |||
| c29501c06d | |||
| c152025706 | |||
| 0444dd2b70 | |||
| 15aded1e2a | |||
| cbff142b8e | |||
| ee16cb39bf | |||
| 7f0eba32de | |||
| 144c9ba7c3 | |||
| b676ff39a4 | |||
| fe709d665d | |||
| d692104051 | |||
| 17ebd603e1 | |||
| b24eb6c565 | |||
| c449504287 | |||
| 8df6b374bb | |||
| e84e1bbff3 | |||
| 3cfc322bdf | |||
| 6da402bf34 | |||
| 126c58ede4 | |||
| 6217d91173 | |||
| d28be61fb5 | |||
| a96ef27857 | |||
| 255541d592 | |||
| 19b4c997e9 | |||
| 93819366a4 | |||
| 7726e2e2d6 | |||
| d95ccdd4ec | |||
| 5698d90e6a | |||
| 44b87b5d95 | |||
| 334412f1cc | |||
| afcb4cd69a | |||
| d8a7c52ee6 | |||
| 05a70bac38 | |||
| 951f10fd3e | |||
| 10a5e2a8de | |||
| 82c32f9a80 | |||
| 17ae93679d | |||
| 27ffa62131 | |||
| 97a4db9c97 | |||
| 6f1a49b8b7 | |||
| 740807d2e3 | |||
| 066b01a788 | |||
| 2ce6578835 | |||
| e7b4c991ee | |||
| 42ee1fc276 | |||
| d56935d66f | |||
| 9e2565d84d | |||
| 73c72b4148 | |||
| 244af9a0da | |||
| 2eb043fb36 | |||
| 2454da368a | |||
| 8e899e949d | |||
| 6b0b697fb8 | |||
| 9a854a2fc9 | |||
| b6f1cf03e3 | |||
| d26cdca687 | |||
| dbeee32b59 | |||
| 0a8663b425 | |||
| 665c3ac59c | |||
| 07c0bb10fb | |||
| cf57ee9285 | |||
| d334aea208 | |||
| 0cf288757d | |||
| 695cd06817 | |||
| ae4522ff55 | |||
| 7f83e99e5f | |||
| d00007bc45 | |||
| abdb8f59a5 | |||
| 34eb2faa0d | |||
| 8c067bb86d | |||
| 77a4d33755 | |||
| 740a9315c3 | |||
| f8c0b9e71f | |||
| 18ae59bea1 |
@@ -1,4 +1,5 @@
|
||||
**/yui/build/** -diff
|
||||
**/amd/build/** -diff
|
||||
lib/dml/oci_native_moodle_package.sql text eol=lf
|
||||
theme/bootstrapbase/style/editor.css -diff
|
||||
theme/bootstrapbase/style/moodle.css -diff
|
||||
|
||||
+9
-6
@@ -23,8 +23,9 @@ addons:
|
||||
- mysql-client-core-5.6
|
||||
- mysql-client-5.6
|
||||
|
||||
services:
|
||||
- redis-server
|
||||
# Redis tests are currently failing on php 7.2 due to https://bugs.php.net/bug.php?id=75628
|
||||
# services:
|
||||
# - redis-server
|
||||
|
||||
env:
|
||||
# Although we want to run these jobs and see failures as quickly as possible, we also want to get the slowest job to
|
||||
@@ -99,8 +100,9 @@ install:
|
||||
fi
|
||||
|
||||
# Enable Redis.
|
||||
echo 'extension="redis.so"' > /tmp/redis.ini
|
||||
phpenv config-add /tmp/redis.ini
|
||||
# Redis tests are currently failing on php 7.2 due to https://bugs.php.net/bug.php?id=75628
|
||||
# echo 'extension="redis.so"' > /tmp/redis.ini
|
||||
# phpenv config-add /tmp/redis.ini
|
||||
|
||||
# Install composer dependencies.
|
||||
# We need --no-interaction in case we hit API limits for composer. This causes it to fall back to a standard clone.
|
||||
@@ -171,10 +173,11 @@ before_script:
|
||||
mkdir -p "$HOME"/roots/phpunit
|
||||
|
||||
# The phpunit dataroot and prefix..
|
||||
# Redis tests are currently failing on php 7.2 due to https://bugs.php.net/bug.php?id=75628
|
||||
# -e "/require_once/i \\define('TEST_SESSION_REDIS_HOST', '127.0.0.1');" \
|
||||
sed -i \
|
||||
-e "/require_once/i \\\$CFG->phpunit_dataroot = '\/home\/travis\/roots\/phpunit';" \
|
||||
-e "/require_once/i \\\$CFG->phpunit_prefix = 'p_';" \
|
||||
-e "/require_once/i \\define('TEST_SESSION_REDIS_HOST', '127.0.0.1');" \
|
||||
config.php ;
|
||||
|
||||
# Initialise PHPUnit for Moodle.
|
||||
@@ -204,7 +207,7 @@ before_script:
|
||||
# We need the official upstream for comparison
|
||||
git remote add upstream https://github.com/moodle/moodle.git;
|
||||
|
||||
git fetch upstream master;
|
||||
git fetch upstream MOODLE_34_STABLE;
|
||||
export GIT_PREVIOUS_COMMIT="`git merge-base FETCH_HEAD $TRAVIS_COMMIT`";
|
||||
export GIT_COMMIT="$TRAVIS_COMMIT";
|
||||
export UPSTREAM_FETCH_HEAD=`git rev-parse FETCH_HEAD`
|
||||
|
||||
@@ -165,6 +165,12 @@ function print_auth_lock_options($auth, $user_fields, $helptext, $retrieveopts,
|
||||
// If custom field then pick name from database.
|
||||
$fieldshortname = str_replace('profile_field_', '', $fieldname);
|
||||
$fieldname = $customfieldname[$fieldshortname]->name;
|
||||
if (core_text::strlen($fieldshortname) > 67) {
|
||||
// If custom profile field name is longer than 67 characters we will not be able to store the setting
|
||||
// such as 'field_updateremote_profile_field_NOTSOSHORTSHORTNAME' in the database because the character
|
||||
// limit for the setting name is 100.
|
||||
continue;
|
||||
}
|
||||
} elseif ($fieldname == 'url') {
|
||||
$fieldname = get_string('webpage');
|
||||
} else {
|
||||
|
||||
+9
-7
@@ -54,14 +54,16 @@ $statusmsg = '';
|
||||
$errormsg = '';
|
||||
|
||||
if ($data = data_submitted() and confirm_sesskey()) {
|
||||
if (admin_write_settings($data)) {
|
||||
$statusmsg = get_string('changessaved');
|
||||
}
|
||||
|
||||
$count = admin_write_settings($data);
|
||||
if (empty($adminroot->errors)) {
|
||||
switch ($return) {
|
||||
case 'site': redirect("$CFG->wwwroot/");
|
||||
case 'admin': redirect("$CFG->wwwroot/$CFG->admin/");
|
||||
// No errors. Did we change any setting? If so, then indicate success.
|
||||
if ($count) {
|
||||
$statusmsg = get_string('changessaved');
|
||||
} else {
|
||||
switch ($return) {
|
||||
case 'site': redirect("$CFG->wwwroot/");
|
||||
case 'admin': redirect("$CFG->wwwroot/$CFG->admin/");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$errormsg = get_string('errorwithsettings', 'admin');
|
||||
|
||||
@@ -2259,4 +2259,180 @@
|
||||
</CUSTOM_CHECK>
|
||||
</CUSTOM_CHECKS>
|
||||
</MOODLE>
|
||||
<MOODLE version="3.5" requires="3.1">
|
||||
<UNICODE level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unicoderequired" />
|
||||
</FEEDBACK>
|
||||
</UNICODE>
|
||||
<DATABASE level="required">
|
||||
<VENDOR name="mariadb" version="5.5.31" />
|
||||
<VENDOR name="mysql" version="5.5.31" />
|
||||
<VENDOR name="postgres" version="9.3" />
|
||||
<VENDOR name="mssql" version="10.0" />
|
||||
<VENDOR name="oracle" version="10.2" />
|
||||
</DATABASE>
|
||||
<PHP version="7.0.0" level="required">
|
||||
</PHP>
|
||||
<PCREUNICODE level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="pcreunicodewarning" />
|
||||
</FEEDBACK>
|
||||
</PCREUNICODE>
|
||||
<PHP_EXTENSIONS>
|
||||
<PHP_EXTENSION name="iconv" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="iconvrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="mbstring" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="mbstringrecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="curl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="curlrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="openssl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="opensslrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="tokenizer" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="tokenizerrecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="xmlrpc" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="xmlrpcrecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="soap" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="soaprecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="ctype" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="ctyperequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="zip" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="ziprequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="zlib" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="gd" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="gdrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="simplexml" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="simplexmlrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="spl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="splrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="pcre" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="dom" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="xml" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="xmlreader" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="intl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="intlrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="json" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="hash" level="required"/>
|
||||
<PHP_EXTENSION name="fileinfo" level="required"/>
|
||||
</PHP_EXTENSIONS>
|
||||
<PHP_SETTINGS>
|
||||
<PHP_SETTING name="memory_limit" value="96M" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="settingmemorylimit" />
|
||||
</FEEDBACK>
|
||||
</PHP_SETTING>
|
||||
<PHP_SETTING name="file_uploads" value="1" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="settingfileuploads" />
|
||||
</FEEDBACK>
|
||||
</PHP_SETTING>
|
||||
<PHP_SETTING name="opcache.enable" value="1" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="opcacherecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_SETTING>
|
||||
</PHP_SETTINGS>
|
||||
<CUSTOM_CHECKS>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_storage_engine" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddbstorageengine" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="question/engine/upgrade/upgradelib.php" function="quiz_attempts_upgraded" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="quizattemptsupgradedmessage" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_slasharguments" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="slashargumentswarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_tables_row_format" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="unsupporteddbtablerowformat" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_unoconv_version" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="unoconvwarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_libcurl_version" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="libcurlwarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_file_format" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddbfileformat" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_file_per_table" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddbfilepertable" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_large_prefix" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddblargeprefix" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_is_https" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="ishttpswarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_incomplete_unicode_support" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="incompleteunicodesupport" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
</CUSTOM_CHECKS>
|
||||
</MOODLE>
|
||||
</COMPATIBILITY_MATRIX>
|
||||
|
||||
@@ -29,9 +29,10 @@ require_once($CFG->libdir.'/adminlib.php');
|
||||
$confirm = optional_param('confirm', 0, PARAM_BOOL);
|
||||
$returnurl = optional_param('returnurl', null, PARAM_LOCALURL);
|
||||
|
||||
admin_externalpage_setup('purgecaches');
|
||||
|
||||
// If we have got here as a confirmed aciton, do it.
|
||||
if ($confirm && isloggedin() && confirm_sesskey()) {
|
||||
require_capability('moodle/site:config', context_system::instance());
|
||||
if ($confirm && confirm_sesskey()) {
|
||||
|
||||
// Valid request. Purge, and redirect the user back to where they came from.
|
||||
purge_all_caches();
|
||||
@@ -45,8 +46,6 @@ if ($confirm && isloggedin() && confirm_sesskey()) {
|
||||
}
|
||||
|
||||
// Otherwise, show a button to actually purge the caches.
|
||||
admin_externalpage_setup('purgecaches');
|
||||
|
||||
$actionurl = new moodle_url('/admin/purgecaches.php', array('sesskey'=>sesskey(), 'confirm'=>1));
|
||||
if ($returnurl) {
|
||||
$actionurl->param('returnurl', $returnurl);
|
||||
|
||||
@@ -46,6 +46,14 @@ $error = optional_param('error', '', PARAM_ALPHANUM);
|
||||
admin_externalpage_setup('registrationmoodleorg');
|
||||
|
||||
if ($url !== HUB_MOODLEORGHUBURL) {
|
||||
// Allow other plugins to confirm registration on hubs other than moodle.net . Plugins implementing this
|
||||
// callback need to redirect or exit. See https://docs.moodle.org/en/Hub_registration .
|
||||
$callbacks = get_plugins_with_function('hub_registration');
|
||||
foreach ($callbacks as $plugintype => $plugins) {
|
||||
foreach ($plugins as $plugin => $callback) {
|
||||
$callback('confirm');
|
||||
}
|
||||
}
|
||||
throw new moodle_exception('errorotherhubsnotsupported', 'hub');
|
||||
}
|
||||
|
||||
|
||||
@@ -40,6 +40,14 @@ $token = optional_param('token', '', PARAM_TEXT);
|
||||
admin_externalpage_setup('registrationmoodleorg');
|
||||
|
||||
if ($url !== HUB_MOODLEORGHUBURL) {
|
||||
// Allow other plugins to renew registration on hubs other than moodle.net . Plugins implementing this
|
||||
// callback need to redirect or exit. See https://docs.moodle.org/en/Hub_registration .
|
||||
$callbacks = get_plugins_with_function('hub_registration');
|
||||
foreach ($callbacks as $plugintype => $plugins) {
|
||||
foreach ($plugins as $plugin => $callback) {
|
||||
$callback('renew');
|
||||
}
|
||||
}
|
||||
throw new moodle_exception('errorotherhubsnotsupported', 'hub');
|
||||
}
|
||||
|
||||
|
||||
+5
-4
@@ -32,15 +32,16 @@ $focus = '';
|
||||
// now we'll deal with the case that the admin has submitted the form with changed settings
|
||||
if ($data = data_submitted() and confirm_sesskey() and isset($data->action) and $data->action == 'save-settings') {
|
||||
require_capability('moodle/site:config', $context);
|
||||
if (admin_write_settings($data)) {
|
||||
redirect($PAGE->url, get_string('changessaved'), null, \core\output\notification::NOTIFY_SUCCESS);
|
||||
}
|
||||
|
||||
$count = admin_write_settings($data);
|
||||
if (!empty($adminroot->errors)) {
|
||||
$errormsg = get_string('errorwithsettings', 'admin');
|
||||
$firsterror = reset($adminroot->errors);
|
||||
$focus = $firsterror->id;
|
||||
} else {
|
||||
// No errors. Did we change any setting? If so, then redirect with success.
|
||||
if ($count) {
|
||||
redirect($PAGE->url, get_string('changessaved'), null, \core\output\notification::NOTIFY_SUCCESS);
|
||||
}
|
||||
redirect($PAGE->url);
|
||||
}
|
||||
}
|
||||
|
||||
+7
-3
@@ -39,11 +39,15 @@ $statusmsg = '';
|
||||
$errormsg = '';
|
||||
|
||||
if ($data = data_submitted() and confirm_sesskey()) {
|
||||
if (admin_write_settings($data)) {
|
||||
redirect($PAGE->url, get_string('changessaved'), null, \core\output\notification::NOTIFY_SUCCESS);
|
||||
}
|
||||
|
||||
$count = admin_write_settings($data);
|
||||
// Regardless of whether any setting change was written (a positive count), check validation errors for those that didn't.
|
||||
if (empty($adminroot->errors)) {
|
||||
// No errors. Did we change any setting? If so, then redirect with success.
|
||||
if ($count) {
|
||||
redirect($PAGE->url, get_string('changessaved'), null, \core\output\notification::NOTIFY_SUCCESS);
|
||||
}
|
||||
// We didn't change a setting.
|
||||
switch ($return) {
|
||||
case 'site': redirect("$CFG->wwwroot/");
|
||||
case 'admin': redirect("$CFG->wwwroot/$CFG->admin/");
|
||||
|
||||
@@ -119,6 +119,9 @@ class models_list implements \renderable, \templatable {
|
||||
debugging("The time splitting method '{$modeldata->timesplitting}' should include a '{$identifier}_help'
|
||||
string to describe its purpose.", DEBUG_DEVELOPER);
|
||||
}
|
||||
} else {
|
||||
$helpicon = new \help_icon('timesplittingnotdefined', 'tool_analytics');
|
||||
$modeldata->timesplittinghelp = $helpicon->export_for_template($output);
|
||||
}
|
||||
|
||||
// Has this model generated predictions?.
|
||||
@@ -207,19 +210,22 @@ class models_list implements \renderable, \templatable {
|
||||
}
|
||||
|
||||
// Enable / disable.
|
||||
if ($model->is_enabled()) {
|
||||
$action = 'disable';
|
||||
$text = get_string('disable');
|
||||
$icontype = 't/block';
|
||||
} else {
|
||||
$action = 'enable';
|
||||
$text = get_string('enable');
|
||||
$icontype = 'i/checked';
|
||||
if ($model->is_enabled() || !empty($modeldata->timesplitting)) {
|
||||
// If there is no timesplitting method set, the model can not be enabled.
|
||||
if ($model->is_enabled()) {
|
||||
$action = 'disable';
|
||||
$text = get_string('disable');
|
||||
$icontype = 't/block';
|
||||
} else {
|
||||
$action = 'enable';
|
||||
$text = get_string('enable');
|
||||
$icontype = 'i/checked';
|
||||
}
|
||||
$urlparams['action'] = $action;
|
||||
$url = new \moodle_url('model.php', $urlparams);
|
||||
$icon = new \action_menu_link_secondary($url, new \pix_icon($icontype, $text), $text);
|
||||
$actionsmenu->add($icon);
|
||||
}
|
||||
$urlparams['action'] = $action;
|
||||
$url = new \moodle_url('model.php', $urlparams);
|
||||
$icon = new \action_menu_link_secondary($url, new \pix_icon($icontype, $text), $text);
|
||||
$actionsmenu->add($icon);
|
||||
|
||||
// Export training data.
|
||||
if (!$model->is_static() && $model->is_trained()) {
|
||||
|
||||
@@ -83,6 +83,8 @@ $string['previouspage'] = 'Previous page';
|
||||
$string['samestartdate'] = 'Current start date is good';
|
||||
$string['sameenddate'] = 'Current end date is good';
|
||||
$string['target'] = 'Target';
|
||||
$string['timesplittingnotdefined'] = 'Time splitting is not defined.';
|
||||
$string['timesplittingnotdefined_help'] = 'You need to select a time-splitting method before enabling the model.';
|
||||
$string['trainandpredictmodel'] = 'Training model and calculating predictions';
|
||||
$string['trainingprocessfinished'] = 'Training process finished';
|
||||
$string['trainingresults'] = 'Training results';
|
||||
|
||||
@@ -160,6 +160,9 @@
|
||||
{{/timesplitting}}
|
||||
{{^timesplitting}}
|
||||
{{#str}}notdefined, tool_analytics{{/str}}
|
||||
{{#timesplittinghelp}}
|
||||
{{>core/help_icon}}
|
||||
{{/timesplittinghelp}}
|
||||
{{/timesplitting}}
|
||||
</td>
|
||||
<td>
|
||||
|
||||
@@ -398,7 +398,7 @@ function print_combined_install_output($processes) {
|
||||
// Show process name in first row.
|
||||
foreach ($processes as $name => $process) {
|
||||
// If we don't have enough space to show full run name then show runX.
|
||||
if ($lengthofprocessline < strlen($name + 2)) {
|
||||
if ($lengthofprocessline < strlen($name) + 2) {
|
||||
$name = substr($name, -5);
|
||||
}
|
||||
// One extra padding as we are adding | separator for rest of the data.
|
||||
|
||||
@@ -38,5 +38,8 @@ function xmldb_tool_customlang_upgrade($oldversion) {
|
||||
// Automatically generated Moodle v3.3.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v3.4.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -47,12 +47,12 @@ class httpsreplace_test extends \advanced_testcase {
|
||||
"Test image from another site should be replaced" => [
|
||||
"content" => '<img src="' . $this->getExternalTestFileUrl('/test.jpg', false) . '">',
|
||||
"outputregex" => '/UPDATE/',
|
||||
"expectedcontent" => '<img src="' . $this->getExternalTestFileUrl('/test.jpg', true) . '">',
|
||||
"expectedcontent" => '<img src="' . $this->get_converted_http_link('/test.jpg') . '">',
|
||||
],
|
||||
"Test object from another site should be replaced" => [
|
||||
"content" => '<object data="' . $this->getExternalTestFileUrl('/test.swf', false) . '">',
|
||||
"outputregex" => '/UPDATE/',
|
||||
"expectedcontent" => '<object data="' . $this->getExternalTestFileUrl('/test.swf', true) . '">',
|
||||
"expectedcontent" => '<object data="' . $this->get_converted_http_link('/test.swf') . '">',
|
||||
],
|
||||
"Test image from a site with international name should be replaced" => [
|
||||
"content" => '<img src="http://中国互联网络信息中心.中国/logosy/201706/W01.png">',
|
||||
@@ -82,7 +82,7 @@ class httpsreplace_test extends \advanced_testcase {
|
||||
"Search for params should be case insensitive" => [
|
||||
"content" => '<object DATA="' . $this->getExternalTestFileUrl('/test.swf', false) . '">',
|
||||
"outputregex" => '/UPDATE/',
|
||||
"expectedcontent" => '<object DATA="' . $this->getExternalTestFileUrl('/test.swf', true) . '">',
|
||||
"expectedcontent" => '<object DATA="' . $this->get_converted_http_link('/test.swf') . '">',
|
||||
],
|
||||
"URL should be case insensitive" => [
|
||||
"content" => '<object data="HTTP://some.site/path?query">',
|
||||
@@ -93,7 +93,7 @@ class httpsreplace_test extends \advanced_testcase {
|
||||
"content" => '<img alt="A picture" src="' . $this->getExternalTestFileUrl('/test.png', false) .
|
||||
'" width="1”><p style="font-size: \'20px\'"></p>',
|
||||
"outputregex" => '/UPDATE/',
|
||||
"expectedcontent" => '<img alt="A picture" src="' . $this->getExternalTestFileUrl('/test.png', true) .
|
||||
"expectedcontent" => '<img alt="A picture" src="' . $this->get_converted_http_link('/test.png') .
|
||||
'" width="1”><p style="font-size: \'20px\'"></p>',
|
||||
],
|
||||
"Broken URL should not be changed" => [
|
||||
@@ -113,11 +113,25 @@ class httpsreplace_test extends \advanced_testcase {
|
||||
$this->getExternalTestFileUrl('/test.jpg', false) . '"></a>',
|
||||
"outputregex" => '/UPDATE/',
|
||||
"expectedcontent" => '<a href="' . $this->getExternalTestFileUrl('/test.png', false) . '"><img src="' .
|
||||
$this->getExternalTestFileUrl('/test.jpg', true) . '"></a>',
|
||||
$this->get_converted_http_link('/test.jpg') . '"></a>',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the HTTP external test file URL to use HTTPS.
|
||||
*
|
||||
* Note: We *must not* use getExternalTestFileUrl with the True option
|
||||
* here, becase it is reasonable to have only one of these set due to
|
||||
* issues with SSL certificates.
|
||||
*
|
||||
* @param string $path Path to be rewritten
|
||||
* @return string
|
||||
*/
|
||||
protected function get_converted_http_link($path) {
|
||||
return preg_replace('/^http:/', 'https:', $this->getExternalTestFileUrl($path, false));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test upgrade_http_links
|
||||
* @param string $content Example content that we'll attempt to replace.
|
||||
@@ -152,7 +166,7 @@ class httpsreplace_test extends \advanced_testcase {
|
||||
// Get the http url, since the default test wwwroot is https.
|
||||
$wwwrootdomain = 'www.example.com';
|
||||
$wwwroothttp = preg_replace('/^https:/', 'http:', $CFG->wwwroot);
|
||||
$testdomain = 'download.moodle.org';
|
||||
$testdomain = $this->get_converted_http_link('');
|
||||
return [
|
||||
"Test image from an available site so shouldn't be reported" => [
|
||||
"content" => '<img src="' . $this->getExternalTestFileUrl('/test.jpg', false) . '">',
|
||||
|
||||
@@ -42,5 +42,8 @@ function xmldb_tool_log_upgrade($oldversion) {
|
||||
// Automatically generated Moodle v3.3.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v3.4.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -36,5 +36,8 @@ function xmldb_logstore_database_upgrade($oldversion) {
|
||||
// Automatically generated Moodle v3.3.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v3.4.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -36,5 +36,8 @@ function xmldb_logstore_standard_upgrade($oldversion) {
|
||||
// Automatically generated Moodle v3.3.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v3.4.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -64,6 +64,7 @@
|
||||
<li>
|
||||
<a href="#">{{#str}}edit{{/str}}</a><b class="caret"></b>
|
||||
<ul class="dropdown dropdown-menu">
|
||||
{{#canmanage}}
|
||||
<li class="dropdown-item">
|
||||
<a href="#" data-action="edit">
|
||||
{{#pix}}t/edit{{/pix}} {{#str}}edit{{/str}}
|
||||
@@ -89,11 +90,13 @@
|
||||
{{#pix}}t/down{{/pix}} {{#str}}movedown{{/str}}
|
||||
</a>
|
||||
</li>
|
||||
{{/canmanage}}
|
||||
<li class="dropdown-item">
|
||||
<a href="#" data-action="linkedcourses">
|
||||
{{#pix}}t/viewdetails{{/pix}} {{#str}}linkedcourses, tool_lp{{/str}}
|
||||
</a>
|
||||
</li>
|
||||
{{#canmanage}}
|
||||
<li class="dropdown-item">
|
||||
<a href="#" data-action="relatedcompetencies">
|
||||
{{#pix}}t/add{{/pix}} {{#str}}addcrossreferencedcompetency, tool_lp{{/str}}
|
||||
@@ -104,6 +107,7 @@
|
||||
{{#pix}}t/edit{{/pix}} {{#str}}competencyrule, tool_lp{{/str}}
|
||||
</a>
|
||||
</li>
|
||||
{{/canmanage}}
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -112,11 +116,11 @@
|
||||
<p data-region="competencyinfo">
|
||||
{{#str}}nocompetencyselected, tool_lp{{/str}}
|
||||
</p>
|
||||
{{#canmanage}}
|
||||
<div data-region="competencyactions">
|
||||
{{#canmanage}}
|
||||
<button class="btn btn-secondary" data-action="add">{{#pix}}t/add{{/pix}} <span data-region="term"></span></button>
|
||||
{{/canmanage}}
|
||||
</div>
|
||||
{{/canmanage}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -76,5 +76,8 @@ function xmldb_tool_monitor_upgrade($oldversion) {
|
||||
// Automatically generated Moodle v3.3.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v3.4.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -78,6 +78,10 @@ class issuer extends persistent {
|
||||
$mform->addRule('clientsecret', get_string('maximumchars', '', 255), 'maxlength', 255, 'client');
|
||||
$mform->addHelpButton('clientsecret', 'issuerclientsecret', 'tool_oauth2');
|
||||
|
||||
// Use basic authentication.
|
||||
$mform->addElement('checkbox', 'basicauth', get_string('usebasicauth', 'tool_oauth2'));
|
||||
$mform->addHelpButton('basicauth', 'usebasicauth', 'tool_oauth2');
|
||||
|
||||
// Login scopes.
|
||||
$mform->addElement('text', 'loginscopes', get_string('issuerloginscopes', 'tool_oauth2'));
|
||||
$mform->addRule('loginscopes', null, 'required', null, 'client');
|
||||
|
||||
@@ -95,6 +95,8 @@ $string['systemaccountconnected_help'] = 'System accounts are used to provide ad
|
||||
$string['systemaccountconnected'] = 'System account connected';
|
||||
$string['systemaccountnotconnected'] = 'System account not connected';
|
||||
$string['systemauthstatus'] = 'System account connected';
|
||||
$string['usebasicauth'] = 'Authenticate token requests via HTTP headers';
|
||||
$string['usebasicauth_help'] = 'Utilise the HTTP Basic authentication scheme when sending client ID and password with a refresh token request. Recommended by the OAuth 2 standard, but may not be available with some issuers.';
|
||||
$string['userfieldexternalfield'] = 'External field name';
|
||||
$string['userfieldexternalfield_help'] = 'Name of the field provided by the external OAuth system.';
|
||||
$string['userfieldinternalfield_help'] = 'Name of the Moodle user field that should be mapped from the external field.';
|
||||
|
||||
@@ -9,6 +9,7 @@ Feature: Basic recycle bin functionality
|
||||
| username | firstname | lastname | email |
|
||||
| teacher1 | Teacher | 1 | teacher@asd.com |
|
||||
| student1 | Student | 1 | student@asd.com |
|
||||
| student2 | Student | 2 | student2@asd.com |
|
||||
And the following "courses" exist:
|
||||
| fullname | shortname |
|
||||
| Course 1 | C1 |
|
||||
@@ -16,6 +17,23 @@ Feature: Basic recycle bin functionality
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
| student1 | C1 | student |
|
||||
| student2 | C1 | student |
|
||||
| teacher1 | C2 | editingteacher |
|
||||
| student1 | C2 | student |
|
||||
| student2 | C2 | student |
|
||||
And the following "groups" exist:
|
||||
| name | course | idnumber |
|
||||
| Group A | C2 | G1 |
|
||||
| Group B | C2 | G2 |
|
||||
| Group C | C2 | G3 |
|
||||
And the following "group members" exist:
|
||||
| user | group |
|
||||
| teacher1 | G1 |
|
||||
| teacher1 | G2 |
|
||||
| student1 | G1 |
|
||||
| student2 | G1 |
|
||||
| student2 | G2 |
|
||||
And the following config values are set as admin:
|
||||
| coursebinenable | 1 | tool_recyclebin |
|
||||
| categorybinenable | 1 | tool_recyclebin |
|
||||
@@ -58,6 +76,12 @@ Feature: Basic recycle bin functionality
|
||||
And I wait to be redirected
|
||||
And I go to the courses management page
|
||||
And I should see "Course 2" in the "#course-listing" "css_element"
|
||||
And I am on "Course 2" course homepage
|
||||
And I navigate to "Groups" node in "Course administration > Users"
|
||||
And I follow "Overview"
|
||||
And "Student 1" "text" should exist in the "Group A" "table_row"
|
||||
And "Student 2" "text" should exist in the "Group A" "table_row"
|
||||
And "Student 2" "text" should exist in the "Group B" "table_row"
|
||||
|
||||
@javascript
|
||||
Scenario: Deleting a single item from the recycle bin
|
||||
|
||||
@@ -358,7 +358,7 @@ if ($formdata = $mform2->is_cancelled()) {
|
||||
|
||||
// add default values for remaining fields
|
||||
$formdefaults = array();
|
||||
if ($updatetype != UU_UPDATE_FILEOVERRIDE && $updatetype != UU_UPDATE_NOCHANGES) {
|
||||
if (!$existinguser || ($updatetype != UU_UPDATE_FILEOVERRIDE && $updatetype != UU_UPDATE_NOCHANGES)) {
|
||||
foreach ($STD_FIELDS as $field) {
|
||||
if (isset($user->$field)) {
|
||||
continue;
|
||||
|
||||
@@ -38,6 +38,31 @@ Feature: Upload users
|
||||
And I set the field "groups" to "Section 1 (1)"
|
||||
And the "members" select box should contain "Tom Jones"
|
||||
|
||||
@javascript
|
||||
Scenario: Upload users enrolling them on courses and groups applying defaults
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname | category |
|
||||
| Maths | math102 | 0 |
|
||||
And the following "groups" exist:
|
||||
| name | course | idnumber |
|
||||
| Section 1 | math102 | S1 |
|
||||
| Section 3 | math102 | S3 |
|
||||
And I log in as "admin"
|
||||
And I navigate to "Upload users" node in "Site administration > Users > Accounts"
|
||||
When I upload "lib/tests/fixtures/upload_users.csv" file to "File" filemanager
|
||||
And I press "Upload users"
|
||||
And I set the following fields to these values:
|
||||
| City/town | Brighton |
|
||||
| Department | Purchasing |
|
||||
And I press "Upload users"
|
||||
And I press "Continue"
|
||||
And I navigate to "Users > Accounts > Browse list of users" in site administration
|
||||
And I should see "Tom Jones"
|
||||
And I follow "Tom Jones"
|
||||
And I follow "Edit profile"
|
||||
And the field "City/town" matches value "Brighton"
|
||||
And the field "Department" matches value "Purchasing"
|
||||
|
||||
@javascript
|
||||
Scenario: Upload users with custom profile fields
|
||||
# Create user profile field.
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
@@ -619,26 +619,43 @@ Tour.prototype.addEventHandler = function (eventName, handler) {
|
||||
*/
|
||||
Tour.prototype.processStepListeners = function (stepConfig) {
|
||||
this.listeners.push(
|
||||
// Next/Previous buttons.
|
||||
{
|
||||
node: this.currentStepNode,
|
||||
args: ['click', '[data-role="next"]', $.proxy(this.next, this)]
|
||||
}, {
|
||||
node: this.currentStepNode,
|
||||
args: ['click', '[data-role="previous"]', $.proxy(this.previous, this)]
|
||||
},
|
||||
// Next/Previous buttons.
|
||||
{
|
||||
node: this.currentStepNode,
|
||||
args: ['click', '[data-role="next"]', $.proxy(this.next, this)]
|
||||
}, {
|
||||
node: this.currentStepNode,
|
||||
args: ['click', '[data-role="previous"]', $.proxy(this.previous, this)]
|
||||
},
|
||||
|
||||
// Close and end tour buttons.
|
||||
{
|
||||
node: this.currentStepNode,
|
||||
args: ['click', '[data-role="end"]', $.proxy(this.endTour, this)]
|
||||
},
|
||||
// Close and end tour buttons.
|
||||
{
|
||||
node: this.currentStepNode,
|
||||
args: ['click', '[data-role="end"]', $.proxy(this.endTour, this)]
|
||||
},
|
||||
|
||||
// Keypresses.
|
||||
{
|
||||
node: $('body'),
|
||||
args: ['keydown', $.proxy(this.handleKeyDown, this)]
|
||||
});
|
||||
// Click backdrop and hide tour.
|
||||
{
|
||||
node: $('[data-flexitour="backdrop"]'),
|
||||
args: ['click', $.proxy(this.hide, this)]
|
||||
},
|
||||
|
||||
// Click out and hide tour without backdrop.
|
||||
{
|
||||
node: $('body'),
|
||||
args: ['click', $.proxy(function (e) {
|
||||
// Handle click in or click out tour content,
|
||||
// if click out, hide tour.
|
||||
if (!this.currentStepNode.is(e.target) && $(e.target).closest('[data-role="flexitour-step"]').length === 0) {
|
||||
this.hide();
|
||||
}}, this)]
|
||||
},
|
||||
|
||||
// Keypresses.
|
||||
{
|
||||
node: $('body'),
|
||||
args: ['keydown', $.proxy(this.handleKeyDown, this)]
|
||||
});
|
||||
|
||||
if (stepConfig.moveOnClick) {
|
||||
var targetNode = this.getStepTarget(stepConfig);
|
||||
@@ -904,7 +921,7 @@ Tour.prototype.announceStep = function (stepConfig) {
|
||||
* @param {EventFacade} e
|
||||
*/
|
||||
Tour.prototype.handleKeyDown = function (e) {
|
||||
var tabbableSelector = 'a[href], link[href], [draggable=true], [contenteditable=true], :input:enabled, [tabindex], button';
|
||||
var tabbableSelector = 'a[href], link[href], [draggable=true], [contenteditable=true], :input:enabled, [tabindex], button:enabled';
|
||||
switch (e.keyCode) {
|
||||
case 27:
|
||||
this.endTour();
|
||||
@@ -923,8 +940,17 @@ Tour.prototype.handleKeyDown = function (e) {
|
||||
var activeElement = $(document.activeElement);
|
||||
var stepTarget = this.getStepTarget(this.currentStepConfig);
|
||||
var tabbableNodes = $(tabbableSelector);
|
||||
var dialogContainer = $('span[data-flexitour="container"]');
|
||||
var currentIndex = void 0;
|
||||
tabbableNodes.filter(function (index, element) {
|
||||
// Filter out element which is not belong to target section or dialogue.
|
||||
if (stepTarget) {
|
||||
tabbableNodes = tabbableNodes.filter(function (index, element) {
|
||||
return stepTarget != null && (stepTarget.has(element).length || dialogContainer.has(element).length || stepTarget.is(element) || dialogContainer.is(element));
|
||||
});
|
||||
}
|
||||
|
||||
// Find index of focusing element.
|
||||
tabbableNodes.each(function (index, element) {
|
||||
if (activeElement.is(element)) {
|
||||
currentIndex = index;
|
||||
return false;
|
||||
@@ -934,7 +960,7 @@ Tour.prototype.handleKeyDown = function (e) {
|
||||
var nextIndex = void 0;
|
||||
var nextNode = void 0;
|
||||
var focusRelevant = void 0;
|
||||
if (currentIndex) {
|
||||
if (currentIndex != void 0) {
|
||||
var direction = 1;
|
||||
if (e.shiftKey) {
|
||||
direction = -1;
|
||||
@@ -1090,6 +1116,16 @@ Tour.prototype.hide = function (transition) {
|
||||
$(this).remove();
|
||||
});
|
||||
|
||||
// Remove aria-describedby and tabindex attributes.
|
||||
if (this.currentStepNode && this.currentStepNode.length) {
|
||||
var stepId = this.currentStepNode.attr('id');
|
||||
if (stepId) {
|
||||
var currentStepElement = '[aria-describedby="' + stepId + '-body"]';
|
||||
$(currentStepElement).removeAttr('tabindex');
|
||||
$(currentStepElement).removeAttr('aria-describedby');
|
||||
}
|
||||
}
|
||||
|
||||
// Reset the listeners.
|
||||
this.resetStepListeners();
|
||||
|
||||
|
||||
@@ -48,5 +48,8 @@ function xmldb_tool_usertours_upgrade($oldversion) {
|
||||
// Automatically generated Moodle v3.3.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v3.4.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -157,3 +157,23 @@ Feature: Apply tour filters to a tour
|
||||
When I am on "Course 2" course homepage
|
||||
And I wait until the page is ready
|
||||
Then I should not see "Welcome to your course tour."
|
||||
|
||||
@javascript
|
||||
Scenario: Aria tags should not exist
|
||||
Given I log in as "admin"
|
||||
And I open the User tour settings page
|
||||
# Turn on default tour for boost theme.
|
||||
And I click on "Enable" "link" in the "Boost - administrator" "table_row"
|
||||
And I am on site homepage
|
||||
When I click on "Next" "button"
|
||||
Then "button[aria-describedby^='tour-step-tool_usertours']" "css_element" should exist
|
||||
And "button[tabindex]" "css_element" should exist
|
||||
When I click on "Next" "button"
|
||||
Then "button[aria-describedby^='tour-step-tool_usertours']" "css_element" should not exist
|
||||
And "button[tabindex]" "css_element" should not exist
|
||||
When I click on "Previous" "button"
|
||||
Then "button[aria-describedby^='tour-step-tool_usertours']" "css_element" should exist
|
||||
And "button[tabindex]" "css_element" should exist
|
||||
When I click on "End tour" "button"
|
||||
Then "button[aria-describedby^='tour-step-tool_usertours']" "css_element" should not exist
|
||||
And "button[tabindex]" "css_element" should not exist
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<location>amd/src/tour.js</location>
|
||||
<name>Flexitour</name>
|
||||
<license>GPLv3</license>
|
||||
<version>0.10.0</version>
|
||||
<version>0.12.0</version>
|
||||
<licenseversion>3</licenseversion>
|
||||
</library>
|
||||
<library>
|
||||
|
||||
+8
-2
@@ -256,11 +256,17 @@
|
||||
$users[$key]->country = $countries[$user->country];
|
||||
}
|
||||
}
|
||||
if ($sort == "country") { // Need to resort by full country name, not code
|
||||
if ($sort == "country") {
|
||||
// Need to resort by full country name, not code.
|
||||
foreach ($users as $user) {
|
||||
$susers[$user->id] = $user->country;
|
||||
}
|
||||
asort($susers);
|
||||
// Sort by country name, according to $dir.
|
||||
if ($dir === 'DESC') {
|
||||
arsort($susers);
|
||||
} else {
|
||||
asort($susers);
|
||||
}
|
||||
foreach ($susers as $key => $value) {
|
||||
$nusers[] = $users[$key];
|
||||
}
|
||||
|
||||
@@ -134,7 +134,7 @@ class course implements \core_analytics\analysable {
|
||||
*
|
||||
* Lazy load of course data, students and teachers.
|
||||
*
|
||||
* @param int|stdClass $course Course id
|
||||
* @param int|\stdClass $course Course id
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($course) {
|
||||
@@ -152,7 +152,7 @@ class course implements \core_analytics\analysable {
|
||||
*
|
||||
* Lazy load of course data, students and teachers.
|
||||
*
|
||||
* @param int|stdClass $course Course object or course id
|
||||
* @param int|\stdClass $course Course object or course id
|
||||
* @return \core_analytics\course
|
||||
*/
|
||||
public static function instance($course) {
|
||||
@@ -184,7 +184,7 @@ class course implements \core_analytics\analysable {
|
||||
/**
|
||||
* Loads the analytics course object.
|
||||
*
|
||||
* @return null
|
||||
* @return void
|
||||
*/
|
||||
protected function load() {
|
||||
|
||||
@@ -451,7 +451,7 @@ class course implements \core_analytics\analysable {
|
||||
/**
|
||||
* Returns the course students.
|
||||
*
|
||||
* @return stdClass[]
|
||||
* @return int[]
|
||||
*/
|
||||
public function get_students() {
|
||||
|
||||
@@ -595,7 +595,7 @@ class course implements \core_analytics\analysable {
|
||||
*
|
||||
* Keys are ignored.
|
||||
*
|
||||
* @param int|float $values Sorted array of values
|
||||
* @param int[]|float[] $values Sorted array of values
|
||||
* @return int
|
||||
*/
|
||||
protected function median($values) {
|
||||
@@ -605,7 +605,7 @@ class course implements \core_analytics\analysable {
|
||||
return reset($values);
|
||||
}
|
||||
|
||||
$middlevalue = floor(($count - 1) / 2);
|
||||
$middlevalue = (int)floor(($count - 1) / 2);
|
||||
|
||||
if ($count % 2) {
|
||||
// Odd number, middle is the median.
|
||||
|
||||
@@ -1013,6 +1013,10 @@ class model {
|
||||
if (!$this->is_static()) {
|
||||
$this->model->trained = 0;
|
||||
}
|
||||
} else if (empty($this->model->timesplitting)) {
|
||||
// A valid timesplitting method needs to be supplied before a model can be enabled.
|
||||
throw new \moodle_exception('invalidtimesplitting', 'analytics', '', $this->model->id);
|
||||
|
||||
}
|
||||
|
||||
// Purge pages with insights as this may change things.
|
||||
|
||||
@@ -138,6 +138,7 @@ class dataset_manager_testcase extends advanced_testcase {
|
||||
// Training and prediction files are not mixed up.
|
||||
$trainingfile1 = \core_analytics\dataset_manager::merge_datasets(array($file), $fakemodelid,
|
||||
'\core\analytics\time_splitting\quarters', \core_analytics\dataset_manager::LABELLED_FILEAREA, false);
|
||||
$this->waitForSecond();
|
||||
$trainingfile2 = \core_analytics\dataset_manager::merge_datasets(array($file), $fakemodelid,
|
||||
'\core\analytics\time_splitting\quarters', \core_analytics\dataset_manager::LABELLED_FILEAREA, false);
|
||||
|
||||
|
||||
@@ -226,13 +226,17 @@ class analytics_model_testcase extends advanced_testcase {
|
||||
$this->model->mark_as_trained();
|
||||
$this->assertEquals($originaluniqueid, $this->model->get_unique_id());
|
||||
|
||||
$this->model->enable();
|
||||
$this->assertEquals($originaluniqueid, $this->model->get_unique_id());
|
||||
// Wait for the current timestamp to change.
|
||||
$this->waitForSecond();
|
||||
$this->model->enable('\core\analytics\time_splitting\deciles');
|
||||
$this->assertNotEquals($originaluniqueid, $this->model->get_unique_id());
|
||||
$uniqueid = $this->model->get_unique_id();
|
||||
|
||||
// Wait 1 sec so the timestamp changes.
|
||||
sleep(1);
|
||||
// Wait for the current timestamp to change.
|
||||
$this->waitForSecond();
|
||||
$this->model->enable('\core\analytics\time_splitting\quarters');
|
||||
$this->assertNotEquals($originaluniqueid, $this->model->get_unique_id());
|
||||
$this->assertNotEquals($uniqueid, $this->model->get_unique_id());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -48,5 +48,8 @@ function xmldb_auth_cas_upgrade($oldversion) {
|
||||
// Automatically generated Moodle v3.3.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v3.4.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -45,5 +45,8 @@ function xmldb_auth_db_upgrade($oldversion) {
|
||||
// Automatically generated Moodle v3.3.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v3.4.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -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. MD5 hashing is useful for connecting to other common web applications like PostNuke.</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 <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_key'] = 'Password format';
|
||||
$string['auth_dbreviveduser'] = 'Revived user {$a->name} id {$a->id}';
|
||||
$string['auth_dbrevivedusererror'] = 'Error reviving user {$a}';
|
||||
|
||||
@@ -45,5 +45,8 @@ function xmldb_auth_email_upgrade($oldversion) {
|
||||
// Automatically generated Moodle v3.3.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v3.4.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
+105
-39
@@ -837,23 +837,7 @@ class auth_plugin_ldap extends auth_plugin_base {
|
||||
/// User Updates - time-consuming (optional)
|
||||
if ($do_updates) {
|
||||
// Narrow down what fields we need to update
|
||||
$all_keys = array_keys(get_object_vars($this->config));
|
||||
$updatekeys = array();
|
||||
foreach ($all_keys as $key) {
|
||||
if (preg_match('/^field_updatelocal_(.+)$/', $key, $match)) {
|
||||
// If we have a field to update it from
|
||||
// and it must be updated 'onlogin' we
|
||||
// update it on cron
|
||||
if (!empty($this->config->{'field_map_'.$match[1]})
|
||||
and $this->config->{$match[0]} === 'onlogin') {
|
||||
array_push($updatekeys, $match[1]); // the actual key name
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($this->config->suspended_attribute && $this->config->sync_suspended) {
|
||||
$updatekeys[] = 'suspended';
|
||||
}
|
||||
unset($all_keys); unset($key);
|
||||
$updatekeys = $this->get_profile_keys();
|
||||
|
||||
} else {
|
||||
print_string('noupdatestobedone', 'auth_ldap');
|
||||
@@ -928,14 +912,18 @@ class auth_plugin_ldap extends auth_plugin_base {
|
||||
|
||||
$id = user_create_user($user, false);
|
||||
echo "\t"; print_string('auth_dbinsertuser', 'auth_db', array('name'=>$user->username, 'id'=>$id)); echo "\n";
|
||||
$user = $DB->get_record('user', array('id' => $id));
|
||||
$euser = $DB->get_record('user', array('id' => $id));
|
||||
|
||||
if (!empty($this->config->forcechangepassword)) {
|
||||
set_user_preference('auth_forcepasswordchange', 1, $id);
|
||||
}
|
||||
|
||||
// Save custom profile fields.
|
||||
$updatekeys = $this->get_profile_keys(true);
|
||||
$this->update_user_record($user->username, $updatekeys, false);
|
||||
|
||||
// Add roles if needed.
|
||||
$this->sync_roles($user);
|
||||
$this->sync_roles($euser);
|
||||
|
||||
}
|
||||
$transaction->allow_commit();
|
||||
@@ -967,6 +955,8 @@ class auth_plugin_ldap extends auth_plugin_base {
|
||||
function update_user_record($username, $updatekeys = false, $triggerevent = false) {
|
||||
global $CFG, $DB;
|
||||
|
||||
require_once($CFG->dirroot.'/user/profile/lib.php');
|
||||
|
||||
// Just in case check text case
|
||||
$username = trim(core_text::strtolower($username));
|
||||
|
||||
@@ -981,6 +971,8 @@ class auth_plugin_ldap extends auth_plugin_base {
|
||||
// Protect the userid from being overwritten
|
||||
$userid = $user->id;
|
||||
|
||||
$needsupdate = false;
|
||||
|
||||
if ($newinfo = $this->get_userinfo($username)) {
|
||||
$newinfo = truncate_userinfo($newinfo);
|
||||
|
||||
@@ -993,6 +985,9 @@ class auth_plugin_ldap extends auth_plugin_base {
|
||||
$newuser->id = $userid;
|
||||
// The cast to int is a workaround for MDL-53959.
|
||||
$newuser->suspended = (int)$this->is_user_suspended((object) $newinfo);
|
||||
// Get all custom fields.
|
||||
$profilefields = (array) profile_user_record($user->id, false);
|
||||
$newprofilefields = [];
|
||||
|
||||
foreach ($updatekeys as $key) {
|
||||
if (isset($newinfo[$key])) {
|
||||
@@ -1002,18 +997,50 @@ class auth_plugin_ldap extends auth_plugin_base {
|
||||
}
|
||||
|
||||
if (!empty($this->config->{'field_updatelocal_' . $key})) {
|
||||
// Only update if it's changed.
|
||||
if ($user->{$key} != $value) {
|
||||
if (preg_match('/^profile_field_(.*)$/', $key, $match)) {
|
||||
// Custom field.
|
||||
$field = $match[1];
|
||||
$currentvalue = isset($profilefields[$field]) ? $profilefields[$field] : null;
|
||||
$newprofilefields[$field] = $value;
|
||||
} else {
|
||||
// Standard field.
|
||||
$currentvalue = isset($user->$key) ? $user->$key : null;
|
||||
$newuser->$key = $value;
|
||||
}
|
||||
}
|
||||
|
||||
// Only update if it's changed.
|
||||
if ($currentvalue !== $value) {
|
||||
$needsupdate = true;
|
||||
}
|
||||
}
|
||||
user_update_user($newuser, false, $triggerevent);
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
|
||||
if ($needsupdate) {
|
||||
user_update_user($newuser, false, $triggerevent);
|
||||
|
||||
// Now, save the profile fields if the user has any.
|
||||
if ($fields = $DB->get_records('user_info_field')) {
|
||||
foreach ($fields as $field) {
|
||||
if (isset($newprofilefields[$field->shortname])) {
|
||||
$conditions = array('fieldid' => $field->id, 'userid' => $newuser->id);
|
||||
$id = $DB->get_field('user_info_data', 'id', $conditions);
|
||||
$data = $newprofilefields[$field->shortname];
|
||||
if ($id) {
|
||||
$DB->set_field('user_info_data', 'data', $data, array('id' => $id));
|
||||
} else {
|
||||
$record = array('fieldid' => $field->id, 'userid' => $newuser->id, 'data' => $data);
|
||||
$DB->insert_record('user_info_data', $record);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $DB->get_record('user', array('id' => $userid, 'deleted' => 0));
|
||||
}
|
||||
}
|
||||
return $DB->get_record('user', array('id'=>$userid, 'deleted'=>0));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1201,6 +1228,14 @@ class auth_plugin_ldap extends auth_plugin_base {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Load old custom fields.
|
||||
$olduserprofilefields = (array) profile_user_record($olduser->id, false);
|
||||
|
||||
$fields = array();
|
||||
foreach (profile_get_custom_fields(false) as $field) {
|
||||
$fields[$field->shortname] = $field;
|
||||
}
|
||||
|
||||
$success = true;
|
||||
$user_info_result = ldap_read($ldapconnection, $user_dn, '(objectClass=*)', $search_attribs);
|
||||
if ($user_info_result) {
|
||||
@@ -1219,19 +1254,24 @@ class auth_plugin_ldap extends auth_plugin_base {
|
||||
$user_entry = $user_entry[0];
|
||||
|
||||
foreach ($attrmap as $key => $ldapkeys) {
|
||||
$profilefield = '';
|
||||
// Only process if the moodle field ($key) has changed and we
|
||||
// are set to update LDAP with it
|
||||
$customprofilefield = 'profile_field_' . $key;
|
||||
if (isset($olduser->$key) and isset($newuser->$key)
|
||||
and ($olduser->$key !== $newuser->$key)) {
|
||||
$profilefield = $key;
|
||||
} else if (isset($olduser->$customprofilefield) && isset($newuser->$customprofilefield)
|
||||
&& $olduser->$customprofilefield !== $newuser->$customprofilefield) {
|
||||
$profilefield = $customprofilefield;
|
||||
if (preg_match('/^profile_field_(.*)$/', $key, $match)) {
|
||||
// Custom field.
|
||||
$fieldname = $match[1];
|
||||
if (isset($fields[$fieldname])) {
|
||||
$class = 'profile_field_' . $fields[$fieldname]->datatype;
|
||||
$formfield = new $class($fields[$fieldname]->id, $olduser->id);
|
||||
$oldvalue = isset($olduserprofilefields[$fieldname]) ? $olduserprofilefields[$fieldname] : null;
|
||||
} else {
|
||||
$oldvalue = null;
|
||||
}
|
||||
$newvalue = $formfield->edit_save_data_preprocess($newuser->{$formfield->inputname}, new stdClass);
|
||||
} else {
|
||||
// Standard field.
|
||||
$oldvalue = isset($olduser->$key) ? $olduser->$key : null;
|
||||
$newvalue = isset($newuser->$key) ? $newuser->$key : null;
|
||||
}
|
||||
|
||||
if (!empty($profilefield) && !empty($this->config->{'field_updateremote_' . $key})) {
|
||||
if ($newvalue !== null and $newvalue !== $oldvalue and !empty($this->config->{'field_updateremote_' . $key})) {
|
||||
// For ldap values that could be in more than one
|
||||
// ldap key, we will do our best to match
|
||||
// where they came from
|
||||
@@ -1244,9 +1284,9 @@ class auth_plugin_ldap extends auth_plugin_base {
|
||||
$ambiguous = false;
|
||||
}
|
||||
|
||||
$nuvalue = core_text::convert($newuser->$profilefield, 'utf-8', $this->config->ldapencoding);
|
||||
$nuvalue = core_text::convert($newvalue, 'utf-8', $this->config->ldapencoding);
|
||||
empty($nuvalue) ? $nuvalue = array() : $nuvalue;
|
||||
$ouvalue = core_text::convert($olduser->$profilefield, 'utf-8', $this->config->ldapencoding);
|
||||
$ouvalue = core_text::convert($oldvalue, 'utf-8', $this->config->ldapencoding);
|
||||
|
||||
foreach ($ldapkeys as $ldapkey) {
|
||||
$ldapkey = $ldapkey;
|
||||
@@ -1684,7 +1724,7 @@ class auth_plugin_ldap extends auth_plugin_base {
|
||||
$sesskey = sesskey();
|
||||
redirect($CFG->wwwroot.'/auth/ldap/ntlmsso_magic.php?sesskey='.$sesskey);
|
||||
} else if ($this->config->ntlmsso_ie_fastpath == AUTH_NTLM_FASTPATH_YESFORM) {
|
||||
redirect($CFG-wwwroot.'/login/index.php?authldap_skipntlmsso=1');
|
||||
redirect($CFG->wwwroot.'/login/index.php?authldap_skipntlmsso=1');
|
||||
}
|
||||
}
|
||||
redirect($CFG->wwwroot.'/auth/ldap/ntlmsso_attempt.php');
|
||||
@@ -2170,4 +2210,30 @@ class auth_plugin_ldap extends auth_plugin_base {
|
||||
echo $OUTPUT->notification(get_string('ldapnotconfigured', 'auth_ldap'), \core\output\notification::NOTIFY_INFO);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of profile fields.
|
||||
*
|
||||
* @param bool $fetchall Fetch all, not just those for update.
|
||||
* @return array
|
||||
*/
|
||||
protected function get_profile_keys($fetchall = false) {
|
||||
$keys = array_keys(get_object_vars($this->config));
|
||||
$updatekeys = [];
|
||||
foreach ($keys as $key) {
|
||||
if (preg_match('/^field_updatelocal_(.+)$/', $key, $match)) {
|
||||
// If we have a field to update it from and it must be updated 'onlogin' we update it on cron.
|
||||
if (!empty($this->config->{'field_map_'.$match[1]})) {
|
||||
if ($fetchall || $this->config->{$match[0]} === 'onlogin') {
|
||||
array_push($updatekeys, $match[1]); // the actual key name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($this->config->suspended_attribute && $this->config->sync_suspended) {
|
||||
$updatekeys[] = 'suspended';
|
||||
}
|
||||
|
||||
return $updatekeys;
|
||||
}
|
||||
} // End of the class
|
||||
|
||||
@@ -66,5 +66,8 @@ function xmldb_auth_ldap_upgrade($oldversion) {
|
||||
}
|
||||
}
|
||||
|
||||
// Automatically generated Moodle v3.4.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -41,12 +41,12 @@ $string['auth_ldapdescription'] = 'This method provides authentication against a
|
||||
entry in its database. This module can read user attributes from LDAP and prefill
|
||||
wanted fields in Moodle. For following logins only the username and
|
||||
password are checked.';
|
||||
$string['auth_ldap_expiration_desc'] = 'Select No to disable expired password checking or LDAP to read passwordexpiration time directly from LDAP';
|
||||
$string['auth_ldap_expiration_key'] = 'Expiration';
|
||||
$string['auth_ldap_expiration_warning_desc'] = 'Number of days before password expiration warning is issued.';
|
||||
$string['auth_ldap_expiration_warning_key'] = 'Expiration warning';
|
||||
$string['auth_ldap_expireattr_desc'] = 'Optional: Overrides the LDAP attribute that stores password expiration time.';
|
||||
$string['auth_ldap_expireattr_key'] = 'Expiration attribute';
|
||||
$string['auth_ldap_expiration_desc'] = 'Select \'{$a->no}\' to disable expired password checking or \'{$a->ldapserver}\' to read the password expiry time directly from the LDAP server.';
|
||||
$string['auth_ldap_expiration_key'] = 'Expiry';
|
||||
$string['auth_ldap_expiration_warning_desc'] = 'Number of days before password expiry warning is issued.';
|
||||
$string['auth_ldap_expiration_warning_key'] = 'Expiry warning';
|
||||
$string['auth_ldap_expireattr_desc'] = 'Optional: Overrides the LDAP attribute that stores password expiry time.';
|
||||
$string['auth_ldap_expireattr_key'] = 'Expiry attribute';
|
||||
$string['auth_ldapextrafields'] = 'These fields are optional. You can choose to pre-fill some Moodle user fields with information from the <b>LDAP fields</b> that you specify here. <p>If you leave these fields blank, then nothing will be transferred from LDAP and Moodle defaults will be used instead.</p><p>In either case, the user will be able to edit all of these fields after they log in.</p>';
|
||||
$string['auth_ldap_graceattr_desc'] = 'Optional: Overrides gracelogin attribute';
|
||||
$string['auth_ldap_gracelogin_key'] = 'Grace login attribute';
|
||||
@@ -75,7 +75,7 @@ $string['auth_ldap_opt_deref'] = 'Determines how aliases are handled during sear
|
||||
$string['auth_ldap_opt_deref_key'] = 'Dereference aliases';
|
||||
$string['auth_ldap_passtype'] = 'Specify the format of new or changed passwords in LDAP server.';
|
||||
$string['auth_ldap_passtype_key'] = 'Password format';
|
||||
$string['auth_ldap_passwdexpire_settings'] = 'LDAP password expiration settings';
|
||||
$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';
|
||||
@@ -91,7 +91,7 @@ $string['auth_ldap_suspended_attribute'] = 'Optional: When provided this attribu
|
||||
$string['auth_ldap_suspended_attribute_key'] = 'Suspended attribute';
|
||||
$string['auth_ldap_user_exists'] = 'LDAP username already exists.';
|
||||
$string['auth_ldap_user_settings'] = 'User lookup settings';
|
||||
$string['auth_ldap_user_type'] = 'Select how users are stored in LDAP. This setting also specifies how login expiration, grace logins and user creation will work.';
|
||||
$string['auth_ldap_user_type'] = 'Select how users are stored in LDAP. This setting also specifies how login expiry, grace logins and user creation will work.';
|
||||
$string['auth_ldap_user_type_key'] = 'User type';
|
||||
$string['auth_ldap_usertypeundefined'] = 'config.user_type not defined or function ldap_expirationtime2unix does not support selected type!';
|
||||
$string['auth_ldap_usertypeundefined2'] = 'config.user_type not defined or function ldap_unixi2expirationtime does not support selected type!';
|
||||
@@ -149,7 +149,7 @@ $string['start_tls_key'] = 'Use TLS';
|
||||
$string['updateremfail'] = 'Error updating LDAP record. Error code: {$a->errno}; Error string: {$a->errstring}<br/>Key ({$a->key}) - old moodle value: \'{$a->ouvalue}\' new value: \'{$a->nuvalue}\'';
|
||||
$string['updateremfailamb'] = 'Failed to update LDAP with ambiguous field {$a->key}; old moodle value: \'{$a->ouvalue}\', new value: \'{$a->nuvalue}\'';
|
||||
$string['updatepasserror'] = 'Error in user_update_password(). Error code: {$a->errno}; Error string: {$a->errstring}';
|
||||
$string['updatepasserrorexpire'] = 'Error in user_update_password() when reading password expiration time. Error code: {$a->errno}; Error string: {$a->errstring}';
|
||||
$string['updatepasserrorexpire'] = 'Error in user_update_password() when reading password expiry time. Error code: {$a->errno}; Error string: {$a->errstring}';
|
||||
$string['updatepasserrorexpiregrace'] = 'Error in user_update_password() when modifying expirationtime and/or gracelogins. Error code: {$a->errno}; Error string: {$a->errstring}';
|
||||
$string['updateusernotfound'] = 'Could not find user while updating externally. Details follow: search base: \'{$a->userdn}\'; search filter: \'(objectClass=*)\'; search attributes: {$a->attribs}';
|
||||
$string['user_activatenotsupportusertype'] = 'auth: ldap user_activate() does not support selected usertype: {$a}';
|
||||
|
||||
+15
-3
@@ -185,12 +185,24 @@ if ($ADMIN->fulltree) {
|
||||
new lang_string('auth_ldap_passwdexpire_settings', 'auth_ldap'), ''));
|
||||
|
||||
// Password Expiration.
|
||||
|
||||
// Create the description lang_string object.
|
||||
$strno = get_string('no');
|
||||
$strldapserver = get_string('pluginname', 'auth_ldap');
|
||||
$langobject = new stdClass();
|
||||
$langobject->no = $strno;
|
||||
$langobject->ldapserver = $strldapserver;
|
||||
$description = new lang_string('auth_ldap_expiration_desc', 'auth_ldap', $langobject);
|
||||
|
||||
// Now create the options.
|
||||
$expiration = array();
|
||||
$expiration['0'] = 'no';
|
||||
$expiration['1'] = 'LDAP';
|
||||
$expiration['0'] = $strno;
|
||||
$expiration['1'] = $strldapserver;
|
||||
|
||||
// Add the setting.
|
||||
$settings->add(new admin_setting_configselect('auth_ldap/expiration',
|
||||
new lang_string('auth_ldap_expiration_key', 'auth_ldap'),
|
||||
new lang_string('auth_ldap_expiration_desc', 'auth_ldap'), 0 , $expiration));
|
||||
$description, 0 , $expiration));
|
||||
|
||||
// Password Expiration warning.
|
||||
$settings->add(new admin_setting_configtext('auth_ldap/expiration_warning',
|
||||
|
||||
@@ -48,5 +48,8 @@ function xmldb_auth_manual_upgrade($oldversion) {
|
||||
// Automatically generated Moodle v3.3.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v3.4.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -47,5 +47,8 @@ function xmldb_auth_mnet_upgrade($oldversion) {
|
||||
// Automatically generated Moodle v3.3.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v3.4.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -45,5 +45,8 @@ function xmldb_auth_none_upgrade($oldversion) {
|
||||
// Automatically generated Moodle v3.3.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v3.4.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -41,5 +41,8 @@ function xmldb_auth_oauth2_upgrade($oldversion) {
|
||||
// Automatically generated Moodle v3.3.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v3.4.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -45,5 +45,8 @@ function xmldb_auth_shibboleth_upgrade($oldversion) {
|
||||
// Automatically generated Moodle v3.3.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v3.4.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ class cc11_resource extends entities11 {
|
||||
$link = 'http://invalidurldetected/';
|
||||
}
|
||||
} else {
|
||||
$link = $rawlink;
|
||||
$link = htmlspecialchars(trim($rawlink), ENT_COMPAT, 'UTF-8', false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,6 +65,7 @@ abstract class base_setting {
|
||||
|
||||
protected $name; // name of the setting
|
||||
protected $value; // value of the setting
|
||||
protected $unlockedvalue; // Value to set after the setting is unlocked.
|
||||
protected $vtype; // type of value (setting_base::IS_BOOLEAN/setting_base::IS_INTEGER...)
|
||||
|
||||
protected $visibility; // visibility of the setting (setting_base::VISIBLE/setting_base::HIDDEN)
|
||||
@@ -118,6 +119,7 @@ abstract class base_setting {
|
||||
$this->value = $value;
|
||||
$this->visibility = $visibility;
|
||||
$this->status = $status;
|
||||
$this->unlockedvalue = $this->value;
|
||||
|
||||
// Generate a default ui
|
||||
$this->uisetting = new base_setting_ui($this);
|
||||
@@ -225,6 +227,11 @@ abstract class base_setting {
|
||||
$this->status = $status;
|
||||
if ($status !== $oldstatus) { // Status has changed, let's inform dependencies
|
||||
$this->inform_dependencies(self::CHANGED_STATUS, $oldstatus);
|
||||
|
||||
if ($status == base_setting::NOT_LOCKED) {
|
||||
// When setting gets unlocked set it to the original value.
|
||||
$this->set_value($this->unlockedvalue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -153,7 +153,7 @@ abstract class setting_dependency {
|
||||
*/
|
||||
abstract public function get_moodleform_properties();
|
||||
/**
|
||||
* Returns true if the dependent setting is locked.
|
||||
* Returns true if the dependent setting is locked by this setting_dependency.
|
||||
* @return bool
|
||||
*/
|
||||
abstract public function is_locked();
|
||||
@@ -185,7 +185,7 @@ class setting_dependency_disabledif_equals extends setting_dependency {
|
||||
$this->value = ($value)?(string)$value:0;
|
||||
}
|
||||
/**
|
||||
* Returns true if the dependent setting is locked.
|
||||
* Returns true if the dependent setting is locked by this setting_dependency.
|
||||
* @return bool
|
||||
*/
|
||||
public function is_locked() {
|
||||
@@ -193,8 +193,8 @@ class setting_dependency_disabledif_equals extends setting_dependency {
|
||||
if ($this->setting->get_status() !== base_setting::NOT_LOCKED || $this->setting->get_value() == $this->value) {
|
||||
return true;
|
||||
}
|
||||
// Else return based upon the dependent settings status
|
||||
return ($this->dependentsetting->get_status() !== base_setting::NOT_LOCKED);
|
||||
// Else the dependent setting is not locked by this setting_dependency.
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Processes a value change in the primary setting
|
||||
@@ -343,7 +343,7 @@ class setting_dependency_disabledif_equals2 extends setting_dependency {
|
||||
$this->value = $value;
|
||||
}
|
||||
/**
|
||||
* Returns true if the dependent setting is locked.
|
||||
* Returns true if the dependent setting is locked by this setting_dependency.
|
||||
* @return bool
|
||||
*/
|
||||
public function is_locked() {
|
||||
@@ -351,8 +351,8 @@ class setting_dependency_disabledif_equals2 extends setting_dependency {
|
||||
if ($this->setting->get_status() !== base_setting::NOT_LOCKED || in_array($this->setting->get_value(), $this->value)) {
|
||||
return true;
|
||||
}
|
||||
// Else return based upon the dependent settings status
|
||||
return ($this->dependentsetting->get_status() !== base_setting::NOT_LOCKED);
|
||||
// Else the dependent setting is not locked by this setting_dependency.
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Processes a value change in the primary setting
|
||||
@@ -537,7 +537,7 @@ class setting_dependency_disabledif_not_empty extends setting_dependency_disable
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the dependent setting is locked.
|
||||
* Returns true if the dependent setting is locked by this setting_dependency.
|
||||
* @return bool
|
||||
*/
|
||||
public function is_locked() {
|
||||
@@ -545,8 +545,8 @@ class setting_dependency_disabledif_not_empty extends setting_dependency_disable
|
||||
if ($this->setting->get_status() !== base_setting::NOT_LOCKED || !empty($value)) {
|
||||
return true;
|
||||
}
|
||||
// Else return based upon the dependent settings status
|
||||
return ($this->dependentsetting->get_status() !== base_setting::NOT_LOCKED);
|
||||
// Else the dependent setting is not locked by this setting_dependency.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -601,7 +601,7 @@ class setting_dependency_disabledif_empty extends setting_dependency_disabledif_
|
||||
return ($prevalue != $this->dependentsetting->get_value());
|
||||
}
|
||||
/**
|
||||
* Returns true if the dependent setting is locked.
|
||||
* Returns true if the dependent setting is locked by this setting_dependency.
|
||||
* @return bool
|
||||
*/
|
||||
public function is_locked() {
|
||||
@@ -609,7 +609,7 @@ class setting_dependency_disabledif_empty extends setting_dependency_disabledif_
|
||||
if ($this->setting->get_status() !== base_setting::NOT_LOCKED || empty($value)) {
|
||||
return true;
|
||||
}
|
||||
// Else return based upon the dependent settings status
|
||||
return ($this->dependentsetting->get_status() !== base_setting::NOT_LOCKED);
|
||||
// Else the dependent setting is not locked by this setting_dependency.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,6 +122,8 @@ class backup_confirmation_form extends backup_moodleform {
|
||||
if (!array_key_exists('setting_root_filename', $errors)) {
|
||||
if (trim($data['setting_root_filename']) == '') {
|
||||
$errors['setting_root_filename'] = get_string('errorfilenamerequired', 'backup');
|
||||
} else if (strlen(trim($data['setting_root_filename'])) > 255) {
|
||||
$errors['setting_root_filename'] = get_string('errorfilenametoolong', 'backup');
|
||||
} else if (!preg_match('#\.mbz$#i', $data['setting_root_filename'])) {
|
||||
$errors['setting_root_filename'] = get_string('errorfilenamemustbezip', 'backup');
|
||||
}
|
||||
|
||||
@@ -307,10 +307,12 @@ abstract class backup_setting_ui extends base_setting_ui {
|
||||
* 2. The setting is locked but only by settings that are of the same level (same page)
|
||||
*
|
||||
* Condition 2 is really why we have this function
|
||||
*
|
||||
* @param int $level Optional, if provided only depedency_settings below or equal to this level are considered,
|
||||
* when checking if the ui_setting is changeable. Although dependencies might cause a lock on this setting,
|
||||
* they could be changeable in the same view.
|
||||
* @return bool
|
||||
*/
|
||||
public function is_changeable() {
|
||||
public function is_changeable($level = null) {
|
||||
if ($this->setting->get_status() === backup_setting::NOT_LOCKED) {
|
||||
// Its not locked so its chanegable.
|
||||
return true;
|
||||
@@ -319,6 +321,9 @@ abstract class backup_setting_ui extends base_setting_ui {
|
||||
return false;
|
||||
} else if ($this->setting->has_dependencies_on_settings()) {
|
||||
foreach ($this->setting->get_settings_depended_on() as $dependency) {
|
||||
if ($level && $dependency->get_setting()->get_level() >= $level) {
|
||||
continue;
|
||||
}
|
||||
if ($dependency->is_locked() && $dependency->get_setting()->get_level() !== $this->setting->get_level()) {
|
||||
// Its not changeable because one or more dependancies arn't changeable.
|
||||
return false;
|
||||
@@ -355,7 +360,8 @@ class backup_setting_ui_text extends backup_setting_ui {
|
||||
*/
|
||||
public function get_element_properties(base_task $task = null, renderer_base $output = null) {
|
||||
$icon = $this->get_icon();
|
||||
$label = $this->get_label($task);
|
||||
$context = context_course::instance($task->get_courseid());
|
||||
$label = format_string($this->get_label($task), true, array('context' => $context));
|
||||
if (!empty($icon)) {
|
||||
$label .= $output->render($icon);
|
||||
}
|
||||
@@ -418,7 +424,8 @@ class backup_setting_ui_checkbox extends backup_setting_ui {
|
||||
public function get_element_properties(base_task $task = null, renderer_base $output = null) {
|
||||
// Name, label, text, attributes.
|
||||
$icon = $this->get_icon();
|
||||
$label = $this->get_label($task);
|
||||
$context = context_course::instance($task->get_courseid());
|
||||
$label = format_string($this->get_label($task), true, array('context' => $context));
|
||||
if (!empty($icon)) {
|
||||
$label .= $output->render($icon);
|
||||
}
|
||||
@@ -456,13 +463,16 @@ class backup_setting_ui_checkbox extends backup_setting_ui {
|
||||
|
||||
/**
|
||||
* Returns true if the setting is changeable
|
||||
* @param int $level Optional, if provided only depedency_settings below or equal to this level are considered,
|
||||
* when checking if the ui_setting is changeable. Although dependencies might cause a lock on this setting,
|
||||
* they could be changeable in the same view.
|
||||
* @return bool
|
||||
*/
|
||||
public function is_changeable() {
|
||||
public function is_changeable($level = null) {
|
||||
if ($this->changeable === false) {
|
||||
return false;
|
||||
} else {
|
||||
return parent::is_changeable();
|
||||
return parent::is_changeable($level);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -525,7 +535,8 @@ class backup_setting_ui_radio extends backup_setting_ui {
|
||||
*/
|
||||
public function get_element_properties(base_task $task = null, renderer_base $output = null) {
|
||||
$icon = $this->get_icon();
|
||||
$label = $this->get_label($task);
|
||||
$context = context_course::instance($task->get_courseid());
|
||||
$label = format_string($this->get_label($task), true, array('context' => $context));
|
||||
if (!empty($icon)) {
|
||||
$label .= $output->render($icon);
|
||||
}
|
||||
@@ -602,7 +613,8 @@ class backup_setting_ui_select extends backup_setting_ui {
|
||||
*/
|
||||
public function get_element_properties(base_task $task = null, renderer_base $output = null) {
|
||||
$icon = $this->get_icon();
|
||||
$label = $this->get_label($task);
|
||||
$context = context_course::instance($task->get_courseid());
|
||||
$label = format_string($this->get_label($task), true, array('context' => $context));
|
||||
if (!empty($icon)) {
|
||||
$label .= $output->render($icon);
|
||||
}
|
||||
@@ -635,13 +647,16 @@ class backup_setting_ui_select extends backup_setting_ui {
|
||||
/**
|
||||
* Returns true if the setting is changeable, false otherwise
|
||||
*
|
||||
* @param int $level Optional, if provided only depedency_settings below or equal to this level are considered,
|
||||
* when checking if the ui_setting is changeable. Although dependencies might cause a lock on this setting,
|
||||
* they could be changeable in the same view.
|
||||
* @return bool
|
||||
*/
|
||||
public function is_changeable() {
|
||||
public function is_changeable($level = null) {
|
||||
if (count($this->values) == 1) {
|
||||
return false;
|
||||
} else {
|
||||
return parent::is_changeable();
|
||||
return parent::is_changeable($level);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -183,11 +183,22 @@ abstract class base_moodleform extends moodleform {
|
||||
public function add_settings(array $settingstasks) {
|
||||
global $OUTPUT;
|
||||
|
||||
// Determine highest setting level, which is displayed in this stage. This is relevant for considering only
|
||||
// locks of dependency settings for parent settings, which are not displayed in this stage.
|
||||
$highestlevel = backup_setting::ACTIVITY_LEVEL;
|
||||
foreach ($settingstasks as $st) {
|
||||
list($setting, $task) = $st;
|
||||
if ($setting->get_level() < $highestlevel) {
|
||||
$highestlevel = $setting->get_level();
|
||||
}
|
||||
}
|
||||
|
||||
$defaults = array();
|
||||
foreach ($settingstasks as $st) {
|
||||
list($setting, $task) = $st;
|
||||
// If the setting cant be changed or isn't visible then add it as a fixed setting.
|
||||
if (!$setting->get_ui()->is_changeable() || $setting->get_visibility() != backup_setting::VISIBLE) {
|
||||
if (!$setting->get_ui()->is_changeable($highestlevel) ||
|
||||
$setting->get_visibility() != backup_setting::VISIBLE) {
|
||||
$this->add_fixed_setting($setting, $task);
|
||||
continue;
|
||||
}
|
||||
@@ -302,7 +313,8 @@ abstract class base_moodleform extends moodleform {
|
||||
$icon = '';
|
||||
break;
|
||||
}
|
||||
$label = $settingui->get_label($task);
|
||||
$context = context_course::instance($task->get_courseid());
|
||||
$label = format_string($settingui->get_label($task), true, array('context' => $context));
|
||||
$labelicon = $settingui->get_icon();
|
||||
if (!empty($labelicon)) {
|
||||
$label .= ' '.$OUTPUT->render($labelicon);
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
@core @core_backup
|
||||
Feature: Restore Moodle 2 course backups with different user data settings
|
||||
In order to decide upon including user data during backup and restore of courses
|
||||
As a teacher and an admin
|
||||
I need to be able to set and override backup and restore settings
|
||||
|
||||
Background:
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| student1 | Student | 1 | student1@example.com |
|
||||
| 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 |
|
||||
| student1 | C1 | student |
|
||||
And the following "activities" exist:
|
||||
| activity | name | intro | course | idnumber |
|
||||
| data | Test database name | n | C1 | data1 |
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I add a "Text input" field to "Test database name" database and I fill the form with:
|
||||
| Field name | Test field name |
|
||||
| Field description | Test field description |
|
||||
And I follow "Templates"
|
||||
And I wait until the page is ready
|
||||
And I log out
|
||||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I add an entry to "Test database name" database with:
|
||||
| Test field name | Student entry |
|
||||
And I press "Save and view"
|
||||
And I log out
|
||||
And I log in as "admin"
|
||||
And I backup "Course 1" course using this options:
|
||||
| Initial | Include enrolled users | 1 |
|
||||
| Confirmation | Filename | test_backup.mbz |
|
||||
|
||||
@javascript
|
||||
Scenario: Restore a backup with user data
|
||||
# "User data" marks the user data field for the section
|
||||
# "-" marks the user data field for the data activity
|
||||
When I restore "test_backup.mbz" backup into a new course using this options:
|
||||
| Settings | Include enrolled users | 1 |
|
||||
| Schema | User data | 1 |
|
||||
| Schema | - | 1 |
|
||||
Then I should see "Test database name"
|
||||
When I follow "Test database name"
|
||||
Then I should see "Student entry"
|
||||
|
||||
@javascript
|
||||
Scenario: Restore a backup without user data for data activity
|
||||
# "User data" marks the user data field for the section
|
||||
# "-" marks the user data field for the data activity
|
||||
When I restore "test_backup.mbz" backup into a new course using this options:
|
||||
| Settings | Include enrolled users | 1 |
|
||||
| Schema | User data | 1 |
|
||||
| Schema | - | 0 |
|
||||
Then I should see "Test database name"
|
||||
When I follow "Test database name"
|
||||
Then I should not see "Student entry"
|
||||
|
||||
@javascript
|
||||
Scenario: Restore a backup without user data for section and data activity
|
||||
# "User data" marks the user data field for the section
|
||||
# "-" marks the user data field for the data activity
|
||||
When I restore "test_backup.mbz" backup into a new course using this options:
|
||||
| Settings | Include enrolled users | 1 |
|
||||
| Schema | User data | 0 |
|
||||
| Schema | - | 0 |
|
||||
Then I should see "Test database name"
|
||||
When I follow "Test database name"
|
||||
Then I should not see "Student entry"
|
||||
|
||||
@javascript
|
||||
Scenario: Restore a backup without user data for section
|
||||
# "User data" marks the user data field for the section
|
||||
# "-" marks the user data field for the data activity
|
||||
When I restore "test_backup.mbz" backup into a new course using this options:
|
||||
| Settings | Include enrolled users | 1 |
|
||||
| Schema | - | 1 |
|
||||
| Schema | User data | 0 |
|
||||
Then I should see "Test database name"
|
||||
When I follow "Test database name"
|
||||
Then I should not see "Student entry"
|
||||
|
||||
@javascript
|
||||
Scenario: Restore a backup with user data with local config for including users set to 0
|
||||
And I restore "test_backup.mbz" backup into a new course using this options:
|
||||
| Settings | Include enrolled users | 0 |
|
||||
Then I should see "Test database name"
|
||||
When I follow "Test database name"
|
||||
Then I should not see "Student entry"
|
||||
|
||||
@javascript
|
||||
Scenario: Restore a backup with user data with site config for including users set to 0
|
||||
Given I navigate to "General restore defaults" node in "Site administration > Courses > Backups"
|
||||
And I set the field "s_restore_restore_general_users" to ""
|
||||
And I press "Save changes"
|
||||
And I am on "Course 1" course homepage
|
||||
And I navigate to "Restore" node in "Course administration"
|
||||
# "User data" marks the user data field for the section
|
||||
# "-" marks the user data field for the data activity
|
||||
And I restore "test_backup.mbz" backup into a new course using this options:
|
||||
| Settings | Include enrolled users | 1 |
|
||||
| Schema | User data | 1 |
|
||||
| Schema | - | 1 |
|
||||
Then I should see "Test database name"
|
||||
When I follow "Test database name"
|
||||
Then I should see "Student entry"
|
||||
|
||||
@javascript
|
||||
Scenario: Restore a backup with user data with local and site config config for including users set to 0
|
||||
Given I navigate to "General restore defaults" node in "Site administration > Courses > Backups"
|
||||
And I set the field "s_restore_restore_general_users" to ""
|
||||
And I press "Save changes"
|
||||
And I am on "Course 1" course homepage
|
||||
And I navigate to "Restore" node in "Course administration"
|
||||
When I restore "test_backup.mbz" backup into a new course using this options:
|
||||
| Settings | Include enrolled users | 0 |
|
||||
Then I should see "Test database name"
|
||||
When I follow "Test database name"
|
||||
Then I should not see "Student entry"
|
||||
+12
-8
@@ -27,18 +27,22 @@ function check_site_access() {
|
||||
var callback = {
|
||||
method: "GET",
|
||||
on: {
|
||||
success: function(id, o, args) {
|
||||
var data = Y.JSON.parse(o.responseText);
|
||||
if (data.code == 'http-unreachable') {
|
||||
add.setHTML(data.response);
|
||||
add.removeClass('hide');
|
||||
}
|
||||
},
|
||||
failure: function(o) { }
|
||||
success: function(id, o) {
|
||||
var data = Y.JSON.parse(o.responseText);
|
||||
if (data.code == 'http-unreachable') {
|
||||
add.setHTML(data.response);
|
||||
add.removeClass('hide');
|
||||
}
|
||||
M.util.js_complete('badge/backpack::check_site_access');
|
||||
},
|
||||
failure: function() {
|
||||
M.util.js_complete('badge/backpack::check_site_access');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Y.use('io-base', function(Y) {
|
||||
M.util.js_pending('badge/backpack::check_site_access');
|
||||
Y.io('ajax.php', callback);
|
||||
});
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ $badge = new issued_badge($id);
|
||||
if (!empty($badge->recipient->id)) {
|
||||
if ($bake && ($badge->recipient->id == $USER->id)) {
|
||||
$name = str_replace(' ', '_', $badge->badgeclass['name']) . '.png';
|
||||
$name = clean_param($name, PARAM_FILE);
|
||||
$filehash = badges_bake($id, $badge->badgeid, $USER->id, true);
|
||||
$fs = get_file_storage();
|
||||
$file = $fs->get_file_by_hash($filehash);
|
||||
|
||||
@@ -159,7 +159,7 @@ class core_badges_external extends external_api {
|
||||
new external_single_structure(
|
||||
array(
|
||||
'id' => new external_value(PARAM_INT, 'Badge id.', VALUE_OPTIONAL),
|
||||
'name' => new external_value(PARAM_FILE, 'Badge name.'),
|
||||
'name' => new external_value(PARAM_TEXT, 'Badge name.'),
|
||||
'description' => new external_value(PARAM_NOTAGS, 'Badge description.'),
|
||||
'badgeurl' => new external_value(PARAM_URL, 'Badge URL.'),
|
||||
'timecreated' => new external_value(PARAM_INT, 'Time created.', VALUE_OPTIONAL),
|
||||
|
||||
@@ -48,8 +48,8 @@ class edit_details_form extends moodleform {
|
||||
|
||||
$mform->addElement('header', 'badgedetails', get_string('badgedetails', 'badges'));
|
||||
$mform->addElement('text', 'name', get_string('name'), array('size' => '70'));
|
||||
// Using PARAM_FILE to avoid problems later when downloading badge files.
|
||||
$mform->setType('name', PARAM_FILE);
|
||||
// When downloading badge, it will be necessary to clean the name as PARAM_FILE.
|
||||
$mform->setType('name', PARAM_TEXT);
|
||||
$mform->addRule('name', null, 'required');
|
||||
$mform->addRule('name', get_string('maximumchars', '', 255), 'maxlength', 255, 'client');
|
||||
|
||||
|
||||
@@ -72,6 +72,7 @@ if ($hide) {
|
||||
require_sesskey();
|
||||
$badge = new badge($download);
|
||||
$name = str_replace(' ', '_', $badge->name) . '.png';
|
||||
$name = clean_param($name, PARAM_FILE);
|
||||
$filehash = badges_bake($hash, $download, $USER->id, true);
|
||||
$fs = get_file_storage();
|
||||
$file = $fs->get_file_by_hash($filehash);
|
||||
|
||||
@@ -48,7 +48,7 @@ class core_badges_badgeslib_testcase extends advanced_testcase {
|
||||
|
||||
$fordb = new stdClass();
|
||||
$fordb->id = null;
|
||||
$fordb->name = "Test badge";
|
||||
$fordb->name = "Test badge with 'apostrophe' and other friends (<>&@#)";
|
||||
$fordb->description = "Testing badges";
|
||||
$fordb->timecreated = time();
|
||||
$fordb->timemodified = time();
|
||||
|
||||
@@ -31,14 +31,14 @@ Feature: Add badges to the system
|
||||
Scenario: Add a badge
|
||||
Given I navigate to "Add a new badge" node in "Site administration > Badges"
|
||||
And I set the following fields to these values:
|
||||
| Name | Test Badge |
|
||||
| Name | Test badge with 'apostrophe' and other friends (<>&@#) |
|
||||
| Description | Test badge description |
|
||||
| issuername | Test Badge Site |
|
||||
| issuercontact | testuser@example.com |
|
||||
And I upload "badges/tests/behat/badge.png" file to "Image" filemanager
|
||||
When I press "Create badge"
|
||||
Then I should see "Edit details"
|
||||
And I should see "Test Badge"
|
||||
And I should see "Test badge with 'apostrophe' and other friends (&@#)"
|
||||
And I should not see "Create badge"
|
||||
And I follow "Manage badges"
|
||||
And I should see "Number of badges available: 1"
|
||||
|
||||
@@ -54,5 +54,8 @@ function xmldb_block_badges_upgrade($oldversion, $block) {
|
||||
// Automatically generated Moodle v3.3.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v3.4.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -54,5 +54,8 @@ function xmldb_block_calendar_month_upgrade($oldversion, $block) {
|
||||
// Automatically generated Moodle v3.3.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v3.4.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -54,5 +54,8 @@ function xmldb_block_calendar_upcoming_upgrade($oldversion, $block) {
|
||||
// Automatically generated Moodle v3.3.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v3.4.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -55,5 +55,8 @@ function xmldb_block_community_upgrade($oldversion) {
|
||||
// Automatically generated Moodle v3.3.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v3.4.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -57,5 +57,8 @@ function xmldb_block_completionstatus_upgrade($oldversion, $block) {
|
||||
// Automatically generated Moodle v3.3.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v3.4.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -57,5 +57,8 @@ function xmldb_block_course_summary_upgrade($oldversion, $block) {
|
||||
// Automatically generated Moodle v3.3.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v3.4.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -74,12 +74,13 @@ class block_globalsearch extends block_base {
|
||||
// Input.
|
||||
$this->content->text .= html_writer::tag('label', get_string('search', 'search'),
|
||||
array('for' => 'searchform_search', 'class' => 'accesshide'));
|
||||
$inputoptions = array('id' => 'searchform_search', 'name' => 'q', 'type' => 'text', 'size' => '15');
|
||||
$inputoptions = array('id' => 'searchform_search', 'name' => 'q', 'class' => 'form-control',
|
||||
'type' => 'text', 'size' => '15');
|
||||
$this->content->text .= html_writer::empty_tag('input', $inputoptions);
|
||||
|
||||
// Search button.
|
||||
$this->content->text .= html_writer::tag('button', get_string('search', 'search'),
|
||||
array('id' => 'searchform_button', 'type' => 'submit', 'title' => 'globalsearch'));
|
||||
array('id' => 'searchform_button', 'type' => 'submit', 'title' => 'globalsearch', 'class' => 'btn btn-secondary'));
|
||||
$this->content->text .= html_writer::end_tag('fieldset');
|
||||
$this->content->text .= html_writer::end_tag('form');
|
||||
$this->content->text .= html_writer::end_tag('div');
|
||||
|
||||
@@ -42,5 +42,8 @@ function xmldb_block_html_upgrade($oldversion) {
|
||||
// Automatically generated Moodle v3.3.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v3.4.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ use core_competency\url;
|
||||
use renderable;
|
||||
use renderer_base;
|
||||
use templatable;
|
||||
use required_capability_exception;
|
||||
|
||||
/**
|
||||
* Summary renderable class.
|
||||
@@ -68,7 +69,11 @@ class summary implements renderable, templatable {
|
||||
$this->user = $user;
|
||||
|
||||
// Get the plans.
|
||||
$this->plans = api::list_user_plans($this->user->id);
|
||||
try {
|
||||
$this->plans = api::list_user_plans($this->user->id);
|
||||
} catch (required_capability_exception $e) {
|
||||
$this->plans = [];
|
||||
}
|
||||
|
||||
// Get the competencies to review.
|
||||
$this->compstoreview = api::list_user_competencies_to_review(0, 3);
|
||||
|
||||
@@ -61,9 +61,15 @@ class main implements renderable, templatable {
|
||||
* @return stdClass
|
||||
*/
|
||||
public function export_for_template(renderer_base $output) {
|
||||
global $USER;
|
||||
global $CFG, $USER;
|
||||
|
||||
$courses = enrol_get_my_courses('*', 'fullname ASC');
|
||||
if (empty($CFG->navsortmycoursessort)) {
|
||||
$sort = 'visible DESC, sortorder ASC';
|
||||
} else {
|
||||
$sort = 'visible DESC, '.$CFG->navsortmycoursessort.' ASC';
|
||||
}
|
||||
|
||||
$courses = enrol_get_my_courses('*', $sort);
|
||||
$coursesprogress = [];
|
||||
|
||||
foreach ($courses as $course) {
|
||||
|
||||
@@ -64,5 +64,8 @@ function xmldb_block_navigation_upgrade($oldversion, $block) {
|
||||
// Automatically generated Moodle v3.3.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v3.4.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -54,5 +54,8 @@ function xmldb_block_quiz_results_upgrade($oldversion, $block) {
|
||||
// Automatically generated Moodle v3.3.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v3.4.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -56,5 +56,8 @@ function xmldb_block_recent_activity_upgrade($oldversion, $block) {
|
||||
// Automatically generated Moodle v3.3.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v3.4.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -42,5 +42,8 @@ function xmldb_block_rss_client_upgrade($oldversion) {
|
||||
// Automatically generated Moodle v3.3.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v3.4.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -58,5 +58,8 @@ function xmldb_block_section_links_upgrade($oldversion, $block) {
|
||||
// Automatically generated Moodle v3.3.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v3.4.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -57,5 +57,8 @@ function xmldb_block_selfcompletion_upgrade($oldversion, $block) {
|
||||
// Automatically generated Moodle v3.3.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v3.4.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -64,5 +64,8 @@ function xmldb_block_settings_upgrade($oldversion, $block) {
|
||||
// Automatically generated Moodle v3.3.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v3.4.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ class block_tags extends block_base {
|
||||
if (empty($this->config->title)) {
|
||||
$this->title = get_string('pluginname', 'block_tags');
|
||||
} else {
|
||||
$this->title = $this->config->title;
|
||||
$this->title = format_string($this->config->title, true, ['context' => $this->context]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Vendored
+1
-1
@@ -1 +1 @@
|
||||
define(["jquery","core/ajax","core/str","core/templates","core/notification","core/custom_interaction_events","core/modal_events","core/modal_factory","core_calendar/modal_event_form","core_calendar/summary_modal","core_calendar/repository","core_calendar/events","core_calendar/view_manager","core_calendar/crud","core_calendar/selectors"],function(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o){var p={ROOT:"[data-region='calendar']",DAY:"[data-region='day']",NEW_EVENT_BUTTON:"[data-action='new-event-button']",DAY_CONTENT:"[data-region='day-content']",LOADING_ICON:".loading-icon",VIEW_DAY_LINK:"[data-action='view-day-link']",CALENDAR_MONTH_WRAPPER:".calendarwrapper",TODAY:".today"},q=function(b,c,f,g){var h=null,i=g.attr("data-day-timestamp");f&&(h=f.attr("data-day-timestamp")),f&&h==i||d.render("core/loading",{}).then(function(a,b){g.find(p.DAY_CONTENT).addClass("hidden"),d.appendNodeContents(g,a,b),f&&(f.find(p.DAY_CONTENT).addClass("hidden"),d.appendNodeContents(f,a,b))}).then(function(){return k.updateEventStartDay(c,i)}).then(function(){a("body").trigger(l.eventMoved,[c,f,g])}).always(function(){var a=g.find(p.LOADING_ICON);if(g.find(p.DAY_CONTENT).removeClass("hidden"),d.replaceNode(a,"",""),f){var b=f.find(p.LOADING_ICON);f.find(p.DAY_CONTENT).removeClass("hidden"),d.replaceNode(b,"","")}}).fail(e.exception)},r=function(b,c){var d=a("body");d.on(l.created,function(){m.reloadCurrentMonth(b)}),d.on(l.deleted,function(){m.reloadCurrentMonth(b)}),d.on(l.updated,function(){m.reloadCurrentMonth(b)}),d.on(l.editActionEvent,function(a,b){window.location.assign(b)}),d.on(l.moveEvent,q),d.on(l.eventMoved,function(){m.reloadCurrentMonth(b)}),n.registerEditListeners(b,c)},s=function(b){b.on("change",o.elements.courseSelector,function(){var c=a(this),d=c.val();m.reloadCurrentMonth(b,d,null).then(function(){return b.find(o.elements.courseSelector).val(d)}).fail(e.exception)});var c=n.registerEventFormModal(b);r(b,c),b.on("click",p.DAY,function(b){var d=a(b.target);if(!d.is(p.VIEW_DAY_LINK)){var f=a(this).attr("data-new-event-timestamp");c.then(function(a){var b=d.closest(o.wrapper);a.setCourseId(b.data("courseid"));var c=b.data("categoryid");"undefined"!=typeof c&&a.setCategoryId(c),a.setContextId(b.data("contextId")),a.setStartTime(f),a.show()}).fail(e.exception),b.preventDefault()}})};return{init:function(b){b=a(b),m.init(b),s(b)}}});
|
||||
define(["jquery","core/ajax","core/str","core/templates","core/notification","core/custom_interaction_events","core/modal_events","core/modal_factory","core_calendar/modal_event_form","core_calendar/summary_modal","core_calendar/repository","core_calendar/events","core_calendar/view_manager","core_calendar/crud","core_calendar/selectors"],function(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o){var p={ROOT:"[data-region='calendar']",DAY:"[data-region='day']",NEW_EVENT_BUTTON:"[data-action='new-event-button']",DAY_CONTENT:"[data-region='day-content']",LOADING_ICON:".loading-icon",VIEW_DAY_LINK:"[data-action='view-day-link']",CALENDAR_MONTH_WRAPPER:".calendarwrapper",TODAY:".today"},q=function(b,c,f,g){var h=null,i=g.attr("data-day-timestamp");f&&(h=f.attr("data-day-timestamp")),f&&h==i||d.render("core/loading",{}).then(function(a,b){g.find(p.DAY_CONTENT).addClass("hidden"),d.appendNodeContents(g,a,b),f&&(f.find(p.DAY_CONTENT).addClass("hidden"),d.appendNodeContents(f,a,b))}).then(function(){return k.updateEventStartDay(c,i)}).then(function(){a("body").trigger(l.eventMoved,[c,f,g])}).always(function(){var a=g.find(p.LOADING_ICON);if(g.find(p.DAY_CONTENT).removeClass("hidden"),d.replaceNode(a,"",""),f){var b=f.find(p.LOADING_ICON);f.find(p.DAY_CONTENT).removeClass("hidden"),d.replaceNode(b,"","")}}).fail(e.exception)},r=function(b,c){var d=a("body");d.on(l.created,function(){m.reloadCurrentMonth(b)}),d.on(l.deleted,function(){m.reloadCurrentMonth(b)}),d.on(l.updated,function(){m.reloadCurrentMonth(b)}),d.on(l.editActionEvent,function(a,b){window.location.assign(b)}),d.on(l.moveEvent,q),d.on(l.eventMoved,function(){m.reloadCurrentMonth(b)}),n.registerEditListeners(b,c)},s=function(b){b.on("change",o.elements.courseSelector,function(){var c=a(this),d=c.val();m.reloadCurrentMonth(b,d,null).then(function(){return b.find(o.elements.courseSelector).val(d)}).fail(e.exception)});var c=n.registerEventFormModal(b),d=a(p.CALENDAR_MONTH_WRAPPER).data("context-id");r(b,c),d&&b.on("click",p.DAY,function(b){var d=a(b.target);if(!d.is(p.VIEW_DAY_LINK)){var f=a(this).attr("data-new-event-timestamp");c.then(function(a){var b=d.closest(o.wrapper);a.setCourseId(b.data("courseid"));var c=b.data("categoryid");"undefined"!=typeof c&&a.setCategoryId(c),a.setContextId(b.data("contextId")),a.setStartTime(f),a.show()}).fail(e.exception),b.preventDefault()}})};return{init:function(b){b=a(b),m.init(b),s(b)}}});
|
||||
@@ -183,35 +183,38 @@ define([
|
||||
.fail(Notification.exception);
|
||||
});
|
||||
|
||||
var eventFormPromise = CalendarCrud.registerEventFormModal(root);
|
||||
var eventFormPromise = CalendarCrud.registerEventFormModal(root),
|
||||
contextId = $(SELECTORS.CALENDAR_MONTH_WRAPPER).data('context-id');
|
||||
registerCalendarEventListeners(root, eventFormPromise);
|
||||
|
||||
// Bind click events to calendar days.
|
||||
root.on('click', SELECTORS.DAY, function(e) {
|
||||
if (contextId) {
|
||||
// Bind click events to calendar days.
|
||||
root.on('click', SELECTORS.DAY, function (e) {
|
||||
|
||||
var target = $(e.target);
|
||||
var target = $(e.target);
|
||||
|
||||
if (!target.is(SELECTORS.VIEW_DAY_LINK)) {
|
||||
var startTime = $(this).attr('data-new-event-timestamp');
|
||||
eventFormPromise.then(function(modal) {
|
||||
var wrapper = target.closest(CalendarSelectors.wrapper);
|
||||
modal.setCourseId(wrapper.data('courseid'));
|
||||
if (!target.is(SELECTORS.VIEW_DAY_LINK)) {
|
||||
var startTime = $(this).attr('data-new-event-timestamp');
|
||||
eventFormPromise.then(function (modal) {
|
||||
var wrapper = target.closest(CalendarSelectors.wrapper);
|
||||
modal.setCourseId(wrapper.data('courseid'));
|
||||
|
||||
var categoryId = wrapper.data('categoryid');
|
||||
if (typeof categoryId !== 'undefined') {
|
||||
modal.setCategoryId(categoryId);
|
||||
}
|
||||
var categoryId = wrapper.data('categoryid');
|
||||
if (typeof categoryId !== 'undefined') {
|
||||
modal.setCategoryId(categoryId);
|
||||
}
|
||||
|
||||
modal.setContextId(wrapper.data('contextId'));
|
||||
modal.setStartTime(startTime);
|
||||
modal.show();
|
||||
return;
|
||||
})
|
||||
.fail(Notification.exception);
|
||||
modal.setContextId(wrapper.data('contextId'));
|
||||
modal.setStartTime(startTime);
|
||||
modal.show();
|
||||
return;
|
||||
})
|
||||
.fail(Notification.exception);
|
||||
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
|
||||
+1
-2
@@ -274,13 +274,12 @@ class month_exporter extends exporter {
|
||||
|
||||
// Calculate which day number is the first, and last day of the week.
|
||||
$firstdayofweek = $this->firstdayofweek;
|
||||
$lastdayofweek = ($firstdayofweek + $daysinweek - 1) % $daysinweek;
|
||||
|
||||
// The first week is special as it may have padding at the beginning.
|
||||
$day = reset($alldays);
|
||||
$firstdayno = $day['wday'];
|
||||
|
||||
$prepadding = ($firstdayno + $daysinweek - 1) % $daysinweek;
|
||||
$prepadding = ($firstdayno + $daysinweek - $firstdayofweek) % $daysinweek;
|
||||
$daysinfirstweek = $daysinweek - $prepadding;
|
||||
$days = array_slice($alldays, 0, $daysinfirstweek);
|
||||
$week = new week_exporter($this->calendar, $days, $prepadding, ($daysinweek - count($days) - $prepadding), $this->related);
|
||||
|
||||
@@ -119,6 +119,7 @@ class event_mapper implements event_mapper_interface {
|
||||
'description' => $event->get_description()->get_value(),
|
||||
'format' => $event->get_description()->get_format(),
|
||||
'courseid' => $event->get_course() ? $event->get_course()->get('id') : null,
|
||||
'categoryid' => $event->get_category() ? $event->get_category()->get('id') : null,
|
||||
'groupid' => $event->get_group() ? $event->get_group()->get('id') : null,
|
||||
'userid' => $event->get_user() ? $event->get_user()->get('id') : null,
|
||||
'repeatid' => $event->get_repeats()->get_id(),
|
||||
|
||||
+29
-37
@@ -127,23 +127,19 @@ class core_calendar_external extends external_api {
|
||||
'eventids' => new external_multiple_structure(
|
||||
new external_value(PARAM_INT, 'event ids')
|
||||
, 'List of event ids',
|
||||
VALUE_DEFAULT, array(), NULL_ALLOWED
|
||||
),
|
||||
VALUE_DEFAULT, array()),
|
||||
'courseids' => new external_multiple_structure(
|
||||
new external_value(PARAM_INT, 'course ids')
|
||||
, 'List of course ids for which events will be returned',
|
||||
VALUE_DEFAULT, array(), NULL_ALLOWED
|
||||
),
|
||||
VALUE_DEFAULT, array()),
|
||||
'groupids' => new external_multiple_structure(
|
||||
new external_value(PARAM_INT, 'group ids')
|
||||
, 'List of group ids for which events should be returned',
|
||||
VALUE_DEFAULT, array(), NULL_ALLOWED
|
||||
),
|
||||
VALUE_DEFAULT, array()),
|
||||
'categoryids' => new external_multiple_structure(
|
||||
new external_value(PARAM_INT, 'Category ids'),
|
||||
'List of category ids for which events will be returned',
|
||||
VALUE_DEFAULT, array()
|
||||
),
|
||||
VALUE_DEFAULT, array()),
|
||||
), 'Event details', VALUE_DEFAULT, array()),
|
||||
'options' => new external_single_structure(
|
||||
array(
|
||||
@@ -226,25 +222,36 @@ class core_calendar_external extends external_api {
|
||||
}
|
||||
|
||||
$categories = array();
|
||||
if (empty($params['events']['categoryids']) && !empty($courses)) {
|
||||
list($wheresql, $sqlparams) = $DB->get_in_or_equal($courses);
|
||||
$wheresql = "id $wheresql";
|
||||
$courseswithcategory = $DB->get_records_select('course', $wheresql, $sqlparams);
|
||||
if ($hassystemcap || !empty($courses)) {
|
||||
|
||||
// Grab the list of course categories for the requested course list.
|
||||
$coursecategories = array();
|
||||
foreach ($courseswithcategory as $course) {
|
||||
if (empty($course->visible)) {
|
||||
if (!has_capability('moodle/course:viewhidden', context_course::instance($course->id))) {
|
||||
continue;
|
||||
if (!empty($courses)) {
|
||||
list($wheresql, $sqlparams) = $DB->get_in_or_equal($courses);
|
||||
$wheresql = "id $wheresql";
|
||||
$courseswithcategory = $DB->get_records_select('course', $wheresql, $sqlparams);
|
||||
|
||||
// Grab the list of course categories for the requested course list.
|
||||
foreach ($courseswithcategory as $course) {
|
||||
if (empty($course->visible)) {
|
||||
if (!has_capability('moodle/course:viewhidden', context_course::instance($course->id))) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
$category = \coursecat::get($course->category);
|
||||
// Fetch parent categories.
|
||||
$coursecategories = array_merge($coursecategories, [$category->id], $category->get_parents());
|
||||
}
|
||||
$category = \coursecat::get($course->category);
|
||||
$coursecategories[] = $category;
|
||||
}
|
||||
|
||||
foreach (\coursecat::get_all() as $category) {
|
||||
if (has_capability('moodle/category:manage', $category->get_context(), $USER, false)) {
|
||||
// Skip categories not requested.
|
||||
if (!empty($params['events']['categoryids'])) {
|
||||
if (!in_array($category->id, $params['events']['categoryids'])) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (has_capability('moodle/category:manage', $category->get_context())) {
|
||||
// If a user can manage a category, then they can see all child categories. as well as all parent categories.
|
||||
$categories[] = $category->id;
|
||||
|
||||
@@ -254,29 +261,14 @@ class core_calendar_external extends external_api {
|
||||
}
|
||||
}
|
||||
$categories = array_merge($categories, $category->get_parents());
|
||||
} else if (isset($coursecategories[$category->id])) {
|
||||
} else if (in_array($category->id, $coursecategories)) {
|
||||
|
||||
// The user has access to a course in this category.
|
||||
// Fetch all of the parents too.
|
||||
$categories = array_merge($categories, [$category->id], $category->get_parents());
|
||||
$categories[] = $category->id;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Build the category list.
|
||||
// This includes the current category.
|
||||
foreach ($params['events']['categoryids'] as $categoryid) {
|
||||
$category = \coursecat::get($categoryid);
|
||||
$categories = [$category->id];
|
||||
// All of its descendants.
|
||||
foreach (\coursecat::get_all() as $cat) {
|
||||
if (array_search($categoryid, $cat->get_parents()) !== false) {
|
||||
$categories[] = $cat->id;
|
||||
}
|
||||
}
|
||||
|
||||
// And all of its parents.
|
||||
$categories = array_merge($categories, $category->get_parents());
|
||||
}
|
||||
}
|
||||
|
||||
$funcparam['categories'] = array_unique($categories);
|
||||
|
||||
+11
-4
@@ -1056,7 +1056,7 @@ class calendar_information {
|
||||
}
|
||||
|
||||
$courses = [$course->id => $course];
|
||||
$category = (\coursecat::get($course->category))->get_db_record();
|
||||
$category = (\coursecat::get($course->category, MUST_EXIST, true))->get_db_record();
|
||||
} else if (!empty($categoryid)) {
|
||||
$course = get_site();
|
||||
$courses = calendar_get_default_courses();
|
||||
@@ -1147,7 +1147,7 @@ class calendar_information {
|
||||
// A specific course was requested.
|
||||
// Fetch the category that this course is in, along with all parents.
|
||||
// Do not include child categories of this category, as the user many not have enrolments in those siblings or children.
|
||||
$category = \coursecat::get($course->category);
|
||||
$category = \coursecat::get($course->category, MUST_EXIST, true);
|
||||
$this->categoryid = $category->id;
|
||||
|
||||
$this->categories = $category->get_parents();
|
||||
@@ -1805,6 +1805,13 @@ function calendar_time_representation($time) {
|
||||
$timeformat = get_config(null, 'calendar_site_timeformat');
|
||||
}
|
||||
|
||||
// Allow language customization of selected time format.
|
||||
if ($timeformat === CALENDAR_TF_12) {
|
||||
$timeformat = get_string('strftimetime12', 'langconfig');
|
||||
} else if ($timeformat === CALENDAR_TF_24) {
|
||||
$timeformat = get_string('strftimetime24', 'langconfig');
|
||||
}
|
||||
|
||||
return userdate($time, empty($timeformat) ? $langtimeformat : $timeformat);
|
||||
}
|
||||
|
||||
@@ -2538,7 +2545,7 @@ function calendar_get_allowed_types(&$allowed, $course = null, $groups = null, $
|
||||
|
||||
if (!empty($course)) {
|
||||
if (!is_object($course)) {
|
||||
$course = $DB->get_record('course', array('id' => $course), '*', MUST_EXIST);
|
||||
$course = $DB->get_record('course', array('id' => $course), 'id, groupmode, groupmodeforce', MUST_EXIST);
|
||||
}
|
||||
if ($course->id != SITEID) {
|
||||
$coursecontext = \context_course::instance($course->id);
|
||||
@@ -2602,7 +2609,7 @@ function calendar_get_all_allowed_types() {
|
||||
// This function warms the context cache for the course so the calls
|
||||
// to load the course context in calendar_get_allowed_types don't result
|
||||
// in additional DB queries.
|
||||
$courses = calendar_get_default_courses(null, '*', true);
|
||||
$courses = calendar_get_default_courses(null, 'id, groupmode, groupmodeforce', true);
|
||||
|
||||
// We want to pre-fetch all of the groups for each course in a single
|
||||
// query to avoid calendar_get_allowed_types from hitting the DB for
|
||||
|
||||
@@ -60,11 +60,12 @@
|
||||
<td class="dayblank"> </td>
|
||||
{{/prepadding}}
|
||||
{{#days}}
|
||||
<td class="clickable day text-sm-center text-md-left{{!
|
||||
<td class="day text-sm-center text-md-left{{!
|
||||
}}{{#istoday}} today{{/istoday}}{{!
|
||||
}}{{#isweekend}} weekend{{/isweekend}}{{!
|
||||
}}{{#durationevents.0}} duration{{/durationevents.0}}{{!
|
||||
}}{{#durationevents}} duration_{{.}}{{/durationevents}}{{!
|
||||
}}{{#defaulteventcontext}} clickable{{/defaulteventcontext}}{{!
|
||||
}}"
|
||||
data-day-timestamp="{{timestamp}}"
|
||||
data-drop-zone="month-view-day"
|
||||
|
||||
@@ -533,6 +533,7 @@ class core_calendar_container_testcase extends advanced_testcase {
|
||||
$record->timesort = 0;
|
||||
$record->type = 1;
|
||||
$record->courseid = 0;
|
||||
$record->categoryid = 0;
|
||||
|
||||
foreach ($properties as $name => $value) {
|
||||
$record->$name = $value;
|
||||
|
||||
@@ -465,6 +465,7 @@ class core_calendar_event_factory_testcase extends advanced_testcase {
|
||||
$record->timesort = 0;
|
||||
$record->type = 1;
|
||||
$record->courseid = 0;
|
||||
$record->categoryid = 0;
|
||||
|
||||
foreach ($properties as $name => $value) {
|
||||
$record->$name = $value;
|
||||
|
||||
@@ -147,6 +147,7 @@ class core_calendar_event_mapper_testcase extends advanced_testcase {
|
||||
$record->timesort = 0;
|
||||
$record->type = 1;
|
||||
$record->courseid = 0;
|
||||
$record->categoryid = 0;
|
||||
|
||||
foreach ($properties as $name => $value) {
|
||||
$record->$name = $value;
|
||||
|
||||
@@ -485,31 +485,58 @@ class core_calendar_externallib_testcase extends externallib_advanced_testcase {
|
||||
// Create some category events.
|
||||
$this->setAdminUser();
|
||||
$record = new stdClass();
|
||||
$record->courseid = 0;
|
||||
$record->categoryid = $category->id;
|
||||
$this->create_calendar_event('category a', $USER->id, 'category', 0, time(), $record);
|
||||
$record->timestart = time() - DAYSECS;
|
||||
$catevent1 = $this->create_calendar_event('category a', $USER->id, 'category', 0, time(), $record);
|
||||
|
||||
$record = new stdClass();
|
||||
$record->courseid = 0;
|
||||
$record->categoryid = $category2->id;
|
||||
$this->create_calendar_event('category b', $USER->id, 'category', 0, time(), $record);
|
||||
$record->timestart = time() + DAYSECS;
|
||||
$catevent2 = $this->create_calendar_event('category b', $USER->id, 'category', 0, time(), $record);
|
||||
|
||||
// Now as student, make sure we get the events of the courses I am enrolled.
|
||||
$this->setUser($user2);
|
||||
$paramevents = array('categoryids' => array($category2b->id));
|
||||
$options = array('timeend' => time() + 7 * WEEKSECS);
|
||||
$options = array('timeend' => time() + 7 * WEEKSECS, 'userevents' => false, 'siteevents' => false);
|
||||
$events = core_calendar_external::get_calendar_events($paramevents, $options);
|
||||
$events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);
|
||||
|
||||
// Should be just one, since there's just one category event of the course I am enrolled (course3 - cat2b).
|
||||
$this->assertEquals(1, count($events['events']));
|
||||
$this->assertEquals($catevent2->id, $events['events'][0]['id']);
|
||||
$this->assertEquals(0, count($events['warnings']));
|
||||
|
||||
// Now get category events but by course (there aren't course events in the course).
|
||||
$paramevents = array('courseids' => array($course3->id));
|
||||
$options = array('timeend' => time() + 7 * WEEKSECS, 'userevents' => false, 'siteevents' => false);
|
||||
$events = core_calendar_external::get_calendar_events($paramevents, $options);
|
||||
$events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);
|
||||
$this->assertEquals(1, count($events['events']));
|
||||
$this->assertEquals($catevent2->id, $events['events'][0]['id']);
|
||||
$this->assertEquals(0, count($events['warnings']));
|
||||
|
||||
// Empty events in one where I'm not enrolled and one parent category
|
||||
// (parent of a category where this is a course where the user is enrolled).
|
||||
$paramevents = array('categoryids' => array($category2->id, $category->id));
|
||||
$options = array('timeend' => time() + 7 * WEEKSECS, 'userevents' => false, 'siteevents' => false);
|
||||
$events = core_calendar_external::get_calendar_events($paramevents, $options);
|
||||
$events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);
|
||||
$this->assertEquals(1, count($events['events']));
|
||||
$this->assertEquals($catevent2->id, $events['events'][0]['id']);
|
||||
$this->assertEquals(0, count($events['warnings']));
|
||||
|
||||
// Admin can see all category events.
|
||||
$this->setAdminUser();
|
||||
$paramevents = array('categoryids' => array($category->id, $category2->id, $category2b->id));
|
||||
$options = array('timeend' => time() + 7 * WEEKSECS);
|
||||
$options = array('timeend' => time() + 7 * WEEKSECS, 'userevents' => false, 'siteevents' => false);
|
||||
$events = core_calendar_external::get_calendar_events($paramevents, $options);
|
||||
$events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);
|
||||
$this->assertEquals(2, count($events['events']));
|
||||
$this->assertEquals(0, count($events['warnings']));
|
||||
$this->assertEquals($catevent1->id, $events['events'][0]['id']);
|
||||
$this->assertEquals($catevent2->id, $events['events'][1]['id']);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2266,7 +2293,7 @@ class core_calendar_externallib_testcase extends externallib_advanced_testcase {
|
||||
// Admin can load the course.
|
||||
$data = external_api::clean_returnvalue(
|
||||
core_calendar_external::get_calendar_monthly_view_returns(),
|
||||
core_calendar_external::get_calendar_monthly_view($timestart->format('n'), $timestart->format('Y'),
|
||||
core_calendar_external::get_calendar_monthly_view($timestart->format('Y'), $timestart->format('n'),
|
||||
$course->id, null, false)
|
||||
);
|
||||
$this->assertEquals($data['courseid'], $course->id);
|
||||
@@ -2274,7 +2301,7 @@ class core_calendar_externallib_testcase extends externallib_advanced_testcase {
|
||||
$this->setUser($user1);
|
||||
$data = external_api::clean_returnvalue(
|
||||
core_calendar_external::get_calendar_monthly_view_returns(),
|
||||
core_calendar_external::get_calendar_monthly_view($timestart->format('n'), $timestart->format('Y'),
|
||||
core_calendar_external::get_calendar_monthly_view($timestart->format('Y'), $timestart->format('n'),
|
||||
$course->id, null, false)
|
||||
);
|
||||
$this->assertEquals($data['courseid'], $course->id);
|
||||
@@ -2283,7 +2310,7 @@ class core_calendar_externallib_testcase extends externallib_advanced_testcase {
|
||||
$this->expectException('require_login_exception');
|
||||
$data = external_api::clean_returnvalue(
|
||||
core_calendar_external::get_calendar_monthly_view_returns(),
|
||||
core_calendar_external::get_calendar_monthly_view($timestart->format('n'), $timestart->format('Y'),
|
||||
core_calendar_external::get_calendar_monthly_view($timestart->format('Y'), $timestart->format('n'),
|
||||
$course->id, null, false)
|
||||
);
|
||||
}
|
||||
@@ -2310,7 +2337,7 @@ class core_calendar_externallib_testcase extends externallib_advanced_testcase {
|
||||
// Admin can load the course.
|
||||
$data = external_api::clean_returnvalue(
|
||||
core_calendar_external::get_calendar_day_view_returns(),
|
||||
core_calendar_external::get_calendar_day_view($timestart->format('n'), $timestart->format('Y'),
|
||||
core_calendar_external::get_calendar_day_view($timestart->format('Y'), $timestart->format('n'),
|
||||
$timestart->format('j'), $course->id, null)
|
||||
);
|
||||
$this->assertEquals($data['courseid'], $course->id);
|
||||
@@ -2318,7 +2345,7 @@ class core_calendar_externallib_testcase extends externallib_advanced_testcase {
|
||||
$this->setUser($user1);
|
||||
$data = external_api::clean_returnvalue(
|
||||
core_calendar_external::get_calendar_day_view_returns(),
|
||||
core_calendar_external::get_calendar_day_view($timestart->format('n'), $timestart->format('Y'),
|
||||
core_calendar_external::get_calendar_day_view($timestart->format('Y'), $timestart->format('n'),
|
||||
$timestart->format('j'), $course->id, null)
|
||||
);
|
||||
$this->assertEquals($data['courseid'], $course->id);
|
||||
@@ -2327,7 +2354,7 @@ class core_calendar_externallib_testcase extends externallib_advanced_testcase {
|
||||
$this->expectException('require_login_exception');
|
||||
$data = external_api::clean_returnvalue(
|
||||
core_calendar_external::get_calendar_day_view_returns(),
|
||||
core_calendar_external::get_calendar_day_view($timestart->format('n'), $timestart->format('Y'),
|
||||
core_calendar_external::get_calendar_day_view($timestart->format('Y'), $timestart->format('n'),
|
||||
$timestart->format('j'), $course->id, null)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -56,6 +56,7 @@ function create_event($properties) {
|
||||
$record->timesort = 0;
|
||||
$record->type = CALENDAR_EVENT_TYPE_STANDARD;
|
||||
$record->courseid = 0;
|
||||
$record->categoryid = 0;
|
||||
|
||||
foreach ($properties as $name => $value) {
|
||||
$record->$name = $value;
|
||||
|
||||
@@ -136,6 +136,7 @@ class core_calendar_repeat_event_collection_testcase extends advanced_testcase {
|
||||
$record->timesort = 0;
|
||||
$record->type = 1;
|
||||
$record->courseid = 0;
|
||||
$record->categoryid = 0;
|
||||
|
||||
foreach ($properties as $name => $value) {
|
||||
$record->$name = $value;
|
||||
|
||||
+4
-15
@@ -123,21 +123,10 @@ echo $renderer->start_layout();
|
||||
echo html_writer::start_tag('div', array('class'=>'heightcontainer'));
|
||||
echo $OUTPUT->heading(get_string('calendar', 'calendar'));
|
||||
|
||||
if ($view == 'day' || $view == 'upcoming') {
|
||||
switch($view) {
|
||||
case 'day':
|
||||
list($data, $template) = calendar_get_view($calendar, $view);
|
||||
echo $renderer->render_from_template($template, $data);
|
||||
break;
|
||||
case 'upcoming':
|
||||
list($data, $template) = calendar_get_view($calendar, $view);
|
||||
echo $renderer->render_from_template($template, $data);
|
||||
break;
|
||||
}
|
||||
} else if ($view == 'month') {
|
||||
list($data, $template) = calendar_get_view($calendar, $view);
|
||||
echo $renderer->render_from_template($template, $data);
|
||||
}
|
||||
|
||||
list($data, $template) = calendar_get_view($calendar, $view);
|
||||
echo $renderer->render_from_template($template, $data);
|
||||
|
||||
echo html_writer::end_tag('div');
|
||||
|
||||
list($data, $template) = calendar_get_footer_options($calendar);
|
||||
|
||||
@@ -165,7 +165,7 @@ class api {
|
||||
require_capability('moodle/competency:competencymanage', $competency->get_context());
|
||||
|
||||
// Reset the sortorder, use reorder instead.
|
||||
$competency->set('sortorder', null);
|
||||
$competency->set('sortorder', 0);
|
||||
$competency->create();
|
||||
|
||||
\core\event\competency_created::create_from_competency($competency)->trigger();
|
||||
|
||||
@@ -76,7 +76,7 @@ class competency extends persistent {
|
||||
'default' => FORMAT_HTML
|
||||
),
|
||||
'sortorder' => array(
|
||||
'default' => null,
|
||||
'default' => 0,
|
||||
'type' => PARAM_INT
|
||||
),
|
||||
'parentid' => array(
|
||||
|
||||
@@ -841,10 +841,10 @@ class external extends external_api {
|
||||
$validcolumns = array('id', 'shortname', 'description', 'sortorder', 'idnumber',
|
||||
'parentid', 'competencyframeworkid');
|
||||
foreach ($params['filters'] as $filter) {
|
||||
if (!in_array($filter->column, $validcolumns)) {
|
||||
if (!in_array($filter['column'], $validcolumns)) {
|
||||
throw new invalid_parameter_exception('Filter column was invalid');
|
||||
}
|
||||
$safefilters[$filter->column] = $filter->value;
|
||||
$safefilters[$filter['column']] = $filter['value'];
|
||||
}
|
||||
|
||||
$context = null;
|
||||
|
||||
@@ -53,7 +53,7 @@ class template_competency extends persistent {
|
||||
),
|
||||
'sortorder' => array(
|
||||
'type' => PARAM_INT,
|
||||
'default' => null,
|
||||
'default' => 0,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -282,7 +282,6 @@ class user_competency_course extends persistent {
|
||||
ORDER BY p.timesproficient ASC, c.id DESC';
|
||||
|
||||
$results = $DB->get_records_sql($sql, $params, $skip, $limit);
|
||||
$a = $DB->get_records_sql('SELECT * from {' . self::TABLE . '}');
|
||||
|
||||
$comps = array();
|
||||
foreach ($results as $r) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user