Compare commits
260 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 23360fd95b | |||
| 0ed1c5d259 | |||
| 28f52bc329 | |||
| 8c18772edc | |||
| dd819dbb88 | |||
| 4c48d88c46 | |||
| af16b393ea | |||
| 2dc0dc6293 | |||
| a3aa1600de | |||
| fb629ce56a | |||
| 33f31a12d4 | |||
| 92033f7e9d | |||
| 8e28bc402b | |||
| 1cee1602be | |||
| bea116e2ff | |||
| 106eb4921a | |||
| bc1d916868 | |||
| a053131595 | |||
| f3b9685ad0 | |||
| 93e09909ab | |||
| f373c08314 | |||
| dacac4d10b | |||
| 35d1b3da7a | |||
| a52742dea7 | |||
| ffd642a654 | |||
| dbbbf02dc0 | |||
| e29ea1b2c9 | |||
| 74accbdd85 | |||
| eea5900c13 | |||
| 01005ff69a | |||
| ee3ba0c3f8 | |||
| 5bbc58a7fb | |||
| c6a447f1b7 | |||
| 2584ce25c7 | |||
| 2dd87cb37a | |||
| 53456587f6 | |||
| b9874d0c13 | |||
| bf58adf836 | |||
| afeb42ed9e | |||
| 52cabc8f66 | |||
| 4197baf775 | |||
| ba9f218e17 | |||
| 32dc9a45d6 | |||
| 8c696ccafc | |||
| 0bfbdaef20 | |||
| 55fc1104d5 | |||
| 7032ff37b7 | |||
| 1d0867ae48 | |||
| 4e50a38018 | |||
| a54703d88f | |||
| 4ba0709401 | |||
| f72bc10fe3 | |||
| b15859b879 | |||
| ed248331a4 | |||
| 5b8ca7ac93 | |||
| 0efb93bbe9 | |||
| f3008f556c | |||
| aac5a4f103 | |||
| e5881ad801 | |||
| c244743775 | |||
| deb442a293 | |||
| 93a935049e | |||
| f2fb8f5a7f | |||
| 3a5ae742f1 | |||
| 017d8f1aec | |||
| 95e1ac08fe | |||
| ef43566698 | |||
| d33f7642dd | |||
| a9a72025b6 | |||
| 222189cc75 | |||
| 62c58d22be | |||
| b962ac2439 | |||
| c2f08942d9 | |||
| 9072b59c0e | |||
| f86bb360b5 | |||
| 90e86c7568 | |||
| f730eb2a81 | |||
| 485decb3a2 | |||
| b95a012124 | |||
| f7e3be1bbb | |||
| 5a5efa8bd9 | |||
| 079c73c98d | |||
| 3fb4b3a9ed | |||
| c7d6a0e356 | |||
| 8b57dd0768 | |||
| 97d966df08 | |||
| fe67ec46da | |||
| 285e7e5eb3 | |||
| 53e3825619 | |||
| 90156e427c | |||
| 5074849703 | |||
| c5a8568799 | |||
| ab7056032d | |||
| 0d063c69ac | |||
| ac6ab5b8d2 | |||
| 74fbdebd0d | |||
| e523626603 | |||
| c33e03ae95 | |||
| b3f3c3c395 | |||
| 072c0b4196 | |||
| 638aa54cbb | |||
| 8d9e621f2c | |||
| bb3956eb5c | |||
| a8fc3a33ab | |||
| 2c6f3befeb | |||
| d11850101e | |||
| 531c1ec0be | |||
| 8ae8ed4aca | |||
| 1faba07075 | |||
| 587b99609d | |||
| c9192ffccb | |||
| 4290182491 | |||
| cb1c0ae4dc | |||
| ffc7fda945 | |||
| a9ba142326 | |||
| 59527f3e7a | |||
| 8122557661 | |||
| ae84db35c7 | |||
| ab8b6fae1a | |||
| b3ca553f3a | |||
| 7e31bb6dc2 | |||
| 5e39900691 | |||
| a4f5cdddcf | |||
| 4d26fcd737 | |||
| 11127354db | |||
| f751b97393 | |||
| 9265a5db56 | |||
| f5942f3e6f | |||
| 3ad8f33235 | |||
| abeb033dfb | |||
| 98b955d665 | |||
| 7624f86fb2 | |||
| 7f4835a7da | |||
| ba76815aaf | |||
| 70dcc1e39a | |||
| 25ffa9a67f | |||
| 99864cdf74 | |||
| d356128f05 | |||
| c33c78a33c | |||
| 3ec562a322 | |||
| 07e6a3c6c1 | |||
| 5ec875b281 | |||
| a202546fd3 | |||
| 589b4c0360 | |||
| 5f6cf92f97 | |||
| 43391de3e2 | |||
| fbf621bd29 | |||
| 5a10b55442 | |||
| 554167b43a | |||
| c90e9381d2 | |||
| 8ac3e5ea59 | |||
| 74554368a0 | |||
| 6f4d9a89d5 | |||
| 7fd70c34a0 | |||
| a31c6bc4b9 | |||
| 6160631e28 | |||
| c82ad7c6e0 | |||
| 087ab1e345 | |||
| f7c9dd2158 | |||
| 984bcd770c | |||
| e84d284e65 | |||
| 352b9b00d6 | |||
| 2a7bb7a0f8 | |||
| 269e1f027e | |||
| 48903d67ea | |||
| 3bfdb64f43 | |||
| a42233487e | |||
| 07da0155a7 | |||
| 1a7cf17ed8 | |||
| 818bc4c9a7 | |||
| 8708ea0968 | |||
| cdffe52b28 | |||
| 67970b8675 | |||
| d979b4614d | |||
| 85eacc3a31 | |||
| bfc16e66a5 | |||
| 3a8f07f241 | |||
| e621a47c48 | |||
| 4bb9787760 | |||
| 2469a838f1 | |||
| c28e5eaee2 | |||
| f85f0c80da | |||
| 4643358a5c | |||
| 2774649389 | |||
| 18d41005e3 | |||
| a281621189 | |||
| ab8fa2ff7a | |||
| fb0e1b10fe | |||
| 78f7595fd9 | |||
| 338097adce | |||
| f98e259ddb | |||
| 0e106b8332 | |||
| 25e3a8a14c | |||
| 46280f7478 | |||
| 80bf9ac40a | |||
| e2b4084bfd | |||
| 2a667a0820 | |||
| a4ad655bf1 | |||
| 653e23bcc1 | |||
| 80d970cd0e | |||
| f8962b4270 | |||
| e2f921ea2a | |||
| 3586517ff8 | |||
| 4e8f93abba | |||
| 164d1e290e | |||
| 373bd248b9 | |||
| c6bbd48e23 | |||
| 4db85a5943 | |||
| 726fce53e7 | |||
| 5607f04f15 | |||
| 5d37f70d68 | |||
| 163e56dfbb | |||
| 07f1e2b49c | |||
| 328159027c | |||
| c6e47712f5 | |||
| 4a1d28e6c6 | |||
| cbbfaad531 | |||
| bb78b2fd22 | |||
| 021b544c7a | |||
| 71e94edfd8 | |||
| 37b143aeaf | |||
| d1e6ca40a0 | |||
| d926390fba | |||
| 1dcc39e9a1 | |||
| e48bab0b24 | |||
| bc71da7f50 | |||
| 3739127caf | |||
| 4321953314 | |||
| d69fcc7bc1 | |||
| 723ed522a5 | |||
| 0d011d9ad3 | |||
| 15e5a39266 | |||
| 1a63aaddeb | |||
| ec66fbbeec | |||
| 11580ef62a | |||
| 8afd92382e | |||
| cf4753e354 | |||
| ed8c3327fb | |||
| 3bd5edccf8 | |||
| 01932fa6fa | |||
| db8ff4bc78 | |||
| 2dced48edf | |||
| 835bc90d7c | |||
| 4d160525d3 | |||
| b3d4341009 | |||
| bfa2ed7f6c | |||
| 00fe8e5e3f | |||
| 5aeb8b003c | |||
| d90b7b734c | |||
| 26aaa71667 | |||
| 2265e74a31 | |||
| 04f82f5669 | |||
| e4d2487dd2 | |||
| b603370a23 | |||
| 6ed25aee09 | |||
| 9fff50ae00 | |||
| 787d1a8f53 | |||
| b84949f618 | |||
| 22227b7701 | |||
| 8a33f2a530 |
+29
-1
@@ -2,7 +2,7 @@
|
||||
# process (which uses our internal CI system) this file is here for the benefit
|
||||
# of community developers git clones - see MDL-51458.
|
||||
|
||||
sudo: false
|
||||
sudo: required
|
||||
|
||||
# We currently disable Travis notifications entirely until https://github.com/travis-ci/travis-ci/issues/4976
|
||||
# is fixed.
|
||||
@@ -16,6 +16,12 @@ php:
|
||||
- 7.1
|
||||
- 5.6
|
||||
|
||||
addons:
|
||||
packages:
|
||||
- mysql-server-5.6
|
||||
- mysql-client-core-5.6
|
||||
- mysql-client-5.6
|
||||
|
||||
services:
|
||||
- redis-server
|
||||
|
||||
@@ -70,6 +76,28 @@ cache:
|
||||
- $HOME/.npm
|
||||
|
||||
install:
|
||||
- sudo apt-get -y install haveged
|
||||
- sudo service haveged start
|
||||
- >
|
||||
if [ "$DB" = 'mysqli' ];
|
||||
then
|
||||
sudo mkdir /mnt/ramdisk
|
||||
sudo mount -t tmpfs -o size=1024m tmpfs /mnt/ramdisk
|
||||
sudo stop mysql
|
||||
sudo mv /var/lib/mysql /mnt/ramdisk
|
||||
sudo ln -s /mnt/ramdisk/mysql /var/lib/mysql
|
||||
sudo start mysql
|
||||
fi
|
||||
- >
|
||||
if [ "$DB" = 'pgsql' ];
|
||||
then
|
||||
sudo mkdir /mnt/ramdisk
|
||||
sudo mount -t tmpfs -o size=1024m tmpfs /mnt/ramdisk
|
||||
sudo service postgresql stop
|
||||
sudo mv /var/lib/postgresql /mnt/ramdisk
|
||||
sudo ln -s /mnt/ramdisk/postgresql /var/lib/postgresql
|
||||
sudo service postgresql start 9.1
|
||||
fi
|
||||
- >
|
||||
if [ "$TASK" = 'PHPUNIT' ];
|
||||
then
|
||||
|
||||
+1
-1
@@ -89,7 +89,7 @@ if ($PAGE->user_allowed_editing()) {
|
||||
$savebutton = false;
|
||||
$outputhtml = '';
|
||||
foreach ($settingspage->children as $childpage) {
|
||||
if ($childpage->is_hidden()) {
|
||||
if ($childpage->is_hidden() || !$childpage->check_access()) {
|
||||
continue;
|
||||
}
|
||||
if ($childpage instanceof admin_externalpage) {
|
||||
|
||||
@@ -53,7 +53,7 @@ Options:
|
||||
-h, --help Print out this help
|
||||
|
||||
Example:
|
||||
\$ sudo -u www-data /usr/bin/php admin/cli/mysql_collation.php --collation=utf8_general_ci
|
||||
\$ sudo -u www-data /usr/bin/php admin/cli/mysql_collation.php --collation=utf8mb4_unicode_ci
|
||||
";
|
||||
|
||||
if (!empty($options['collation'])) {
|
||||
@@ -145,9 +145,22 @@ if (!empty($options['collation'])) {
|
||||
$skipped++;
|
||||
|
||||
} else {
|
||||
$DB->change_database_structure("ALTER TABLE $table->name DEFAULT CHARACTER SET $charset DEFAULT COLLATE = $collation");
|
||||
echo "CONVERTED\n";
|
||||
$converted++;
|
||||
try {
|
||||
$DB->change_database_structure("ALTER TABLE $table->name CONVERT TO CHARACTER SET $charset COLLATE $collation");
|
||||
echo "CONVERTED\n";
|
||||
$converted++;
|
||||
} catch (ddl_exception $e) {
|
||||
$result = mysql_set_row_format($table->name, $charset, $collation, $engine);
|
||||
if ($result) {
|
||||
echo "CONVERTED\n";
|
||||
$converted++;
|
||||
} else {
|
||||
// We don't know what the problem is. Stop the conversion.
|
||||
cli_error("Error: Tried to convert $table->name, but there was a problem. Please check the details of this
|
||||
table and try again.");
|
||||
die();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$sql = "SHOW FULL COLUMNS FROM $table->name WHERE collation IS NOT NULL";
|
||||
@@ -290,3 +303,26 @@ function mysql_get_column_collations($tablename) {
|
||||
$rs->close();
|
||||
return $collations;
|
||||
}
|
||||
|
||||
function mysql_set_row_format($tablename, $charset, $collation, $engine) {
|
||||
global $DB;
|
||||
|
||||
$sql = "SELECT row_format
|
||||
FROM INFORMATION_SCHEMA.TABLES
|
||||
WHERE table_schema = DATABASE() AND table_name = ?";
|
||||
$rs = $DB->get_record_sql($sql, array($tablename));
|
||||
if ($rs) {
|
||||
if ($rs->row_format == 'Compact' || $rs->row_format == 'Redundant') {
|
||||
$rowformat = $DB->get_row_format_sql($engine, $collation);
|
||||
// Try to convert to compressed format and then try updating the collation again.
|
||||
$DB->change_database_structure("ALTER TABLE $tablename $rowformat");
|
||||
$DB->change_database_structure("ALTER TABLE $tablename CONVERT TO CHARACTER SET $charset COLLATE $collation");
|
||||
} else {
|
||||
// Row format may not be the problem. Can not diagnose problem. Send fail reply.
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -232,7 +232,7 @@ class site_registration_form extends moodleform {
|
||||
}
|
||||
$language = get_config('hub', 'site_language_' . $cleanhuburl);
|
||||
if ($language === false) {
|
||||
$language = current_language();
|
||||
$language = explode('_', current_language())[0];
|
||||
}
|
||||
$geolocation = get_config('hub', 'site_geolocation_' . $cleanhuburl);
|
||||
$contactable = get_config('hub', 'site_contactable_' . $cleanhuburl);
|
||||
|
||||
@@ -179,7 +179,8 @@ preferences,moodle|/user/preferences.php|preferences',
|
||||
'idnumber' => new lang_string('sort_idnumber', 'admin'),
|
||||
);
|
||||
$temp->add(new admin_setting_configselect('navsortmycoursessort', new lang_string('navsortmycoursessort', 'admin'), new lang_string('navsortmycoursessort_help', 'admin'), 'sortorder', $sortoptions));
|
||||
$temp->add(new admin_setting_configtext('navcourselimit',new lang_string('navcourselimit','admin'),new lang_string('confignavcourselimit', 'admin'),20,PARAM_INT));
|
||||
$temp->add(new admin_setting_configtext('navcourselimit', new lang_string('navcourselimit', 'admin'),
|
||||
new lang_string('confignavcourselimit', 'admin'), 10, PARAM_INT));
|
||||
$temp->add(new admin_setting_configcheckbox('usesitenameforsitepages', new lang_string('usesitenameforsitepages', 'admin'), new lang_string('configusesitenameforsitepages', 'admin'), 0));
|
||||
$temp->add(new admin_setting_configcheckbox('linkadmincategories', new lang_string('linkadmincategories', 'admin'), new lang_string('linkadmincategories_help', 'admin'), 1));
|
||||
$temp->add(new admin_setting_configcheckbox('linkcoursesections', new lang_string('linkcoursesections', 'admin'), new lang_string('linkcoursesections_help', 'admin'), 0));
|
||||
|
||||
@@ -31,7 +31,7 @@ $string['delete_confirmation'] = 'Are you absolutely sure you want to remove <st
|
||||
$string['deletea'] = 'Delete {$a}';
|
||||
$string['deletefiletypes'] = 'Delete a file type';
|
||||
$string['description'] = 'Custom description';
|
||||
$string['description_help'] = 'Simple file type description, e.g. ‘Kindle ebook’. If your site supports multiple languages and uses the multi-language filter, you can enter multi-language tags in this field to supply a description in different languages.';
|
||||
$string['description_help'] = 'Simple file type description, e.g. \'Kindle ebook\'. If your site supports multiple languages and uses the multi-language filter, you can enter multi-language tags in this field to supply a description in different languages.';
|
||||
$string['descriptiontype'] = 'Description type';
|
||||
$string['descriptiontype_help'] = 'There are three possible ways to specify a description.
|
||||
|
||||
@@ -49,15 +49,15 @@ $string['error_defaulticon'] = 'Another file extension with the same MIME type i
|
||||
$string['error_extension'] = 'The file type extension <strong>{$a}</strong> already exists or is invalid. File extensions must be unique and must not contain special characters.';
|
||||
$string['error_notfound'] = 'The file type with extension {$a} cannot be found.';
|
||||
$string['extension'] = 'Extension';
|
||||
$string['extension_help'] = 'File name extension without the dot, e.g. ‘mobi’';
|
||||
$string['extension_help'] = 'File name extension without the dot, e.g. \'mobi\'';
|
||||
$string['groups'] = 'Type groups';
|
||||
$string['groups_help'] = 'Optional list of file type groups that this type belongs to. These are generic categories such as ‘document’ and ‘image’.';
|
||||
$string['groups_help'] = 'Optional list of file type groups that this type belongs to. These are generic categories such as \'document\' and \'image\'.';
|
||||
$string['icon'] = 'File icon';
|
||||
$string['icon_help'] = 'Icon filename.
|
||||
|
||||
The list of icons is taken from the /pix/f directory inside your Moodle installation. You can add custom icons to this folder if required.';
|
||||
$string['mimetype'] = 'MIME type';
|
||||
$string['mimetype_help'] = 'MIME type associated with this file type, e.g. ‘application/x-mobipocket-ebook’';
|
||||
$string['mimetype_help'] = 'MIME type associated with this file type, e.g. \'application/x-mobipocket-ebook\'';
|
||||
$string['pluginname'] = 'File types';
|
||||
$string['revert'] = 'Restore {$a} to Moodle defaults';
|
||||
$string['revert_confirmation'] = 'Are you sure you want to restore <strong>.{$a}</strong> to Moodle defaults, discarding your changes?';
|
||||
|
||||
@@ -40,7 +40,7 @@ if (empty($CFG->langotherroot)) {
|
||||
$mode = optional_param('mode', 0, PARAM_INT); // action
|
||||
$pack = optional_param_array('pack', array(), PARAM_SAFEDIR); // pack to install
|
||||
$uninstalllang = optional_param_array('uninstalllang', array(), PARAM_LANG);// installed pack to uninstall
|
||||
$confirmtounistall = optional_param('confirmtouninstall', '', PARAM_ALPHAEXT); // uninstallation confirmation
|
||||
$confirmtounistall = optional_param('confirmtouninstall', '', PARAM_SAFEPATH); // uninstallation confirmation
|
||||
$purgecaches = optional_param('purgecaches', false, PARAM_BOOL); // explicit caches reset
|
||||
|
||||
if ($purgecaches) {
|
||||
@@ -74,7 +74,7 @@ if ($mode == DELETION_OF_SELECTED_LANG and (!empty($uninstalllang) or !empty($co
|
||||
// Actually deleting languages, languages to delete are passed as GET parameter as string
|
||||
// ...need to populate them to array.
|
||||
if (empty($uninstalllang)) {
|
||||
$uninstalllang = explode('-', $confirmtounistall);
|
||||
$uninstalllang = explode('/', $confirmtounistall);
|
||||
}
|
||||
|
||||
if (in_array('en', $uninstalllang)) {
|
||||
@@ -84,8 +84,10 @@ if ($mode == DELETION_OF_SELECTED_LANG and (!empty($uninstalllang) or !empty($co
|
||||
} else if (empty($confirmtounistall) and confirm_sesskey()) { // User chose langs to be deleted, show confirmation.
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->confirm(get_string('uninstallconfirm', 'tool_langimport', implode(', ', $uninstalllang)),
|
||||
'index.php?mode='.DELETION_OF_SELECTED_LANG.'&confirmtouninstall='.implode('-', $uninstalllang),
|
||||
'index.php');
|
||||
new moodle_url($PAGE->url, array(
|
||||
'mode' => DELETION_OF_SELECTED_LANG,
|
||||
'confirmtouninstall' => implode('/', $uninstalllang),
|
||||
)), $PAGE->url);
|
||||
echo $OUTPUT->footer();
|
||||
die;
|
||||
|
||||
|
||||
@@ -84,8 +84,7 @@ abstract class restore_tool_log_logstore_subplugin extends restore_subplugin {
|
||||
}
|
||||
}
|
||||
|
||||
// Roll dates.
|
||||
$data->timecreated = $this->apply_date_offset($data->timecreated);
|
||||
// There is no need to roll dates. Logs are supposed to be immutable. See MDL-44961.
|
||||
|
||||
// Revert other to its original php way.
|
||||
$data->other = unserialize(base64_decode($data->other));
|
||||
|
||||
@@ -88,6 +88,7 @@ class store implements \tool_log\log\writer, \core\log\sql_reader {
|
||||
$dboptions['dbport'] = $this->get_config('dbport', '');
|
||||
$dboptions['dbschema'] = $this->get_config('dbschema', '');
|
||||
$dboptions['dbcollation'] = $this->get_config('dbcollation', '');
|
||||
$dboptions['dbhandlesoptions'] = $this->get_config('dbhandlesoptions', false);
|
||||
try {
|
||||
$db->connect($this->get_config('dbhost'), $this->get_config('dbuser'), $this->get_config('dbpass'),
|
||||
$this->get_config('dbname'), false, $dboptions);
|
||||
|
||||
@@ -31,6 +31,8 @@ $string['databasesettings_help'] = 'Connection details for the external log data
|
||||
$string['databasepersist'] = 'Persistent database connections';
|
||||
$string['databaseschema'] = 'Database schema';
|
||||
$string['databasecollation'] = 'Database collation';
|
||||
$string['databasehandlesoptions'] = 'Database handles options';
|
||||
$string['databasehandlesoptions_help'] = 'Does the remote database handle its own options.';
|
||||
$string['databasetable'] = 'Database table';
|
||||
$string['databasetable_help'] = 'Name of the table where logs will be stored. This table should have a structure identical to the one used by logstore_standard (mdl_logstore_standard_log).';
|
||||
$string['includeactions'] = 'Include actions of these types';
|
||||
|
||||
@@ -54,6 +54,8 @@ if ($hassiteconfig) {
|
||||
'logstore_database'), '', ''));
|
||||
$settings->add(new admin_setting_configtext('logstore_database/dbcollation', get_string('databasecollation',
|
||||
'logstore_database'), '', ''));
|
||||
$settings->add(new admin_setting_configcheckbox('logstore_database/dbhandlesoptions', get_string('databasehandlesoptions',
|
||||
'logstore_database'), get_string('databasehandlesoptions_help', 'logstore_database'), '0'));
|
||||
$settings->add(new admin_setting_configtext('logstore_database/buffersize', get_string('buffersize',
|
||||
'logstore_database'), get_string('buffersize_help', 'logstore_database'), 50));
|
||||
|
||||
|
||||
@@ -64,6 +64,7 @@ $dboptions['dbsocket'] = get_config('logstore_database', 'dbsocket');
|
||||
$dboptions['dbport'] = get_config('logstore_database', 'dbport');
|
||||
$dboptions['dbschema'] = get_config('logstore_database', 'dbschema');
|
||||
$dboptions['dbcollation'] = get_config('logstore_database', 'dbcollation');
|
||||
$dboptions['dbhandlesoptions'] = get_config('logstore_database', 'dbhandlesoptions');
|
||||
|
||||
try {
|
||||
$db->connect(get_config('logstore_database', 'dbhost'), get_config('logstore_database', 'dbuser'),
|
||||
|
||||
@@ -83,6 +83,11 @@ class logstore_database_store_testcase extends advanced_testcase {
|
||||
} else {
|
||||
set_config('dbcollation', '', 'logstore_database');
|
||||
}
|
||||
if (!empty($CFG->dboptions['dbhandlesoptions'])) {
|
||||
set_config('dbhandlesoptions', $CFG->dboptions['dbhandlesoptions'], 'logstore_database');
|
||||
} else {
|
||||
set_config('dbhandlesoptions', false, 'logstore_database');
|
||||
}
|
||||
|
||||
// Enable logging plugin.
|
||||
set_config('enabled_stores', 'logstore_database', 'tool_log');
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
This files describes API changes in the logstore_database code.
|
||||
|
||||
=== 3.2.4 ===
|
||||
* PostgreSQL connections now use advanced options to reduce connection overhead. These options are not compatible
|
||||
with some connection poolers. The dbhandlesoptions parameter has been added to allow the database to configure the
|
||||
required defaults. The parameters that are required in the database are;
|
||||
ALTER DATABASE moodle SET client_encoding = UTF8;
|
||||
ALTER DATABASE moodle SET standard_conforming_strings = on;
|
||||
ALTER DATABASE moodle SET search_path = 'moodle,public'; -- Optional, if you wish to use a custom schema.
|
||||
You can set these options against the database or the moodle user who connects.
|
||||
|
||||
@@ -24,6 +24,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2016120500; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->version = 2016120501; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2016112900; // Requires this Moodle version.
|
||||
$plugin->component = 'logstore_database'; // Full name of the plugin (used for diagnostics).
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div data-region="footer" class="pull-xs-right">
|
||||
<input type="button" data-action="rate" value="{{#str}}rate, tool_lp{{/str}}" class="btn btn-primary">
|
||||
<button data-action="rate" class="btn btn-primary">{{#str}}rate, tool_lp{{/str}}</button>
|
||||
<button data-action="cancel" class="btn btn-secondary">{{#str}}cancel{{/str}}</button>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
<div data-region="rule-base" class="form">
|
||||
<div data-region="rule-outcome" class="form-group">
|
||||
<label>{{#str}}outcome, tool_lp{{/str}}</label>
|
||||
<select name="outcome" class="custom-select" ng-label="{{#str}}outcome, tool_lp{{/str}}">
|
||||
<select name="outcome" class="custom-select">
|
||||
{{#outcomes}}
|
||||
<option value="{{code}}" {{#selected}}selected{{/selected}}>{{name}}</option>
|
||||
{{/outcomes}}
|
||||
@@ -68,7 +68,7 @@
|
||||
</div>
|
||||
<div data-region="rule-type" class="form-group">
|
||||
<label>{{#str}}when, tool_lp{{/str}}</label>
|
||||
<select name="rule" class="custom-select" ng-label="{{#str}}when, tool_lp{{/str}}">
|
||||
<select name="rule" class="custom-select">
|
||||
<option value="-1">{{#str}}choosedots{{/str}}</option>
|
||||
{{#rules}}
|
||||
<option value="{{type}}" {{#selected}}selected{{/selected}}>{{name}}</option>
|
||||
@@ -81,10 +81,11 @@
|
||||
{{/config}}
|
||||
</div>
|
||||
|
||||
<div data-region="footer" class="pull-xs-right">
|
||||
<div data-region="footer" class="pull-xs-right m-t-1">
|
||||
{{#config}}
|
||||
<input type="button" class="btn btn-primary" data-action="save" value="{{#str}}savechanges{{/str}}"/>
|
||||
{{/config}}
|
||||
<input type="button" class="btn btn-secondary" data-action="cancel" value="{{#str}}cancel{{/str}}"/>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
|
||||
@@ -70,6 +70,9 @@ class api {
|
||||
// Look at all the templates dirs for subsystems.
|
||||
$subsystems = core_component::get_core_subsystems();
|
||||
foreach ($subsystems as $subsystem => $dir) {
|
||||
if (empty($dir)) {
|
||||
continue;
|
||||
}
|
||||
$dir .= '/templates';
|
||||
if (is_dir($dir)) {
|
||||
$dirs = mustache_template_finder::get_template_directories_for_component('core_' . $subsystem, $themename);
|
||||
|
||||
+12
-12
@@ -3187,6 +3187,18 @@ class CAS_Client
|
||||
false/*$no_response*/, true/*$bad_response*/, $text_response
|
||||
);
|
||||
$result = false;
|
||||
} else if ( $tree_response->getElementsByTagName("authenticationFailure")->length != 0) {
|
||||
// authentication failed, extract the error code and message and throw exception
|
||||
$auth_fail_list = $tree_response
|
||||
->getElementsByTagName("authenticationFailure");
|
||||
throw new CAS_AuthenticationException(
|
||||
$this, 'Ticket not validated', $validate_url,
|
||||
false/*$no_response*/, false/*$bad_response*/,
|
||||
$text_response,
|
||||
$auth_fail_list->item(0)->getAttribute('code')/*$err_code*/,
|
||||
trim($auth_fail_list->item(0)->nodeValue)/*$err_msg*/
|
||||
);
|
||||
$result = false;
|
||||
} else if ($tree_response->getElementsByTagName("authenticationSuccess")->length != 0) {
|
||||
// authentication succeded, extract the user name
|
||||
$success_elements = $tree_response
|
||||
@@ -3227,18 +3239,6 @@ class CAS_Client
|
||||
$result = true;
|
||||
}
|
||||
}
|
||||
} else if ( $tree_response->getElementsByTagName("authenticationFailure")->length != 0) {
|
||||
// authentication succeded, extract the error code and message
|
||||
$auth_fail_list = $tree_response
|
||||
->getElementsByTagName("authenticationFailure");
|
||||
throw new CAS_AuthenticationException(
|
||||
$this, 'Ticket not validated', $validate_url,
|
||||
false/*$no_response*/, false/*$bad_response*/,
|
||||
$text_response,
|
||||
$auth_fail_list->item(0)->getAttribute('code')/*$err_code*/,
|
||||
trim($auth_fail_list->item(0)->nodeValue)/*$err_msg*/
|
||||
);
|
||||
$result = false;
|
||||
} else {
|
||||
throw new CAS_AuthenticationException(
|
||||
$this, 'Ticket not validated', $validate_url,
|
||||
|
||||
@@ -2,3 +2,4 @@ Description of phpCAS 1.3.4 library import
|
||||
|
||||
* downloaded from http://downloads.jasig.org/cas-clients/php/current/
|
||||
|
||||
* MDL-59456 phpCAS library has been patched because of an authentication bypass security vulnerability.
|
||||
@@ -143,7 +143,7 @@ class login implements renderable, templatable {
|
||||
$data->error = $this->error;
|
||||
$data->forgotpasswordurl = $this->forgotpasswordurl->out(false);
|
||||
$data->hasidentityproviders = !empty($this->identityproviders);
|
||||
$data->hasinstructions = !empty($this->instructions);
|
||||
$data->hasinstructions = !empty($this->instructions) || $this->cansignup;
|
||||
$data->identityproviders = $identityproviders;
|
||||
list($data->instructions, $data->instructionsformat) = external_format_text($this->instructions, FORMAT_MOODLE,
|
||||
context_system::instance()->id);
|
||||
|
||||
+9
-9
@@ -276,7 +276,7 @@ class auth_plugin_ldap extends auth_plugin_base {
|
||||
}
|
||||
$ldapval = NULL;
|
||||
foreach ($values as $value) {
|
||||
$entry = array_change_key_case($user_entry[0], CASE_LOWER);
|
||||
$entry = $user_entry[0];
|
||||
if (($value == 'dn') || ($value == 'distinguishedname')) {
|
||||
$result[$key] = $user_dn;
|
||||
continue;
|
||||
@@ -634,7 +634,7 @@ class auth_plugin_ldap extends auth_plugin_base {
|
||||
if ($sr) {
|
||||
$info = ldap_get_entries_moodle($ldapconnection, $sr);
|
||||
if (!empty ($info)) {
|
||||
$info = array_change_key_case($info[0], CASE_LOWER);
|
||||
$info = $info[0];
|
||||
if (isset($info[$this->config->expireattr][0])) {
|
||||
$expiretime = $this->ldap_expirationtime2unix($info[$this->config->expireattr][0], $ldapconnection, $user_dn);
|
||||
if ($expiretime != 0) {
|
||||
@@ -1201,7 +1201,7 @@ class auth_plugin_ldap extends auth_plugin_base {
|
||||
return false;
|
||||
}
|
||||
|
||||
$user_entry = array_change_key_case($user_entry[0], CASE_LOWER);
|
||||
$user_entry = $user_entry[0];
|
||||
|
||||
foreach ($attrmap as $key => $ldapkeys) {
|
||||
$profilefield = '';
|
||||
@@ -1369,7 +1369,7 @@ class auth_plugin_ldap extends auth_plugin_base {
|
||||
$sr = ldap_read($ldapconnection, $user_dn, '(objectClass=*)', $search_attribs);
|
||||
if ($sr) {
|
||||
$entry = ldap_get_entries_moodle($ldapconnection, $sr);
|
||||
$info = array_change_key_case($entry[0], CASE_LOWER);
|
||||
$info = $entry[0];
|
||||
$newattrs = array();
|
||||
if (!empty($info[$this->config->expireattr][0])) {
|
||||
// Set expiration time only if passwordExpirationInterval is defined
|
||||
@@ -2024,7 +2024,7 @@ class auth_plugin_ldap extends auth_plugin_base {
|
||||
}
|
||||
|
||||
$entry = ldap_get_entries_moodle($ldapconn, $sr);
|
||||
$info = array_change_key_case($entry[0], CASE_LOWER);
|
||||
$info = $entry[0];
|
||||
$useraccountcontrol = $info['useraccountcontrol'][0];
|
||||
if ($useraccountcontrol & UF_DONT_EXPIRE_PASSWD) {
|
||||
// Password doesn't expire.
|
||||
@@ -2069,17 +2069,17 @@ class auth_plugin_ldap extends auth_plugin_base {
|
||||
}
|
||||
|
||||
$entry = ldap_get_entries_moodle($ldapconn, $sr);
|
||||
$info = array_change_key_case($entry[0], CASE_LOWER);
|
||||
$info = $entry[0];
|
||||
$domaindn = $info['defaultnamingcontext'][0];
|
||||
|
||||
$sr = ldap_read ($ldapconn, $domaindn, '(objectClass=*)',
|
||||
array('maxPwdAge'));
|
||||
$entry = ldap_get_entries_moodle($ldapconn, $sr);
|
||||
$info = array_change_key_case($entry[0], CASE_LOWER);
|
||||
$info = $entry[0];
|
||||
$maxpwdage = $info['maxpwdage'][0];
|
||||
if ($sr = ldap_read($ldapconn, $user_dn, '(objectClass=*)', array('msDS-ResultantPSO'))) {
|
||||
if ($entry = ldap_get_entries_moodle($ldapconn, $sr)) {
|
||||
$info = array_change_key_case($entry[0], CASE_LOWER);
|
||||
$info = $entry[0];
|
||||
$userpso = $info['msds-resultantpso'][0];
|
||||
|
||||
// If a PSO exists, FGPP is being utilized.
|
||||
@@ -2087,7 +2087,7 @@ class auth_plugin_ldap extends auth_plugin_base {
|
||||
if (!empty($userpso)) {
|
||||
$sr = ldap_read($ldapconn, $userpso, '(objectClass=*)', array('msDS-MaximumPasswordAge'));
|
||||
if ($entry = ldap_get_entries_moodle($ldapconn, $sr)) {
|
||||
$info = array_change_key_case($entry[0], CASE_LOWER);
|
||||
$info = $entry[0];
|
||||
// Default value of msds-maximumpasswordage is 42 and is always set.
|
||||
$maxpwdage = $info['msds-maximumpasswordage'][0];
|
||||
}
|
||||
|
||||
@@ -15,6 +15,17 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* This script is used to configure and execute the backup proccess.
|
||||
*
|
||||
* @package core
|
||||
* @subpackage backup
|
||||
* @copyright Moodle
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
define('NO_OUTPUT_BUFFERING', true);
|
||||
|
||||
require_once('../config.php');
|
||||
require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
|
||||
require_once($CFG->dirroot . '/backup/moodle2/backup_plan_builder.class.php');
|
||||
|
||||
@@ -1,5 +1,31 @@
|
||||
<?php
|
||||
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* This script is used to configure and execute the import proccess.
|
||||
*
|
||||
* @package core
|
||||
* @subpackage backup
|
||||
* @copyright Moodle
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
define('NO_OUTPUT_BUFFERING', true);
|
||||
|
||||
// Require both the backup and restore libs
|
||||
require_once('../config.php');
|
||||
require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
|
||||
|
||||
@@ -869,6 +869,14 @@ class backup_calendarevents_structure_step extends backup_structure_step {
|
||||
AND (eventtype = 'course' OR eventtype = 'group')";
|
||||
$calendar_items_params = array('courseid'=>backup::VAR_COURSEID);
|
||||
$event->set_source_sql($calendar_items_sql, $calendar_items_params);
|
||||
} else if ($this->name == 'activity_calendar') {
|
||||
$params = array('instance' => backup::VAR_ACTIVITYID, 'modulename' => backup::VAR_MODNAME);
|
||||
// If we don't want to include the userinfo in the backup then setting the courseid
|
||||
// will filter out all of the user override events (which have a course id of zero).
|
||||
if (!$this->get_setting_value('userinfo')) {
|
||||
$params['courseid'] = backup::VAR_COURSEID;
|
||||
}
|
||||
$event->set_source_table('event', $params);
|
||||
} else {
|
||||
$event->set_source_table('event', array('courseid' => backup::VAR_COURSEID, 'instance' => backup::VAR_ACTIVITYID, 'modulename' => backup::VAR_MODNAME));
|
||||
}
|
||||
|
||||
@@ -2632,6 +2632,17 @@ class restore_calendarevents_structure_step extends restore_structure_step {
|
||||
$data = (object)$data;
|
||||
$oldid = $data->id;
|
||||
$restorefiles = true; // We'll restore the files
|
||||
// User overrides for activities are identified by having a courseid of zero with
|
||||
// both a modulename and instance value set.
|
||||
$isuseroverride = !$data->courseid && $data->modulename && $data->instance;
|
||||
|
||||
// If we don't want to include user data and this record is a user override event
|
||||
// for an activity then we should not create it. (Only activity events can be user override events - which must have this
|
||||
// setting).
|
||||
if ($isuseroverride && $this->task->setting_exists('userinfo') && !$this->task->get_setting_value('userinfo')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the userid and the groupid associated with the event.
|
||||
$data->userid = $this->get_mappingid('user', $data->userid);
|
||||
if ($data->userid === false) {
|
||||
@@ -2667,7 +2678,9 @@ class restore_calendarevents_structure_step extends restore_structure_step {
|
||||
'name' => $data->name,
|
||||
'description' => $data->description,
|
||||
'format' => $data->format,
|
||||
'courseid' => $this->get_courseid(),
|
||||
// User overrides in activities use a course id of zero. All other event types
|
||||
// must use the mapped course id.
|
||||
'courseid' => $data->courseid ? $this->get_courseid() : 0,
|
||||
'groupid' => $data->groupid,
|
||||
'userid' => $data->userid,
|
||||
'repeatid' => $this->get_mappingid('event', $data->repeatid),
|
||||
@@ -2689,10 +2702,11 @@ class restore_calendarevents_structure_step extends restore_structure_step {
|
||||
WHERE " . $DB->sql_compare_text('name', 255) . " = " . $DB->sql_compare_text('?', 255) . "
|
||||
AND courseid = ?
|
||||
AND modulename = ?
|
||||
AND instance = ?
|
||||
AND timestart = ?
|
||||
AND timeduration = ?
|
||||
AND " . $DB->sql_compare_text('description', 255) . " = " . $DB->sql_compare_text('?', 255);
|
||||
$arg = array ($params['name'], $params['courseid'], $params['modulename'], $params['timestart'], $params['timeduration'], $params['description']);
|
||||
$arg = array ($params['name'], $params['courseid'], $params['modulename'], $params['instance'], $params['timestart'], $params['timeduration'], $params['description']);
|
||||
$result = $DB->record_exists_sql($sql, $arg);
|
||||
if (empty($result)) {
|
||||
$newitemid = $DB->insert_record('event', $params);
|
||||
@@ -3045,7 +3059,8 @@ class restore_course_logs_structure_step extends restore_structure_step {
|
||||
|
||||
$data = (object)($data);
|
||||
|
||||
$data->time = $this->apply_date_offset($data->time);
|
||||
// There is no need to roll dates. Logs are supposed to be immutable. See MDL-44961.
|
||||
|
||||
$data->userid = $this->get_mappingid('user', $data->userid);
|
||||
$data->course = $this->get_courseid();
|
||||
$data->cmid = 0;
|
||||
@@ -3092,7 +3107,8 @@ class restore_activity_logs_structure_step extends restore_course_logs_structure
|
||||
|
||||
$data = (object)($data);
|
||||
|
||||
$data->time = $this->apply_date_offset($data->time);
|
||||
// There is no need to roll dates. Logs are supposed to be immutable. See MDL-44961.
|
||||
|
||||
$data->userid = $this->get_mappingid('user', $data->userid);
|
||||
$data->course = $this->get_courseid();
|
||||
$data->cmid = $this->task->get_moduleid();
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Tests for backup_xml_transformer class.
|
||||
*
|
||||
* @package core_backup
|
||||
* @subpackage moodle2
|
||||
* @category backup
|
||||
* @copyright 2017 Dmitrii Metelkin (dmitriim@catalyst-au.net)
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
global $CFG;
|
||||
require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
|
||||
require_once($CFG->dirroot . '/backup/moodle2/backup_plan_builder.class.php');
|
||||
|
||||
/**
|
||||
* Tests for backup_xml_transformer.
|
||||
*
|
||||
* @package core_backup
|
||||
* @copyright 2017 Dmitrii Metelkin (dmitriim@catalyst-au.net)
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class backup_xml_transformer_testcase extends advanced_testcase {
|
||||
|
||||
/**
|
||||
* Initial set up.
|
||||
*/
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->resetAfterTest(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for ::test_filephp_links_replace.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function filephp_links_replace_data_provider() {
|
||||
return array(
|
||||
array('http://test.test/', 'http://test.test/'),
|
||||
array('http://test.test/file.php/1', 'http://test.test/file.php/1'),
|
||||
array('http://test.test/file.php/2/1.jpg', 'http://test.test/file.php/2/1.jpg'),
|
||||
array('http://test.test/file.php/2', 'http://test.test/file.php/2'),
|
||||
array('http://test.test/file.php/1/1.jpg', '$@FILEPHP@$$@SLASH@$1.jpg'),
|
||||
array('http://test.test/file.php/1//1.jpg', '$@FILEPHP@$$@SLASH@$$@SLASH@$1.jpg'),
|
||||
array('http://test.test/file.php?file=/1', '$@FILEPHP@$'),
|
||||
array('http://test.test/file.php?file=/2/1.jpg', 'http://test.test/file.php?file=/2/1.jpg'),
|
||||
array('http://test.test/file.php?file=/2', 'http://test.test/file.php?file=/2'),
|
||||
array('http://test.test/file.php?file=/1/1.jpg', '$@FILEPHP@$$@SLASH@$1.jpg'),
|
||||
array('http://test.test/file.php?file=/1//1.jpg', '$@FILEPHP@$$@SLASH@$$@SLASH@$1.jpg'),
|
||||
array('http://test.test/file.php?file=%2f1', '$@FILEPHP@$'),
|
||||
array('http://test.test/file.php?file=%2f2%2f1.jpg', 'http://test.test/file.php?file=%2f2%2f1.jpg'),
|
||||
array('http://test.test/file.php?file=%2f2', 'http://test.test/file.php?file=%2f2'),
|
||||
array('http://test.test/file.php?file=%2f1%2f1.jpg', '$@FILEPHP@$$@SLASH@$1.jpg'),
|
||||
array('http://test.test/file.php?file=%2f1%2f%2f1.jpg', '$@FILEPHP@$$@SLASH@$$@SLASH@$1.jpg'),
|
||||
array('http://test.test/file.php?file=%2F1', '$@FILEPHP@$'),
|
||||
array('http://test.test/file.php?file=%2F2%2F1.jpg', 'http://test.test/file.php?file=%2F2%2F1.jpg'),
|
||||
array('http://test.test/file.php?file=%2F2', 'http://test.test/file.php?file=%2F2'),
|
||||
array('http://test.test/file.php?file=%2F1%2F1.jpg', '$@FILEPHP@$$@SLASH@$1.jpg'),
|
||||
array('http://test.test/file.php?file=%2F1%2F%2F1.jpg', '$@FILEPHP@$$@SLASH@$$@SLASH@$1.jpg'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that backup_xml_transformer replaces file php links to $@FILEPHP@$.
|
||||
*
|
||||
* @dataProvider filephp_links_replace_data_provider
|
||||
* @param string $content Testing content.
|
||||
* @param string $expected Expected result.
|
||||
*/
|
||||
public function test_filephp_links_replace($content, $expected) {
|
||||
global $CFG;
|
||||
|
||||
$CFG->wwwroot = 'http://test.test';
|
||||
|
||||
$transformer = new backup_xml_transformer(1);
|
||||
|
||||
$this->assertEquals($expected, $transformer->process($content));
|
||||
}
|
||||
|
||||
}
|
||||
+25
-1
@@ -1,5 +1,29 @@
|
||||
<?php
|
||||
//This script is used to configure and execute the restore proccess.
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* This script is used to configure and execute the restore proccess.
|
||||
*
|
||||
* @package core
|
||||
* @subpackage backup
|
||||
* @copyright Moodle
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
define('NO_OUTPUT_BUFFERING', true);
|
||||
|
||||
require_once('../config.php');
|
||||
require_once($CFG->dirroot . '/backup/util/includes/restore_includes.php');
|
||||
|
||||
@@ -60,17 +60,26 @@ class restore_structure_parser_processor extends grouped_parser_processor {
|
||||
} else if (strpos($cdata, '$@FILEPHP@$') === false) { // No $@FILEPHP@$, nothing to convert
|
||||
return $cdata;
|
||||
}
|
||||
|
||||
if ($CFG->slasharguments) {
|
||||
$slash = '/';
|
||||
$forcedownload = '?forcedownload=1';
|
||||
} else {
|
||||
$slash = '%2F';
|
||||
$forcedownload = '&forcedownload=1';
|
||||
}
|
||||
|
||||
// We have to remove trailing slashes, otherwise file URLs will be restored with an extra slash.
|
||||
$basefileurl = rtrim(moodle_url::make_legacyfile_url($this->courseid, null)->out(true), $slash);
|
||||
// Decode file.php calls
|
||||
$search = array ("$@FILEPHP@$");
|
||||
$replace = array(moodle_url::make_legacyfile_url($this->courseid, null));
|
||||
$replace = array($basefileurl);
|
||||
$result = str_replace($search, $replace, $cdata);
|
||||
|
||||
// Now $@SLASH@$ and $@FORCEDOWNLOAD@$ MDL-18799
|
||||
$search = array('$@SLASH@$', '$@FORCEDOWNLOAD@$');
|
||||
if ($CFG->slasharguments) {
|
||||
$replace = array('/', '?forcedownload=1');
|
||||
} else {
|
||||
$replace = array('%2F', '&forcedownload=1');
|
||||
}
|
||||
$replace = array($slash, $forcedownload);
|
||||
|
||||
return str_replace($search, $replace, $result);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Tests for restore_structure_parser_processor class.
|
||||
*
|
||||
* @package core_backup
|
||||
* @category test
|
||||
* @copyright 2017 Dmitrii Metelkin (dmitriim@catalyst-au.net)
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
global $CFG;
|
||||
|
||||
require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
|
||||
require_once($CFG->dirroot . '/backup/util/helper/restore_structure_parser_processor.class.php');
|
||||
|
||||
/**
|
||||
* Tests for restore_structure_parser_processor class.
|
||||
*
|
||||
* @package core_backup
|
||||
* @copyright 2017 Dmitrii Metelkin (dmitriim@catalyst-au.net)
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class restore_structure_parser_processor_test extends advanced_testcase {
|
||||
|
||||
/**
|
||||
* Initial set up.
|
||||
*/
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->resetAfterTest(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for ::test_process_cdata.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function process_cdata_data_provider() {
|
||||
return array(
|
||||
array(null, null, true),
|
||||
array("$@NULL@$", null, true),
|
||||
array("$@NULL@$ ", "$@NULL@$ ", true),
|
||||
array(1, 1, true),
|
||||
array(" ", " ", true),
|
||||
array("1", "1", true),
|
||||
array("$@FILEPHP@$1.jpg", "$@FILEPHP@$1.jpg", true),
|
||||
array(
|
||||
"http://test.test/$@SLASH@$",
|
||||
"http://test.test/$@SLASH@$",
|
||||
true
|
||||
),
|
||||
array(
|
||||
"<a href='$@FILEPHP@$1.jpg'>Image</a>",
|
||||
"<a href='http://test.test/file.php/11.jpg'>Image</a>",
|
||||
true
|
||||
),
|
||||
array(
|
||||
"<a href='$@FILEPHP@$$@SLASH@$1.jpg'>Image</a>",
|
||||
"<a href='http://test.test/file.php/1/1.jpg'>Image</a>",
|
||||
true
|
||||
),
|
||||
array(
|
||||
"<a href='$@FILEPHP@$$@SLASH@$$@SLASH@$1.jpg'>Image</a>",
|
||||
"<a href='http://test.test/file.php/1//1.jpg'>Image</a>",
|
||||
true
|
||||
),
|
||||
array(
|
||||
"<a href='$@FILEPHP@$1.jpg'>Image</a>",
|
||||
"<a href='http://test.test/file.php?file=%2F11.jpg'>Image</a>",
|
||||
false
|
||||
),
|
||||
array(
|
||||
"<a href='$@FILEPHP@$$@SLASH@$1.jpg'>Image</a>",
|
||||
"<a href='http://test.test/file.php?file=%2F1%2F1.jpg'>Image</a>",
|
||||
false
|
||||
),
|
||||
array(
|
||||
"<a href='$@FILEPHP@$$@SLASH@$$@SLASH@$1.jpg'>Image</a>",
|
||||
"<a href='http://test.test/file.php?file=%2F1%2F%2F1.jpg'>Image</a>",
|
||||
false
|
||||
),
|
||||
array(
|
||||
"<a href='$@FILEPHP@$$@SLASH@$1.jpg$@FORCEDOWNLOAD@$'>Image</a>",
|
||||
"<a href='http://test.test/file.php/1/1.jpg?forcedownload=1'>Image</a>",
|
||||
true
|
||||
),
|
||||
array(
|
||||
"<a href='$@FILEPHP@$$@SLASH@$1.jpg$@FORCEDOWNLOAD@$'>Image</a>",
|
||||
"<a href='http://test.test/file.php?file=%2F1%2F1.jpg&forcedownload=1'>Image</a>",
|
||||
false
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that restore_structure_parser_processor replaces $@FILEPHP@$ to correct file php links.
|
||||
*
|
||||
* @dataProvider process_cdata_data_provider
|
||||
* @param string $content Testing content.
|
||||
* @param string $expected Expected result.
|
||||
* @param bool $slasharguments A value for $CFG->slasharguments setting.
|
||||
*/
|
||||
public function test_process_cdata($content, $expected, $slasharguments) {
|
||||
global $CFG;
|
||||
|
||||
$CFG->slasharguments = $slasharguments;
|
||||
$CFG->wwwroot = 'http://test.test';
|
||||
|
||||
$processor = new restore_structure_parser_processor(1, 1);
|
||||
|
||||
$this->assertEquals($expected, $processor->process_cdata($content));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -90,7 +90,7 @@ echo html_writer::start_tag('tbody');
|
||||
if ($USER->id != $user->id) {
|
||||
echo html_writer::start_tag('tr');
|
||||
echo html_writer::start_tag('td', array('colspan' => '2'));
|
||||
echo html_writer::tag('b', get_string('showinguser', 'completion'));
|
||||
echo html_writer::tag('b', get_string('showinguser', 'completion') . ' ');
|
||||
$url = new moodle_url('/user/view.php', array('id' => $user->id, 'course' => $course->id));
|
||||
echo html_writer::link($url, fullname($user));
|
||||
echo html_writer::end_tag('td');
|
||||
@@ -99,7 +99,7 @@ if ($USER->id != $user->id) {
|
||||
|
||||
echo html_writer::start_tag('tr');
|
||||
echo html_writer::start_tag('td', array('colspan' => '2'));
|
||||
echo html_writer::tag('b', get_string('status'));
|
||||
echo html_writer::tag('b', get_string('status') . ' ');
|
||||
|
||||
// Is course complete?
|
||||
$coursecomplete = $info->is_course_complete($user->id);
|
||||
@@ -141,7 +141,7 @@ if (empty($completions)) {
|
||||
} else {
|
||||
echo html_writer::start_tag('tr');
|
||||
echo html_writer::start_tag('td', array('colspan' => '2'));
|
||||
echo html_writer::tag('b', get_string('required'));
|
||||
echo html_writer::tag('b', get_string('required') . ' ');
|
||||
|
||||
// Get overall aggregation method.
|
||||
$overall = $info->get_aggregation_method();
|
||||
@@ -214,7 +214,7 @@ if (empty($completions)) {
|
||||
echo core_text::strtolower(get_string('any', 'completion'));
|
||||
}
|
||||
|
||||
echo html_writer::end_tag('i') .core_text::strtolower(get_string('required')).')';
|
||||
echo ' ' . html_writer::end_tag('i') .core_text::strtolower(get_string('required')).')';
|
||||
$agg_type = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,7 +119,9 @@ class block_login extends block_base {
|
||||
$this->content->text .= '<h6>' . get_string('potentialidps', 'auth') . '</h6>';
|
||||
$this->content->text .= '<div class="potentialidplist">';
|
||||
foreach ($potentialidps as $idp) {
|
||||
$this->content->text .= '<div class="potentialidp"><a href="' . $idp['url']->out() . '" title="' . s($idp['name']) . '">';
|
||||
$this->content->text .= '<div class="potentialidp">';
|
||||
$this->content->text .= '<a class="btn btn-default btn-block" ';
|
||||
$this->content->text .= 'href="' . $idp['url']->out() . '" title="' . s($idp['name']) . '">';
|
||||
$this->content->text .= $OUTPUT->render($idp['icon'], $idp['name']) . s($idp['name']) . '</a></div>';
|
||||
}
|
||||
$this->content->text .= '</div>';
|
||||
|
||||
Vendored
+2
-2
@@ -1018,7 +1018,7 @@ class cache implements cache_loader {
|
||||
$result = $data;
|
||||
}
|
||||
}
|
||||
if ($result) {
|
||||
if ($result !== false) {
|
||||
if ($this->perfdebug) {
|
||||
cache_helper::record_cache_hit('** static acceleration **', $this->definition);
|
||||
}
|
||||
@@ -2197,4 +2197,4 @@ class cache_session extends cache {
|
||||
*/
|
||||
class cache_request extends cache {
|
||||
// This comment appeases code pre-checker ;) !
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+33
@@ -2173,6 +2173,39 @@ class core_cache_testcase extends advanced_testcase {
|
||||
$startstats[$requestid]['stores']['cachestore_static']['sets']);
|
||||
}
|
||||
|
||||
public function test_static_cache() {
|
||||
global $CFG;
|
||||
$this->resetAfterTest(true);
|
||||
$CFG->perfdebug = 15;
|
||||
|
||||
// Create cache store with static acceleration.
|
||||
$instance = cache_config_testing::instance();
|
||||
$applicationid = 'phpunit/applicationperf';
|
||||
$instance->phpunit_add_definition($applicationid, array(
|
||||
'mode' => cache_store::MODE_APPLICATION,
|
||||
'component' => 'phpunit',
|
||||
'area' => 'applicationperf',
|
||||
'simplekeys' => true,
|
||||
'staticacceleration' => true,
|
||||
'staticaccelerationsize' => 3
|
||||
));
|
||||
|
||||
$application = cache::make('phpunit', 'applicationperf');
|
||||
|
||||
// Check that stores register sets.
|
||||
$this->assertTrue($application->set('setMe1', 1));
|
||||
$this->assertTrue($application->set('setMe2', 0));
|
||||
$this->assertTrue($application->set('setMe3', array()));
|
||||
$this->assertTrue($application->get('setMe1') !== false);
|
||||
$this->assertTrue($application->get('setMe2') !== false);
|
||||
$this->assertTrue($application->get('setMe3') !== false);
|
||||
|
||||
// Check that the static acceleration worked, even on empty arrays and the number 0.
|
||||
$endstats = cache_helper::get_stats();
|
||||
$this->assertEquals(0, $endstats[$applicationid]['stores']['** static acceleration **']['misses']);
|
||||
$this->assertEquals(3, $endstats[$applicationid]['stores']['** static acceleration **']['hits']);
|
||||
}
|
||||
|
||||
public function test_performance_debug_off() {
|
||||
global $CFG;
|
||||
$this->resetAfterTest(true);
|
||||
|
||||
@@ -244,13 +244,16 @@ class rrule_manager {
|
||||
// Generate timestamps that obey the rrule.
|
||||
$eventtimes = $this->generate_recurring_event_times($eventrec);
|
||||
|
||||
// Adjust the parent event's timestart, if necessary.
|
||||
// Update the parent event. Make sure that its repeat ID is the same as its ID.
|
||||
$calevent = new calendar_event($eventrec);
|
||||
$updatedata = new stdClass();
|
||||
$updatedata->repeatid = $event->id;
|
||||
// Also, adjust the parent event's timestart, if necessary.
|
||||
if (count($eventtimes) > 0 && !in_array($eventrec->timestart, $eventtimes)) {
|
||||
$calevent = new calendar_event($eventrec);
|
||||
$updatedata = (object)['timestart' => $eventtimes[0], 'repeatid' => $eventrec->id];
|
||||
$calevent->update($updatedata, false);
|
||||
$eventrec->timestart = $calevent->timestart;
|
||||
$updatedata->timestart = reset($eventtimes);
|
||||
}
|
||||
$calevent->update($updatedata, false);
|
||||
$eventrec->timestart = $calevent->timestart;
|
||||
|
||||
// Create the recurring calendar events.
|
||||
$this->create_recurring_events($eventrec, $eventtimes);
|
||||
@@ -720,6 +723,8 @@ class rrule_manager {
|
||||
$cloneevent->repeatid = $event->id;
|
||||
$cloneevent->timestart = $time;
|
||||
unset($cloneevent->id);
|
||||
// UUID should only be set on the first instance of the recurring events.
|
||||
unset($cloneevent->uuid);
|
||||
calendar_event::create($cloneevent, false);
|
||||
}
|
||||
|
||||
|
||||
@@ -72,7 +72,8 @@ class event_form extends moodleform {
|
||||
if (!empty($eventtypes->groups) && is_array($eventtypes->groups)) {
|
||||
$groupoptions = array();
|
||||
foreach ($eventtypes->groups as $group) {
|
||||
$groupoptions[$group->id] = $group->name;
|
||||
$groupoptions[$group->id] = format_string($group->name, true,
|
||||
array('context' => context_course::instance($group->courseid)));
|
||||
}
|
||||
$mform->addElement('select', 'groupid', get_string('typegroup', 'calendar'), $groupoptions);
|
||||
$mform->disabledIf('groupid', 'eventtype', 'noteq', 'group');
|
||||
|
||||
+3
-2
@@ -77,7 +77,8 @@ if (!empty($day) && !empty($mon) && !empty($year)) {
|
||||
}
|
||||
|
||||
if ($courseid != SITEID && !empty($courseid)) {
|
||||
$course = $DB->get_record('course', array('id' => $courseid));
|
||||
// Course ID must be valid and existing.
|
||||
$course = $DB->get_record('course', array('id' => $courseid), '*', MUST_EXIST);
|
||||
$courses = array($course->id => $course);
|
||||
$issite = false;
|
||||
} else {
|
||||
@@ -85,7 +86,7 @@ if ($courseid != SITEID && !empty($courseid)) {
|
||||
$courses = calendar_get_default_courses();
|
||||
$issite = true;
|
||||
}
|
||||
require_course_login($course);
|
||||
require_login($course, false);
|
||||
|
||||
$url = new moodle_url('/calendar/export.php', array('time' => $time));
|
||||
|
||||
|
||||
@@ -193,10 +193,20 @@ foreach($events as $event) {
|
||||
$hostaddress = str_replace('http://', '', $CFG->wwwroot);
|
||||
$hostaddress = str_replace('https://', '', $hostaddress);
|
||||
|
||||
$ev = new iCalendar_event;
|
||||
$me = new calendar_event($event); // To use moodle calendar event services.
|
||||
$ev = new iCalendar_event; // To export in ical format.
|
||||
$ev->add_property('uid', $event->id.'@'.$hostaddress);
|
||||
$ev->add_property('summary', $event->name);
|
||||
$ev->add_property('description', clean_param($event->description, PARAM_NOTAGS));
|
||||
|
||||
// Set iCal event summary from event name.
|
||||
$ev->add_property('summary', format_string($event->name, true, ['context' => $me->context]));
|
||||
|
||||
// Format the description text.
|
||||
$description = format_text($me->description, $me->format, ['context' => $me->context]);
|
||||
// Then convert it to plain text, since it's the only format allowed for the event description property.
|
||||
// We use html_to_text in order to convert <br> and <p> tags to new line characters for descriptions in HTML format.
|
||||
$description = html_to_text($description, 0);
|
||||
$ev->add_property('description', $description);
|
||||
|
||||
$ev->add_property('class', 'PUBLIC'); // PUBLIC / PRIVATE / CONFIDENTIAL
|
||||
$ev->add_property('last-modified', Bennu::timestamp_to_datetime($event->timemodified));
|
||||
$ev->add_property('dtstamp', Bennu::timestamp_to_datetime()); // now
|
||||
|
||||
@@ -45,13 +45,15 @@ $PAGE->set_pagelayout('admin');
|
||||
$PAGE->navbar->add(get_string('managesubscriptions', 'calendar'));
|
||||
|
||||
if ($courseid != SITEID && !empty($courseid)) {
|
||||
$course = $DB->get_record('course', array('id' => $courseid));
|
||||
// Course ID must be valid and existing.
|
||||
$course = $DB->get_record('course', array('id' => $courseid), '*', MUST_EXIST);
|
||||
$courses = array($course->id => $course);
|
||||
} else {
|
||||
$course = get_site();
|
||||
$courses = calendar_get_default_courses();
|
||||
}
|
||||
require_course_login($course);
|
||||
require_login($course, false);
|
||||
|
||||
if (!calendar_user_can_add_event($course)) {
|
||||
print_error('errorcannotimport', 'calendar');
|
||||
}
|
||||
|
||||
@@ -171,4 +171,55 @@ class core_calendar_lib_testcase extends advanced_testcase {
|
||||
$event = reset($events);
|
||||
$this->assertEquals('assign', $event->modulename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to create calendar events using the old code.
|
||||
*
|
||||
* @param array $properties A list of calendar event properties to set
|
||||
* @return calendar_event|bool
|
||||
*/
|
||||
protected function create_event($properties = []) {
|
||||
$record = new \stdClass();
|
||||
$record->name = 'event name';
|
||||
$record->eventtype = 'global';
|
||||
$record->timestart = time();
|
||||
$record->timeduration = 0;
|
||||
$record->timesort = 0;
|
||||
$record->type = 1;
|
||||
$record->courseid = 0;
|
||||
|
||||
foreach ($properties as $name => $value) {
|
||||
$record->$name = $value;
|
||||
}
|
||||
|
||||
$event = new calendar_event($record);
|
||||
return $event->create($record, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that when course module is deleted all events are also deleted.
|
||||
*/
|
||||
public function test_delete_module_delete_events() {
|
||||
global $DB;
|
||||
$this->resetAfterTest(true);
|
||||
$this->setAdminUser();
|
||||
$user = $this->getDataGenerator()->create_user();
|
||||
// Create the course we will be using.
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
$group = $this->getDataGenerator()->create_group(['courseid' => $course->id]);
|
||||
|
||||
foreach (core_component::get_plugin_list('mod') as $modname => $unused) {
|
||||
$module = $this->getDataGenerator()->create_module($modname, ['course' => $course->id]);
|
||||
|
||||
// Create bunch of events of different type (user override, group override, module event).
|
||||
$this->create_event(['userid' => $user->id, 'modulename' => $modname, 'instance' => $module->id]);
|
||||
$this->create_event(['groupid' => $group->id, 'modulename' => $modname, 'instance' => $module->id]);
|
||||
$this->create_event(['modulename' => $modname, 'instance' => $module->id]);
|
||||
$this->create_event(['modulename' => $modname, 'instance' => $module->id, 'courseid' => $course->id]);
|
||||
|
||||
// Delete module and make sure all events are deleted.
|
||||
course_delete_module($module->cmid);
|
||||
$this->assertEmpty($DB->get_record('event', ['modulename' => $modname, 'instance' => $module->id]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -451,6 +451,9 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
|
||||
*/
|
||||
public function test_every_300_days_forever() {
|
||||
global $DB;
|
||||
|
||||
// Change the start date for forever events to 9am of the current date.
|
||||
$this->change_event_startdate(date('Ymd\T090000'));
|
||||
$startdatetime = new DateTime(date('Y-m-d H:i:s', $this->event->timestart));
|
||||
|
||||
$interval = new DateInterval('P300D');
|
||||
@@ -463,14 +466,25 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
|
||||
$mang = new rrule_manager($rrule);
|
||||
$mang->parse_rrule();
|
||||
$mang->create_events($this->event);
|
||||
$records = $DB->get_records('event', array('repeatid' => $this->event->id), 'timestart ASC');
|
||||
// Get the first 100 samples. This should be enough to verify that we have generated the recurring events correctly.
|
||||
$records = $DB->get_records('event', array('repeatid' => $this->event->id), 'timestart ASC', 0, 100);
|
||||
|
||||
$expecteddate = clone($startdatetime);
|
||||
$first = true;
|
||||
foreach ($records as $record) {
|
||||
$this->assertLessThanOrEqual($until, $record->timestart);
|
||||
$this->assertEquals($expecteddate->format('Y-m-d H:i:s'), date('Y-m-d H:i:s', $record->timestart));
|
||||
// Go to next iteration.
|
||||
$expecteddate->add($interval);
|
||||
// Check UUID.
|
||||
if ($first) {
|
||||
// The first instance of the event contains the UUID.
|
||||
$this->assertEquals('uuid', $record->uuid);
|
||||
$first = false;
|
||||
} else {
|
||||
// Succeeding instances will not contain the UUID.
|
||||
$this->assertEmpty($record->uuid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -542,8 +556,20 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
|
||||
$expecteddate->add($interval);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Forever event. This should generate events over time() + 10 year period, every 50th Monday.
|
||||
/**
|
||||
* Test recurrence rules for weekly frequency for RRULE with BYDAY rule set, recurring forever.
|
||||
*/
|
||||
public function test_weekly_byday_forever() {
|
||||
global $DB;
|
||||
|
||||
// Set the next Monday as the starting date of this event.
|
||||
$startdate = new DateTime('next Monday');
|
||||
// Change the start date of the parent event.
|
||||
$startdate = $this->change_event_startdate($startdate->format('Ymd\T090000'));
|
||||
|
||||
// Forever event. This should generate events over time() + 10 year period, every 50 weeks.
|
||||
$rrule = 'FREQ=WEEKLY;BYDAY=MO;INTERVAL=50';
|
||||
|
||||
$mang = new rrule_manager($rrule);
|
||||
@@ -554,13 +580,14 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
|
||||
$untildate->add(new DateInterval('P10Y'));
|
||||
$until = $untildate->getTimestamp();
|
||||
|
||||
$interval = new DateInterval('P50W');
|
||||
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart');
|
||||
|
||||
// First instance of this set of recurring events: Monday, 17-08-1998.
|
||||
$interval = new DateInterval('P50W');
|
||||
|
||||
// First instance of this set of recurring events.
|
||||
$expecteddate = clone($startdate);
|
||||
$expecteddate->modify('1998-08-17');
|
||||
$expecteddate->add($offsetinterval);
|
||||
|
||||
// Iterate over each record and increment the expected date accordingly.
|
||||
foreach ($records as $record) {
|
||||
$eventdateexpected = $expecteddate->format('Y-m-d H:i:s');
|
||||
$eventdateactual = date('Y-m-d H:i:s', $record->timestart);
|
||||
@@ -666,17 +693,21 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
|
||||
public function test_monthly_events_with_bymonthday_forever() {
|
||||
global $DB;
|
||||
|
||||
// Change the start date for forever events to 9am of the 2nd day of the current month and year.
|
||||
$this->change_event_startdate(date('Ym02\T090000'));
|
||||
$startdatetime = new DateTime(date('Y-m-d H:i:s', $this->event->timestart));
|
||||
$startdate = new DateTime(date('Y-m-d', $this->event->timestart));
|
||||
|
||||
$offsetinterval = $startdatetime->diff($startdate, true);
|
||||
$interval = new DateInterval('P12M');
|
||||
|
||||
// Forever event. This should generate events over 10 year period, on 2nd day of every 12th month.
|
||||
// Forever event. This should generate events over a 10-year period, on 2nd day of the month, every 12 months.
|
||||
$rrule = "FREQ=MONTHLY;INTERVAL=12;BYMONTHDAY=2";
|
||||
|
||||
$mang = new rrule_manager($rrule);
|
||||
$until = time() + (YEARSECS * $mang::TIME_UNLIMITED_YEARS);
|
||||
$untildate = new DateTime();
|
||||
$untildate->add(new DateInterval('P' . $mang::TIME_UNLIMITED_YEARS . 'Y'));
|
||||
$until = $untildate->getTimestamp();
|
||||
|
||||
$mang->parse_rrule();
|
||||
$mang->create_events($this->event);
|
||||
@@ -818,24 +849,33 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
|
||||
public function test_monthly_events_with_byday_forever() {
|
||||
global $DB;
|
||||
|
||||
// Change the start date for forever events to 9am of the 2nd day of the current month and year.
|
||||
$this->change_event_startdate(date('Ym02\T090000'));
|
||||
|
||||
$startdatetime = new DateTime(date('Y-m-d H:i:s', $this->event->timestart));
|
||||
$startdate = new DateTime(date('Y-m-d', $this->event->timestart));
|
||||
|
||||
$offsetinterval = $startdatetime->diff($startdate, true);
|
||||
$interval = new DateInterval('P12M');
|
||||
|
||||
// Forever event. This should generate events over 10 year period, on 2nd day of every 12th month.
|
||||
// Forever event. This should generate events over a 10 year period, on 1st Monday of the month every 12 months.
|
||||
$rrule = "FREQ=MONTHLY;INTERVAL=12;BYDAY=1MO";
|
||||
|
||||
$mang = new rrule_manager($rrule);
|
||||
$until = time() + (YEARSECS * $mang::TIME_UNLIMITED_YEARS);
|
||||
$untildate = new DateTime();
|
||||
$untildate->add(new DateInterval('P' . $mang::TIME_UNLIMITED_YEARS . 'Y'));
|
||||
$until = $untildate->getTimestamp();
|
||||
|
||||
$mang->parse_rrule();
|
||||
$mang->create_events($this->event);
|
||||
|
||||
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart');
|
||||
|
||||
$expecteddate = new DateTime('first Monday of September 1998');
|
||||
$expecteddate = new DateTime('first Monday of this month');
|
||||
// Move to the next interval's first Monday if the calculated start date is after this month's first Monday.
|
||||
if ($expecteddate->getTimestamp() < $startdatetime->getTimestamp()) {
|
||||
$expecteddate->add($interval);
|
||||
$expecteddate->modify('first Monday of this month');
|
||||
}
|
||||
foreach ($records as $record) {
|
||||
$expecteddate->add($offsetinterval);
|
||||
$this->assertLessThanOrEqual($until, $record->timestart);
|
||||
@@ -880,7 +920,7 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
|
||||
// Create a yearly event, until the time limit is hit.
|
||||
$until = strtotime('+20 day +10 years', $this->event->timestart);
|
||||
$until = date('Ymd\THis\Z', $until);
|
||||
$rrule = "FREQ=YEARLY;BYMONTH=9;UNTIL=$until"; // Forever event.
|
||||
$rrule = "FREQ=YEARLY;BYMONTH=9;UNTIL=$until";
|
||||
$mang = new rrule_manager($rrule);
|
||||
$mang->parse_rrule();
|
||||
$mang->create_events($this->event);
|
||||
@@ -907,18 +947,6 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
|
||||
$this->assertTrue($result);
|
||||
}
|
||||
|
||||
$rrule = "FREQ=YEARLY;BYMONTH=9;INTERVAL=2"; // Forever event.
|
||||
$mang = new rrule_manager($rrule);
|
||||
$until = time() + (YEARSECS * $mang::TIME_UNLIMITED_YEARS);
|
||||
$mang->parse_rrule();
|
||||
$mang->create_events($this->event);
|
||||
for ($i = 0, $time = $this->event->timestart; $time < $until; $i++, $yoffset = $i * 2,
|
||||
$time = strtotime("+$yoffset years", $this->event->timestart)) {
|
||||
$result = $DB->record_exists('event', array('repeatid' => $this->event->id,
|
||||
'timestart' => ($time)));
|
||||
$this->assertTrue($result);
|
||||
}
|
||||
|
||||
$rrule = "FREQ=YEARLY;COUNT=3;BYMONTH=9;BYDAY=1MO"; // This should generate 3 events in total.
|
||||
$mang = new rrule_manager($rrule);
|
||||
$mang->parse_rrule();
|
||||
@@ -994,12 +1022,45 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for rrule with FREQ=YEARLY and INTERVAL=2 with BYMONTH rule set, recurring forever.
|
||||
*/
|
||||
public function test_yearly_september_every_two_years_forever() {
|
||||
global $DB;
|
||||
|
||||
// Change the start date for forever events to 9am on the 2nd day of September of the current year.
|
||||
$this->change_event_startdate(date('Y0902\T090000'));
|
||||
|
||||
$rrule = "FREQ=YEARLY;BYMONTH=9;INTERVAL=2"; // Forever event.
|
||||
$mang = new rrule_manager($rrule);
|
||||
$untildate = new DateTime();
|
||||
$untildate->add(new DateInterval('P' . $mang::TIME_UNLIMITED_YEARS . 'Y'));
|
||||
$untiltimestamp = $untildate->getTimestamp();
|
||||
$mang->parse_rrule();
|
||||
$mang->create_events($this->event);
|
||||
|
||||
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart');
|
||||
|
||||
$interval = new DateInterval('P2Y');
|
||||
$expecteddate = new DateTime(date('Y0902\T090000'));
|
||||
foreach ($records as $record) {
|
||||
$this->assertLessThanOrEqual($untiltimestamp, $record->timestart);
|
||||
$this->assertEquals($expecteddate->format('Y-m-d H:i:s'), date('Y-m-d H:i:s', $record->timestart));
|
||||
|
||||
// Go to the next expected date.
|
||||
$expecteddate->add($interval);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for rrule with FREQ=YEARLY with BYMONTH and BYDAY rules set, recurring forever.
|
||||
*/
|
||||
public function test_yearly_bymonth_byday_forever() {
|
||||
global $DB;
|
||||
|
||||
// Change the start date for forever events to the first day of September of the current year at 9am.
|
||||
$this->change_event_startdate(date('Y0901\T090000'));
|
||||
|
||||
// Every 2 years on the first Monday of September.
|
||||
$rrule = "FREQ=YEARLY;BYMONTH=9;INTERVAL=2;BYDAY=1MO";
|
||||
$mang = new rrule_manager($rrule);
|
||||
@@ -1018,9 +1079,9 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
|
||||
$offsetinterval = $startdatetime->diff($startdate, true);
|
||||
$interval = new DateInterval('P2Y');
|
||||
|
||||
// First occurrence of this set of events is on the first Monday of September 1999.
|
||||
// First occurrence of this set of events is on the first Monday of September.
|
||||
$expecteddate = clone($startdatetime);
|
||||
$expecteddate->modify('first Monday of September 1999');
|
||||
$expecteddate->modify('first Monday of September');
|
||||
$expecteddate->add($offsetinterval);
|
||||
foreach ($records as $record) {
|
||||
$this->assertLessThanOrEqual($untiltimestamp, $record->timestart);
|
||||
@@ -1040,6 +1101,9 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
|
||||
public function test_yearly_forever() {
|
||||
global $DB;
|
||||
|
||||
// Change the start date for forever events to 9am of the current date.
|
||||
$this->change_event_startdate(date('Ymd\T090000'));
|
||||
|
||||
$startdatetime = new DateTime(date('Y-m-d H:i:s', $this->event->timestart));
|
||||
|
||||
$interval = new DateInterval('P2Y');
|
||||
@@ -1137,14 +1201,19 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
|
||||
/**
|
||||
* Every other day - forever:
|
||||
*
|
||||
* DTSTART;TZID=US-Eastern:19970902T090000
|
||||
* DTSTART;TZID=US-Eastern:[Current date]T090000
|
||||
* RRULE:FREQ=DAILY;INTERVAL=2
|
||||
* ==> (1997 9:00 AM EDT)September2,4,6,8...24,26,28,30;October 2,4,6...20,22,24
|
||||
* (1997 9:00 AM EST)October 26,28,30;November 1,3,5,7...25,27,29;Dec 1,3,...
|
||||
*
|
||||
* Sample results (e.g. in the year 1997):
|
||||
* (1997 9:00 AM EDT)September2,4,6,8...24,26,28,30;October 2,4,6...20,22,24
|
||||
* (1997 9:00 AM EST)October 26,28,30;November 1,3,5,7...25,27,29;Dec 1,3,...
|
||||
*/
|
||||
public function test_every_other_day_forever() {
|
||||
global $DB;
|
||||
|
||||
// Change the start date for forever events to 9am of the current date in US/Eastern time.
|
||||
$this->change_event_startdate(date('Ymd\T090000'), 'US/Eastern');
|
||||
|
||||
$startdatetime = new DateTime(date('Y-m-d H:i:s', $this->event->timestart));
|
||||
$interval = new DateInterval('P2D');
|
||||
|
||||
@@ -1153,7 +1222,8 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
|
||||
$mang->parse_rrule();
|
||||
$mang->create_events($this->event);
|
||||
|
||||
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart');
|
||||
// Get the first 100 samples. This should be enough to verify that we have generated the recurring events correctly.
|
||||
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart', 0, 100);
|
||||
|
||||
$untildate = new DateTime();
|
||||
$untildate->add(new DateInterval('P' . $mang::TIME_UNLIMITED_YEARS . 'Y'));
|
||||
@@ -1331,16 +1401,21 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
|
||||
/**
|
||||
* Every other week - forever:
|
||||
*
|
||||
* DTSTART;TZID=US-Eastern:19970902T090000
|
||||
* DTSTART;TZID=US-Eastern:[Current date]T090000
|
||||
* RRULE:FREQ=WEEKLY;INTERVAL=2;WKST=SU
|
||||
* ==> (1997 9:00 AM EDT)September 2,16,30;October 14
|
||||
* (1997 9:00 AM EST)October 28;November 11,25;December 9,23
|
||||
* (1998 9:00 AM EST)January 6,20;February
|
||||
* ...
|
||||
*
|
||||
* Sample results (e.g. in the year 1997):
|
||||
* (1997 9:00 AM EDT)September 2,16,30;October 14
|
||||
* (1997 9:00 AM EST)October 28;November 11,25;December 9,23
|
||||
* (1998 9:00 AM EST)January 6,20;February
|
||||
* ...
|
||||
*/
|
||||
public function test_every_other_week_forever() {
|
||||
global $DB;
|
||||
|
||||
// Change the start date for forever events to 9am of the current date in US/Eastern time.
|
||||
$this->change_event_startdate(date('Ymd\T090000'), 'US/Eastern');
|
||||
|
||||
$interval = new DateInterval('P2W');
|
||||
|
||||
$rrule = 'FREQ=WEEKLY;INTERVAL=2;WKST=SU';
|
||||
@@ -1348,7 +1423,8 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
|
||||
$mang->parse_rrule();
|
||||
$mang->create_events($this->event);
|
||||
|
||||
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart');
|
||||
// Get the first 100 samples. This should be enough to verify that we have generated the recurring events correctly.
|
||||
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart', 0, 100);
|
||||
|
||||
$untildate = new DateTime();
|
||||
$untildate->add(new DateInterval('P' . $mang::TIME_UNLIMITED_YEARS . 'Y'));
|
||||
@@ -1694,25 +1770,28 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
|
||||
/**
|
||||
* Monthly on the third to the last day of the month, forever:
|
||||
*
|
||||
* DTSTART;TZID=US-Eastern:19970928T090000
|
||||
* DTSTART;TZID=US-Eastern:[Current year]0928T090000
|
||||
* RRULE:FREQ=MONTHLY;BYMONTHDAY=-3
|
||||
* ==> (1997 9:00 AM EDT)September 28
|
||||
* (1997 9:00 AM EST)October 29;November 28;December 29
|
||||
* (1998 9:00 AM EST)January 29;February 26
|
||||
* ...
|
||||
*
|
||||
* Sample results (e.g. in the year 1997):
|
||||
* (1997 9:00 AM EDT)September 28
|
||||
* (1997 9:00 AM EST)October 29;November 28;December 29
|
||||
* (1998 9:00 AM EST)January 29;February 26
|
||||
* ...
|
||||
*/
|
||||
public function test_third_to_the_last_day_of_the_month_forever() {
|
||||
global $DB;
|
||||
|
||||
// Change our event's date to 05-09-1997, based on the example from the RFC.
|
||||
$this->change_event_startdate('19970928T090000', 'US/Eastern');
|
||||
// Change our event's date to 28 September of the current year, based on the example from the RFC.
|
||||
$this->change_event_startdate(date('Y0928\T090000'), 'US/Eastern');
|
||||
|
||||
$rrule = 'FREQ=MONTHLY;BYMONTHDAY=-3';
|
||||
$mang = new rrule_manager($rrule);
|
||||
$mang->parse_rrule();
|
||||
$mang->create_events($this->event);
|
||||
|
||||
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart');
|
||||
// Get the first 100 samples. This should be enough to verify that we have generated the recurring events correctly.
|
||||
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart', 0, 100);
|
||||
|
||||
$untildate = new DateTime();
|
||||
$untildate->add(new DateInterval('P' . $mang::TIME_UNLIMITED_YEARS . 'Y'));
|
||||
@@ -1868,22 +1947,29 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
|
||||
/**
|
||||
* Every Tuesday, every other month:
|
||||
*
|
||||
* DTSTART;TZID=US-Eastern:19970902T090000
|
||||
* DTSTART;TZID=US-Eastern:[Next Tuesday]T090000
|
||||
* RRULE:FREQ=MONTHLY;INTERVAL=2;BYDAY=TU
|
||||
* ==> (1997 9:00 AM EDT)September 2,9,16,23,30
|
||||
* (1997 9:00 AM EST)November 4,11,18,25
|
||||
* (1998 9:00 AM EST)January 6,13,20,27;March 3,10,17,24,31
|
||||
* ...
|
||||
*
|
||||
* Sample results (e.g. in the year 1997):
|
||||
* (1997 9:00 AM EDT)September 2,9,16,23,30
|
||||
* (1997 9:00 AM EST)November 4,11,18,25
|
||||
* (1998 9:00 AM EST)January 6,13,20,27;March 3,10,17,24,31
|
||||
* ...
|
||||
*/
|
||||
public function test_every_tuesday_every_other_month_forever() {
|
||||
global $DB;
|
||||
|
||||
// Change the start date for forever events to 9am of the Tuesday on or before of the current date in US/Eastern time.
|
||||
$nexttuesday = new DateTime('next Tuesday');
|
||||
$this->change_event_startdate($nexttuesday->format('Ymd\T090000'), 'US/Eastern');
|
||||
|
||||
$rrule = 'FREQ=MONTHLY;INTERVAL=2;BYDAY=TU';
|
||||
$mang = new rrule_manager($rrule);
|
||||
$mang->parse_rrule();
|
||||
$mang->create_events($this->event);
|
||||
|
||||
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart');
|
||||
// Get the first 100 samples. This should be enough to verify that we have generated the recurring events correctly.
|
||||
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart', 0, 100);
|
||||
|
||||
$untildate = new DateTime();
|
||||
$untildate->add(new DateInterval('P' . $mang::TIME_UNLIMITED_YEARS . 'Y'));
|
||||
@@ -2053,18 +2139,22 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
|
||||
/**
|
||||
* Every 20th Monday of the year, forever:
|
||||
*
|
||||
* DTSTART;TZID=US-Eastern:19970519T090000
|
||||
* DTSTART;TZID=US-Eastern:[20th Monday of the current year]T090000
|
||||
* RRULE:FREQ=YEARLY;BYDAY=20MO
|
||||
* ==> (1997 9:00 AM EDT)May 19
|
||||
* (1998 9:00 AM EDT)May 18
|
||||
* (1999 9:00 AM EDT)May 17
|
||||
* ...
|
||||
*
|
||||
* Sample results (e.g. in the year 1997):
|
||||
* (1997 9:00 AM EDT)May 19
|
||||
* (1998 9:00 AM EDT)May 18
|
||||
* (1999 9:00 AM EDT)May 17
|
||||
* ...
|
||||
*/
|
||||
public function test_yearly_every_20th_monday_forever() {
|
||||
global $DB;
|
||||
|
||||
// Change our event's date to 19-05-1997, based on the example from the RFC.
|
||||
$startdatetime = $this->change_event_startdate('19970519T090000', 'US/Eastern');
|
||||
// Change our event's date to the 20th Monday of the current year.
|
||||
$twentiethmonday = new DateTime(date('Y-01-01'));
|
||||
$twentiethmonday->modify('+20 Monday');
|
||||
$startdatetime = $this->change_event_startdate($twentiethmonday->format('Ymd\T090000'), 'US/Eastern');
|
||||
|
||||
$startdate = new DateTime($startdatetime->format('Y-m-d'));
|
||||
|
||||
@@ -2100,18 +2190,22 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
|
||||
/**
|
||||
* Monday of week number 20 (where the default start of the week is Monday), forever:
|
||||
*
|
||||
* DTSTART;TZID=US-Eastern:19970512T090000
|
||||
* DTSTART;TZID=US-Eastern:[1st day of the 20th week this year]T090000
|
||||
* RRULE:FREQ=YEARLY;BYWEEKNO=20;BYDAY=MO
|
||||
* ==> (1997 9:00 AM EDT)May 12
|
||||
* (1998 9:00 AM EDT)May 11
|
||||
* (1999 9:00 AM EDT)May 17
|
||||
* ...
|
||||
*
|
||||
* Sample results (e.g. in the year 1997):
|
||||
* (1997 9:00 AM EDT)May 12
|
||||
* (1998 9:00 AM EDT)May 11
|
||||
* (1999 9:00 AM EDT)May 17
|
||||
* ...
|
||||
*/
|
||||
public function test_yearly_byweekno_forever() {
|
||||
global $DB;
|
||||
|
||||
// Change our event's date to 12-05-1997, based on the example from the RFC.
|
||||
$startdatetime = $this->change_event_startdate('19970512T090000', 'US/Eastern');
|
||||
// Change our event's date to the start of the 20th week of the current year.
|
||||
$twentiethweek = new DateTime(date('Y-01-01'));
|
||||
$twentiethweek->setISODate($twentiethweek->format('Y'), 20);
|
||||
$startdatetime = $this->change_event_startdate($twentiethweek->format('Ymd\T090000'), 'US/Eastern');
|
||||
|
||||
$startdate = clone($startdatetime);
|
||||
$startdate->modify($startdate->format('Y-m-d'));
|
||||
@@ -2146,18 +2240,21 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
|
||||
/**
|
||||
* Every Thursday in March, forever:
|
||||
*
|
||||
* DTSTART;TZID=US-Eastern:19970313T090000
|
||||
* DTSTART;TZID=US-Eastern:[First thursday of March of the current year]T090000
|
||||
* RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=TH
|
||||
* ==> (1997 9:00 AM EST)March 13,20,27
|
||||
* (1998 9:00 AM EST)March 5,12,19,26
|
||||
* (1999 9:00 AM EST)March 4,11,18,25
|
||||
* ...
|
||||
*
|
||||
* Sample results (e.g. in the year 1997):
|
||||
* (1997 9:00 AM EST)March 13,20,27
|
||||
* (1998 9:00 AM EST)March 5,12,19,26
|
||||
* (1999 9:00 AM EST)March 4,11,18,25
|
||||
* ...
|
||||
*/
|
||||
public function test_every_thursday_in_march_forever() {
|
||||
global $DB;
|
||||
|
||||
// Change our event's date to 12-05-1997, based on the example from the RFC.
|
||||
$startdatetime = $this->change_event_startdate('19970313T090000', 'US/Eastern');
|
||||
// Change our event's date to the first Thursday of March of the current year at 9am US/Eastern time.
|
||||
$firstthursdayofmarch = new DateTime('first Thursday of March');
|
||||
$startdatetime = $this->change_event_startdate($firstthursdayofmarch->format('Ymd\T090000'), 'US/Eastern');
|
||||
|
||||
$interval = new DateInterval('P1Y');
|
||||
|
||||
@@ -2166,7 +2263,8 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
|
||||
$mang->parse_rrule();
|
||||
$mang->create_events($this->event);
|
||||
|
||||
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart');
|
||||
// Get the first 100 samples. This should be enough to verify that we have generated the recurring events correctly.
|
||||
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart', 0, 100);
|
||||
|
||||
$untildate = new DateTime();
|
||||
$untildate->add(new DateInterval('P' . $mang::TIME_UNLIMITED_YEARS . 'Y'));
|
||||
@@ -2176,7 +2274,7 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
|
||||
$startdate = new DateTime($startdatetime->format('Y-m-d'));
|
||||
$offsetinterval = $startdatetime->diff($startdate, true);
|
||||
$expecteddate->setTimezone(new DateTimeZone(get_user_timezone()));
|
||||
$april1st = new DateTime('1997-04-01');
|
||||
$april1st = new DateTime('April 1');
|
||||
foreach ($records as $record) {
|
||||
$this->assertLessThanOrEqual($untiltimestamp, $record->timestart);
|
||||
$this->assertEquals($expecteddate->format('Y-m-d H:i:s'), date('Y-m-d H:i:s', $record->timestart));
|
||||
@@ -2201,18 +2299,21 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
|
||||
/**
|
||||
* Every Thursday, but only during June, July, and August, forever:
|
||||
*
|
||||
* DTSTART;TZID=US-Eastern:19970605T090000
|
||||
* DTSTART;TZID=US-Eastern:[First Thursday of June of the current year]T090000
|
||||
* RRULE:FREQ=YEARLY;BYDAY=TH;BYMONTH=6,7,8
|
||||
* ==> (1997 9:00 AM EDT)June 5,12,19,26;July 3,10,17,24,31;August 7,14,21,28
|
||||
* (1998 9:00 AM EDT)June 4,11,18,25;July 2,9,16,23,30;August 6,13,20,27
|
||||
* (1999 9:00 AM EDT)June 3,10,17,24;July 1,8,15,22,29;August 5,12,19,26
|
||||
* ...
|
||||
*
|
||||
* Sample results (e.g. in the year 1997):
|
||||
* (1997 9:00 AM EDT)June 5,12,19,26;July 3,10,17,24,31;August 7,14,21,28
|
||||
* (1998 9:00 AM EDT)June 4,11,18,25;July 2,9,16,23,30;August 6,13,20,27
|
||||
* (1999 9:00 AM EDT)June 3,10,17,24;July 1,8,15,22,29;August 5,12,19,26
|
||||
* ...
|
||||
*/
|
||||
public function test_every_thursday_june_july_august_forever() {
|
||||
global $DB;
|
||||
|
||||
// Change our event's date to 05-06-1997, based on the example from the RFC.
|
||||
$startdatetime = $this->change_event_startdate('19970605T090000', 'US/Eastern');
|
||||
// Change our event's date to the first Thursday of June in the current year at 9am US/Eastern time.
|
||||
$firstthursdayofjune = new DateTime('first Thursday of June');
|
||||
$startdatetime = $this->change_event_startdate($firstthursdayofjune->format('Ymd\T090000'), 'US/Eastern');
|
||||
|
||||
$startdate = new DateTime($startdatetime->format('Y-m-d'));
|
||||
|
||||
@@ -2225,14 +2326,15 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
|
||||
$mang->parse_rrule();
|
||||
$mang->create_events($this->event);
|
||||
|
||||
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart');
|
||||
// Get the first 100 samples. This should be enough to verify that we have generated the recurring events correctly.
|
||||
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart', 0, 100);
|
||||
|
||||
$untildate = new DateTime();
|
||||
$untildate->add(new DateInterval('P' . $mang::TIME_UNLIMITED_YEARS . 'Y'));
|
||||
$untiltimestamp = $untildate->getTimestamp();
|
||||
|
||||
$expecteddate = new DateTime(date('Y-m-d H:i:s', $startdatetime->getTimestamp()));
|
||||
$september1st = new DateTime('1997-09-01');
|
||||
$september1st = new DateTime('September 1');
|
||||
foreach ($records as $record) {
|
||||
$this->assertLessThanOrEqual($untiltimestamp, $record->timestart);
|
||||
$this->assertEquals($expecteddate->format('Y-m-d H:i:s'), date('Y-m-d H:i:s', $record->timestart));
|
||||
@@ -2254,22 +2356,28 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
|
||||
/**
|
||||
* Every Friday the 13th, forever:
|
||||
*
|
||||
* DTSTART;TZID=US-Eastern:19970902T090000
|
||||
* EXDATE;TZID=US-Eastern:19970902T090000
|
||||
* DTSTART;TZID=US-Eastern:[Current date]T090000
|
||||
* RRULE:FREQ=MONTHLY;BYDAY=FR;BYMONTHDAY=13
|
||||
* ==> (1998 9:00 AM EST)February 13;March 13;November 13
|
||||
* (1999 9:00 AM EDT)August 13
|
||||
* (2000 9:00 AM EDT)October 13
|
||||
*
|
||||
* Sample results (e.g. in the year 1997):
|
||||
* (1998 9:00 AM EST)February 13;March 13;November 13
|
||||
* (1999 9:00 AM EDT)August 13
|
||||
* (2000 9:00 AM EDT)October 13
|
||||
* ...
|
||||
*/
|
||||
public function test_friday_the_thirteenth_forever() {
|
||||
global $DB;
|
||||
|
||||
// Change our event's date to the first Thursday of June in the current year at 9am US/Eastern time.
|
||||
$this->change_event_startdate(date('Ymd\T090000'), 'US/Eastern');
|
||||
|
||||
$rrule = 'FREQ=MONTHLY;BYDAY=FR;BYMONTHDAY=13';
|
||||
$mang = new rrule_manager($rrule);
|
||||
$mang->parse_rrule();
|
||||
$mang->create_events($this->event);
|
||||
|
||||
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart');
|
||||
// Get the first 100 samples. This should be enough to verify that we have generated the recurring events correctly.
|
||||
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart', 0, 100);
|
||||
|
||||
$untildate = new DateTime();
|
||||
$untildate->add(new DateInterval('P' . $mang::TIME_UNLIMITED_YEARS . 'Y'));
|
||||
@@ -2285,17 +2393,22 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
|
||||
/**
|
||||
* The first Saturday that follows the first Sunday of the month, forever:
|
||||
*
|
||||
* DTSTART;TZID=US-Eastern:19970913T090000
|
||||
* DTSTART;TZID=US-Eastern:[The Saturday after the month's first Sunday]T090000
|
||||
* RRULE:FREQ=MONTHLY;BYDAY=SA;BYMONTHDAY=7,8,9,10,11,12,13
|
||||
* ==> (1997 9:00 AM EDT)September 13;October 11
|
||||
* (1997 9:00 AM EST)November 8;December 13
|
||||
* (1998 9:00 AM EST)January 10;February 7;March 7
|
||||
* (1998 9:00 AM EDT)April 11;May 9;June 13...
|
||||
*
|
||||
* Sample results (e.g. from 13 September 1997):
|
||||
* (1997 9:00 AM EDT)September 13;October 11
|
||||
* (1997 9:00 AM EST)November 8;December 13
|
||||
* (1998 9:00 AM EST)January 10;February 7;March 7
|
||||
* (1998 9:00 AM EDT)April 11;May 9;June 13...
|
||||
*/
|
||||
public function test_first_saturday_following_first_sunday_forever() {
|
||||
global $DB;
|
||||
|
||||
$startdatetime = $this->change_event_startdate('19970913T090000', 'US/Eastern');
|
||||
// Change our event's date to the next Saturday after the first Sunday of the the current month at 9am US/Eastern time.
|
||||
$firstsaturdayafterfirstsunday = new DateTime('first Sunday of this month');
|
||||
$firstsaturdayafterfirstsunday->modify('next Saturday');
|
||||
$startdatetime = $this->change_event_startdate($firstsaturdayafterfirstsunday->format('Ymd\T090000'), 'US/Eastern');
|
||||
$startdate = new DateTime($startdatetime->format('Y-m-d'));
|
||||
$offset = $startdatetime->diff($startdate, true);
|
||||
|
||||
@@ -2304,7 +2417,8 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
|
||||
$mang->parse_rrule();
|
||||
$mang->create_events($this->event);
|
||||
|
||||
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart');
|
||||
// Get the first 100 samples. This should be enough to verify that we have generated the recurring events correctly.
|
||||
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart', 0, 100);
|
||||
|
||||
$untildate = new DateTime();
|
||||
$untildate->add(new DateInterval('P' . $mang::TIME_UNLIMITED_YEARS . 'Y'));
|
||||
@@ -2330,17 +2444,29 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
|
||||
/**
|
||||
* Every four years, the first Tuesday after a Monday in November, forever (U.S. Presidential Election day):
|
||||
*
|
||||
* DTSTART;TZID=US-Eastern:19961105T090000
|
||||
* DTSTART;TZID=US-Eastern:[Most recent election date]T090000
|
||||
* RRULE:FREQ=YEARLY;INTERVAL=4;BYMONTH=11;BYDAY=TU;BYMONTHDAY=2,3,4,5,6,7,8
|
||||
* ==> (1996 9:00 AM EST)November 5
|
||||
* (2000 9:00 AM EST)November 7
|
||||
* (2004 9:00 AM EST)November 2
|
||||
* ...
|
||||
*
|
||||
* Sample results (e.g. from 05 November 1996):
|
||||
* (1996 9:00 AM EST)November 5
|
||||
* (2000 9:00 AM EST)November 7
|
||||
* (2004 9:00 AM EST)November 2
|
||||
* ...
|
||||
*/
|
||||
public function test_every_us_presidential_election_forever() {
|
||||
global $DB;
|
||||
|
||||
$startdatetime = $this->change_event_startdate('19961105T090000', 'US/Eastern');
|
||||
// Calculate the most recent election date, starting from 1996 (e.g. today's 2017 so the most recent election was in 2016).
|
||||
$currentyear = (int) date('Y');
|
||||
$electionyear = 1996;
|
||||
while ($electionyear + 4 < $currentyear) {
|
||||
$electionyear += 4;
|
||||
}
|
||||
$electiondate = new DateTime('first Monday of November ' . $electionyear);
|
||||
$electiondate->modify('+1 Tuesday');
|
||||
|
||||
// Use the most recent election date as the starting date of our recurring events.
|
||||
$startdatetime = $this->change_event_startdate($electiondate->format('Ymd\T090000'), 'US/Eastern');
|
||||
$startdate = new DateTime($startdatetime->format('Y-m-d'));
|
||||
$offset = $startdatetime->diff($startdate, true);
|
||||
|
||||
@@ -2407,23 +2533,27 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
|
||||
* The 2nd to last weekday of the month:
|
||||
*
|
||||
* DTSTART;TZID=US-Eastern:19970929T090000
|
||||
* RRULE:FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-2
|
||||
* RRULE:FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-2;COUNT=7
|
||||
* ==> (1997 9:00 AM EDT)September 29
|
||||
* (1997 9:00 AM EST)October 30;November 27;December 30
|
||||
* (1998 9:00 AM EST)January 29;February 26;March 30
|
||||
* ...
|
||||
*
|
||||
* (Original RFC example is set to recur forever. But we just want to verify that the results match the dates listed from
|
||||
* the RFC example. So just limit the count to 7.)
|
||||
*/
|
||||
public function test_second_to_the_last_weekday_of_the_month_forever() {
|
||||
public function test_second_to_the_last_weekday_of_the_month() {
|
||||
global $DB;
|
||||
|
||||
$this->change_event_startdate('19970929T090000', 'US/Eastern');
|
||||
|
||||
$rrule = 'FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-2';
|
||||
$rrule = 'FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-2;COUNT=7';
|
||||
$mang = new rrule_manager($rrule);
|
||||
$mang->parse_rrule();
|
||||
$mang->create_events($this->event);
|
||||
|
||||
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart');
|
||||
// Get the first 7 samples. This should be enough to verify that we have generated the recurring events correctly.
|
||||
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart', 0, 7);
|
||||
|
||||
$expecteddates = [
|
||||
(new DateTime('1997-09-29 09:00:00 EDT'))->getTimestamp(),
|
||||
@@ -2444,10 +2574,8 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
|
||||
$this->assertLessThanOrEqual($untiltimestamp, $record->timestart);
|
||||
|
||||
// Confirm that the first 7 records correspond to the expected dates listed above.
|
||||
if ($i < 7) {
|
||||
$this->assertEquals($expecteddates[$i], $record->timestart);
|
||||
$i++;
|
||||
}
|
||||
$this->assertEquals($expecteddates[$i], $record->timestart);
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2747,13 +2875,19 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
|
||||
/**
|
||||
* Change the event's timestart (DTSTART) based on the test's needs.
|
||||
*
|
||||
* @param string $datestr The date string. In YYYYmmddThhiiss format. e.g. 19990902T090000.
|
||||
* @param string $timezonestr A valid timezone string. e.g. 'US/Eastern'.
|
||||
* @param string $datestr The date string. In 'Ymd\This' format. e.g. 19990902T090000.
|
||||
* @param null|string $timezonestr A valid timezone string. e.g. 'US/Eastern'.
|
||||
* If not provided, the default timezone will be used.
|
||||
* @return bool|DateTime
|
||||
*/
|
||||
protected function change_event_startdate($datestr, $timezonestr) {
|
||||
$timezone = new DateTimeZone($timezonestr);
|
||||
$newdatetime = DateTime::createFromFormat('Ymd\THis', $datestr, $timezone);
|
||||
protected function change_event_startdate($datestr, $timezonestr = null) {
|
||||
// Use default timezone if not provided.
|
||||
if ($timezonestr === null) {
|
||||
$newdatetime = DateTime::createFromFormat('Ymd\THis', $datestr);
|
||||
} else {
|
||||
$timezone = new DateTimeZone($timezonestr);
|
||||
$newdatetime = DateTime::createFromFormat('Ymd\THis', $datestr, $timezone);
|
||||
}
|
||||
|
||||
// Update the start date of the parent event.
|
||||
$calevent = calendar_event::load($this->event->id);
|
||||
|
||||
+3
-2
@@ -85,7 +85,8 @@ $url->param('time', $time);
|
||||
$PAGE->set_url($url);
|
||||
|
||||
if ($courseid != SITEID && !empty($courseid)) {
|
||||
$course = $DB->get_record('course', array('id' => $courseid));
|
||||
// Course ID must be valid and existing.
|
||||
$course = $DB->get_record('course', array('id' => $courseid), '*', MUST_EXIST);
|
||||
$courses = array($course->id => $course);
|
||||
$issite = false;
|
||||
navigation_node::override_active_url(new moodle_url('/course/view.php', array('id' => $course->id)));
|
||||
@@ -95,7 +96,7 @@ if ($courseid != SITEID && !empty($courseid)) {
|
||||
$issite = true;
|
||||
}
|
||||
|
||||
require_course_login($course);
|
||||
require_login($course, false);
|
||||
|
||||
$calendar = new calendar_information(0, 0, 0, $time);
|
||||
$calendar->prepare_for_view($course, $courses);
|
||||
|
||||
@@ -243,7 +243,9 @@ class course_competency extends persistent {
|
||||
public static function list_courses($competencyid) {
|
||||
global $DB;
|
||||
|
||||
$results = $DB->get_records_sql('SELECT course.id, course.visible, course.shortname, course.idnumber, course.fullname
|
||||
$results = $DB->get_records_sql('SELECT course.id, course.visible, course.shortname, course.idnumber,
|
||||
course.fullname, course.summary, course.summaryformat, course.startdate,
|
||||
course.enddate
|
||||
FROM {course} course
|
||||
JOIN {' . self::TABLE . '} coursecomp
|
||||
ON coursecomp.courseid = course.id
|
||||
|
||||
@@ -243,6 +243,8 @@ class user_competency_course extends persistent {
|
||||
|
||||
$sql = 'SELECT COUNT(comp.id)
|
||||
FROM {' . self::TABLE . '} usercoursecomp
|
||||
JOIN {' . course_competency::TABLE . '} cc
|
||||
ON usercoursecomp.competencyid = cc.competencyid AND cc.courseid = usercoursecomp.courseid
|
||||
JOIN {' . competency::TABLE . '} comp
|
||||
ON usercoursecomp.competencyid = comp.id
|
||||
WHERE usercoursecomp.courseid = ? AND usercoursecomp.userid = ? AND usercoursecomp.proficiency = ?';
|
||||
|
||||
@@ -74,7 +74,16 @@ class completion_completion extends data_object {
|
||||
* @return data_object instance of data_object or false if none found.
|
||||
*/
|
||||
public static function fetch($params) {
|
||||
return self::fetch_helper('course_completions', __CLASS__, $params);
|
||||
$cache = cache::make('core', 'coursecompletion');
|
||||
|
||||
$key = $params['userid'] . '_' . $params['course'];
|
||||
if ($hit = $cache->get($key)) {
|
||||
return $hit['value'];
|
||||
}
|
||||
|
||||
$tocache = self::fetch_helper('course_completions', __CLASS__, $params);
|
||||
$cache->set($key, ['value' => $tocache]);
|
||||
return $tocache;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -179,9 +188,10 @@ class completion_completion extends data_object {
|
||||
$this->timeenrolled = 0;
|
||||
}
|
||||
|
||||
$result = false;
|
||||
// Save record
|
||||
if ($this->id) {
|
||||
return $this->update();
|
||||
$result = $this->update();
|
||||
} else {
|
||||
// Make sure reaggregate field is not null
|
||||
if (!$this->reaggregate) {
|
||||
@@ -193,7 +203,17 @@ class completion_completion extends data_object {
|
||||
$this->timestarted = 0;
|
||||
}
|
||||
|
||||
return $this->insert();
|
||||
$result = $this->insert();
|
||||
}
|
||||
|
||||
if ($result) {
|
||||
// Update the cached record.
|
||||
$cache = cache::make('core', 'coursecompletion');
|
||||
$data = $this->get_record_data();
|
||||
$key = $data->userid . '_' . $data->course;
|
||||
$cache->set($key, ['value' => $data]);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -724,6 +724,11 @@ class core_course_external extends external_api {
|
||||
//Note: create_course() core function check shortname, idnumber, category
|
||||
$course['id'] = create_course((object) $course)->id;
|
||||
|
||||
// Create sections that aren't created by core create_course().
|
||||
if (!empty($course['numsections']) && $course['numsections'] > 0) {
|
||||
course_create_sections_if_missing((object)$course, range(0, $course['numsections']));
|
||||
}
|
||||
|
||||
$resultcourses[] = array('id' => $course['id'], 'shortname' => $course['shortname']);
|
||||
}
|
||||
|
||||
|
||||
+47
-1
@@ -55,6 +55,10 @@ define('FIRSTUSEDEXCELROW', 3);
|
||||
define('MOD_CLASS_ACTIVITY', 0);
|
||||
define('MOD_CLASS_RESOURCE', 1);
|
||||
|
||||
define('COURSE_TIMELINE_PAST', 'past');
|
||||
define('COURSE_TIMELINE_INPROGRESS', 'inprogress');
|
||||
define('COURSE_TIMELINE_FUTURE', 'future');
|
||||
|
||||
function make_log_url($module, $url) {
|
||||
switch ($module) {
|
||||
case 'course':
|
||||
@@ -1153,8 +1157,10 @@ function course_delete_module($cmid, $async = false) {
|
||||
|
||||
// Delete events from calendar.
|
||||
if ($events = $DB->get_records('event', array('instance' => $cm->instance, 'modulename' => $modulename))) {
|
||||
$coursecontext = context_course::instance($cm->course);
|
||||
foreach($events as $event) {
|
||||
$calendarevent = calendar_event::load($event->id);
|
||||
$event->context = $coursecontext;
|
||||
$calendarevent = calendar_event::load($event);
|
||||
$calendarevent->delete();
|
||||
}
|
||||
}
|
||||
@@ -3920,6 +3926,46 @@ function course_check_updates($course, $tocheck, $filter = array()) {
|
||||
return array($instances, $warnings);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function classifies a course as past, in progress or future.
|
||||
*
|
||||
* This function may incur a DB hit to calculate course completion.
|
||||
* @param stdClass $course Course record
|
||||
* @param stdClass $user User record (optional - defaults to $USER).
|
||||
* @param completion_info $completioninfo Completion record for the user (optional - will be fetched if required).
|
||||
* @return string (one of COURSE_TIMELINE_FUTURE, COURSE_TIMELINE_INPROGRESS or COURSE_TIMELINE_PAST)
|
||||
*/
|
||||
function course_classify_for_timeline($course, $user = null, $completioninfo = null) {
|
||||
global $USER;
|
||||
|
||||
if ($user == null) {
|
||||
$user = $USER;
|
||||
}
|
||||
|
||||
$today = time();
|
||||
// End date past.
|
||||
if (!empty($course->enddate) && $course->enddate < $today) {
|
||||
return COURSE_TIMELINE_PAST;
|
||||
}
|
||||
|
||||
if ($completioninfo == null) {
|
||||
$completioninfo = new completion_info($course);
|
||||
}
|
||||
|
||||
// Course was completed.
|
||||
if ($completioninfo->is_enabled() && $completioninfo->is_course_complete($user->id)) {
|
||||
return COURSE_TIMELINE_PAST;
|
||||
}
|
||||
|
||||
// Start date not reached.
|
||||
if (!empty($course->startdate) && $course->startdate > $today) {
|
||||
return COURSE_TIMELINE_FUTURE;
|
||||
}
|
||||
|
||||
// Everything else is in progress.
|
||||
return COURSE_TIMELINE_INPROGRESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check module updates since a given time.
|
||||
* This function checks for updates in the module config, file areas, completion, grades, comments and ratings.
|
||||
|
||||
@@ -20,16 +20,18 @@
|
||||
// //
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
/**
|
||||
* This page display the publication backup form
|
||||
*
|
||||
* @package course
|
||||
* @subpackage publish
|
||||
* @author Jerome Mouneyrac <jerome@mouneyrac.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL
|
||||
* @copyright (C) 1999 onwards Martin Dougiamas http://dougiamas.com
|
||||
*
|
||||
* This page display the publication backup form
|
||||
*/
|
||||
|
||||
define('NO_OUTPUT_BUFFERING', true);
|
||||
|
||||
require_once('../../config.php');
|
||||
require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
|
||||
require_once($CFG->dirroot . '/backup/moodle2/backup_plan_builder.class.php');
|
||||
|
||||
@@ -101,7 +101,8 @@ if ($switchrole > 0 && has_capability('moodle/role:switchroles', $context)) {
|
||||
|
||||
foreach ($roles as $key => $role) {
|
||||
$url = new moodle_url('/course/switchrole.php', array('id' => $id, 'switchrole' => $key, 'returnurl' => $returnurl));
|
||||
echo $OUTPUT->container($OUTPUT->single_button($url, $role), 'm-x-3 m-b-1');
|
||||
// Button encodes special characters, apply htmlspecialchars_decode() to avoid double escaping.
|
||||
echo $OUTPUT->container($OUTPUT->single_button($url, htmlspecialchars_decode($role)), 'm-x-3 m-b-1');
|
||||
}
|
||||
|
||||
$url = new moodle_url($returnurl);
|
||||
|
||||
@@ -3689,4 +3689,52 @@ class core_course_courselib_testcase extends advanced_testcase {
|
||||
}
|
||||
$this->assertEquals(2, $count);
|
||||
}
|
||||
|
||||
public function test_classify_course_for_timeline() {
|
||||
global $DB, $CFG;
|
||||
|
||||
require_once($CFG->dirroot.'/completion/criteria/completion_criteria_self.php');
|
||||
|
||||
set_config('enablecompletion', COMPLETION_ENABLED);
|
||||
|
||||
$this->resetAfterTest(true);
|
||||
$this->setAdminUser();
|
||||
|
||||
// Create courses for testing.
|
||||
$generator = $this->getDataGenerator();
|
||||
$future = time() + 3600;
|
||||
$past = time() - 3600;
|
||||
$futurecourse = $generator->create_course(['startdate' => $future]);
|
||||
$pastcourse = $generator->create_course(['startdate' => $past - 60, 'enddate' => $past]);
|
||||
$completedcourse = $generator->create_course(['enablecompletion' => COMPLETION_ENABLED]);
|
||||
$inprogresscourse = $generator->create_course();
|
||||
|
||||
// Set completion rules.
|
||||
$criteriadata = new stdClass();
|
||||
$criteriadata->id = $completedcourse->id;
|
||||
|
||||
// Self completion.
|
||||
$criteriadata->criteria_self = COMPLETION_CRITERIA_TYPE_SELF;
|
||||
$class = 'completion_criteria_self';
|
||||
$criterion = new $class();
|
||||
$criterion->update_config($criteriadata);
|
||||
|
||||
$user = $this->getDataGenerator()->create_user();
|
||||
$studentrole = $DB->get_record('role', array('shortname' => 'student'));
|
||||
$this->getDataGenerator()->enrol_user($user->id, $futurecourse->id, $studentrole->id);
|
||||
$this->getDataGenerator()->enrol_user($user->id, $pastcourse->id, $studentrole->id);
|
||||
$this->getDataGenerator()->enrol_user($user->id, $completedcourse->id, $studentrole->id);
|
||||
$this->getDataGenerator()->enrol_user($user->id, $inprogresscourse->id, $studentrole->id);
|
||||
|
||||
$this->setUser($user);
|
||||
core_completion_external::mark_course_self_completed($completedcourse->id);
|
||||
$ccompletion = new completion_completion(array('course' => $completedcourse->id, 'userid' => $user->id));
|
||||
$ccompletion->mark_complete();
|
||||
|
||||
// Aggregate the completions.
|
||||
$this->assertEquals(COURSE_TIMELINE_PAST, course_classify_for_timeline($pastcourse));
|
||||
$this->assertEquals(COURSE_TIMELINE_FUTURE, course_classify_for_timeline($futurecourse));
|
||||
$this->assertEquals(COURSE_TIMELINE_PAST, course_classify_for_timeline($completedcourse));
|
||||
$this->assertEquals(COURSE_TIMELINE_INPROGRESS, course_classify_for_timeline($inprogresscourse));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -361,6 +361,40 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
|
||||
core_course_external::update_categories($categories);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test create_courses numsections
|
||||
*/
|
||||
public function test_create_course_numsections() {
|
||||
global $DB;
|
||||
|
||||
$this->resetAfterTest(true);
|
||||
|
||||
// Set the required capabilities by the external function.
|
||||
$contextid = context_system::instance()->id;
|
||||
$roleid = $this->assignUserCapability('moodle/course:create', $contextid);
|
||||
$this->assignUserCapability('moodle/course:visibility', $contextid, $roleid);
|
||||
|
||||
$numsections = 10;
|
||||
$category = self::getDataGenerator()->create_category();
|
||||
|
||||
// Create base categories.
|
||||
$course1['fullname'] = 'Test course 1';
|
||||
$course1['shortname'] = 'Testcourse1';
|
||||
$course1['categoryid'] = $category->id;
|
||||
$course1['courseformatoptions'][] = array('name' => 'numsections', 'value' => $numsections);
|
||||
|
||||
$courses = array($course1);
|
||||
|
||||
$createdcourses = core_course_external::create_courses($courses);
|
||||
foreach ($createdcourses as $createdcourse) {
|
||||
$existingsections = $DB->get_records('course_sections', array('course' => $createdcourse['id']));
|
||||
$modinfo = get_fast_modinfo($createdcourse['id']);
|
||||
$sections = $modinfo->get_section_info_all();
|
||||
$this->assertEquals(count($sections), $numsections + 1); // Includes generic section.
|
||||
$this->assertEquals(count($existingsections), $numsections + 1); // Includes generic section.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test create_courses
|
||||
*/
|
||||
|
||||
@@ -42,11 +42,9 @@ class writer extends \core\dataformat\base {
|
||||
public $extension = ".html";
|
||||
|
||||
/**
|
||||
* Write the start of the format
|
||||
*
|
||||
* @param array $columns
|
||||
* Write the start of the output
|
||||
*/
|
||||
public function write_header($columns) {
|
||||
public function start_output() {
|
||||
echo "<!DOCTYPE html><html>";
|
||||
echo \html_writer::tag('title', $this->filename);
|
||||
echo "<style>
|
||||
@@ -75,9 +73,16 @@ table {
|
||||
margin: auto;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<table border=1 cellspacing=0 cellpadding=3>
|
||||
";
|
||||
<body>";
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the start of the sheet we will be adding data to.
|
||||
*
|
||||
* @param array $columns
|
||||
*/
|
||||
public function start_sheet($columns) {
|
||||
echo "<table border=1 cellspacing=0 cellpadding=3>";
|
||||
echo \html_writer::start_tag('tr');
|
||||
foreach ($columns as $k => $v) {
|
||||
echo \html_writer::tag('th', $v);
|
||||
@@ -100,12 +105,18 @@ table {
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the end of the format
|
||||
* Write the end of the sheet containing the data.
|
||||
*
|
||||
* @param array $columns
|
||||
*/
|
||||
public function write_footer($columns) {
|
||||
echo "</table></body></html>";
|
||||
public function close_sheet($columns) {
|
||||
echo "</table>";
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the end of the sheet containing the data.
|
||||
*/
|
||||
public function close_output() {
|
||||
echo "</body></html>";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,12 +41,31 @@ class writer extends \core\dataformat\base {
|
||||
/** @var $extension */
|
||||
public $extension = ".json";
|
||||
|
||||
/** @var $sheetstarted */
|
||||
public $sheetstarted = false;
|
||||
|
||||
/** @var $sheetdatadded */
|
||||
public $sheetdatadded = false;
|
||||
|
||||
/**
|
||||
* Write the start of the format
|
||||
* Write the start of the file.
|
||||
*/
|
||||
public function start_output() {
|
||||
echo "[";
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the start of the sheet we will be adding data to.
|
||||
*
|
||||
* @param array $columns
|
||||
*/
|
||||
public function write_header($columns) {
|
||||
public function start_sheet($columns) {
|
||||
if ($this->sheetstarted) {
|
||||
echo ",";
|
||||
} else {
|
||||
$this->sheetstarted = true;
|
||||
}
|
||||
$this->sheetdatadded = false;
|
||||
echo "[";
|
||||
}
|
||||
|
||||
@@ -57,19 +76,28 @@ class writer extends \core\dataformat\base {
|
||||
* @param int $rownum
|
||||
*/
|
||||
public function write_record($record, $rownum) {
|
||||
if ($rownum) {
|
||||
if ($this->sheetdatadded) {
|
||||
echo ",";
|
||||
}
|
||||
|
||||
echo json_encode($record);
|
||||
|
||||
$this->sheetdatadded = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the end of the format
|
||||
* Write the end of the sheet containing the data.
|
||||
*
|
||||
* @param array $columns
|
||||
*/
|
||||
public function write_footer($columns) {
|
||||
public function close_sheet($columns) {
|
||||
echo "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the end of the file.
|
||||
*/
|
||||
public function close_output() {
|
||||
echo "]";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
This files describes API changes in /dataformat/ download system,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
=== 3.2.4 ===
|
||||
|
||||
* In order to allow multiple sheets in an exported file the functions write_header() and write_footer() have
|
||||
been removed from core dataformat plugins and have been replaced.
|
||||
- write_header() has been replaced with the two functions start_output() and start_sheet().
|
||||
- write_footer() has been replaced with the two functions close_output() and close_sheet().
|
||||
For backwards compatibility write_header() and write_footer() will continue to work.
|
||||
|
||||
=== 3.1 ===
|
||||
* Added new plugin system with low memory support for csv, ods, xls and json
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ class enrol_guest_enrol_form extends moodleform {
|
||||
$heading = $plugin->get_instance_name($instance);
|
||||
$mform->addElement('header', 'guestheader', $heading);
|
||||
|
||||
$mform->addElement('passwordunmask', 'guestpassword', get_string('password', 'enrol_guest'));
|
||||
$mform->addElement('password', 'guestpassword', get_string('password', 'enrol_guest'));
|
||||
|
||||
$this->add_action_buttons(false, get_string('submit'));
|
||||
|
||||
|
||||
+2
-2
@@ -328,7 +328,7 @@ class enrol_ldap_plugin extends enrol_plugin {
|
||||
return;
|
||||
}
|
||||
|
||||
$ldap_pagedresults = ldap_paged_results_supported($this->get_config('ldap_version'));
|
||||
$ldap_pagedresults = ldap_paged_results_supported($this->get_config('ldap_version'), $this->ldapconnection);
|
||||
|
||||
// we may need a lot of memory here
|
||||
core_php_time_limit::raise();
|
||||
@@ -761,7 +761,7 @@ class enrol_ldap_plugin extends enrol_plugin {
|
||||
|
||||
// Get all contexts and look for first matching user
|
||||
$ldap_contexts = explode(';', $ldap_contexts);
|
||||
$ldap_pagedresults = ldap_paged_results_supported($this->get_config('ldap_version'));
|
||||
$ldap_pagedresults = ldap_paged_results_supported($this->get_config('ldap_version'), $this->ldapconnection);
|
||||
foreach ($ldap_contexts as $context) {
|
||||
$context = trim($context);
|
||||
if (empty($context)) {
|
||||
|
||||
@@ -78,7 +78,7 @@ class enrol_self_enrol_form extends moodleform {
|
||||
|
||||
if ($instance->password) {
|
||||
// Change the id of self enrolment key input as there can be multiple self enrolment methods.
|
||||
$mform->addElement('passwordunmask', 'enrolpassword', get_string('password', 'enrol_self'),
|
||||
$mform->addElement('password', 'enrolpassword', get_string('password', 'enrol_self'),
|
||||
array('id' => 'enrolpassword_'.$instance->id));
|
||||
$context = context_course::instance($this->instance->courseid);
|
||||
$keyholders = get_users_by_capability($context, 'enrol/self:holdkey', user_picture::fields('u'));
|
||||
|
||||
@@ -32,7 +32,7 @@ $action = optional_param('action', '', PARAM_ALPHA);
|
||||
/// Make sure they can even access this course
|
||||
if ($courseid) {
|
||||
if (!$course = $DB->get_record('course', array('id' => $courseid))) {
|
||||
print_error('nocourseid');
|
||||
print_error('invalidcourseid');
|
||||
}
|
||||
require_login($course);
|
||||
$context = context_course::instance($course->id);
|
||||
|
||||
@@ -38,7 +38,7 @@ $PAGE->set_pagelayout('admin');
|
||||
/// Make sure they can even access this course
|
||||
if ($courseid) {
|
||||
if (!$course = $DB->get_record('course', array('id' => $courseid))) {
|
||||
print_error('nocourseid');
|
||||
print_error('invalidcourseid');
|
||||
}
|
||||
require_login($course);
|
||||
$context = context_course::instance($course->id);
|
||||
|
||||
@@ -71,7 +71,7 @@ if ($id) {
|
||||
$heading = get_string('addscale', 'grades');
|
||||
/// adding new scale from course
|
||||
if (!$course = $DB->get_record('course', array('id' => $courseid))) {
|
||||
print_error('nocourseid');
|
||||
print_error('invalidcourseid');
|
||||
}
|
||||
$scale_rec = new stdClass();
|
||||
$scale_rec->standard = 0;
|
||||
|
||||
@@ -34,7 +34,7 @@ $PAGE->set_url('/grade/edit/scale/index.php', array('id' => $courseid));
|
||||
/// Make sure they can even access this course
|
||||
if ($courseid) {
|
||||
if (!$course = $DB->get_record('course', array('id' => $courseid))) {
|
||||
print_error('nocourseid');
|
||||
print_error('invalidcourseid');
|
||||
}
|
||||
require_login($course);
|
||||
$context = context_course::instance($course->id);
|
||||
|
||||
@@ -33,7 +33,7 @@ $PAGE->set_url('/grade/edit/settings/index.php', array('id'=>$courseid));
|
||||
$PAGE->set_pagelayout('admin');
|
||||
|
||||
if (!$course = $DB->get_record('course', array('id' => $courseid))) {
|
||||
print_error('nocourseid');
|
||||
print_error('invalidcourseid');
|
||||
}
|
||||
require_login($course);
|
||||
$context = context_course::instance($course->id);
|
||||
|
||||
@@ -33,7 +33,7 @@ $PAGE->set_url('/grade/edit/tree/action.php', array('id'=>$courseid, 'action'=>$
|
||||
|
||||
/// Make sure they can even access this course
|
||||
if (!$course = $DB->get_record('course', array('id' => $courseid))) {
|
||||
print_error('nocourseid');
|
||||
print_error('invalidcourseid');
|
||||
}
|
||||
require_login($course);
|
||||
$context = context_course::instance($course->id);
|
||||
|
||||
@@ -39,7 +39,7 @@ if ($section !== 'calculation') {
|
||||
$PAGE->set_url($url);
|
||||
|
||||
if (!$course = $DB->get_record('course', array('id' => $courseid))) {
|
||||
print_error('nocourseid');
|
||||
print_error('invalidcourseid');
|
||||
}
|
||||
|
||||
require_login($course);
|
||||
|
||||
@@ -40,7 +40,7 @@ navigation_node::override_active_url(new moodle_url('/grade/edit/tree/index.php'
|
||||
array('id'=>$courseid)));
|
||||
|
||||
if (!$course = $DB->get_record('course', array('id' => $courseid))) {
|
||||
print_error('nocourseid');
|
||||
print_error('invalidcourseid');
|
||||
}
|
||||
|
||||
require_login($course);
|
||||
|
||||
@@ -45,7 +45,7 @@ if ($userid !== 0) {
|
||||
$PAGE->set_url($url);
|
||||
|
||||
if (!$course = $DB->get_record('course', array('id' => $courseid))) {
|
||||
print_error('nocourseid');
|
||||
print_error('invalidcourseid');
|
||||
}
|
||||
|
||||
$PAGE->set_pagelayout('incourse');
|
||||
|
||||
@@ -38,7 +38,7 @@ $PAGE->set_pagelayout('admin');
|
||||
|
||||
/// Make sure they can even access this course
|
||||
if (!$course = $DB->get_record('course', array('id' => $courseid))) {
|
||||
print_error('nocourseid');
|
||||
print_error('invalidcourseid');
|
||||
}
|
||||
|
||||
require_login($course);
|
||||
|
||||
@@ -41,7 +41,7 @@ navigation_node::override_active_url(new moodle_url('/grade/edit/tree/index.php'
|
||||
array('id'=>$courseid)));
|
||||
|
||||
if (!$course = $DB->get_record('course', array('id' => $courseid))) {
|
||||
print_error('nocourseid');
|
||||
print_error('invalidcourseid');
|
||||
}
|
||||
|
||||
require_login($course);
|
||||
|
||||
@@ -40,7 +40,7 @@ navigation_node::override_active_url(new moodle_url('/grade/edit/tree/index.php'
|
||||
array('id'=>$courseid)));
|
||||
|
||||
if (!$course = $DB->get_record('course', array('id' => $courseid))) {
|
||||
print_error('nocourseid');
|
||||
print_error('invalidcourseid');
|
||||
}
|
||||
|
||||
require_login($course);
|
||||
|
||||
@@ -31,7 +31,7 @@ $id = required_param('id', PARAM_INT); // course id
|
||||
$PAGE->set_url('/grade/export/keymanager.php', array('id' => $id));
|
||||
|
||||
if (!$course = $DB->get_record('course', array('id'=>$id))) {
|
||||
print_error('nocourseid');
|
||||
print_error('invalidcourseid');
|
||||
}
|
||||
|
||||
require_login($course);
|
||||
|
||||
@@ -28,7 +28,7 @@ $decimalpoints = optional_param('decimalpoints', $CFG->grade_export_decimal
|
||||
$onlyactive = optional_param('export_onlyactive', 0, PARAM_BOOL);
|
||||
|
||||
if (!$course = $DB->get_record('course', array('id'=>$id))) {
|
||||
print_error('nocourseid');
|
||||
print_error('invalidcourseid');
|
||||
}
|
||||
|
||||
require_user_key_login('grade/export', $id); // we want different keys for each course
|
||||
|
||||
@@ -23,7 +23,7 @@ $id = required_param('id', PARAM_INT); // course id
|
||||
$PAGE->set_url('/grade/export/ods/export.php', array('id'=>$id));
|
||||
|
||||
if (!$course = $DB->get_record('course', array('id'=>$id))) {
|
||||
print_error('nocourseid');
|
||||
print_error('invalidcourseid');
|
||||
}
|
||||
|
||||
require_login($course);
|
||||
|
||||
@@ -24,7 +24,7 @@ $id = required_param('id', PARAM_INT); // course id
|
||||
$PAGE->set_url('/grade/export/ods/index.php', array('id'=>$id));
|
||||
|
||||
if (!$course = $DB->get_record('course', array('id'=>$id))) {
|
||||
print_error('nocourseid');
|
||||
print_error('invalidcourseid');
|
||||
}
|
||||
|
||||
require_login($course);
|
||||
|
||||
@@ -29,7 +29,7 @@ $decimalpoints = optional_param('decimalpoints', $CFG->grade_export_decimal
|
||||
$onlyactive = optional_param('export_onlyactive', 0, PARAM_BOOL);
|
||||
|
||||
if (!$course = $DB->get_record('course', array('id'=>$id))) {
|
||||
print_error('nocourseid');
|
||||
print_error('invalidcourseid');
|
||||
}
|
||||
|
||||
require_user_key_login('grade/export', $id); // we want different keys for each course
|
||||
|
||||
@@ -23,7 +23,7 @@ $id = required_param('id', PARAM_INT); // course id
|
||||
$PAGE->set_url('/grade/export/txt/export.php', array('id'=>$id));
|
||||
|
||||
if (!$course = $DB->get_record('course', array('id'=>$id))) {
|
||||
print_error('nocourseid');
|
||||
print_error('invalidcourseid');
|
||||
}
|
||||
|
||||
require_login($course);
|
||||
|
||||
@@ -24,7 +24,7 @@ $id = required_param('id', PARAM_INT); // course id
|
||||
$PAGE->set_url('/grade/export/txt/index.php', array('id'=>$id));
|
||||
|
||||
if (!$course = $DB->get_record('course', array('id'=>$id))) {
|
||||
print_error('nocourseid');
|
||||
print_error('invalidcourseid');
|
||||
}
|
||||
|
||||
require_login($course);
|
||||
|
||||
@@ -28,7 +28,7 @@ $decimalpoints = optional_param('decimalpoints', $CFG->grade_export_decimal
|
||||
$onlyactive = optional_param('export_onlyactive', 0, PARAM_BOOL);
|
||||
|
||||
if (!$course = $DB->get_record('course', array('id'=>$id))) {
|
||||
print_error('nocourseid');
|
||||
print_error('invalidcourseid');
|
||||
}
|
||||
|
||||
require_user_key_login('grade/export', $id); // we want different keys for each course
|
||||
|
||||
@@ -23,7 +23,7 @@ $id = required_param('id', PARAM_INT); // course id
|
||||
$PAGE->set_url('/grade/export/xls/export.php', array('id'=>$id));
|
||||
|
||||
if (!$course = $DB->get_record('course', array('id'=>$id))) {
|
||||
print_error('nocourseid');
|
||||
print_error('invalidcourseid');
|
||||
}
|
||||
|
||||
require_login($course);
|
||||
|
||||
@@ -24,7 +24,7 @@ $id = required_param('id', PARAM_INT); // course id
|
||||
$PAGE->set_url('/grade/export/xls/index.php', array('id'=>$id));
|
||||
|
||||
if (!$course = $DB->get_record('course', array('id'=>$id))) {
|
||||
print_error('nocourseid');
|
||||
print_error('invalidcourseid');
|
||||
}
|
||||
|
||||
require_login($course);
|
||||
|
||||
@@ -29,7 +29,7 @@ $decimalpoints = optional_param('decimalpoints', $CFG->grade_export_decimal
|
||||
$onlyactive = optional_param('export_onlyactive', 0, PARAM_BOOL);
|
||||
|
||||
if (!$course = $DB->get_record('course', array('id'=>$id))) {
|
||||
print_error('nocourseid');
|
||||
print_error('invalidcourseid');
|
||||
}
|
||||
|
||||
require_user_key_login('grade/export', $id); // we want different keys for each course
|
||||
|
||||
@@ -23,7 +23,7 @@ $id = required_param('id', PARAM_INT); // course id
|
||||
$PAGE->set_url('/grade/export/xml/export.php', array('id'=>$id));
|
||||
|
||||
if (!$course = $DB->get_record('course', array('id'=>$id))) {
|
||||
print_error('nocourseid');
|
||||
print_error('invalidcourseid');
|
||||
}
|
||||
|
||||
require_login($course);
|
||||
|
||||
@@ -24,7 +24,7 @@ $id = required_param('id', PARAM_INT); // course id
|
||||
$PAGE->set_url('/grade/export/xml/index.php', array('id'=>$id));
|
||||
|
||||
if (!$course = $DB->get_record('course', array('id'=>$id))) {
|
||||
print_error('nocourseid');
|
||||
print_error('invalidcourseid');
|
||||
}
|
||||
|
||||
require_login($course);
|
||||
|
||||
@@ -39,7 +39,7 @@ if ($verbosescales !== 1) {
|
||||
$PAGE->set_url($url);
|
||||
|
||||
if (!$course = $DB->get_record('course', array('id'=>$id))) {
|
||||
print_error('nocourseid');
|
||||
print_error('invalidcourseid');
|
||||
}
|
||||
|
||||
require_login($course);
|
||||
|
||||
@@ -35,7 +35,7 @@ if ($verbosescales !== 1) {
|
||||
$PAGE->set_url($url);
|
||||
|
||||
if (!$course = $DB->get_record('course', array('id' => $id))) {
|
||||
print_error('nocourseid');
|
||||
print_error('invalidcourseid');
|
||||
}
|
||||
|
||||
require_login($course);
|
||||
|
||||
@@ -31,7 +31,7 @@ $id = required_param('id', PARAM_INT); // course id
|
||||
$PAGE->set_url('/grade/import/keymanager.php', array('id' => $id));
|
||||
|
||||
if (!$course = $DB->get_record('course', array('id'=>$id))) {
|
||||
print_error('nocourseid');
|
||||
print_error('invalidcourseid');
|
||||
}
|
||||
|
||||
require_login($course);
|
||||
|
||||
@@ -20,7 +20,7 @@ require_once '../../../config.php';
|
||||
|
||||
$id = required_param('id', PARAM_INT); // course id
|
||||
if (!$course = $DB->get_record('course', array('id'=>$id))) {
|
||||
print_error('nocourseid');
|
||||
print_error('invalidcourseid');
|
||||
}
|
||||
|
||||
require_user_key_login('grade/import', $id); // we want different keys for each course
|
||||
|
||||
@@ -30,7 +30,7 @@ if ($feedback !== 0) {
|
||||
$PAGE->set_url($url);
|
||||
|
||||
if (!$course = $DB->get_record('course', array('id'=>$id))) {
|
||||
print_error('nocourseid');
|
||||
print_error('invalidcourseid');
|
||||
}
|
||||
|
||||
require_login($course);
|
||||
|
||||
@@ -25,7 +25,7 @@ $PAGE->set_url(new moodle_url('/grade/import/xml/index.php', array('id'=>$id)));
|
||||
$PAGE->set_pagelayout('admin');
|
||||
|
||||
if (!$course = $DB->get_record('course', array('id'=>$id))) {
|
||||
print_error('nocourseid');
|
||||
print_error('invalidcourseid');
|
||||
}
|
||||
|
||||
require_login($course);
|
||||
|
||||
@@ -37,7 +37,7 @@ $newvalue = optional_param('newvalue', false, PARAM_TEXT);
|
||||
|
||||
/// basic access checks
|
||||
if (!$course = $DB->get_record('course', array('id' => $courseid))) {
|
||||
print_error('nocourseid');
|
||||
print_error('invalidcourseid');
|
||||
}
|
||||
$context = context_course::instance($course->id);
|
||||
require_login($course);
|
||||
|
||||
@@ -56,7 +56,7 @@ $PAGE->requires->yui_module('moodle-gradereport_grader-gradereporttable', 'Y.M.g
|
||||
|
||||
// basic access checks
|
||||
if (!$course = $DB->get_record('course', array('id' => $courseid))) {
|
||||
print_error('nocourseid');
|
||||
print_error('invalidcourseid');
|
||||
}
|
||||
require_login($course);
|
||||
$context = context_course::instance($course->id);
|
||||
@@ -188,7 +188,8 @@ if ($USER->gradeediting[$course->id] && ($report->get_pref('showquickfeedback')
|
||||
echo '<input type="hidden" value="grader" name="report"/>';
|
||||
echo '<input type="hidden" value="'.$page.'" name="page"/>';
|
||||
echo $reporthtml;
|
||||
echo '<div class="submit"><input type="submit" id="gradersubmit" value="'.s(get_string('savechanges')).'" /></div>';
|
||||
echo '<div class="submit"><input type="submit" id="gradersubmit" class="btn btn-primary"
|
||||
value="'.s(get_string('savechanges')).'" /></div>';
|
||||
echo '</div></form>';
|
||||
} else {
|
||||
echo $reporthtml;
|
||||
|
||||
@@ -448,22 +448,22 @@ class grade_report_grader extends grade_report {
|
||||
$this->groupwheresql_params, $enrolledparams, $relatedctxparams);
|
||||
|
||||
$sortjoin = "LEFT JOIN {grade_grades} g ON g.userid = u.id AND g.itemid = $this->sortitemid";
|
||||
$sort = "g.finalgrade $this->sortorder";
|
||||
$sort = "g.finalgrade $this->sortorder, u.idnumber, u.lastname, u.firstname, u.email";
|
||||
} else {
|
||||
$sortjoin = '';
|
||||
switch($this->sortitemid) {
|
||||
case 'lastname':
|
||||
$sort = "u.lastname $this->sortorder, u.firstname $this->sortorder";
|
||||
$sort = "u.lastname $this->sortorder, u.firstname $this->sortorder, u.idnumber, u.email";
|
||||
break;
|
||||
case 'firstname':
|
||||
$sort = "u.firstname $this->sortorder, u.lastname $this->sortorder";
|
||||
$sort = "u.firstname $this->sortorder, u.lastname $this->sortorder, u.idnumber, u.email";
|
||||
break;
|
||||
case 'email':
|
||||
$sort = "u.email $this->sortorder";
|
||||
$sort = "u.email $this->sortorder, u.firstname, u.lastname, u.idnumber";
|
||||
break;
|
||||
case 'idnumber':
|
||||
default:
|
||||
$sort = "u.idnumber $this->sortorder";
|
||||
$sort = "u.idnumber $this->sortorder, u.firstname, u.lastname, u.email";
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -444,6 +444,7 @@ M.gradereport_grader.classes.ajax.prototype.submit = function(properties, values
|
||||
}
|
||||
// If feedback is editable and has changed add to the IO queue for it
|
||||
if (values.editablefeedback && values.feedback !== values.oldfeedback) {
|
||||
values.feedback = encodeURIComponent(values.feedback);
|
||||
this.pendingsubmissions.push({transaction:this.report.Y.io.queue(M.cfg.wwwroot+'/grade/report/grader/ajax_callbacks.php', {
|
||||
method : 'POST',
|
||||
data : 'id='+this.courseid+'&userid='+properties.userid+'&itemid='+properties.itemid+'&action=update&newvalue='+values.feedback+'&type=feedback&sesskey='+M.cfg.sesskey,
|
||||
|
||||
@@ -35,7 +35,7 @@ $PAGE->set_pagelayout('admin');
|
||||
/// Make sure they can even access this course
|
||||
|
||||
if (!$course = $DB->get_record('course', array('id' => $courseid))) {
|
||||
print_error('nocourseid');
|
||||
print_error('invalidcourseid');
|
||||
}
|
||||
|
||||
require_login($course);
|
||||
|
||||
@@ -44,7 +44,7 @@ $PAGE->set_url($url);
|
||||
|
||||
/// basic access checks
|
||||
if (!$course = $DB->get_record('course', array('id' => $courseid))) {
|
||||
print_error('nocourseid');
|
||||
print_error('invalidcourseid');
|
||||
}
|
||||
|
||||
if (!$item = $DB->get_record('grade_items', array('id' => $itemid))) {
|
||||
|
||||
@@ -30,7 +30,7 @@ $PAGE->set_url('/grade/report/index.php', array('id'=>$courseid));
|
||||
|
||||
/// basic access checks
|
||||
if (!$course = $DB->get_record('course', array('id' => $courseid))) {
|
||||
print_error('nocourseid');
|
||||
print_error('invalidcourseid');
|
||||
}
|
||||
require_login($course);
|
||||
$context = context_course::instance($course->id);
|
||||
|
||||
@@ -31,7 +31,7 @@ $courseid = required_param('id', PARAM_INT); // course id
|
||||
$PAGE->set_url('/grade/report/outcomes/index.php', array('id'=>$courseid));
|
||||
|
||||
if (!$course = $DB->get_record('course', array('id' => $courseid))) {
|
||||
print_error('nocourseid');
|
||||
print_error('invalidcourseid');
|
||||
}
|
||||
|
||||
require_login($course);
|
||||
|
||||
@@ -33,7 +33,7 @@ $userid = optional_param('userid', $USER->id, PARAM_INT);
|
||||
$PAGE->set_url(new moodle_url('/grade/report/overview/index.php', array('id' => $courseid, 'userid' => $userid)));
|
||||
|
||||
if (!$course = $DB->get_record('course', array('id' => $courseid))) {
|
||||
print_error('nocourseid');
|
||||
print_error('invalidcourseid');
|
||||
}
|
||||
require_login(null, false);
|
||||
$PAGE->set_course($course);
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
define('NO_OUTPUT_BUFFERING', true);
|
||||
|
||||
require_once('../../../config.php');
|
||||
require_once($CFG->dirroot.'/lib/gradelib.php');
|
||||
require_once($CFG->dirroot.'/grade/lib.php');
|
||||
@@ -59,7 +61,7 @@ $PAGE->set_url(new moodle_url('/grade/report/singleview/index.php', $pageparams)
|
||||
$PAGE->set_pagelayout('incourse');
|
||||
|
||||
if (!$course = $DB->get_record('course', $courseparams)) {
|
||||
print_error('nocourseid');
|
||||
print_error('invalidcourseid');
|
||||
}
|
||||
|
||||
require_login($course);
|
||||
|
||||
@@ -41,7 +41,7 @@ if ($userview == 0) {
|
||||
|
||||
/// basic access checks
|
||||
if (!$course = $DB->get_record('course', array('id' => $courseid))) {
|
||||
print_error('nocourseid');
|
||||
print_error('invalidcourseid');
|
||||
}
|
||||
require_login($course);
|
||||
$PAGE->set_pagelayout('report');
|
||||
|
||||
+4
-3
@@ -152,10 +152,10 @@ echo $OUTPUT->header();
|
||||
</select></div></td>
|
||||
<td id="buttonscell">
|
||||
<p class="arrow_button">
|
||||
<input name="add" id="add" type="submit"
|
||||
<input class="btn btn-secondary" name="add" id="add" type="submit"
|
||||
value="<?php echo $OUTPUT->larrow().' '.get_string('add'); ?>"
|
||||
title="<?php print_string('add'); ?>" /><br>
|
||||
<input name="remove" id="remove" type="submit"
|
||||
<input class="btn btn-secondary" name="remove" id="remove" type="submit"
|
||||
value="<?php echo get_string('remove').' '.$OUTPUT->rarrow(); ?>"
|
||||
title="<?php print_string('remove'); ?>" />
|
||||
</p>
|
||||
@@ -173,7 +173,8 @@ echo $OUTPUT->header();
|
||||
</td>
|
||||
</tr>
|
||||
<tr><td colspan="3" id="backcell">
|
||||
<input type="submit" name="cancel" value="<?php print_string('backtogroupings', 'group'); ?>" />
|
||||
<input class="btn btn-secondary" type="submit" name="cancel"
|
||||
value="<?php print_string('backtogroupings', 'group'); ?>" />
|
||||
</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user