Compare commits
261 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| be3e6f6202 | |||
| 49f4e7c976 | |||
| 2d73956d8e | |||
| f4dc567e79 | |||
| 67bbf0d422 | |||
| 89784be6ff | |||
| 8f938ff9a6 | |||
| c35df119a5 | |||
| 98dfa7cae8 | |||
| 4d7ecf45a1 | |||
| 2e12b4cffb | |||
| c2383703ea | |||
| 9db4890064 | |||
| c6e925dbf0 | |||
| 35a615aa33 | |||
| f1fb96b698 | |||
| b6f112957e | |||
| ccc1e11099 | |||
| 44f6bc4ead | |||
| 6e650b4c0a | |||
| 84fd0fd52c | |||
| 2a433ad067 | |||
| e527aff4d2 | |||
| da9dfe70d4 | |||
| e2d00f5195 | |||
| 6afe470648 | |||
| 76bd7cea87 | |||
| 2b6bb87e59 | |||
| d259d014bb | |||
| fba097e3ce | |||
| 21b910b487 | |||
| 83866c3c2a | |||
| 4475f1e478 | |||
| c353a62026 | |||
| 1a67f29f38 | |||
| 50f2d4d645 | |||
| f479a30931 | |||
| a62cc33c1f | |||
| 4ab4ec652c | |||
| 0899c0adc0 | |||
| 64e2179478 | |||
| 51094c6560 | |||
| 3f316035b4 | |||
| 0dedf765e0 | |||
| 5219605a81 | |||
| 1b24951778 | |||
| 952bc6c5a6 | |||
| 3cf5c751ed | |||
| fb50700b4e | |||
| 7c0e5b20b6 | |||
| bb790b84ca | |||
| e1c81e5284 | |||
| e89a286905 | |||
| c80f356bca | |||
| cf49d1850e | |||
| 2abfecbc8c | |||
| 6fe7343a94 | |||
| 9b1c53771a | |||
| f18a66f1ea | |||
| 3272e14576 | |||
| 181269bf32 | |||
| fc63b8cf81 | |||
| 84be895b94 | |||
| 8732862bb5 | |||
| ede8ae0399 | |||
| 2d7c31b550 | |||
| 9a055f40c2 | |||
| 40b53bda8c | |||
| c49003263e | |||
| c9e9862ed6 | |||
| a455f2fa45 | |||
| b34fc1800a | |||
| 8a15bcf759 | |||
| 4f2308d541 | |||
| 41ab3ae676 | |||
| d2782c3d4b | |||
| b907bc26f6 | |||
| 105e1af010 | |||
| 06b5e1f1e1 | |||
| 9c2e581e82 | |||
| 0c8096792d | |||
| aa2b7c3b48 | |||
| 56145a4d6e | |||
| 34fcdf2da4 | |||
| 5e872af220 | |||
| 40155b1ca0 | |||
| 75b594848e | |||
| ad4d28ff76 | |||
| a721901beb | |||
| e0c5923c07 | |||
| bbc7df8d52 | |||
| 1ab376e86f | |||
| 4c30d78891 | |||
| 87e581f91a | |||
| 4571805430 | |||
| ec943fe107 | |||
| 8235b610bb | |||
| aff125ae03 | |||
| 41adb95781 | |||
| 7546d2e1c3 | |||
| 282fdb22ca | |||
| dac942ff58 | |||
| 38a219301e | |||
| 7001bf9a8c | |||
| 7f8ae8f54e | |||
| f5a176c125 | |||
| cf015aa1f0 | |||
| d34122424c | |||
| 6c1a52e67c | |||
| 373252e7da | |||
| 2f4dfae509 | |||
| 68adf314ec | |||
| 1c703690cd | |||
| 0289d8c766 | |||
| a4e657878b | |||
| b7a6e68906 | |||
| 65b48f6850 | |||
| 6e84137b30 | |||
| e9a6191801 | |||
| 376d6d9bc0 | |||
| 94b3cc37aa | |||
| 401465fe7c | |||
| 95337e5974 | |||
| a9e2dd494b | |||
| d153a4a39d | |||
| 5b7e7362a9 | |||
| 5eed950dd2 | |||
| fe5ecacb2b | |||
| 84b1aeba07 | |||
| d940409a40 | |||
| 58ebc0a42d | |||
| 6eba5f4dfa | |||
| a99654771f | |||
| 27a5f957ba | |||
| 1a825a276e | |||
| dabbf48f50 | |||
| 10a382f1c8 | |||
| 21e8f813dc | |||
| 49f1acf174 | |||
| 4f9ccc21d8 | |||
| a92cd1e420 | |||
| 40b72c27e8 | |||
| f266c90917 | |||
| 71ce7d03ee | |||
| 7c339df7cb | |||
| 8f990cc5bf | |||
| 51112014d2 | |||
| 361370bae3 | |||
| 201f5085c6 | |||
| ea836818a5 | |||
| 2fb32e8591 | |||
| d7e275f123 | |||
| 0a976df90c | |||
| 924ef95068 | |||
| 67c51ec7ec | |||
| 6473207888 | |||
| da6815741e | |||
| 537fd32c02 | |||
| 9461ad93fd | |||
| 32a491a8d2 | |||
| f4241a5974 | |||
| 1c65824b82 | |||
| f556dce6a5 | |||
| 0cce3ea50d | |||
| 52781ec82f | |||
| 2ee301e041 | |||
| fdc6ac362e | |||
| ceee804962 | |||
| f16383191b | |||
| 1e968e2d27 | |||
| fa75bb63e3 | |||
| d71119dbc5 | |||
| b60a617d3d | |||
| a1504fd7bc | |||
| 531cc5c727 | |||
| 17f0e2a4af | |||
| 6561015165 | |||
| 69d4a9b94f | |||
| de90103193 | |||
| e470238304 | |||
| 4d31580f93 | |||
| e89bda0f80 | |||
| 68b7d5ce4a | |||
| 1f70c8582d | |||
| 6db8c22913 | |||
| 8b198fec72 | |||
| bec8c20cab | |||
| 3359719ce9 | |||
| 9c6dab862a | |||
| 6da3248b9f | |||
| bd8926f9f3 | |||
| 93aa18b8de | |||
| 4dd5623f18 | |||
| 722e179f30 | |||
| c3ab0b8bbf | |||
| cc8ac87f01 | |||
| 96dc38c46a | |||
| 354e304f29 | |||
| 89b92ecbb9 | |||
| 37dd88e750 | |||
| 1e826d374e | |||
| 14a59f1eee | |||
| f4966d09b2 | |||
| d603a9c792 | |||
| 7606f81a88 | |||
| abb61b1a65 | |||
| 14caa61bd4 | |||
| 45acb77a3f | |||
| 9e98e66cb2 | |||
| b7f6f1c601 | |||
| 8bde103118 | |||
| ed67b6fb06 | |||
| 4151d0aa1f | |||
| 8bca20b7ec | |||
| a6de116442 | |||
| 314c64ef2f | |||
| a43f2c6338 | |||
| 401697c397 | |||
| 8060291174 | |||
| 45c07b94fd | |||
| 5b8a93a867 | |||
| 93e95c2579 | |||
| 8298719c51 | |||
| 76ec958619 | |||
| fa224641d8 | |||
| d9324ce9ee | |||
| 7728a2cae3 | |||
| 36125f82fa | |||
| 9555ae2d10 | |||
| 8ead44805a | |||
| e2d914b204 | |||
| 47c6fb2bd3 | |||
| 8bb969d6cc | |||
| dcde7ca176 | |||
| 798790c4e8 | |||
| 48a515c37b | |||
| 07f99ca6d6 | |||
| b4ac530cf2 | |||
| b3486b0192 | |||
| ab4a3e8cb1 | |||
| c9d53c1e17 | |||
| 66293e8414 | |||
| f8fe046fb5 | |||
| a686d8374a | |||
| c441c21e7a | |||
| d3f49a8c84 | |||
| 060c2d3c9c | |||
| 846711d69f | |||
| 6dbf42a600 | |||
| 4a97b8476b | |||
| 9f5571d405 | |||
| fa5aa434bd | |||
| 1ff8d56a2e | |||
| 2e77d5ec7b | |||
| e5a35eb25f | |||
| d5da6e42c2 | |||
| 116dd8a02f | |||
| 044b689308 | |||
| 054609f8b0 | |||
| 7bc0151a4c | |||
| 85f5d4ac95 |
@@ -278,9 +278,6 @@ if ($hassiteconfig) {
|
||||
$ADMIN->add('webservicesettings', new admin_externalpage('webservicedocumentation', new lang_string('wsdocapi', 'webservice'), "$CFG->wwwroot/$CFG->admin/webservice/documentation.php", 'moodle/site:config', false));
|
||||
/// manage service
|
||||
$temp = new admin_settingpage('externalservices', new lang_string('externalservices', 'webservice'));
|
||||
$temp->add(new admin_setting_enablemobileservice('enablemobilewebservice',
|
||||
new lang_string('enablemobilewebservice', 'admin'),
|
||||
new lang_string('configenablemobilewebservice', 'admin', $enablemobiledoclink), 0));
|
||||
$temp->add(new admin_setting_heading('manageserviceshelpexplaination', new lang_string('information', 'webservice'), new lang_string('servicehelpexplanation', 'webservice')));
|
||||
$temp->add(new admin_setting_manageexternalservices());
|
||||
$ADMIN->add('webservicesettings', $temp);
|
||||
|
||||
@@ -308,8 +308,7 @@ class tool_generator_course_backend extends tool_generator_backend {
|
||||
$username = 'tool_generator_' . $textnumber;
|
||||
|
||||
// Create user account.
|
||||
$record = array('firstname' => get_string('firstname', 'tool_generator'),
|
||||
'lastname' => $number, 'username' => $username);
|
||||
$record = array('username' => $username, 'idnumber' => $number);
|
||||
|
||||
// We add a user password if it has been specified.
|
||||
if (!empty($CFG->tool_generator_users_password)) {
|
||||
|
||||
@@ -62,7 +62,6 @@ $string['error_nonexistingcourse'] = 'The specified course does not exist';
|
||||
$string['error_nopageinstances'] = 'The selected course does not contain page module instances';
|
||||
$string['error_notdebugging'] = 'Not available on this server because debugging is not set to DEVELOPER';
|
||||
$string['error_nouserspassword'] = 'You need to set $CFG->tool_generator_users_password in config.php to generate the test plan';
|
||||
$string['firstname'] = 'Test course user';
|
||||
$string['fullname'] = 'Test course: {$a->size}';
|
||||
$string['maketestcourse'] = 'Make test course';
|
||||
$string['maketestplan'] = 'Make JMeter test plan';
|
||||
|
||||
@@ -136,7 +136,7 @@ class tool_generator_maketestcourse_testcase extends advanced_testcase {
|
||||
$lastusernumber = 0;
|
||||
$discussionstarters = array();
|
||||
foreach ($discussions as $discussion) {
|
||||
$usernumber = intval($discussion->lastname);
|
||||
$usernumber = core_user::get_user($discussion->userid, 'id, idnumber')->idnumber;
|
||||
|
||||
// Checks that the users are odd numbers.
|
||||
$this->assertEquals(1, $usernumber % 2);
|
||||
|
||||
@@ -156,7 +156,7 @@ class controller {
|
||||
$updateablelangs = array();
|
||||
foreach ($currentlangs as $clang) {
|
||||
if (!array_key_exists($clang, $md5array)) {
|
||||
$noticeok[] = get_string('langpackupdateskipped', 'tool_langimport', $clang);
|
||||
$this->info[] = get_string('langpackupdateskipped', 'tool_langimport', $clang);
|
||||
continue;
|
||||
}
|
||||
$dest1 = $CFG->dataroot.'/lang/'.$clang;
|
||||
@@ -175,36 +175,10 @@ class controller {
|
||||
}
|
||||
}
|
||||
|
||||
// Clean-up currently installed versions of the packs.
|
||||
foreach ($neededlangs as $packindex => $pack) {
|
||||
if ($pack == 'en') {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Delete old directories.
|
||||
$dest1 = $CFG->dataroot.'/lang/'.$pack;
|
||||
$dest2 = $CFG->dirroot.'/lang/'.$pack;
|
||||
if (file_exists($dest1)) {
|
||||
if (!remove_dir($dest1)) {
|
||||
$noticeerror[] = 'Could not delete old directory '.$dest1.', update of '.$pack
|
||||
.' failed, please check permissions.';
|
||||
unset($neededlangs[$packindex]);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (file_exists($dest2)) {
|
||||
if (!remove_dir($dest2)) {
|
||||
$noticeerror[] = 'Could not delete old directory '.$dest2.', update of '.$pack
|
||||
.' failed, please check permissions.';
|
||||
unset($neededlangs[$packindex]);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$updated = $this->install_languagepacks($neededlangs, true);
|
||||
} catch (\moodle_exception $e) {
|
||||
$this->errors[] = 'An exception occurred while installing language packs: ' . $e->getMessage();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -58,27 +58,22 @@ class tool_task_edit_scheduled_task_form extends moodleform {
|
||||
$mform->addElement('text', 'minute', get_string('taskscheduleminute', 'tool_task'));
|
||||
$mform->setType('minute', PARAM_RAW);
|
||||
$mform->addHelpButton('minute', 'taskscheduleminute', 'tool_task');
|
||||
$mform->addRule('minute', get_string('required'), 'required');
|
||||
|
||||
$mform->addElement('text', 'hour', get_string('taskschedulehour', 'tool_task'));
|
||||
$mform->setType('hour', PARAM_RAW);
|
||||
$mform->addHelpButton('hour', 'taskschedulehour', 'tool_task');
|
||||
$mform->addRule('hour', get_string('required'), 'required');
|
||||
|
||||
$mform->addElement('text', 'day', get_string('taskscheduleday', 'tool_task'));
|
||||
$mform->setType('day', PARAM_RAW);
|
||||
$mform->addHelpButton('day', 'taskscheduleday', 'tool_task');
|
||||
$mform->addRule('day', get_string('required'), 'required');
|
||||
|
||||
$mform->addElement('text', 'month', get_string('taskschedulemonth', 'tool_task'));
|
||||
$mform->setType('month', PARAM_RAW);
|
||||
$mform->addHelpButton('month', 'taskschedulemonth', 'tool_task');
|
||||
$mform->addRule('month', get_string('required'), 'required');
|
||||
|
||||
$mform->addElement('text', 'dayofweek', get_string('taskscheduledayofweek', 'tool_task'));
|
||||
$mform->setType('dayofweek', PARAM_RAW);
|
||||
$mform->addHelpButton('dayofweek', 'taskscheduledayofweek', 'tool_task');
|
||||
$mform->addRule('dayofweek', get_string('required'), 'required');
|
||||
|
||||
$mform->addElement('advcheckbox', 'disabled', get_string('disabled', 'tool_task'));
|
||||
$mform->addHelpButton('disabled', 'disabled', 'tool_task');
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
@tool @tool_task @javascript
|
||||
Feature: Manage scheduled tasks
|
||||
In order to configure scheduled tasks
|
||||
As an admin
|
||||
I need to be able to disable, enable, edit and reset to default scheduled tasks
|
||||
|
||||
Background:
|
||||
Given I log in as "admin"
|
||||
And I navigate to "Scheduled tasks" node in "Site administration > Server"
|
||||
|
||||
Scenario: Disable scheduled task
|
||||
When I click on "Edit task schedule: Log table cleanup" "link" in the "Log table cleanup" "table_row"
|
||||
Then I should see "Edit task schedule: Log table cleanup"
|
||||
And I set the following fields to these values:
|
||||
| disabled | 1 |
|
||||
And I press "Save changes"
|
||||
Then I should see "Changes saved"
|
||||
And I should see "Task disabled" in the "Log table cleanup" "table_row"
|
||||
|
||||
Scenario: Enable scheduled task
|
||||
When I click on "Edit task schedule: Log table cleanup" "link" in the "Log table cleanup" "table_row"
|
||||
Then I should see "Edit task schedule: Log table cleanup"
|
||||
And I set the following fields to these values:
|
||||
| disabled | 0 |
|
||||
And I press "Save changes"
|
||||
Then I should see "Changes saved"
|
||||
And I should not see "Task disabled" in the "Log table cleanup" "table_row"
|
||||
|
||||
Scenario: Edit scheduled task
|
||||
When I click on "Edit task schedule: Log table cleanup" "link" in the "Log table cleanup" "table_row"
|
||||
Then I should see "Edit task schedule: Log table cleanup"
|
||||
And I set the following fields to these values:
|
||||
| minute | */5 |
|
||||
| hour | 1 |
|
||||
| day | 2 |
|
||||
| month | 3 |
|
||||
| dayofweek | 4 |
|
||||
And I press "Save changes"
|
||||
Then I should see "Changes saved"
|
||||
And the following should exist in the "admintable" table:
|
||||
| Component | Minute | Hour | Day | Day of week | Month |
|
||||
| Standard log | */5 | 1 | 2 | 4 | 3 |
|
||||
|
||||
Scenario: Reset scheduled task to default
|
||||
When I click on "Edit task schedule: Log table cleanup" "link" in the "Log table cleanup" "table_row"
|
||||
Then I should see "Edit task schedule: Log table cleanup"
|
||||
And I set the following fields to these values:
|
||||
| resettodefaults | 1 |
|
||||
And I press "Save changes"
|
||||
Then I should see "Changes saved"
|
||||
And the following should not exist in the "admintable" table:
|
||||
| Name | Component | Minute | Hour | Day | Day of week | Month |
|
||||
| Log table cleanup | Standard log | */5 | 1 | 2 | 4 | 3 |
|
||||
@@ -157,6 +157,13 @@ class external_service_form extends moodleform {
|
||||
|
||||
$errors = parent::validation($data, $files);
|
||||
|
||||
// Add field validation check for duplicate name.
|
||||
if ($webservice = $DB->get_record('external_services', array('name' => $data['name']))) {
|
||||
if (empty($data['id']) || $webservice->id != $data['id']) {
|
||||
$errors['name'] = get_string('nameexists', 'webservice');
|
||||
}
|
||||
}
|
||||
|
||||
// Add field validation check for duplicate shortname.
|
||||
// Allow duplicated "empty" shortnames.
|
||||
if (!empty($data['shortname'])) {
|
||||
|
||||
@@ -143,7 +143,8 @@ class auth_plugin_shibboleth extends auth_plugin_base {
|
||||
$configarray = (array) $this->config;
|
||||
|
||||
$moodleattributes = array();
|
||||
foreach ($this->userfields as $field) {
|
||||
$userfields = array_merge($this->userfields, $this->get_custom_user_profile_fields());
|
||||
foreach ($userfields as $field) {
|
||||
if (isset($configarray["field_map_$field"])) {
|
||||
$moodleattributes[$field] = $configarray["field_map_$field"];
|
||||
}
|
||||
|
||||
@@ -138,7 +138,7 @@ urn:mace:organization2:providerID, Example Organization 2, /Shibboleth.sso/WAYF/
|
||||
|
||||
<?php
|
||||
|
||||
print_auth_lock_options($this->authtype, $user_fields, '<!-- empty help -->', true, false);
|
||||
print_auth_lock_options($this->authtype, $user_fields, '<!-- empty help -->', true, false, $this->get_custom_user_profile_fields());
|
||||
|
||||
?>
|
||||
</table>
|
||||
|
||||
@@ -109,17 +109,17 @@ Feature: display_availability
|
||||
|
||||
# Page 1 display still there but should be dimmed and not a link.
|
||||
Then I should see "Page 1" in the "#section-1 .dimmed_text" "css_element"
|
||||
And ".activityinstance a" "css_element" should not exist in the "#section-1" "css_element"
|
||||
And ".activityinstance a" "css_element" should not exist in the "Topic 1" "section"
|
||||
|
||||
# Date display should be present.
|
||||
And I should see "Available until" in the "#section-1" "css_element"
|
||||
And I should see "Available until" in the "Topic 1" "section"
|
||||
|
||||
# Page 2 display not there at all
|
||||
And I should not see "Page 2" in the "region-main" "region"
|
||||
|
||||
# Page 3 display and link
|
||||
And I should see "Page 3" in the "region-main" "region"
|
||||
And ".activityinstance a" "css_element" should exist in the "#section-3" "css_element"
|
||||
And ".activityinstance a" "css_element" should exist in the "Topic 3" "section"
|
||||
|
||||
@javascript
|
||||
Scenario: Section availability display
|
||||
|
||||
@@ -66,7 +66,7 @@ abstract class backup_factory {
|
||||
|
||||
// Create database_logger, observing $CFG->backup_database_logger_level and defaulting to LOG_WARNING
|
||||
// and pointing to the backup_logs table
|
||||
$dllevel = isset($CFG->backup_database_logger_level) ? $CFG->backup_database_logger_level : backup::LOG_WARNING;
|
||||
$dllevel = isset($CFG->backup_database_logger_level) ? $CFG->backup_database_logger_level : $dfltloglevel;
|
||||
$columns = array('backupid' => $backupid);
|
||||
$enabledloggers[] = new database_logger($dllevel, 'timecreated', 'loglevel', 'message', 'backup_logs', $columns);
|
||||
|
||||
|
||||
@@ -34,6 +34,6 @@ Feature: Duplicate activities
|
||||
| Name | Duplicated database name |
|
||||
| Description | Duplicated database description |
|
||||
And I press "Save and return to course"
|
||||
Then I should see "Original database name" in the "#section-1" "css_element"
|
||||
And I should see "Duplicated database name" in the "#section-1" "css_element"
|
||||
Then I should see "Original database name" in the "Topic 1" "section"
|
||||
And I should see "Duplicated database name" in the "Topic 1" "section"
|
||||
And "Original database name" "link" should appear before "Duplicated database name" "link"
|
||||
|
||||
@@ -126,5 +126,5 @@ Feature: Restore Moodle 2 course backups
|
||||
And section "3" should be hidden
|
||||
And section "7" should be hidden
|
||||
And section "15" should be visible
|
||||
And I should see "Test URL name" in the "#section-3" "css_element"
|
||||
And I should see "Test forum name" in the "#section-1" "css_element"
|
||||
And I should see "Test URL name" in the "Topic 3" "section"
|
||||
And I should see "Test forum name" in the "Topic 1" "section"
|
||||
|
||||
@@ -49,7 +49,7 @@ $assertion = filter_input(
|
||||
// Audience is the site url scheme + host + port only.
|
||||
$wwwparts = parse_url($CFG->wwwroot);
|
||||
$audience = $wwwparts['scheme'] . '://' . $wwwparts['host'];
|
||||
$audience .= isset($wwwparts['port']) ? $wwwparts['port'] : '';
|
||||
$audience .= isset($wwwparts['port']) ? ':' . $wwwparts['port'] : '';
|
||||
$params = 'assertion=' . urlencode($assertion) . '&audience=' .
|
||||
urlencode($audience);
|
||||
|
||||
|
||||
+5
-6
@@ -26,6 +26,7 @@
|
||||
|
||||
require_once(dirname(dirname(__FILE__)) . '/config.php');
|
||||
require_once($CFG->libdir . '/badgeslib.php');
|
||||
require_once($CFG->libdir . '/filelib.php');
|
||||
|
||||
$id = required_param('hash', PARAM_ALPHANUM);
|
||||
$bake = optional_param('bake', 0, PARAM_BOOL);
|
||||
@@ -37,12 +38,10 @@ $badge = new issued_badge($id);
|
||||
|
||||
if ($bake && ($badge->recipient->id == $USER->id)) {
|
||||
$name = str_replace(' ', '_', $badge->badgeclass['name']) . '.png';
|
||||
ob_start();
|
||||
$file = badges_bake($id, $badge->badgeid);
|
||||
header('Content-Type: image/png');
|
||||
header('Content-Disposition: attachment; filename="'. $name .'"');
|
||||
readfile($file);
|
||||
ob_flush();
|
||||
$filehash = badges_bake($id, $badge->badgeid, $USER->id, true);
|
||||
$fs = get_file_storage();
|
||||
$file = $fs->get_file_by_hash($filehash);
|
||||
send_stored_file($file, 0, 0, true, array('filename' => $name));
|
||||
}
|
||||
|
||||
$PAGE->set_url('/badges/badge.php', array('hash' => $id));
|
||||
|
||||
+5
-8
@@ -26,6 +26,7 @@
|
||||
|
||||
require_once(dirname(dirname(__FILE__)) . '/config.php');
|
||||
require_once($CFG->libdir . '/badgeslib.php');
|
||||
require_once($CFG->libdir . '/filelib.php');
|
||||
|
||||
$page = optional_param('page', 0, PARAM_INT);
|
||||
$search = optional_param('search', '', PARAM_CLEAN);
|
||||
@@ -71,17 +72,13 @@ if ($hide) {
|
||||
require_sesskey();
|
||||
$badge = new badge($download);
|
||||
$name = str_replace(' ', '_', $badge->name) . '.png';
|
||||
ob_start();
|
||||
$file = badges_bake($hash, $download);
|
||||
header('Content-Type: image/png');
|
||||
header('Content-Disposition: attachment; filename="'. $name .'"');
|
||||
readfile($file);
|
||||
ob_flush();
|
||||
$filehash = badges_bake($hash, $download, $USER->id, true);
|
||||
$fs = get_file_storage();
|
||||
$file = $fs->get_file_by_hash($filehash);
|
||||
send_stored_file($file, 0, 0, true, array('filename' => $name));
|
||||
} else if ($downloadall) {
|
||||
require_sesskey();
|
||||
ob_start();
|
||||
badges_download($USER->id);
|
||||
ob_flush();
|
||||
}
|
||||
|
||||
$context = context_user::instance($USER->id);
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
$string['activityoverview'] = 'You have {$a}s that need attention';
|
||||
$string['alwaysshowall'] = 'Always show all';
|
||||
$string['collapseall'] = 'Collapse all course lists';
|
||||
$string['configotherexpanded'] = 'If enabled, other courses will be expanded by default unless overriden by user preferences.';
|
||||
$string['configotherexpanded'] = 'If enabled, other courses will be expanded by default unless overridden by user preferences.';
|
||||
$string['configpreservestates'] = 'If enabled, the collapsed/expanded states set by the user are stored and used on each load.';
|
||||
$string['course_overview:addinstance'] = 'Add a new course overview block';
|
||||
$string['course_overview:myaddinstance'] = 'Add a new course overview block to My home';
|
||||
|
||||
@@ -552,9 +552,21 @@ class block_base {
|
||||
&& $page->context->contextlevel == CONTEXT_USER // Page belongs to a user
|
||||
&& $page->context->instanceid == $USER->id // Page belongs to this user
|
||||
&& $page->pagetype == 'my-index') { // Ensure we are on the My Moodle page
|
||||
$capability = 'block/' . $this->name() . ':myaddinstance';
|
||||
return $this->has_add_block_capability($page, $capability)
|
||||
&& has_capability('moodle/my:manageblocks', $page->context);
|
||||
|
||||
// If the block cannot be displayed on /my it is ok if the myaddinstance capability is not defined.
|
||||
$formats = $this->applicable_formats();
|
||||
// Is 'my' explicitly forbidden?
|
||||
// If 'all' has not been allowed, has 'my' been explicitly allowed?
|
||||
if ((isset($formats['my']) && $formats['my'] == false)
|
||||
|| (empty($formats['all']) && empty($formats['my']))) {
|
||||
|
||||
// Block cannot be added to /my regardless of capabilities.
|
||||
return false;
|
||||
} else {
|
||||
$capability = 'block/' . $this->name() . ':myaddinstance';
|
||||
return $this->has_add_block_capability($page, $capability)
|
||||
&& has_capability('moodle/my:manageblocks', $page->context);
|
||||
}
|
||||
}
|
||||
|
||||
$capability = 'block/' . $this->name() . ':addinstance';
|
||||
|
||||
@@ -56,3 +56,16 @@ Feature: Add and configure blocks throughout the site
|
||||
And I follow "Course 1"
|
||||
And I follow "Turn editing on"
|
||||
Then I should see "Assign roles in Search forums block"
|
||||
|
||||
@javascript
|
||||
Scenario: Blocks can safely be customised
|
||||
Given I log in as "admin"
|
||||
And I click on "My home" "link" in the "Navigation" "block"
|
||||
And I press "Customise this page"
|
||||
And I add the "HTML" block
|
||||
And I configure the "(new HTML block)" block
|
||||
And I set the following fields to these values:
|
||||
| Block title | Foo " onload="document.getElementsByTagName('body')[0].remove()" alt="
|
||||
| Content | Example
|
||||
When I press "Save changes"
|
||||
Then I should see "Course overview"
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
@core @core_block
|
||||
Feature: Show hidden blocks in a docked block region when editing
|
||||
In order to edit blocks in a hidden region
|
||||
As a teacher
|
||||
I need to be able to see the blocks when editing is on
|
||||
|
||||
Background:
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname | format |
|
||||
| Course 1 | C1 | topics |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| admin | C1 | editingteacher |
|
||||
And I log in as "admin"
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
# Hide all the blocks in the non-default region
|
||||
And I configure the "Search forums" block
|
||||
And I set the following fields to these values:
|
||||
| Visible | No |
|
||||
And I click on "Save changes" "button"
|
||||
And I configure the "Latest news" block
|
||||
And I set the following fields to these values:
|
||||
| Visible | No |
|
||||
And I click on "Save changes" "button"
|
||||
And I configure the "Upcoming events" block
|
||||
And I set the following fields to these values:
|
||||
| Visible | No |
|
||||
And I click on "Save changes" "button"
|
||||
And I configure the "Recent activity" block
|
||||
And I set the following fields to these values:
|
||||
| Visible | No |
|
||||
When I click on "Save changes" "button"
|
||||
# Editing is on so they should be visible
|
||||
Then I should see "Search forums"
|
||||
And I should see "Latest news"
|
||||
And I should see "Upcoming events"
|
||||
And I should see "Recent activity"
|
||||
And I turn editing mode off
|
||||
# Editing is off, so they should no longer be visible
|
||||
And I should not see "Search forums"
|
||||
And I should not see "Latest news"
|
||||
And I should not see "Upcoming events"
|
||||
And I should not see "Recent activity"
|
||||
|
||||
@javascript
|
||||
Scenario: Check that a region with only hidden blocks is not docked in editing mode (javascript enabled)
|
||||
|
||||
Scenario: Check that a region with only hidden blocks is not docked in editing mode (javascript disabled)
|
||||
@@ -0,0 +1,28 @@
|
||||
@core @core_block
|
||||
Feature: Block visibility
|
||||
In order to configure blocks visibility
|
||||
As a teacher
|
||||
I need to show and hide blocks on a page
|
||||
|
||||
Background:
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname | category |
|
||||
| Course 1 | C1 | 0 |
|
||||
And I log in as "admin"
|
||||
And I am on homepage
|
||||
And I follow "Course 1"
|
||||
And I follow "Turn editing on"
|
||||
|
||||
@javascript
|
||||
Scenario: Hiding all blocks on the page should remove the column they're in
|
||||
Given I open the "Search forums" blocks action menu
|
||||
And I click on "Hide Search forums block" "link" in the "Search forums" "block"
|
||||
And I open the "Latest news" blocks action menu
|
||||
And I click on "Hide Latest news block" "link" in the "Latest news" "block"
|
||||
And I open the "Upcoming events" blocks action menu
|
||||
And I click on "Hide Upcoming events block" "link" in the "Upcoming events" "block"
|
||||
And I open the "Recent activity" blocks action menu
|
||||
When I click on "Hide Recent activity block" "link" in the "Recent activity" "block"
|
||||
Then ".empty-region-side-post" "css_element" should not exist in the "body" "css_element"
|
||||
And I follow "Turn editing off"
|
||||
And ".empty-region-side-post" "css_element" should exist in the "body" "css_element"
|
||||
+3
-2
@@ -991,7 +991,7 @@ function calendar_filter_controls_element(moodle_url $url, $type) {
|
||||
$str = get_string('show'.$typeforhumans.'events', 'calendar');
|
||||
}
|
||||
$content = html_writer::start_tag('li', array('class' => 'calendar_event'));
|
||||
$content .= html_writer::start_tag('a', array('href' => $url));
|
||||
$content .= html_writer::start_tag('a', array('href' => $url, 'rel' => 'nofollow'));
|
||||
$content .= html_writer::tag('span', $icon, array('class' => $class));
|
||||
$content .= html_writer::tag('span', $str, array('class' => 'eventname'));
|
||||
$content .= html_writer::end_tag('a');
|
||||
@@ -2953,11 +2953,12 @@ function calendar_add_icalendar_event($event, $courseid, $subscriptionid, $timez
|
||||
$description = '';
|
||||
} else {
|
||||
$description = $event->properties['DESCRIPTION'][0]->value;
|
||||
$description = clean_param($description, PARAM_NOTAGS);
|
||||
$description = str_replace('\n', '<br />', $description);
|
||||
$description = str_replace('\\', '', $description);
|
||||
$description = preg_replace('/\s+/', ' ', $description);
|
||||
}
|
||||
$eventrecord->description = clean_param($description, PARAM_NOTAGS);
|
||||
$eventrecord->description = $description;
|
||||
|
||||
// Probably a repeating event with RRULE etc. TODO: skip for now.
|
||||
if (empty($event->properties['DTSTART'][0]->value)) {
|
||||
|
||||
+2
-2
@@ -242,7 +242,7 @@ $CFG->admin = 'admin';
|
||||
// $CFG->session_memcached_save_path = '127.0.0.1:11211';
|
||||
// $CFG->session_memcached_prefix = 'memc.sess.key.';
|
||||
// $CFG->session_memcached_acquire_lock_timeout = 120;
|
||||
// $CFG->session_memcached_lock_expire = 7200; // Ignored if memcached extension <= 2.1.0
|
||||
// $CFG->session_memcached_lock_expire = 7200; // Ignored if PECL memcached is below version 2.2.0
|
||||
//
|
||||
// Memcache session handler (requires memcached server and memcache extension):
|
||||
// $CFG->session_handler_class = '\core\session\memcache';
|
||||
@@ -507,7 +507,7 @@ $CFG->admin = 'admin';
|
||||
// Uses lock files stored by default in the dataroot. Whether this
|
||||
// works on clusters depends on the file system used for the dataroot.
|
||||
//
|
||||
// "\\core\\lock\\db_row_lock_factory" - DB locking based on table rows.
|
||||
// "\\core\\lock\\db_record_lock_factory" - DB locking based on table rows.
|
||||
//
|
||||
// "\\core\\lock\\postgres_lock_factory" - DB locking based on postgres advisory locks.
|
||||
//
|
||||
|
||||
+12
-6
@@ -77,11 +77,14 @@ class core_course_external extends external_api {
|
||||
//retrieve the course
|
||||
$course = $DB->get_record('course', array('id' => $params['courseid']), '*', MUST_EXIST);
|
||||
|
||||
//check course format exist
|
||||
if (!file_exists($CFG->dirroot . '/course/format/' . $course->format . '/lib.php')) {
|
||||
throw new moodle_exception('cannotgetcoursecontents', 'webservice', '', null, get_string('courseformatnotfound', 'error', '', $course->format));
|
||||
} else {
|
||||
require_once($CFG->dirroot . '/course/format/' . $course->format . '/lib.php');
|
||||
if ($course->id != SITEID) {
|
||||
// Check course format exist.
|
||||
if (!file_exists($CFG->dirroot . '/course/format/' . $course->format . '/lib.php')) {
|
||||
throw new moodle_exception('cannotgetcoursecontents', 'webservice', '', null,
|
||||
get_string('courseformatnotfound', 'error', $course->format));
|
||||
} else {
|
||||
require_once($CFG->dirroot . '/course/format/' . $course->format . '/lib.php');
|
||||
}
|
||||
}
|
||||
|
||||
// now security checks
|
||||
@@ -217,6 +220,7 @@ class core_course_external extends external_api {
|
||||
'id' => new external_value(PARAM_INT, 'activity id'),
|
||||
'url' => new external_value(PARAM_URL, 'activity url', VALUE_OPTIONAL),
|
||||
'name' => new external_value(PARAM_RAW, 'activity module name'),
|
||||
'instance' => new external_value(PARAM_INT, 'instance id', VALUE_OPTIONAL),
|
||||
'description' => new external_value(PARAM_RAW, 'activity description', VALUE_OPTIONAL),
|
||||
'visible' => new external_value(PARAM_INT, 'is the module visible', VALUE_OPTIONAL),
|
||||
'modicon' => new external_value(PARAM_URL, 'activity icon url'),
|
||||
@@ -849,6 +853,7 @@ class core_course_external extends external_api {
|
||||
|
||||
// Check if the current user has enought permissions.
|
||||
if (!can_delete_course($courseid)) {
|
||||
fix_course_sortorder();
|
||||
throw new moodle_exception('cannotdeletecategorycourse', 'error',
|
||||
'', format_string($course->fullname)." (id: $courseid)");
|
||||
}
|
||||
@@ -857,6 +862,7 @@ class core_course_external extends external_api {
|
||||
}
|
||||
|
||||
$transaction->allow_commit();
|
||||
fix_course_sortorder();
|
||||
|
||||
return null;
|
||||
}
|
||||
@@ -1028,7 +1034,7 @@ class core_course_external extends external_api {
|
||||
|
||||
// Check if we need to unzip the file because the backup temp dir does not contains backup files.
|
||||
if (!file_exists($backupbasepath . "/moodle_backup.xml")) {
|
||||
$file->extract_to_pathname(get_file_packer(), $backupbasepath);
|
||||
$file->extract_to_pathname(get_file_packer('application/vnd.moodle.backup'), $backupbasepath);
|
||||
}
|
||||
|
||||
// Create new course.
|
||||
|
||||
@@ -42,18 +42,18 @@ Feature: Course activity controls works as expected
|
||||
And I click on "Actions" "link" in the "Recent activity" "block"
|
||||
And I click on "Delete Recent activity block" "link"
|
||||
And I press "Yes"
|
||||
And "#section-2" "css_element" <should_see_other_sections> exist
|
||||
And <belowpage> "section" <should_see_other_sections> exist
|
||||
And I add a "Forum" to section "1" and I fill the form with:
|
||||
| Forum name | Test forum name 1 |
|
||||
| Description | Test forum description 1 |
|
||||
And I add a "Forum" to section "1" and I fill the form with:
|
||||
| Forum name | Test forum name 2 |
|
||||
| Description | Test forum description 2 |
|
||||
And "#section-2" "css_element" <should_see_other_sections> exist
|
||||
And <belowpage> "section" <should_see_other_sections> exist
|
||||
And I indent right "Test forum name 1" activity
|
||||
And "#section-2" "css_element" <should_see_other_sections> exist
|
||||
And <belowpage> "section" <should_see_other_sections> exist
|
||||
And I indent left "Test forum name 1" activity
|
||||
And "#section-2" "css_element" <should_see_other_sections> exist
|
||||
And <belowpage> "section" <should_see_other_sections> exist
|
||||
And I open "Test forum name 1" actions menu
|
||||
And I click on "Edit settings" "link" in the "Test forum name 1" activity
|
||||
And I should see "Updating Forum"
|
||||
@@ -63,38 +63,38 @@ Feature: Course activity controls works as expected
|
||||
| Description | Just to check that I can edit the description |
|
||||
| Display description on course page | 1 |
|
||||
And I click on "Cancel" "button"
|
||||
And "#section-2" "css_element" <should_see_other_sections> exist
|
||||
And <belowpage> "section" <should_see_other_sections> exist
|
||||
And I open "Test forum name 1" actions menu
|
||||
And I click on "Hide" "link" in the "Test forum name 1" activity
|
||||
And "#section-2" "css_element" <should_see_other_sections> exist
|
||||
And <belowpage> "section" <should_see_other_sections> exist
|
||||
And I delete "Test forum name 1" activity
|
||||
And I should not see "Test forum name 1" in the "#region-main" "css_element"
|
||||
And I duplicate "Test forum name 2" activity editing the new copy with:
|
||||
| Forum name | Edited test forum name 2 |
|
||||
And "#section-2" "css_element" <should_see_other_sections> exist
|
||||
And <belowpage> "section" <should_see_other_sections> exist
|
||||
And I should see "Test forum name 2"
|
||||
And I should see "Edited test forum name 2"
|
||||
And I hide section "1"
|
||||
And "#section-2" "css_element" <should_see_other_sections> exist
|
||||
And <belowpage> "section" <should_see_other_sections> exist
|
||||
And section "1" should be hidden
|
||||
And all activities in section "1" should be hidden
|
||||
And I show section "1"
|
||||
And "#section-2" "css_element" <should_see_other_sections> exist
|
||||
And <belowpage> "section" <should_see_other_sections> exist
|
||||
And section "1" should be visible
|
||||
And I add the "Section links" block
|
||||
And "#section-2" "css_element" <should_see_other_sections> exist
|
||||
And <belowpage> "section" <should_see_other_sections> exist
|
||||
And I should see "1 2 3 4 5" in the "Section links" "block"
|
||||
And I click on "2" "link" in the "Section links" "block"
|
||||
And I <should_see_other_sections_following_block_sections_links> see "Test forum name 2"
|
||||
|
||||
Examples:
|
||||
| courseformat | coursedisplay | targetpage | should_see_other_sections | should_see_other_sections_following_block_sections_links |
|
||||
| topics | 0 | "Course 1" | should | should |
|
||||
| topics | 1 | "Topic 1" | should not | should not |
|
||||
| topics | 1 | "Course 1" | should | should not |
|
||||
| weeks | 0 | "Course 1" | should | should |
|
||||
| weeks | 1 | "1 January - 7 January" | should not | should not |
|
||||
| weeks | 1 | "Course 1" | should | should not |
|
||||
| courseformat | coursedisplay | targetpage | should_see_other_sections | should_see_other_sections_following_block_sections_links | belowpage |
|
||||
| topics | 0 | "Course 1" | should | should | "Topic 2" |
|
||||
| topics | 1 | "Topic 1" | should not | should not | "Topic 2" |
|
||||
| topics | 1 | "Course 1" | should | should not | "Topic 2" |
|
||||
| weeks | 0 | "Course 1" | should | should | "8 January - 14 January" |
|
||||
| weeks | 1 | "1 January - 7 January" | should not | should not | "8 January - 14 January" |
|
||||
| weeks | 1 | "Course 1" | should | should not | "8 January - 14 January" |
|
||||
|
||||
Scenario Outline: General activities course controls using topics and weeks formats, and paged mode and not paged mode works as expected
|
||||
Given the following "users" exist:
|
||||
@@ -122,51 +122,51 @@ Feature: Course activity controls works as expected
|
||||
And I click on "Actions" "link" in the "Recent activity" "block"
|
||||
And I click on "Delete Recent activity block" "link"
|
||||
And I press "Yes"
|
||||
And "#section-2" "css_element" <should_see_other_sections> exist
|
||||
And <belowpage> "section" <should_see_other_sections> exist
|
||||
And I add a "Forum" to section "1" and I fill the form with:
|
||||
| Forum name | Test forum name 1 |
|
||||
| Description | Test forum description 1 |
|
||||
And I add a "Forum" to section "1" and I fill the form with:
|
||||
| Forum name | Test forum name 2 |
|
||||
| Description | Test forum description 2 |
|
||||
And "#section-2" "css_element" <should_see_other_sections> exist
|
||||
And <belowpage> "section" <should_see_other_sections> exist
|
||||
And I indent right "Test forum name 1" activity
|
||||
And "#section-2" "css_element" <should_see_other_sections> exist
|
||||
And <belowpage> "section" <should_see_other_sections> exist
|
||||
And I indent left "Test forum name 1" activity
|
||||
And "#section-2" "css_element" <should_see_other_sections> exist
|
||||
And <belowpage> "section" <should_see_other_sections> exist
|
||||
And I click on "Edit settings" "link" in the "Test forum name 1" activity
|
||||
And I should see "Updating Forum"
|
||||
And I should see "Display description on course page"
|
||||
And I press "Save and return to course"
|
||||
And "#section-2" "css_element" <should_see_other_sections> exist
|
||||
And <belowpage> "section" <should_see_other_sections> exist
|
||||
And I click on "Hide" "link" in the "Test forum name 1" activity
|
||||
And "#section-2" "css_element" <should_see_other_sections> exist
|
||||
And <belowpage> "section" <should_see_other_sections> exist
|
||||
And I delete "Test forum name 1" activity
|
||||
And "#section-2" "css_element" <should_see_other_sections> exist
|
||||
And <belowpage> "section" <should_see_other_sections> exist
|
||||
And I should not see "Test forum name 1" in the "#region-main" "css_element"
|
||||
And I duplicate "Test forum name 2" activity editing the new copy with:
|
||||
| Forum name | Edited test forum name 2 |
|
||||
And "#section-2" "css_element" <should_see_other_sections> exist
|
||||
And <belowpage> "section" <should_see_other_sections> exist
|
||||
And I should see "Test forum name 2"
|
||||
And I should see "Edited test forum name 2"
|
||||
And I hide section "1"
|
||||
And "#section-2" "css_element" <should_see_other_sections> exist
|
||||
And <belowpage> "section" <should_see_other_sections> exist
|
||||
And section "1" should be hidden
|
||||
And all activities in section "1" should be hidden
|
||||
And I show section "1"
|
||||
And "#section-2" "css_element" <should_see_other_sections> exist
|
||||
And <belowpage> "section" <should_see_other_sections> exist
|
||||
And section "1" should be visible
|
||||
And I add the "Section links" block
|
||||
And "#section-2" "css_element" <should_see_other_sections> exist
|
||||
And <belowpage> "section" <should_see_other_sections> exist
|
||||
And I should see "1 2 3 4 5" in the "Section links" "block"
|
||||
And I click on "2" "link" in the "Section links" "block"
|
||||
And I <should_see_other_sections_following_block_sections_links> see "Test forum name 2"
|
||||
|
||||
Examples:
|
||||
| courseformat | coursedisplay | targetpage | should_see_other_sections | should_see_other_sections_following_block_sections_links |
|
||||
| topics | 0 | "Course 1" | should | should |
|
||||
| topics | 1 | "Topic 1" | should not | should not |
|
||||
| topics | 1 | "Course 1" | should | should not |
|
||||
| weeks | 0 | "Course 1" | should | should |
|
||||
| weeks | 1 | "1 January - 7 January" | should not | should not |
|
||||
| weeks | 1 | "Course 1" | should | should not |
|
||||
| courseformat | coursedisplay | targetpage | should_see_other_sections | should_see_other_sections_following_block_sections_links | belowpage |
|
||||
| topics | 0 | "Course 1" | should | should | "Topic 2" |
|
||||
| topics | 1 | "Topic 1" | should not | should not | "Topic 2" |
|
||||
| topics | 1 | "Course 1" | should | should not | "Topic 2" |
|
||||
| weeks | 0 | "Course 1" | should | should | "8 January - 14 January" |
|
||||
| weeks | 1 | "1 January - 7 January" | should not | should not | "8 January - 14 January" |
|
||||
| weeks | 1 | "Course 1" | should | should not | "8 January - 14 January" |
|
||||
|
||||
@@ -29,8 +29,8 @@ Feature: Activities can be moved between sections
|
||||
|
||||
Scenario: Move activities in a single page course with Javascript disabled
|
||||
When I move "Test forum name" activity to section "2"
|
||||
Then I should see "Test forum name" in the "#section-2" "css_element"
|
||||
And I should not see "Test forum name" in the "#section-1" "css_element"
|
||||
Then I should see "Test forum name" in the "Topic 2" "section"
|
||||
And I should not see "Test forum name" in the "Topic 1" "section"
|
||||
|
||||
Scenario: Move activities in the course home with Javascript disabled using paged mode
|
||||
Given I click on "Edit settings" "link" in the "Administration" "block"
|
||||
@@ -38,8 +38,8 @@ Feature: Activities can be moved between sections
|
||||
| Course layout | Show one section per page |
|
||||
And I press "Save changes"
|
||||
When I move "Test forum name" activity to section "2"
|
||||
Then I should see "Test forum name" in the "#section-2" "css_element"
|
||||
And I should not see "Test forum name" in the "#section-1" "css_element"
|
||||
Then I should see "Test forum name" in the "Topic 2" "section"
|
||||
And I should not see "Test forum name" in the "Topic 1" "section"
|
||||
|
||||
Scenario: Move activities in a course section with Javascript disabled using paged mode
|
||||
Given I click on "Edit settings" "link" in the "Administration" "block"
|
||||
|
||||
@@ -23,9 +23,9 @@ Feature: Sections can be moved
|
||||
| Forum name | Test forum name |
|
||||
| Description | Test forum description |
|
||||
When I move down section "1"
|
||||
Then I should see "Test forum name" in the "#section-2" "css_element"
|
||||
Then I should see "Test forum name" in the "Topic 2" "section"
|
||||
And I move up section "2"
|
||||
And I should see "Test forum name" in the "#section-1" "css_element"
|
||||
And I should see "Test forum name" in the "Topic 1" "section"
|
||||
|
||||
Scenario: Move up and down a section with Javascript disabled in the course home of a course using paged mode
|
||||
Given I click on "Edit settings" "link" in the "Administration" "block"
|
||||
@@ -36,9 +36,9 @@ Feature: Sections can be moved
|
||||
| Forum name | Test forum name |
|
||||
| Description | Test forum description |
|
||||
When I move down section "1"
|
||||
Then I should see "Test forum name" in the "#section-2" "css_element"
|
||||
Then I should see "Test forum name" in the "Topic 2" "section"
|
||||
And I move up section "2"
|
||||
And I should see "Test forum name" in the "#section-1" "css_element"
|
||||
And I should see "Test forum name" in the "Topic 1" "section"
|
||||
|
||||
Scenario: Sections can not be moved with Javascript disabled in a section page of a course using paged mode
|
||||
Given I click on "Edit settings" "link" in the "Administration" "block"
|
||||
@@ -49,7 +49,7 @@ Feature: Sections can be moved
|
||||
| Forum name | Test forum name |
|
||||
| Description | Test forum description |
|
||||
When I follow "Topic 2"
|
||||
Then "#section-1" "css_element" should not exist
|
||||
And "#section-3" "css_element" should not exist
|
||||
Then "Topic 1" "section" should not exist
|
||||
And "Topic 3" "section" should not exist
|
||||
And "Move down" "link" should not exist
|
||||
And "Move up" "link" should not exist
|
||||
|
||||
@@ -11,11 +11,11 @@ Feature: Course paged mode
|
||||
| Course 1 | C1 | 0 | <courseformat> | 1 | 3 |
|
||||
And I log in as "admin"
|
||||
And I follow "Course 1"
|
||||
Then I click on <section2> "link" in the "#section-2" "css_element"
|
||||
Then I click on <section2> "link" in the <section2> "section"
|
||||
And I follow "C1"
|
||||
And I click on <section3> "link" in the "#section-3" "css_element"
|
||||
And I click on <section3> "link" in the <section3> "section"
|
||||
And I follow "C1"
|
||||
And I click on <section1> "link" in the "#section-1" "css_element"
|
||||
And I click on <section1> "link" in the <section1> "section"
|
||||
And I should see <section1> in the "div.single-section" "css_element"
|
||||
And I should see <section2> in the ".single-section span.mdl-right" "css_element"
|
||||
And I should not see <prevunexistingsection> in the ".single-section" "css_element"
|
||||
@@ -44,11 +44,11 @@ Feature: Course paged mode
|
||||
| Course 1 | C1 | 0 | <courseformat> | 1 | 3 |
|
||||
And I log in as "admin"
|
||||
And I follow "Course 1"
|
||||
Then I click on <section2> "link" in the "#section-2" "css_element"
|
||||
Then I click on <section2> "link" in the <section2> "section"
|
||||
And I follow "C1"
|
||||
And I click on <section3> "link" in the "#section-3" "css_element"
|
||||
And I click on <section3> "link" in the <section3> "section"
|
||||
And I follow "C1"
|
||||
And I click on <section1> "link" in the "#section-1" "css_element"
|
||||
And I click on <section1> "link" in the <section1> "section"
|
||||
And I should see <section1> in the "div.single-section" "css_element"
|
||||
And I should see <section2> in the ".single-section span.mdl-right" "css_element"
|
||||
And I should not see <prevunexistingsection> in the ".single-section" "css_element"
|
||||
|
||||
@@ -1726,7 +1726,7 @@ class core_course_courselib_testcase extends advanced_testcase {
|
||||
$bc->execute_plan();
|
||||
$results = $bc->get_results();
|
||||
$file = $results['backup_destination'];
|
||||
$fp = get_file_packer();
|
||||
$fp = get_file_packer('application/vnd.moodle.backup');
|
||||
$filepath = $CFG->dataroot . '/temp/backup/test-restore-course-event';
|
||||
$file->extract_to_pathname($fp, $filepath);
|
||||
$bc->destroy();
|
||||
|
||||
@@ -611,12 +611,14 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
|
||||
$formattedtext = format_text($cm->content, FORMAT_HTML,
|
||||
array('noclean' => true, 'para' => false, 'filter' => false));
|
||||
$this->assertEquals($formattedtext, $module['description']);
|
||||
$this->assertEquals($forumcm->instance, $module['instance']);
|
||||
$testexecuted = $testexecuted + 1;
|
||||
} else if ($module['id'] == $labelcm->id and $module['modname'] == 'label') {
|
||||
$cm = $modinfo->cms[$labelcm->id];
|
||||
$formattedtext = format_text($cm->content, FORMAT_HTML,
|
||||
array('noclean' => true, 'para' => false, 'filter' => false));
|
||||
$this->assertEquals($formattedtext, $module['description']);
|
||||
$this->assertEquals($labelcm->instance, $module['instance']);
|
||||
$testexecuted = $testexecuted + 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -263,8 +263,10 @@ class enrol_manual_plugin extends enrol_plugin {
|
||||
'enrol',
|
||||
'enrolmentoptions',
|
||||
'enrolusers',
|
||||
'enrolxusers',
|
||||
'errajaxfailedenrol',
|
||||
'errajaxsearch',
|
||||
'foundxcohorts',
|
||||
'none',
|
||||
'usersearch',
|
||||
'unlimitedduration',
|
||||
|
||||
+2
-2
@@ -451,13 +451,13 @@ YUI.add('moodle-enrol_manual-quickenrolment', function(Y) {
|
||||
.append(create('<div class="'+CSS.DETAILS+'"></div>')
|
||||
.append(create('<div class="'+CSS.COHORTNAME+'">'+cohort.name+'</div>')))
|
||||
.append(create('<div class="'+CSS.OPTIONS+'"></div>')
|
||||
.append(create('<input type="button" class="'+CSS.ENROL+'" value="'+'Enrol '+cohort.cnt+' users'+'" />'))) // TODO string
|
||||
.append(create('<input type="button" class="' + CSS.ENROL + '" value="' + M.util.get_string('enrolxusers', 'enrol', cohort.cnt) + '" />')))
|
||||
);
|
||||
}
|
||||
this.set(UEP.COHORTCOUNT, count);
|
||||
if (!args.append) {
|
||||
//var usersstr = (result.response.totalusers == '1')?M.str.enrol.ajaxoneuserfound:M.util.get_string('ajaxxusersfound','enrol', result.response.totalusers);
|
||||
var cohortsstr = 'Found '+result.response.totalcohorts+' cohorts'; // TODO
|
||||
var cohortsstr = M.util.get_string('foundxcohorts', 'enrol', result.response.totalcohorts);
|
||||
var content = create('<div class="'+CSS.SEARCHRESULTS+'"></div>')
|
||||
.append(create('<div class="'+CSS.TOTALCOHORTS+'">'+cohortsstr+'</div>'))
|
||||
.append(cohorts);
|
||||
|
||||
@@ -759,8 +759,10 @@ class course_enrolment_other_users_table extends course_enrolment_table {
|
||||
'enrol',
|
||||
'enrolmentoptions',
|
||||
'enrolusers',
|
||||
'enrolxusers',
|
||||
'errajaxfailedenrol',
|
||||
'errajaxsearch',
|
||||
'foundxcohorts',
|
||||
'none',
|
||||
'usersearch',
|
||||
'unlimitedduration',
|
||||
|
||||
@@ -39,8 +39,10 @@ class enrol_self_edit_form extends moodleform {
|
||||
|
||||
$mform->addElement('header', 'header', get_string('pluginname', 'enrol_self'));
|
||||
|
||||
$mform->addElement('text', 'name', get_string('custominstancename', 'enrol'));
|
||||
$nameattribs = array('size' => '20', 'maxlength' => '255');
|
||||
$mform->addElement('text', 'name', get_string('custominstancename', 'enrol'), $nameattribs);
|
||||
$mform->setType('name', PARAM_TEXT);
|
||||
$mform->addRule('name', get_string('maximumchars', '', 255), 'maxlength', 255, 'server');
|
||||
|
||||
$options = array(ENROL_INSTANCE_ENABLED => get_string('yes'),
|
||||
ENROL_INSTANCE_DISABLED => get_string('no'));
|
||||
@@ -52,11 +54,13 @@ class enrol_self_edit_form extends moodleform {
|
||||
$mform->addHelpButton('customint6', 'newenrols', 'enrol_self');
|
||||
$mform->disabledIf('customint6', 'status', 'eq', ENROL_INSTANCE_DISABLED);
|
||||
|
||||
$mform->addElement('passwordunmask', 'password', get_string('password', 'enrol_self'));
|
||||
$passattribs = array('size' => '20', 'maxlength' => '50');
|
||||
$mform->addElement('passwordunmask', 'password', get_string('password', 'enrol_self'), $passattribs);
|
||||
$mform->addHelpButton('password', 'password', 'enrol_self');
|
||||
if (empty($instance->id) and $plugin->get_config('requirepassword')) {
|
||||
$mform->addRule('password', get_string('required'), 'required', null, 'client');
|
||||
}
|
||||
$mform->addRule('password', get_string('maximumchars', '', 50), 'maxlength', 50, 'server');
|
||||
|
||||
$options = array(1 => get_string('yes'),
|
||||
0 => get_string('no'));
|
||||
|
||||
@@ -87,7 +87,8 @@ if (!$file = $fs->get_file_by_hash(sha1($fullpath))) {
|
||||
if (strrpos($fullpath, '/') !== strlen($fullpath) -1 ) {
|
||||
$fullpath .= '/';
|
||||
}
|
||||
if (!$file = $fs->get_file_by_hash(sha1($fullpath.'/.'))) {
|
||||
// Try to fallback to the directory named as the supposed file.
|
||||
if (!$file = $fs->get_file_by_hash(sha1($fullpath.'.'))) {
|
||||
send_file_not_found();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,47 @@ function xmldb_filter_mathjaxloader_upgrade($oldversion) {
|
||||
|
||||
// Moodle v2.8.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
if ($oldversion < 2014111001) {
|
||||
|
||||
$oldconfig = get_config('filter_mathjaxloader', 'mathjaxconfig');
|
||||
$olddefault = 'MathJax.Hub.Config({
|
||||
config: ["MMLorHTML.js", "Safe.js"],
|
||||
jax: ["input/TeX","input/MathML","output/HTML-CSS","output/NativeMML"],
|
||||
extensions: ["tex2jax.js","mml2jax.js","MathMenu.js","MathZoom.js"],
|
||||
TeX: {
|
||||
extensions: ["AMSmath.js","AMSsymbols.js","noErrors.js","noUndefined.js"]
|
||||
},
|
||||
menuSettings: {
|
||||
zoom: "Double-Click",
|
||||
mpContext: true,
|
||||
mpMouse: true
|
||||
},
|
||||
errorSettings: { message: ["!"] },
|
||||
skipStartupTypeset: true,
|
||||
messageStyle: "none"
|
||||
});
|
||||
';
|
||||
$newdefault = '
|
||||
MathJax.Hub.Config({
|
||||
config: ["Accessible.js", "Safe.js"],
|
||||
errorSettings: { message: ["!"] },
|
||||
skipStartupTypeset: true,
|
||||
messageStyle: "none"
|
||||
});
|
||||
';
|
||||
|
||||
// Ignore white space changes.
|
||||
$oldconfig = trim(preg_replace('/\s+/', ' ', $oldconfig));
|
||||
$olddefault = trim(preg_replace('/\s+/', ' ', $olddefault));
|
||||
|
||||
// Update the default config for mathjax only if it has not been customised.
|
||||
|
||||
if ($oldconfig == $olddefault) {
|
||||
set_config('mathjaxconfig', $newdefault, 'filter_mathjaxloader');
|
||||
}
|
||||
|
||||
upgrade_plugin_savepoint(true, 2014111001, 'filter', 'mathjaxloader');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ class filter_mathjaxloader extends moodle_text_filter {
|
||||
$text = str_replace('[tex]', '\\(', $text);
|
||||
$text = str_replace('[/tex]', '\\)', $text);
|
||||
// E.g. "$$ blah $$".
|
||||
$text = preg_replace('|\$\$[\S\s]\$\$|u', '\\(\1\\)', $text);
|
||||
$text = preg_replace('|\$\$([\S\s]*?)\$\$|u', '\\(\1\\)', $text);
|
||||
// E.g. "\[ blah \]".
|
||||
$text = str_replace('\\[', '\\(', $text);
|
||||
$text = str_replace('\\]', '\\)', $text);
|
||||
|
||||
@@ -52,17 +52,7 @@ if ($ADMIN->fulltree) {
|
||||
|
||||
$default = '
|
||||
MathJax.Hub.Config({
|
||||
config: ["MMLorHTML.js", "Safe.js"],
|
||||
jax: ["input/TeX","input/MathML","output/HTML-CSS","output/NativeMML"],
|
||||
extensions: ["tex2jax.js","mml2jax.js","MathMenu.js","MathZoom.js"],
|
||||
TeX: {
|
||||
extensions: ["AMSmath.js","AMSsymbols.js","noErrors.js","noUndefined.js"]
|
||||
},
|
||||
menuSettings: {
|
||||
zoom: "Double-Click",
|
||||
mpContext: true,
|
||||
mpMouse: true
|
||||
},
|
||||
config: ["Accessible.js", "Safe.js"],
|
||||
errorSettings: { message: ["!"] },
|
||||
skipStartupTypeset: true,
|
||||
messageStyle: "none"
|
||||
|
||||
@@ -24,6 +24,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2014111000;
|
||||
$plugin->version = 2014111001;
|
||||
$plugin->requires = 2014110400; // Requires this Moodle version
|
||||
$plugin->component= 'filter_mathjaxloader';
|
||||
|
||||
@@ -134,10 +134,9 @@ class filter_urltolink extends moodle_text_filter {
|
||||
|
||||
// Lookbehind assertions.
|
||||
// Is not HTML attribute or CSS URL property. Unfortunately legit text like "url(http://...)" will not be a link.
|
||||
$lookbehindstart = "(?<!=[\"']|\burl\([\"' ]|\burl\()";
|
||||
$lookbehindend = "(?<![]),.;])";
|
||||
|
||||
$regex = "$lookbehindstart$urlstart((?:$domainsegment\.)+$domainsegment|$numericip)" .
|
||||
$regex = "$urlstart((?:$domainsegment\.)+$domainsegment|$numericip)" .
|
||||
"($port?$path$querystring?$fragment?)$lookbehindend";
|
||||
if ($unicoderegexp) {
|
||||
$regex = '#' . $regex . '#ui';
|
||||
@@ -145,7 +144,38 @@ class filter_urltolink extends moodle_text_filter {
|
||||
$regex = '#' . preg_replace(array('\pLl', '\PL'), 'a-z', $regex) . '#i';
|
||||
}
|
||||
|
||||
$text = preg_replace($regex, '<a href="http$1://$2$3$4" class="_blanktarget">$0</a>', $text);
|
||||
// Locate any HTML tags.
|
||||
$matches = preg_split('/(<[^<|>]*>)/i', $text, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
|
||||
|
||||
// Iterate through the tokenized text to handle chunks (html and content).
|
||||
foreach ($matches as $idx => $chunk) {
|
||||
// Nothing to do. We skip completely any html chunk.
|
||||
if (strpos(trim($chunk), '<') === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Nothing to do. We skip any content chunk having any of these attributes.
|
||||
if (preg_match('#(background=")|(action=")|(style="background)|(href=")|(src=")|(url [(])#', $chunk)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Arrived here, we want to process every word in this chunk.
|
||||
$text = $chunk;
|
||||
$words = explode(' ', $text);
|
||||
|
||||
foreach ($words as $idx2 => $word) {
|
||||
// ReDoS protection. Stop processing if a word is too large.
|
||||
if (strlen($word) < 4096) {
|
||||
$words[$idx2] = preg_replace($regex, '<a href="http$1://$2$3$4" class="_blanktarget">$0</a>', $word);
|
||||
}
|
||||
}
|
||||
$text = implode(' ', $words);
|
||||
|
||||
// Copy the result back to the array.
|
||||
$matches[$idx] = $text;
|
||||
}
|
||||
|
||||
$text = implode('', $matches);
|
||||
|
||||
if (!empty($ignoretags)) {
|
||||
$ignoretags = array_reverse($ignoretags); /// Reversed so "progressive" str_replace() will solve some nesting problems.
|
||||
|
||||
@@ -29,9 +29,13 @@ global $CFG;
|
||||
require_once($CFG->dirroot . '/filter/urltolink/filter.php'); // Include the code to test
|
||||
|
||||
|
||||
class filter_urltolink_testcase extends basic_testcase {
|
||||
class filter_urltolink_filter_testcase extends basic_testcase {
|
||||
|
||||
function get_convert_urls_into_links_test_cases() {
|
||||
// Create a 4095 and 4096 long URLs.
|
||||
$superlong4095 = str_pad('http://www.superlong4095.com?this=something', 4095, 'a');
|
||||
$superlong4096 = str_pad('http://www.superlong4096.com?this=something', 4096, 'a');
|
||||
|
||||
$texts = array (
|
||||
//just a url
|
||||
'http://moodle.org - URL' => '<a href="http://moodle.org" class="_blanktarget">http://moodle.org</a> - URL',
|
||||
@@ -130,6 +134,7 @@ class filter_urltolink_testcase extends basic_testcase {
|
||||
'<td background="http://moodle.org"> </td>' => '<td background="http://moodle.org"> </td>',
|
||||
'<td background="www.moodle.org"> </td>' => '<td background="www.moodle.org"> </td>',
|
||||
'<form name="input" action="http://moodle.org/submit.asp" method="get">'=>'<form name="input" action="http://moodle.org/submit.asp" method="get">',
|
||||
'<input type="submit" value="Go to http://moodle.org">' => '<input type="submit" value="Go to http://moodle.org">',
|
||||
'<td background="https://www.moodle.org"> </td>' => '<td background="https://www.moodle.org"> </td>',
|
||||
// CSS URLs.
|
||||
'<table style="background-image: url(\'http://moodle.org/pic.jpg\');">' => '<table style="background-image: url(\'http://moodle.org/pic.jpg\');">',
|
||||
@@ -148,6 +153,27 @@ class filter_urltolink_testcase extends basic_testcase {
|
||||
//Encoded URLs in the query
|
||||
'URL: http://127.0.0.1/path/to?param=value_with%28parenthesis%29¶m2=1' => 'URL: <a href="http://127.0.0.1/path/to?param=value_with%28parenthesis%29¶m2=1" class="_blanktarget">http://127.0.0.1/path/to?param=value_with%28parenthesis%29¶m2=1</a>',
|
||||
'URL: www.localhost.com/path/to?param=value_with%28parenthesis%29¶m2=1' => 'URL: <a href="http://www.localhost.com/path/to?param=value_with%28parenthesis%29¶m2=1" class="_blanktarget">www.localhost.com/path/to?param=value_with%28parenthesis%29¶m2=1</a>',
|
||||
// Test URL less than 4096 characters in size is converted to link.
|
||||
'URL: ' . $superlong4095 => 'URL: <a href="' . $superlong4095 . '" class="_blanktarget">' . $superlong4095 . '</a>',
|
||||
// Test URL equal to or greater than 4096 characters in size is not converted to link.
|
||||
'URL: ' . $superlong4096 => 'URL: ' . $superlong4096,
|
||||
// Testing URL within a span tag.
|
||||
'URL: <span style="kasd"> my link to http://google.com </span>' => 'URL: <span style="kasd"> my link to <a href="http://google.com" class="_blanktarget">http://google.com</a> </span>',
|
||||
// Nested tags test.
|
||||
'<b><i>www.google.com</i></b>' => '<b><i><a href="http://www.google.com" class="_blanktarget">www.google.com</a></i></b>',
|
||||
'<input type="submit" value="Go to http://moodle.org">' => '<input type="submit" value="Go to http://moodle.org">',
|
||||
// Test realistic content.
|
||||
'<p><span style="color: rgb(37, 37, 37); font-family: sans-serif; line-height: 22.3999996185303px;">Lorem ipsum amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut http://google.com aliquip ex ea <a href="http://google.com">commodo consequat</a>. Duis aute irure in reprehenderit in excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia https://docs.google.com/document/d/BrokenLinkPleaseAyacDHc_Ov8aoskoSVQsfmLHP_jYAkRMk/edit?usp=sharing https://docs.google.com/document/d/BrokenLinkPleaseAyacDHc_Ov8aoskoSVQsfmLHP_jYAkRMk/edit?usp=sharing mollit anim id est laborum.</span><br></p>'
|
||||
=>
|
||||
'<p><span style="color: rgb(37, 37, 37); font-family: sans-serif; line-height: 22.3999996185303px;">Lorem ipsum amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut <a href="http://google.com" class="_blanktarget">http://google.com</a> aliquip ex ea <a href="http://google.com">commodo consequat</a>. Duis aute irure in reprehenderit in excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia <a href="https://docs.google.com/document/d/BrokenLinkPleaseAyacDHc_Ov8aoskoSVQsfmLHP_jYAkRMk/edit?usp=sharing" class="_blanktarget">https://docs.google.com/document/d/BrokenLinkPleaseAyacDHc_Ov8aoskoSVQsfmLHP_jYAkRMk/edit?usp=sharing</a> <a href="https://docs.google.com/document/d/BrokenLinkPleaseAyacDHc_Ov8aoskoSVQsfmLHP_jYAkRMk/edit?usp=sharing" class="_blanktarget">https://docs.google.com/document/d/BrokenLinkPleaseAyacDHc_Ov8aoskoSVQsfmLHP_jYAkRMk/edit?usp=sharing</a> mollit anim id est laborum.</span><br></p>',
|
||||
// Test some broken html.
|
||||
'5 < 10 www.google.com <a href="hi.com">im a link</a>' => '5 < 10 <a href="http://www.google.com" class="_blanktarget">www.google.com</a> <a href="hi.com">im a link</a>',
|
||||
'h3 (www.styles.com/h3) < h1 (www.styles.com/h1)' => 'h3 (<a href="http://www.styles.com/h3" class="_blanktarget">www.styles.com/h3</a>) < h1 (<a href="http://www.styles.com/h1" class="_blanktarget">www.styles.com/h1</a>)',
|
||||
'<p>text www.moodle.org</p> text' => '<p>text <a href="http://www.moodle.org" class="_blanktarget">www.moodle.org</a></p> text',
|
||||
// Some more urls.
|
||||
'<link rel="search" type="application/opensearchdescription+xml" href="/osd.jsp" title="Peer review - Moodle Tracker"/>' => '<link rel="search" type="application/opensearchdescription+xml" href="/osd.jsp" title="Peer review - Moodle Tracker"/>',
|
||||
'<a href="https://docs.moodle.org/dev/Main_Page"></a><span>www.google.com</span><span class="placeholder"></span>' => '<a href="https://docs.moodle.org/dev/Main_Page"></a><span><a href="http://www.google.com" class="_blanktarget">www.google.com</a></span><span class="placeholder"></span>',
|
||||
'http://nolandforzombies.com <a href="zombiesFTW.com">Zombies FTW</a> http://aliens.org' => '<a href="http://nolandforzombies.com" class="_blanktarget">http://nolandforzombies.com</a> <a href="zombiesFTW.com">Zombies FTW</a> <a href="http://aliens.org" class="_blanktarget">http://aliens.org</a>',
|
||||
//URLs in Javascript. Commented out as part of MDL-21183
|
||||
//'var url="http://moodle.org";'=>'var url="http://moodle.org";',
|
||||
//'var url = "http://moodle.org";'=>'var url = "http://moodle.org";',
|
||||
|
||||
@@ -196,6 +196,8 @@ class grade_export_form extends moodleform {
|
||||
$submitstring = get_string('download');
|
||||
if (empty($features['simpleui'])) {
|
||||
$submitstring = get_string('submit');
|
||||
} else if (!empty($CFG->gradepublishing)) {
|
||||
$submitstring = get_string('export', 'grades');
|
||||
}
|
||||
|
||||
$this->add_action_buttons(false, $submitstring);
|
||||
|
||||
+169
-10
@@ -383,16 +383,30 @@ abstract class grade_export {
|
||||
$itemidsparam = '-1';
|
||||
}
|
||||
|
||||
$params = array('id' =>$this->course->id,
|
||||
'groupid' =>$this->groupid,
|
||||
'itemids' =>$itemidsparam,
|
||||
'export_letters' =>$this->export_letters,
|
||||
'export_feedback' =>$this->export_feedback,
|
||||
'updatedgradesonly' =>$this->updatedgradesonly,
|
||||
'displaytype' =>$this->displaytype,
|
||||
'decimalpoints' =>$this->decimalpoints,
|
||||
'export_onlyactive' =>$this->onlyactive,
|
||||
'usercustomfields' =>$this->usercustomfields);
|
||||
// We have a single grade display type constant.
|
||||
if (!is_array($this->displaytype)) {
|
||||
$displaytypes = $this->displaytype;
|
||||
} else {
|
||||
// Implode the grade display types array as moodle_url function doesn't accept arrays.
|
||||
$displaytypes = implode(',', $this->displaytype);
|
||||
}
|
||||
|
||||
if (!empty($this->updatedgradesonly)) {
|
||||
$updatedgradesonly = $this->updatedgradesonly;
|
||||
} else {
|
||||
$updatedgradesonly = 0;
|
||||
}
|
||||
$params = array('id' => $this->course->id,
|
||||
'groupid' => $this->groupid,
|
||||
'itemids' => $itemidsparam,
|
||||
'export_letters' => $this->export_letters,
|
||||
'export_feedback' => $this->export_feedback,
|
||||
'updatedgradesonly' => $updatedgradesonly,
|
||||
'decimalpoints' => $this->decimalpoints,
|
||||
'export_onlyactive' => $this->onlyactive,
|
||||
'usercustomfields' => $this->usercustomfields,
|
||||
'displaytype' => $displaytypes,
|
||||
'key' => $this->userkey);
|
||||
|
||||
return $params;
|
||||
}
|
||||
@@ -436,6 +450,151 @@ abstract class grade_export {
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the export url.
|
||||
*
|
||||
* Get submitted form data and create the url to be used on the grade publish feature.
|
||||
*
|
||||
* @return moodle_url the url of grade publishing export.
|
||||
*/
|
||||
public function get_export_url() {
|
||||
return new moodle_url('/grade/export/'.$this->plugin.'/dump.php', $this->get_export_params());
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the grade display types parameter into the required array to grade exporting class.
|
||||
*
|
||||
* In order to export, the array key must be the display type name and the value must be the grade display type
|
||||
* constant.
|
||||
*
|
||||
* Note: Added support for combined display types constants like the (GRADE_DISPLAY_TYPE_PERCENTAGE_REAL) as
|
||||
* the $CFG->grade_export_displaytype config is still used on 2.7 in case of missing displaytype url param.
|
||||
* In these cases, the file will be exported with a column for each display type.
|
||||
*
|
||||
* @param string $displaytypes can be a single or multiple display type constants comma separated.
|
||||
* @return array $types
|
||||
*/
|
||||
public static function convert_flat_displaytypes_to_array($displaytypes) {
|
||||
$types = array();
|
||||
|
||||
// We have a single grade display type constant.
|
||||
if (is_int($displaytypes)) {
|
||||
$displaytype = clean_param($displaytypes, PARAM_INT);
|
||||
|
||||
// Let's set a default value, will be replaced below by the grade display type constant.
|
||||
$display[$displaytype] = 1;
|
||||
} else {
|
||||
// Multiple grade display types constants.
|
||||
$display = array_flip(explode(',', $displaytypes));
|
||||
}
|
||||
|
||||
// Now, create the array in the required format by grade exporting class.
|
||||
foreach ($display as $type => $value) {
|
||||
$type = clean_param($type, PARAM_INT);
|
||||
if ($type == GRADE_DISPLAY_TYPE_LETTER) {
|
||||
$types['letter'] = GRADE_DISPLAY_TYPE_LETTER;
|
||||
} else if ($type == GRADE_DISPLAY_TYPE_PERCENTAGE) {
|
||||
$types['percentage'] = GRADE_DISPLAY_TYPE_PERCENTAGE;
|
||||
} else if ($type == GRADE_DISPLAY_TYPE_REAL) {
|
||||
$types['real'] = GRADE_DISPLAY_TYPE_REAL;
|
||||
} else if ($type == GRADE_DISPLAY_TYPE_REAL_PERCENTAGE) {
|
||||
$types['real'] = GRADE_DISPLAY_TYPE_REAL;
|
||||
$types['percentage'] = GRADE_DISPLAY_TYPE_PERCENTAGE;
|
||||
} else if ($type == GRADE_DISPLAY_TYPE_REAL_LETTER) {
|
||||
$types['real'] = GRADE_DISPLAY_TYPE_REAL;
|
||||
$types['letter'] = GRADE_DISPLAY_TYPE_LETTER;
|
||||
} else if ($type == GRADE_DISPLAY_TYPE_LETTER_REAL) {
|
||||
$types['letter'] = GRADE_DISPLAY_TYPE_LETTER;
|
||||
$types['real'] = GRADE_DISPLAY_TYPE_REAL;
|
||||
} else if ($type == GRADE_DISPLAY_TYPE_LETTER_PERCENTAGE) {
|
||||
$types['letter'] = GRADE_DISPLAY_TYPE_LETTER;
|
||||
$types['percentage'] = GRADE_DISPLAY_TYPE_PERCENTAGE;
|
||||
} else if ($type == GRADE_DISPLAY_TYPE_PERCENTAGE_LETTER) {
|
||||
$types['percentage'] = GRADE_DISPLAY_TYPE_PERCENTAGE;
|
||||
$types['letter'] = GRADE_DISPLAY_TYPE_LETTER;
|
||||
} else if ($type == GRADE_DISPLAY_TYPE_PERCENTAGE_REAL) {
|
||||
$types['percentage'] = GRADE_DISPLAY_TYPE_PERCENTAGE;
|
||||
$types['real'] = GRADE_DISPLAY_TYPE_REAL;
|
||||
}
|
||||
}
|
||||
return $types;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the item ids parameter into the required array to grade exporting class.
|
||||
*
|
||||
* In order to export, the array key must be the grade item id and all values must be one.
|
||||
*
|
||||
* @param string $itemids can be a single item id or many item ids comma separated.
|
||||
* @return array $items correctly formatted array.
|
||||
*/
|
||||
public static function convert_flat_itemids_to_array($itemids) {
|
||||
$items = array();
|
||||
|
||||
// We just have one single item id.
|
||||
if (is_int($itemids)) {
|
||||
$itemid = clean_param($itemids, PARAM_INT);
|
||||
$items[$itemid] = 1;
|
||||
} else {
|
||||
// Few grade items.
|
||||
$items = array_flip(explode(',', $itemids));
|
||||
foreach ($items as $itemid => $value) {
|
||||
$itemid = clean_param($itemid, PARAM_INT);
|
||||
$items[$itemid] = 1;
|
||||
}
|
||||
}
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the html code of the grade publishing feature.
|
||||
*
|
||||
* @return string $output html code of the grade publishing.
|
||||
*/
|
||||
public function get_grade_publishing_url() {
|
||||
$url = $this->get_export_url();
|
||||
$output = html_writer::start_div();
|
||||
$output .= html_writer::tag('p', get_string('gradepublishinglink', 'grades', html_writer::link($url, $url)));
|
||||
$output .= html_writer::end_div();
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a stdClass object from URL parameters to be used by grade_export class.
|
||||
*
|
||||
* @param int $id course id.
|
||||
* @param string $itemids grade items comma separated.
|
||||
* @param bool $exportfeedback export feedback option.
|
||||
* @param bool $onlyactive only enrolled active students.
|
||||
* @param string $displaytype grade display type constants comma separated.
|
||||
* @param int $decimalpoints grade decimal points.
|
||||
* @param null $updatedgradesonly recently updated grades only (Used by XML exporting only).
|
||||
* @param null $separator separator character: tab, comma, colon and semicolon (Used by TXT exporting only).
|
||||
*
|
||||
* @return stdClass $formdata
|
||||
*/
|
||||
public static function export_bulk_export_data($id, $itemids, $exportfeedback, $onlyactive, $displaytype,
|
||||
$decimalpoints, $updatedgradesonly = null, $separator = null) {
|
||||
|
||||
$formdata = new \stdClass();
|
||||
$formdata->id = $id;
|
||||
$formdata->itemids = self::convert_flat_itemids_to_array($itemids);
|
||||
$formdata->exportfeedback = $exportfeedback;
|
||||
$formdata->export_onlyactive = $onlyactive;
|
||||
$formdata->display = self::convert_flat_displaytypes_to_array($displaytype);
|
||||
$formdata->decimals = $decimalpoints;
|
||||
|
||||
if (!empty($updatedgradesonly)) {
|
||||
$formdata->updatedgradesonly = $updatedgradesonly;
|
||||
}
|
||||
|
||||
if (!empty($separator)) {
|
||||
$formdata->separator = $separator;
|
||||
}
|
||||
|
||||
return $formdata;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,8 +17,16 @@
|
||||
|
||||
define('NO_MOODLE_COOKIES', true); // session not used here
|
||||
require_once '../../../config.php';
|
||||
require_once($CFG->dirroot.'/grade/export/ods/grade_export_ods.php');
|
||||
|
||||
$id = required_param('id', PARAM_INT);
|
||||
$groupid = optional_param('groupid', 0, PARAM_INT);
|
||||
$itemids = required_param('itemids', PARAM_RAW);
|
||||
$exportfeedback = optional_param('export_feedback', 0, PARAM_BOOL);
|
||||
$displaytype = optional_param('displaytype', $CFG->grade_export_displaytype, PARAM_RAW);
|
||||
$decimalpoints = optional_param('decimalpoints', $CFG->grade_export_decimalpoints, PARAM_INT);
|
||||
$onlyactive = optional_param('export_onlyactive', 0, PARAM_BOOL);
|
||||
|
||||
$id = required_param('id', PARAM_INT); // course id
|
||||
if (!$course = $DB->get_record('course', array('id'=>$id))) {
|
||||
print_error('nocourseid');
|
||||
}
|
||||
@@ -30,9 +38,19 @@ if (empty($CFG->gradepublishing)) {
|
||||
}
|
||||
|
||||
$context = context_course::instance($id);
|
||||
require_capability('moodle/grade:export', $context);
|
||||
require_capability('gradeexport/ods:view', $context);
|
||||
require_capability('gradeexport/ods:publish', $context);
|
||||
|
||||
// use the same page parameters as export.php and append &key=sdhakjsahdksahdkjsahksadjksahdkjsadhksa
|
||||
require 'export.php';
|
||||
if (!groups_group_visible($groupid, $COURSE)) {
|
||||
print_error('cannotaccessgroup', 'grades');
|
||||
}
|
||||
|
||||
// Get all url parameters and create an object to simulate a form submission.
|
||||
$formdata = grade_export::export_bulk_export_data($id, $itemids, $exportfeedback, $onlyactive, $displaytype,
|
||||
$decimalpoints);
|
||||
|
||||
$export = new grade_export_ods($course, $groupid, $formdata);
|
||||
$export->print_grades();
|
||||
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ require_once $CFG->dirroot.'/grade/export/lib.php';
|
||||
require_once 'grade_export_ods.php';
|
||||
|
||||
$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');
|
||||
@@ -32,6 +33,13 @@ $groupid = groups_get_course_group($course, true);
|
||||
require_capability('moodle/grade:export', $context);
|
||||
require_capability('gradeexport/ods:view', $context);
|
||||
|
||||
// We need to call this method here before any output otherwise the menu won't display.
|
||||
// If you use this method without this check, will break the direct grade exporting (without publishing).
|
||||
$key = optional_param('key', '', PARAM_RAW);
|
||||
if (!empty($CFG->gradepublishing) && !empty($key)) {
|
||||
print_grade_page_head($COURSE->id, 'export', 'ods', get_string('exportto', 'grades') . ' ' . get_string('pluginname', 'gradeexport_ods'));
|
||||
}
|
||||
|
||||
if (groups_get_course_groupmode($COURSE) == SEPARATEGROUPS and !has_capability('moodle/site:accessallgroups', $context)) {
|
||||
if (!groups_is_member($groupid, $USER->id)) {
|
||||
print_error('cannotaccessgroup', 'grades');
|
||||
@@ -39,9 +47,13 @@ if (groups_get_course_groupmode($COURSE) == SEPARATEGROUPS and !has_capability('
|
||||
}
|
||||
$mform = new grade_export_form(null, array('publishing' => true, 'simpleui' => true, 'multipledisplaytypes' => true));
|
||||
$data = $mform->get_data();
|
||||
|
||||
// print all the exported data here
|
||||
$export = new grade_export_ods($course, $groupid, $data);
|
||||
$export->print_grades();
|
||||
|
||||
|
||||
// If the gradepublishing is enabled and user key is selected print the grade publishing link.
|
||||
if (!empty($CFG->gradepublishing) && !empty($key)) {
|
||||
groups_print_course_menu($course, 'index.php?id='.$id);
|
||||
echo $export->get_grade_publishing_url();
|
||||
echo $OUTPUT->footer();
|
||||
} else {
|
||||
$export->print_grades();
|
||||
}
|
||||
|
||||
@@ -17,8 +17,17 @@
|
||||
|
||||
define('NO_MOODLE_COOKIES', true); // session not used here
|
||||
require_once '../../../config.php';
|
||||
require_once($CFG->dirroot.'/grade/export/txt/grade_export_txt.php');
|
||||
|
||||
$id = required_param('id', PARAM_INT);
|
||||
$groupid = optional_param('groupid', 0, PARAM_INT);
|
||||
$itemids = required_param('itemids', PARAM_RAW);
|
||||
$exportfeedback = optional_param('export_feedback', 0, PARAM_BOOL);
|
||||
$separator = optional_param('separator', 'comma', PARAM_ALPHA);
|
||||
$displaytype = optional_param('displaytype', $CFG->grade_export_displaytype, PARAM_RAW);
|
||||
$decimalpoints = optional_param('decimalpoints', $CFG->grade_export_decimalpoints, PARAM_INT);
|
||||
$onlyactive = optional_param('export_onlyactive', 0, PARAM_BOOL);
|
||||
|
||||
$id = required_param('id', PARAM_INT); // course id
|
||||
if (!$course = $DB->get_record('course', array('id'=>$id))) {
|
||||
print_error('nocourseid');
|
||||
}
|
||||
@@ -30,9 +39,19 @@ if (empty($CFG->gradepublishing)) {
|
||||
}
|
||||
|
||||
$context = context_course::instance($id);
|
||||
require_capability('moodle/grade:export', $context);
|
||||
require_capability('gradeexport/txt:publish', $context);
|
||||
require_capability('gradeexport/txt:view', $context);
|
||||
|
||||
// use the same page parameters as export.php and append &key=sdhakjsahdksahdkjsahksadjksahdkjsadhksa
|
||||
require 'export.php';
|
||||
if (!groups_group_visible($groupid, $COURSE)) {
|
||||
print_error('cannotaccessgroup', 'grades');
|
||||
}
|
||||
|
||||
// Get all url parameters and create an object to simulate a form submission.
|
||||
$formdata = grade_export::export_bulk_export_data($id, $itemids, $exportfeedback, $onlyactive, $displaytype,
|
||||
$decimalpoints, null, $separator);
|
||||
|
||||
$export = new grade_export_txt($course, $groupid, $formdata);
|
||||
$export->print_grades();
|
||||
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ require_once $CFG->dirroot.'/grade/export/lib.php';
|
||||
require_once 'grade_export_txt.php';
|
||||
|
||||
$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');
|
||||
@@ -32,6 +33,13 @@ $groupid = groups_get_course_group($course, true);
|
||||
require_capability('moodle/grade:export', $context);
|
||||
require_capability('gradeexport/txt:view', $context);
|
||||
|
||||
// We need to call this method here before any print otherwise the menu won't display.
|
||||
// If you use this method without this check, will break the direct grade exporting (without publishing).
|
||||
$key = optional_param('key', '', PARAM_RAW);
|
||||
if (!empty($CFG->gradepublishing) && !empty($key)) {
|
||||
print_grade_page_head($COURSE->id, 'export', 'txt', get_string('exportto', 'grades') . ' ' . get_string('pluginname', 'gradeexport_txt'));
|
||||
}
|
||||
|
||||
if (groups_get_course_groupmode($COURSE) == SEPARATEGROUPS and !has_capability('moodle/site:accessallgroups', $context)) {
|
||||
if (!groups_is_member($groupid, $USER->id)) {
|
||||
print_error('cannotaccessgroup', 'grades');
|
||||
@@ -46,8 +54,13 @@ $params = array(
|
||||
);
|
||||
$mform = new grade_export_form(null, $params);
|
||||
$data = $mform->get_data();
|
||||
|
||||
// Print all the exported data here.
|
||||
$export = new grade_export_txt($course, $groupid, $data);
|
||||
$export->print_grades();
|
||||
|
||||
// If the gradepublishing is enabled and user key is selected print the grade publishing link.
|
||||
if (!empty($CFG->gradepublishing) && !empty($key)) {
|
||||
groups_print_course_menu($course, 'index.php?id='.$id);
|
||||
echo $export->get_grade_publishing_url();
|
||||
echo $OUTPUT->footer();
|
||||
} else {
|
||||
$export->print_grades();
|
||||
}
|
||||
|
||||
@@ -17,8 +17,16 @@
|
||||
|
||||
define('NO_MOODLE_COOKIES', true); // session not used here
|
||||
require_once '../../../config.php';
|
||||
require_once($CFG->dirroot.'/grade/export/xls/grade_export_xls.php');
|
||||
|
||||
$id = required_param('id', PARAM_INT);
|
||||
$groupid = optional_param('groupid', 0, PARAM_INT);
|
||||
$itemids = required_param('itemids', PARAM_RAW);
|
||||
$exportfeedback = optional_param('export_feedback', 0, PARAM_BOOL);
|
||||
$displaytype = optional_param('displaytype', $CFG->grade_export_displaytype, PARAM_RAW);
|
||||
$decimalpoints = optional_param('decimalpoints', $CFG->grade_export_decimalpoints, PARAM_INT);
|
||||
$onlyactive = optional_param('export_onlyactive', 0, PARAM_BOOL);
|
||||
|
||||
$id = required_param('id', PARAM_INT); // course id
|
||||
if (!$course = $DB->get_record('course', array('id'=>$id))) {
|
||||
print_error('nocourseid');
|
||||
}
|
||||
@@ -30,9 +38,19 @@ if (empty($CFG->gradepublishing)) {
|
||||
}
|
||||
|
||||
$context = context_course::instance($id);
|
||||
require_capability('moodle/grade:export', $context);
|
||||
require_capability('gradeexport/xls:view', $context);
|
||||
require_capability('gradeexport/xls:publish', $context);
|
||||
|
||||
// use the same page parameters as export.php and append &key=sdhakjsahdksahdkjsahksadjksahdkjsadhksa
|
||||
require 'export.php';
|
||||
if (!groups_group_visible($groupid, $COURSE)) {
|
||||
print_error('cannotaccessgroup', 'grades');
|
||||
}
|
||||
|
||||
// Get all url parameters and create an object to simulate a form submission.
|
||||
$formdata = grade_export::export_bulk_export_data($id, $itemids, $exportfeedback, $onlyactive, $displaytype,
|
||||
$decimalpoints);
|
||||
|
||||
$export = new grade_export_xls($course, $groupid, $formdata);
|
||||
$export->print_grades();
|
||||
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ require_once $CFG->dirroot.'/grade/export/lib.php';
|
||||
require_once 'grade_export_xls.php';
|
||||
|
||||
$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');
|
||||
@@ -32,6 +33,13 @@ $groupid = groups_get_course_group($course, true);
|
||||
require_capability('moodle/grade:export', $context);
|
||||
require_capability('gradeexport/xls:view', $context);
|
||||
|
||||
// We need to call this method here before any print otherwise the menu won't display.
|
||||
// If you use this method without this check, will break the direct grade exporting (without publishing).
|
||||
$key = optional_param('key', '', PARAM_RAW);
|
||||
if (!empty($CFG->gradepublishing) && !empty($key)) {
|
||||
print_grade_page_head($COURSE->id, 'export', 'xls', get_string('exportto', 'grades') . ' ' . get_string('pluginname', 'gradeexport_xls'));
|
||||
}
|
||||
|
||||
if (groups_get_course_groupmode($COURSE) == SEPARATEGROUPS and !has_capability('moodle/site:accessallgroups', $context)) {
|
||||
if (!groups_is_member($groupid, $USER->id)) {
|
||||
print_error('cannotaccessgroup', 'grades');
|
||||
@@ -39,9 +47,14 @@ if (groups_get_course_groupmode($COURSE) == SEPARATEGROUPS and !has_capability('
|
||||
}
|
||||
$mform = new grade_export_form(null, array('publishing' => true, 'simpleui' => true, 'multipledisplaytypes' => true));
|
||||
$formdata = $mform->get_data();
|
||||
|
||||
// print all the exported data here
|
||||
$export = new grade_export_xls($course, $groupid, $formdata);
|
||||
$export->print_grades();
|
||||
|
||||
// If the gradepublishing is enabled and user key is selected print the grade publishing link.
|
||||
if (!empty($CFG->gradepublishing) && !empty($key)) {
|
||||
groups_print_course_menu($course, 'index.php?id='.$id);
|
||||
echo $export->get_grade_publishing_url();
|
||||
echo $OUTPUT->footer();
|
||||
} else {
|
||||
$export->print_grades();
|
||||
}
|
||||
|
||||
|
||||
@@ -17,8 +17,17 @@
|
||||
|
||||
define('NO_MOODLE_COOKIES', true); // session not used here
|
||||
require_once '../../../config.php';
|
||||
require_once($CFG->dirroot.'/grade/export/xml/grade_export_xml.php');
|
||||
|
||||
$id = required_param('id', PARAM_INT);
|
||||
$groupid = optional_param('groupid', 0, PARAM_INT);
|
||||
$itemids = required_param('itemids', PARAM_RAW);
|
||||
$exportfeedback = optional_param('export_feedback', 0, PARAM_BOOL);
|
||||
$updatedgradesonly = optional_param('updatedgradesonly', false, PARAM_BOOL);
|
||||
$displaytype = optional_param('displaytype', $CFG->grade_export_displaytype, PARAM_RAW);
|
||||
$decimalpoints = optional_param('decimalpoints', $CFG->grade_export_decimalpoints, PARAM_INT);
|
||||
$onlyactive = optional_param('export_onlyactive', 0, PARAM_BOOL);
|
||||
|
||||
$id = required_param('id', PARAM_INT); // course id
|
||||
if (!$course = $DB->get_record('course', array('id'=>$id))) {
|
||||
print_error('nocourseid');
|
||||
}
|
||||
@@ -30,9 +39,19 @@ if (empty($CFG->gradepublishing)) {
|
||||
}
|
||||
|
||||
$context = context_course::instance($id);
|
||||
require_capability('moodle/grade:export', $context);
|
||||
require_capability('gradeexport/xml:publish', $context);
|
||||
require_capability('gradeexport/xml:view', $context);
|
||||
|
||||
// use the same page parameters as export.php and append &key=sdhakjsahdksahdkjsahksadjksahdkjsadhksa
|
||||
require 'export.php';
|
||||
if (!groups_group_visible($groupid, $COURSE)) {
|
||||
print_error('cannotaccessgroup', 'grades');
|
||||
}
|
||||
|
||||
// Get all url parameters and create an object to simulate a form submission.
|
||||
$formdata = grade_export::export_bulk_export_data($id, $itemids, $exportfeedback, $onlyactive, $displaytype,
|
||||
$decimalpoints, $updatedgradesonly, null);
|
||||
|
||||
$export = new grade_export_xml($course, $groupid, $formdata);
|
||||
$export->print_grades();
|
||||
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ require_once $CFG->dirroot.'/grade/export/lib.php';
|
||||
require_once 'grade_export_xml.php';
|
||||
|
||||
$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');
|
||||
@@ -32,17 +33,30 @@ $groupid = groups_get_course_group($course, true);
|
||||
require_capability('moodle/grade:export', $context);
|
||||
require_capability('gradeexport/xml:view', $context);
|
||||
|
||||
// We need to call this method here before any print otherwise the menu won't display.
|
||||
// If you use this method without this check, will break the direct grade exporting (without publishing).
|
||||
$key = optional_param('key', '', PARAM_RAW);
|
||||
if (!empty($CFG->gradepublishing) && !empty($key)) {
|
||||
print_grade_page_head($COURSE->id, 'export', 'xml', get_string('exportto', 'grades') . ' ' . get_string('pluginname', 'gradeexport_xml'));
|
||||
}
|
||||
|
||||
if (groups_get_course_groupmode($COURSE) == SEPARATEGROUPS and !has_capability('moodle/site:accessallgroups', $context)) {
|
||||
if (!groups_is_member($groupid, $USER->id)) {
|
||||
print_error('cannotaccessgroup', 'grades');
|
||||
}
|
||||
}
|
||||
$mform = new grade_export_form(null, array('publishing' => true, 'simpleui' => true, 'multipledisplaytypes' => false,
|
||||
'idnumberrequired' => true));
|
||||
'idnumberrequired' => true, 'updategradesonly' => true));
|
||||
$formdata = $mform->get_data();
|
||||
|
||||
// print all the exported data here
|
||||
$export = new grade_export_xml($course, $groupid, $formdata);
|
||||
$export->print_grades();
|
||||
|
||||
// If the gradepublishing is enabled and user key is selected print the grade publishing link.
|
||||
if (!empty($CFG->gradepublishing) && !empty($key)) {
|
||||
groups_print_course_menu($course, 'index.php?id='.$id);
|
||||
echo $export->get_grade_publishing_url();
|
||||
echo $OUTPUT->footer();
|
||||
} else {
|
||||
$export->print_grades();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -51,9 +51,11 @@ class gradingform_guide_editguide extends moodleform {
|
||||
$form->setType('returnurl', PARAM_LOCALURL);
|
||||
|
||||
// Name.
|
||||
$form->addElement('text', 'name', get_string('name', 'gradingform_guide'), array('size'=>52));
|
||||
$form->addElement('text', 'name', get_string('name', 'gradingform_guide'),
|
||||
array('size' => 52, 'maxlength' => 255));
|
||||
$form->addRule('name', get_string('required'), 'required');
|
||||
$form->setType('name', PARAM_TEXT);
|
||||
$form->addRule('name', null, 'maxlength', 255, 'client');
|
||||
|
||||
// Description.
|
||||
$options = gradingform_guide_controller::description_form_field_options($this->_customdata['context']);
|
||||
|
||||
@@ -197,6 +197,10 @@ class moodlequickform_guideeditor extends HTML_QuickForm_input {
|
||||
$errors['err_noshortname'] = 1;
|
||||
$criterion['error_description'] = true;
|
||||
}
|
||||
if (strlen(trim($criterion['shortname'])) > 255) {
|
||||
$errors['err_shortnametoolong'] = 1;
|
||||
$criterion['error_description'] = true;
|
||||
}
|
||||
if (!strlen(trim($criterion['maxscore']))) {
|
||||
$errors['err_nomaxscore'] = 1;
|
||||
$criterion['error_description'] = true;
|
||||
|
||||
@@ -54,6 +54,7 @@ $string['err_nodescription'] = 'Student description can not be empty';
|
||||
$string['err_nodescriptionmarkers'] = 'Marker description can not be empty';
|
||||
$string['err_nomaxscore'] = 'Criterion max score can not be empty';
|
||||
$string['err_noshortname'] = 'Criterion name can not be empty';
|
||||
$string['err_shortnametoolong'] = 'Criterion name must be less than 256 characters';
|
||||
$string['err_scoreinvalid'] = 'The score given to {$a->criterianame} is not valid, the max score is: {$a->maxscore}';
|
||||
$string['gradingof'] = '{$a} grading';
|
||||
$string['guidemappingexplained'] = 'WARNING: Your marking guide has a maximum grade of <b>{$a->maxscore} points</b> but the maximum grade set in your activity is {$a->modulegrade} The maximum score set in your marking guide will be scaled to the maximum grade in the module.<br />
|
||||
|
||||
@@ -180,7 +180,7 @@ class gradeimport_csv_load_data {
|
||||
* @param array $header The column headers from the CSV file.
|
||||
* @param int $key Current row identifier.
|
||||
* @param string $value The value for this row (final grade).
|
||||
* @return array new grades that are ready for commiting to the gradebook.
|
||||
* @return stdClass new grade that is ready for commiting to the gradebook.
|
||||
*/
|
||||
protected function import_new_grade_item($header, $key, $value) {
|
||||
global $DB, $USER;
|
||||
@@ -199,14 +199,16 @@ class gradeimport_csv_load_data {
|
||||
$newgrade = new stdClass();
|
||||
$newgrade->newgradeitem = $this->newgradeitems[$key];
|
||||
|
||||
// If the user has a grade for this grade item.
|
||||
if (trim($value) != '-') {
|
||||
// Instead of omitting the grade we could insert one with finalgrade set to 0.
|
||||
// We do not have access to grade item min grade.
|
||||
$trimmed = trim($value);
|
||||
if ($trimmed === '' or $trimmed == '-') {
|
||||
// Blank or dash grade means null, ie "no grade".
|
||||
$newgrade->finalgrade = null;
|
||||
} else {
|
||||
// We have an actual grade.
|
||||
$newgrade->finalgrade = $value;
|
||||
$newgrades[] = $newgrade;
|
||||
}
|
||||
return $newgrades;
|
||||
$this->newgrades[] = $newgrade;
|
||||
return $newgrade;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -385,7 +387,7 @@ class gradeimport_csv_load_data {
|
||||
}
|
||||
break;
|
||||
case 'new':
|
||||
$this->newgrades = $this->import_new_grade_item($header, $key, $value);
|
||||
$this->import_new_grade_item($header, $key, $value);
|
||||
break;
|
||||
case 'feedback':
|
||||
if ($feedbackgradeid) {
|
||||
|
||||
@@ -41,9 +41,9 @@ require_once($CFG->libdir . '/grade/tests/fixtures/lib.php');
|
||||
class gradeimport_csv_load_data_testcase extends grade_base_testcase {
|
||||
|
||||
/** @var string $oktext Text to be imported. This data should have no issues being imported. */
|
||||
protected $oktext = '"First name",Surname,"ID number",Institution,Department,"Email address","Assignment: Assignment for grape group", "Feedback: Assignment for grape group","Course total"
|
||||
Anne,Able,,"Moodle HQ","Rock on!",student7@mail.com,56.00,"We welcome feedback",56.00
|
||||
Bobby,Bunce,,"Moodle HQ","Rock on!",student5@mail.com,75.00,,75.00';
|
||||
protected $oktext = '"First name",Surname,"ID number",Institution,Department,"Email address","Assignment: Assignment for grape group", "Feedback: Assignment for grape group","Assignment: Second new grade item","Course total"
|
||||
Anne,Able,,"Moodle HQ","Rock on!",student7@mail.com,56.00,"We welcome feedback",,56.00
|
||||
Bobby,Bunce,,"Moodle HQ","Rock on!",student5@mail.com,75.00,,45.0,75.00';
|
||||
|
||||
/** @var string $badtext Text to be imported. This data has an extra column and should not succeed in being imported. */
|
||||
protected $badtext = '"First name",Surname,"ID number",Institution,Department,"Email address","Assignment: Assignment for grape group","Course total"
|
||||
@@ -109,6 +109,7 @@ Bobby,Bunce,,"Moodle HQ","Rock on!",student5@mail.com,75.00,,75.00,{exportdate}'
|
||||
'student7@mail.com',
|
||||
56.00,
|
||||
'We welcome feedback',
|
||||
'',
|
||||
56.00
|
||||
),
|
||||
array(
|
||||
@@ -120,6 +121,7 @@ Bobby,Bunce,,"Moodle HQ","Rock on!",student5@mail.com,75.00,,75.00,{exportdate}'
|
||||
'student5@mail.com',
|
||||
75.00,
|
||||
'',
|
||||
45.0,
|
||||
75.00
|
||||
)
|
||||
);
|
||||
@@ -133,6 +135,7 @@ Bobby,Bunce,,"Moodle HQ","Rock on!",student5@mail.com,75.00,,75.00,{exportdate}'
|
||||
'Email address',
|
||||
'Assignment: Assignment for grape group',
|
||||
'Feedback: Assignment for grape group',
|
||||
'Assignment: Second new grade item',
|
||||
'Course total'
|
||||
);
|
||||
// Check that general data is returned as expected.
|
||||
@@ -371,6 +374,14 @@ Bobby,Bunce,,"Moodle HQ","Rock on!",student5@mail.com,75.00,,75.00,{exportdate}'
|
||||
// Check that the final grade is the same as the one inserted.
|
||||
$this->assertEquals($testarray[0][6], $newgrades[0]->finalgrade);
|
||||
|
||||
$newgrades = $testobject->test_map_user_data_with_value('new', $testarray[0][8], $this->columns, $map, $key,
|
||||
$this->courseid, $map[$key], $verbosescales);
|
||||
// Check that the final grade is the same as the one inserted.
|
||||
// The testobject should now contain 2 new grade items.
|
||||
$this->assertEquals(2, count($newgrades));
|
||||
// Because this grade item is empty, the value for final grade should be null.
|
||||
$this->assertNull($newgrades[1]->finalgrade);
|
||||
|
||||
$feedback = $testobject->test_map_user_data_with_value('feedback', $testarray[0][7], $this->columns, $map, $key,
|
||||
$this->courseid, $map[$key], $verbosescales);
|
||||
// Expected result.
|
||||
|
||||
+3
-3
@@ -617,7 +617,7 @@ function grade_print_tabs($active_type, $active_plugin, $plugin_info, $return=fa
|
||||
$top_row = array();
|
||||
$bottom_row = array();
|
||||
$inactive = array($active_plugin);
|
||||
$activated = array();
|
||||
$activated = array($active_type);
|
||||
|
||||
$count = 0;
|
||||
$active = '';
|
||||
@@ -661,9 +661,9 @@ function grade_print_tabs($active_type, $active_plugin, $plugin_info, $return=fa
|
||||
$tabs[] = $bottom_row;
|
||||
|
||||
if ($return) {
|
||||
return print_tabs($tabs, $active_type, $inactive, $activated, true);
|
||||
return print_tabs($tabs, $active_plugin, $inactive, $activated, true);
|
||||
} else {
|
||||
print_tabs($tabs, $active_type, $inactive, $activated);
|
||||
print_tabs($tabs, $active_plugin, $inactive, $activated);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+29
-24
@@ -412,8 +412,14 @@ class grade_report_grader extends grade_report {
|
||||
// Limit to users with a gradeable role.
|
||||
list($gradebookrolessql, $gradebookrolesparams) = $DB->get_in_or_equal(explode(',', $this->gradebookroles), SQL_PARAMS_NAMED, 'grbr0');
|
||||
|
||||
// Check the status of showing only active enrolments.
|
||||
$coursecontext = $this->context->get_course_context(true);
|
||||
$defaultgradeshowactiveenrol = !empty($CFG->grade_report_showonlyactiveenrol);
|
||||
$showonlyactiveenrol = get_user_preferences('grade_report_showonlyactiveenrol', $defaultgradeshowactiveenrol);
|
||||
$showonlyactiveenrol = $showonlyactiveenrol || !has_capability('moodle/course:viewsuspendedusers', $coursecontext);
|
||||
|
||||
// Limit to users with an active enrollment.
|
||||
list($enrolledsql, $enrolledparams) = get_enrolled_sql($this->context);
|
||||
list($enrolledsql, $enrolledparams) = get_enrolled_sql($this->context, '', 0, $showonlyactiveenrol);
|
||||
|
||||
// Fields we need from the user table.
|
||||
$userfields = user_picture::fields('u', get_extra_user_fields($this->context));
|
||||
@@ -476,30 +482,29 @@ class grade_report_grader extends grade_report {
|
||||
$this->userselect = "AND g.userid $usql";
|
||||
$this->userselect_params = $uparams;
|
||||
|
||||
// Add a flag to each user indicating whether their enrolment is active.
|
||||
$sql = "SELECT ue.userid
|
||||
FROM {user_enrolments} ue
|
||||
JOIN {enrol} e ON e.id = ue.enrolid
|
||||
WHERE ue.userid $usql
|
||||
AND ue.status = :uestatus
|
||||
AND e.status = :estatus
|
||||
AND e.courseid = :courseid
|
||||
AND ue.timestart < :now1 AND (ue.timeend = 0 OR ue.timeend > :now2)
|
||||
GROUP BY ue.userid";
|
||||
$coursecontext = $this->context->get_course_context(true);
|
||||
$time = time();
|
||||
$params = array_merge($uparams, array('estatus' => ENROL_INSTANCE_ENABLED, 'uestatus' => ENROL_USER_ACTIVE,
|
||||
'courseid' => $coursecontext->instanceid, 'now1' => $time, 'now2' => $time));
|
||||
$useractiveenrolments = $DB->get_records_sql($sql, $params);
|
||||
|
||||
$defaultgradeshowactiveenrol = !empty($CFG->grade_report_showonlyactiveenrol);
|
||||
$showonlyactiveenrol = get_user_preferences('grade_report_showonlyactiveenrol', $defaultgradeshowactiveenrol);
|
||||
$showonlyactiveenrol = $showonlyactiveenrol || !has_capability('moodle/course:viewsuspendedusers', $coursecontext);
|
||||
// First flag everyone as not suspended.
|
||||
foreach ($this->users as $user) {
|
||||
// If we are showing only active enrolments, then remove suspended users from list.
|
||||
if ($showonlyactiveenrol && !array_key_exists($user->id, $useractiveenrolments)) {
|
||||
unset($this->users[$user->id]);
|
||||
} else {
|
||||
$this->users[$user->id]->suspendedenrolment = false;
|
||||
}
|
||||
|
||||
// If we want to mix both suspended and not suspended users, let's find out who is suspended.
|
||||
if (!$showonlyactiveenrol) {
|
||||
$sql = "SELECT ue.userid
|
||||
FROM {user_enrolments} ue
|
||||
JOIN {enrol} e ON e.id = ue.enrolid
|
||||
WHERE ue.userid $usql
|
||||
AND ue.status = :uestatus
|
||||
AND e.status = :estatus
|
||||
AND e.courseid = :courseid
|
||||
AND ue.timestart < :now1 AND (ue.timeend = 0 OR ue.timeend > :now2)
|
||||
GROUP BY ue.userid";
|
||||
|
||||
$time = time();
|
||||
$params = array_merge($uparams, array('estatus' => ENROL_INSTANCE_ENABLED, 'uestatus' => ENROL_USER_ACTIVE,
|
||||
'courseid' => $coursecontext->instanceid, 'now1' => $time, 'now2' => $time));
|
||||
$useractiveenrolments = $DB->get_records_sql($sql, $params);
|
||||
|
||||
foreach ($this->users as $user) {
|
||||
$this->users[$user->id]->suspendedenrolment = !array_key_exists($user->id, $useractiveenrolments);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ foreach ($outcomes as $outcomeid => $outcome) {
|
||||
FROM {grade_grades}
|
||||
WHERE itemid = ?".
|
||||
$hidesuspendedsql.
|
||||
"GROUP BY itemid";
|
||||
" GROUP BY itemid";
|
||||
$info = $DB->get_records_sql($sql, $params);
|
||||
|
||||
if (!$info) {
|
||||
|
||||
@@ -48,6 +48,7 @@ define('AJAX_SCRIPT', false); // prevents some warnings later
|
||||
define('CACHE_DISABLE_ALL', true); // Disables caching.. just in case.
|
||||
define('PHPUNIT_TEST', false);
|
||||
define('IGNORE_COMPONENT_CACHE', true);
|
||||
define('MDL_PERF_TEST', false);
|
||||
|
||||
// Servers should define a default timezone in php.ini, but if they don't then make sure something is defined.
|
||||
// This is a quick hack. Ideally we should ask the admin for a value. See MDL-22625 for more on this.
|
||||
|
||||
@@ -39,6 +39,7 @@ $string['cannotsavemd5file'] = 'Ezin da Md5 fitxategia gorde';
|
||||
$string['cannotsavezipfile'] = 'Ezin da ZIP fitxategia gorde';
|
||||
$string['cannotunzipfile'] = 'Ezin da fitxategia deskonprimatu';
|
||||
$string['componentisuptodate'] = 'Osagaia eguneratu da';
|
||||
$string['dmlexceptiononinstall'] = '<p>Datu-basearen errorea gertatu da [{$a->errorcode}].<br />{$a->debuginfo}</p>';
|
||||
$string['downloadedfilecheckfailed'] = 'Jaitsitako fitxategiaren konprobazioak kale egin du.';
|
||||
$string['invalidmd5'] = 'md5 ez da baliagarria';
|
||||
$string['missingrequiredfield'] = 'Beharrezko eremuren bat falta da.';
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Automatically generated strings for Moodle installer
|
||||
*
|
||||
* Do not edit this file manually! It contains just a subset of strings
|
||||
* needed during the very first steps of installation. This file was
|
||||
* generated automatically by export-installer.php (which is part of AMOS
|
||||
* {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
|
||||
* list of strings defined in /install/stringnames.txt.
|
||||
*
|
||||
* @package installer
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$string['parentlanguage'] = 'fi';
|
||||
$string['thislanguage'] = 'Suomi yrityksille';
|
||||
@@ -39,4 +39,4 @@ $string['clitypevaluedefault'] = 'érték beírása, Enter esetén alapérték (
|
||||
$string['cliunknowoption'] = 'Ismeretlen paraméter: {$a}. Használja a --help paramétert.';
|
||||
$string['cliyesnoprompt'] = 'írjon be i-t (igen) vagy n-t (nem)';
|
||||
$string['environmentrequireinstall'] = 'telepíteni kell és be kell kapcsolni';
|
||||
$string['environmentrequireversion'] = 'a {$a->needed} változatot kell a mostani {$a->current} helyett használni';
|
||||
$string['environmentrequireversion'] = 'minimum a {$a->needed} változat szükséges, jelenleg a {$a->current} verziót használja';
|
||||
|
||||
@@ -32,4 +32,4 @@ defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$string['parentlanguage'] = '';
|
||||
$string['thisdirection'] = 'ltr';
|
||||
$string['thislanguage'] = 'Lithuanian';
|
||||
$string['thislanguage'] = 'Lietuvių';
|
||||
|
||||
@@ -39,4 +39,4 @@ $string['clitypevaluedefault'] = 'тип значення, натисніть En
|
||||
$string['cliunknowoption'] = 'Невизначені опції: {$a}. Будь ласка, використайте опцію --help.';
|
||||
$string['cliyesnoprompt'] = 'натисніть y (означає так) або n (означає ні)';
|
||||
$string['environmentrequireinstall'] = 'повинен бути встановлений і включений';
|
||||
$string['environmentrequireversion'] = 'рекомендується версія {$a->needed}, використовується версія {$a->current}';
|
||||
$string['environmentrequireversion'] = 'потрібна версія {$a->needed}, ви запускаєте {$a->current}';
|
||||
|
||||
@@ -61,6 +61,7 @@ $string['enrolnotpermitted'] = 'You do not have permission or are not allowed to
|
||||
$string['enrolperiod'] = 'Enrolment duration';
|
||||
$string['enrolusage'] = 'Instances / enrolments';
|
||||
$string['enrolusers'] = 'Enrol users';
|
||||
$string['enrolxusers'] = 'Enrol {$a} users';
|
||||
$string['enroltimecreated'] = 'Enrolment created';
|
||||
$string['enroltimeend'] = 'Enrolment ends';
|
||||
$string['enroltimestart'] = 'Enrolment starts';
|
||||
@@ -82,6 +83,7 @@ $string['expirynotifyhour'] = 'Hour to send enrolment expiry notifications';
|
||||
$string['expirythreshold'] = 'Notification threshold';
|
||||
$string['expirythreshold_help'] = 'How long before enrolment expiry should users be notified?';
|
||||
$string['finishenrollingusers'] = 'Finish enrolling users';
|
||||
$string['foundxcohorts'] = 'Found {$a} cohorts';
|
||||
$string['instanceeditselfwarning'] = 'Warning:';
|
||||
$string['instanceeditselfwarningtext'] = 'You are enrolled into this course through this enrolment method, changes may affect your access to this course.';
|
||||
$string['invalidenrolinstance'] = 'Invalid enrolment instance';
|
||||
|
||||
@@ -145,6 +145,7 @@ $string['cannotsetupblock'] = 'Blocks tables could NOT be set up successfully!';
|
||||
$string['cannotsetupcapformod'] = 'Could not set up the capabilities for {$a}';
|
||||
$string['cannotsetupcapforplugin'] = 'Could not set up the capabilities for {$a}';
|
||||
$string['cannotshowhidecoursesincategory'] = 'Cannot show/hide the courses in category {$a}.';
|
||||
$string['cannotsignup'] = 'You cannot create a new account because you are already logged in as {$a}.';
|
||||
$string['cannotunassigncap'] = 'Could not unassign deprecated capability {$a->cap} from role {$a->role}';
|
||||
$string['cannotunassignrolefrom'] = 'Cannot unassign this user from role id: {$a}';
|
||||
$string['cannotunzipfile'] = 'Cannot unzip file';
|
||||
|
||||
@@ -35,9 +35,11 @@ $string['categoryrole'] = 'Category role';
|
||||
$string['contains'] = 'contains';
|
||||
$string['content'] = 'Content';
|
||||
$string['contentandheadings'] = 'Content and headings';
|
||||
$string['coursecategory'] = 'course category';
|
||||
$string['courserole'] = 'Course role';
|
||||
$string['courserolelabel'] = '{$a->label} is {$a->rolename} in {$a->coursename} from {$a->categoryname}';
|
||||
$string['courserolelabelerror'] = '{$a->label} error: course {$a->coursename} does not exist';
|
||||
$string['coursevalue'] = 'course value';
|
||||
$string['datelabelisafter'] = '{$a->label} is after {$a->after}';
|
||||
$string['datelabelisbefore'] = '{$a->label} is before {$a->before}';
|
||||
$string['datelabelisbetween'] = '{$a->label} is between {$a->after} and {$a->before}';
|
||||
@@ -63,6 +65,7 @@ $string['isempty'] = 'is empty';
|
||||
$string['isequalto'] = 'is equal to';
|
||||
$string['isnotdefined'] = 'isn\'t defined';
|
||||
$string['isnotequalto'] = 'isn\'t equal to';
|
||||
$string['limiterfor'] = '{$a} field limiter';
|
||||
$string['neveraccessed'] = 'Never accessed';
|
||||
$string['nevermodified'] = 'Never modified';
|
||||
$string['newfilter'] = 'New filter';
|
||||
@@ -70,6 +73,8 @@ $string['nofiltersenabled'] = 'No filter plugins have been enabled on this site.
|
||||
$string['off'] = 'Off';
|
||||
$string['offbutavailable'] = 'Off, but available';
|
||||
$string['on'] = 'On';
|
||||
$string['profilefilterfield'] = 'Profile field name';
|
||||
$string['profilefilterlimiter'] = 'Profile field operator';
|
||||
$string['profilelabel'] = '{$a->label}: {$a->profile} {$a->operator} {$a->value}';
|
||||
$string['profilelabelnovalue'] = '{$a->label}: {$a->profile} {$a->operator}';
|
||||
$string['removeall'] = 'Remove all filters';
|
||||
@@ -79,3 +84,4 @@ $string['startswith'] = 'starts with';
|
||||
$string['tablenosave'] = 'Changes in table above are saved automatically.';
|
||||
$string['textlabel'] = '{$a->label} {$a->operator} {$a->value}';
|
||||
$string['textlabelnovalue'] = '{$a->label} {$a->operator}';
|
||||
$string['valuefor'] = '{$a} value';
|
||||
|
||||
+1
-1
@@ -32,7 +32,7 @@ $string['err_alphanumeric'] = 'You must enter only letters or numbers here.';
|
||||
$string['err_email'] = 'You must enter a valid email address here.';
|
||||
$string['err_lettersonly'] = 'You must enter only letters here.';
|
||||
$string['err_maxfiles'] = 'You must not attach more than {$a} files here.';
|
||||
$string['err_maxlength'] = 'You must enter not more than {$a->format} characters here.';
|
||||
$string['err_maxlength'] = 'You must enter no more than {$a->format} characters here.';
|
||||
$string['err_minlength'] = 'You must enter at least {$a->format} characters here.';
|
||||
$string['err_nonzero'] = 'You must enter a number not starting with a 0 here.';
|
||||
$string['err_nopunctuation'] = 'You must enter no punctuation characters here.';
|
||||
|
||||
@@ -305,6 +305,7 @@ $string['gradepointmax_validateerror'] = 'This setting must be an integer betwee
|
||||
$string['gradepreferences'] = 'Grade preferences';
|
||||
$string['gradepreferenceshelp'] = 'Grade preferences Help';
|
||||
$string['gradepublishing'] = 'Enable publishing';
|
||||
$string['gradepublishinglink'] = 'Download: {$a}';
|
||||
$string['gradepublishing_help'] = 'Enable publishing in exports and imports: Exported grades can be accessed by accessing a URL, without having to log on to a Moodle site. Grades can be imported by accessing such a URL (which means that a Moodle site can import grades published by another site). By default only administrators may use this feature, please educate users before adding required capabilities to other roles (dangers of bookmark sharing and download accelerators, IP restrictions, etc.).';
|
||||
$string['gradereport'] = 'Grade report';
|
||||
$string['graderreport'] = 'Grader report';
|
||||
|
||||
+1
-1
@@ -1561,7 +1561,7 @@ $string['rssarticles'] = 'Number of RSS recent articles';
|
||||
$string['rsserror'] = 'Error reading RSS data';
|
||||
$string['rsserrorauth'] = 'Your RSS link does not contain a valid authentication token.';
|
||||
$string['rsserrorguest'] = 'This feed uses guest access to access the data, but guest does not have permission to read the data. Visit the original location that this feed comes from (URL) as a valid user and get a new RSS link from there.';
|
||||
$string['rsskeyshelp'] = 'To ensure security and privacy, RSS feed URLs contain a special token that identifies the user they are for. This prevents other users from accessing areas of Moodle they shouldn\'t have access to via RSS feeds.</p><p>This token is automatically created the first time you access an area of Moodle that produces an RSS feed. If you feel that your RSS feed token has been compromised in some way you can request a new one by clicking the Reset link here. Please note that your current RSS feed URLs will then become invalid.';
|
||||
$string['rsskeyshelp'] = '<p>To ensure security and privacy, RSS feed URLs contain a special token that identifies the user they are for. This prevents other users from accessing areas of the site where they are not allowed.</p><p>The token is automatically created the first time you access an area that produces an RSS feed. If you think that your RSS feed token has been compromised, you can request a new one by clicking the reset link. Please note that your current RSS feed URLs will then become invalid.</p>';
|
||||
$string['rsstype'] = 'RSS feed for this activity';
|
||||
$string['saveandnext'] = 'Save and show next';
|
||||
$string['savedat'] = 'Saved at:';
|
||||
|
||||
@@ -62,16 +62,16 @@ $string['close'] = 'Close';
|
||||
$string['commonrepositorysettings'] = 'Common repository settings';
|
||||
$string['configallowexternallinks'] = 'This option enables all users to choose whether or not external media is copied into Moodle or not. If this is off then media is always copied into Moodle (this is usually best for overall data integrity and security). If this is on then users can choose each time they add media to a text.';
|
||||
$string['configcacheexpire'] = 'The amount of time that file listings are cached locally (in seconds) when browsing external repositories.';
|
||||
$string['configgetfiletimeout'] = 'Timeout in seconds for downloading the external file into moodle.';
|
||||
$string['configgetfiletimeout'] = 'Timeout in seconds for downloading an external file into Moodle.';
|
||||
$string['configsaved'] = 'Configuration saved!';
|
||||
$string['configsyncfiletimeout'] = 'Timeout in seconds for syncronising the external file size.';
|
||||
$string['configsyncimagetimeout'] = 'Timeout in seconds for downloading an image file from external repository during syncronisation.';
|
||||
$string['confirmdelete'] = 'Are you sure you want to delete this repository - {$a}? If you choose "Continue and download", file references to external contents will be downloaded to moodle, but it could take long time to process.';
|
||||
$string['confirmdelete'] = 'Are you sure you want to delete the repository {$a}? If you choose "Continue and download", file references to external contents will be downloaded to Moodle. This could take a long time to process.';
|
||||
$string['confirmdeletefile'] = 'Are you sure you want to delete this file?';
|
||||
$string['confirmrenamefile'] = 'Are you sure you want to rename/move this file? There are {$a} alias/shortcut files that use this file as their source. If you proceed then those aliases will be converted to true copies.';
|
||||
$string['confirmdeletefilewithhref'] = 'Are you sure you want to delete this file? There are {$a} alias/shortcut files that use this file as their source. If you proceed then those aliases will be converted to true copies.';
|
||||
$string['confirmdeletefolder'] = 'Are you sure you want to delete this folder? All files and subfolders will be deleted.';
|
||||
$string['confirmremove'] = 'Are you sure you want to remove this repository plugin, its options and <strong>all of its instances</strong> - {$a}? If you choose "Continue and download", file references to external contents will be downloaded to moodle, but it could take long time to process.';
|
||||
$string['confirmremove'] = 'Are you sure you want to remove this repository plugin, its options and <strong>all of its instances</strong> - {$a}? If you choose "Continue and download", file references to external contents will be downloaded to Moodle. This could take a long time to process.';
|
||||
$string['confirmrenamefolder'] = ' Are you sure you want to move/rename this folder? Any alias/shortcut files that reference files in this folder will be converted into true copies.';
|
||||
$string['continueuninstall'] = 'Continue';
|
||||
$string['continueuninstallanddownload'] = 'Continue and download';
|
||||
@@ -241,7 +241,7 @@ $string['usenonjsfilemanager'] = 'Open file manager in new window';
|
||||
$string['usenonjsfilepicker'] = 'Open file picker in new window';
|
||||
$string['unzipped'] = 'Unzipped successfully';
|
||||
$string['wrongcontext'] = 'You cannot access to this context';
|
||||
$string['xhtmlerror'] = 'You are probably using XHTML strict header, some YUI Component doesn\'t work in this mode, please turn it off in moodle';
|
||||
$string['xhtmlerror'] = 'You are probably using an XHTML strict header. Certain YUI components don\'t work in this mode; please turn it off.';
|
||||
$string['ziped'] = 'Compress folder successfully';
|
||||
|
||||
// Deprecated since Moodle 2.8.
|
||||
|
||||
+2
-2
@@ -171,10 +171,10 @@ $string['defaultx'] = 'Default: {$a}';
|
||||
$string['defineroles'] = 'Define roles';
|
||||
$string['deletecourseoverrides'] = 'Delete all overrides in course';
|
||||
$string['deletelocalroles'] = 'Delete all local role assignments';
|
||||
$string['deleterolesure'] = 'Are you sure that you want to delete role "{$a->name} ({$a->shortname})"?</p><p>Currently this role is assigned to {$a->count} users.';
|
||||
$string['deleterolesure'] = '<p>Are you sure that you want to delete role "{$a->name} ({$a->shortname})"?</p><p>Currently this role is assigned to {$a->count} users.</p>';
|
||||
$string['deletexrole'] = 'Delete {$a} role';
|
||||
$string['duplicaterole'] = 'Duplicate role';
|
||||
$string['duplicaterolesure'] = 'Are you sure that you want to duplicate role "{$a->name} ({$a->shortname})"?</p>';
|
||||
$string['duplicaterolesure'] = '<p>Are you sure that you want to duplicate role "{$a->name} ({$a->shortname})"?</p>';
|
||||
$string['editingrolex'] = 'Editing role \'{$a}\'';
|
||||
$string['editrole'] = 'Edit role';
|
||||
$string['editxrole'] = 'Edit {$a} role';
|
||||
|
||||
@@ -127,6 +127,7 @@ $string['missingusername'] = 'Missing username';
|
||||
$string['missingversionfile'] = 'Coding error: version.php file is missing for the component {$a}';
|
||||
$string['mobilewsdisabled'] = 'Disabled';
|
||||
$string['mobilewsenabled'] = 'Enabled';
|
||||
$string['nameexists'] = 'This name is already in use by another service';
|
||||
$string['nocapabilitytouseparameter'] = 'The user does not have the required capability to use the parameter {$a}';
|
||||
$string['nofunctions'] = 'This service has no functions.';
|
||||
$string['norequiredcapability'] = 'No required capability';
|
||||
|
||||
+30
-15
@@ -6447,14 +6447,17 @@ class context_user extends context {
|
||||
protected static function create_level_instances() {
|
||||
global $DB;
|
||||
|
||||
$sql = "INSERT INTO {context} (contextlevel, instanceid)
|
||||
SELECT ".CONTEXT_USER.", u.id
|
||||
$sql = "SELECT ".CONTEXT_USER.", u.id
|
||||
FROM {user} u
|
||||
WHERE u.deleted = 0
|
||||
AND NOT EXISTS (SELECT 'x'
|
||||
FROM {context} cx
|
||||
WHERE u.id = cx.instanceid AND cx.contextlevel=".CONTEXT_USER.")";
|
||||
$DB->execute($sql);
|
||||
$contextdata = $DB->get_recordset_sql($sql);
|
||||
foreach ($contextdata as $context) {
|
||||
context::insert_context_record(CONTEXT_USER, $context->id, null);
|
||||
}
|
||||
$contextdata->close();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -6655,13 +6658,16 @@ class context_coursecat extends context {
|
||||
protected static function create_level_instances() {
|
||||
global $DB;
|
||||
|
||||
$sql = "INSERT INTO {context} (contextlevel, instanceid)
|
||||
SELECT ".CONTEXT_COURSECAT.", cc.id
|
||||
$sql = "SELECT ".CONTEXT_COURSECAT.", cc.id
|
||||
FROM {course_categories} cc
|
||||
WHERE NOT EXISTS (SELECT 'x'
|
||||
FROM {context} cx
|
||||
WHERE cc.id = cx.instanceid AND cx.contextlevel=".CONTEXT_COURSECAT.")";
|
||||
$DB->execute($sql);
|
||||
$contextdata = $DB->get_recordset_sql($sql);
|
||||
foreach ($contextdata as $context) {
|
||||
context::insert_context_record(CONTEXT_COURSECAT, $context->id, null);
|
||||
}
|
||||
$contextdata->close();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -6878,13 +6884,16 @@ class context_course extends context {
|
||||
protected static function create_level_instances() {
|
||||
global $DB;
|
||||
|
||||
$sql = "INSERT INTO {context} (contextlevel, instanceid)
|
||||
SELECT ".CONTEXT_COURSE.", c.id
|
||||
$sql = "SELECT ".CONTEXT_COURSE.", c.id
|
||||
FROM {course} c
|
||||
WHERE NOT EXISTS (SELECT 'x'
|
||||
FROM {context} cx
|
||||
WHERE c.id = cx.instanceid AND cx.contextlevel=".CONTEXT_COURSE.")";
|
||||
$DB->execute($sql);
|
||||
$contextdata = $DB->get_recordset_sql($sql);
|
||||
foreach ($contextdata as $context) {
|
||||
context::insert_context_record(CONTEXT_COURSE, $context->id, null);
|
||||
}
|
||||
$contextdata->close();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -7132,13 +7141,16 @@ class context_module extends context {
|
||||
protected static function create_level_instances() {
|
||||
global $DB;
|
||||
|
||||
$sql = "INSERT INTO {context} (contextlevel, instanceid)
|
||||
SELECT ".CONTEXT_MODULE.", cm.id
|
||||
$sql = "SELECT ".CONTEXT_MODULE.", cm.id
|
||||
FROM {course_modules} cm
|
||||
WHERE NOT EXISTS (SELECT 'x'
|
||||
FROM {context} cx
|
||||
WHERE cm.id = cx.instanceid AND cx.contextlevel=".CONTEXT_MODULE.")";
|
||||
$DB->execute($sql);
|
||||
$contextdata = $DB->get_recordset_sql($sql);
|
||||
foreach ($contextdata as $context) {
|
||||
context::insert_context_record(CONTEXT_MODULE, $context->id, null);
|
||||
}
|
||||
$contextdata->close();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -7349,13 +7361,16 @@ class context_block extends context {
|
||||
protected static function create_level_instances() {
|
||||
global $DB;
|
||||
|
||||
$sql = "INSERT INTO {context} (contextlevel, instanceid)
|
||||
SELECT ".CONTEXT_BLOCK.", bi.id
|
||||
$sql = "SELECT ".CONTEXT_BLOCK.", bi.id
|
||||
FROM {block_instances} bi
|
||||
WHERE NOT EXISTS (SELECT 'x'
|
||||
FROM {context} cx
|
||||
WHERE bi.id = cx.instanceid AND cx.contextlevel=".CONTEXT_BLOCK.")";
|
||||
$DB->execute($sql);
|
||||
$contextdata = $DB->get_recordset_sql($sql);
|
||||
foreach ($contextdata as $context) {
|
||||
context::insert_context_record(CONTEXT_BLOCK, $context->id, null);
|
||||
}
|
||||
$contextdata->close();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+12
-8
@@ -3231,16 +3231,20 @@ class admin_setting_configtime extends admin_setting {
|
||||
$defaultinfo = NULL;
|
||||
}
|
||||
|
||||
$return = '<div class="form-time defaultsnext">'.
|
||||
'<select id="'.$this->get_id().'h" name="'.$this->get_full_name().'[h]">';
|
||||
$return = '<div class="form-time defaultsnext">';
|
||||
$return .= '<label class="accesshide" for="' . $this->get_id() . 'h">' . get_string('hours') . '</label>';
|
||||
$return .= '<select id="' . $this->get_id() . 'h" name="' . $this->get_full_name() . '[h]">';
|
||||
for ($i = 0; $i < 24; $i++) {
|
||||
$return .= '<option value="'.$i.'"'.($i == $data['h'] ? ' selected="selected"' : '').'>'.$i.'</option>';
|
||||
$return .= '<option value="' . $i . '"' . ($i == $data['h'] ? ' selected="selected"' : '') . '>' . $i . '</option>';
|
||||
}
|
||||
$return .= '</select>:<select id="'.$this->get_id().'m" name="'.$this->get_full_name().'[m]">';
|
||||
$return .= '</select>:';
|
||||
$return .= '<label class="accesshide" for="' . $this->get_id() . 'm">' . get_string('minutes') . '</label>';
|
||||
$return .= '<select id="' . $this->get_id() . 'm" name="' . $this->get_full_name() . '[m]">';
|
||||
for ($i = 0; $i < 60; $i += 5) {
|
||||
$return .= '<option value="'.$i.'"'.($i == $data['m'] ? ' selected="selected"' : '').'>'.$i.'</option>';
|
||||
$return .= '<option value="' . $i . '"' . ($i == $data['m'] ? ' selected="selected"' : '') . '>' . $i . '</option>';
|
||||
}
|
||||
$return .= '</select></div>';
|
||||
$return .= '</select>';
|
||||
$return .= '</div>';
|
||||
return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', $defaultinfo, $query);
|
||||
}
|
||||
|
||||
@@ -7771,11 +7775,11 @@ class admin_setting_webservicesoverview extends admin_setting {
|
||||
get_string('enablemobilewebservice', 'admin'),
|
||||
get_string('configenablemobilewebservice',
|
||||
'admin', ''), 0); //we don't want to display it but to know the ws mobile status
|
||||
$manageserviceurl = new moodle_url("/admin/settings.php?section=externalservices");
|
||||
$manageserviceurl = new moodle_url("/admin/settings.php?section=mobile");
|
||||
$wsmobileparam = new stdClass();
|
||||
$wsmobileparam->enablemobileservice = get_string('enablemobilewebservice', 'admin');
|
||||
$wsmobileparam->manageservicelink = html_writer::link($manageserviceurl,
|
||||
get_string('externalservices', 'webservice'));
|
||||
get_string('mobile', 'admin'));
|
||||
$mobilestatus = $enablemobile->get_setting()?get_string('mobilewsenabled', 'webservice'):get_string('mobilewsdisabled', 'webservice');
|
||||
$wsmobileparam->wsmobilestatus = html_writer::tag('strong', $mobilestatus);
|
||||
$return .= $OUTPUT->heading(get_string('enablemobilewebservice', 'admin'), 3, 'main');
|
||||
|
||||
+1
-1
@@ -28,7 +28,7 @@ require_once(dirname(__FILE__) . '/../../config.php');
|
||||
// Initialise ALL common incoming parameters here, up front.
|
||||
$courseid = required_param('courseid', PARAM_INT);
|
||||
$pagelayout = required_param('pagelayout', PARAM_ALPHAEXT);
|
||||
$pagetype = required_param('pagetype', PARAM_ALPHAEXT);
|
||||
$pagetype = required_param('pagetype', PARAM_ALPHANUMEXT);
|
||||
$contextid = required_param('contextid', PARAM_INT);
|
||||
$subpage = optional_param('subpage', '', PARAM_ALPHANUMEXT);
|
||||
$cmid = optional_param('cmid', null, PARAM_INT);
|
||||
|
||||
+2
-1
@@ -1126,7 +1126,8 @@ function badges_download($userid) {
|
||||
if ($zipper->archive_to_pathname($filelist, $tempzip)) {
|
||||
send_temp_file($tempzip, 'badges.zip');
|
||||
} else {
|
||||
debugging("Problems with archiving the files.");
|
||||
debugging("Problems with archiving the files.", DEBUG_DEVELOPER);
|
||||
die;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -302,6 +302,11 @@ class behat_base extends Behat\MinkExtension\Context\RawMinkContext {
|
||||
$loops = $timeout;
|
||||
}
|
||||
|
||||
// DOM will never change on non-javascript case; do not wait or try again.
|
||||
if (!$this->running_javascript()) {
|
||||
$loops = 1;
|
||||
}
|
||||
|
||||
for ($i = 0; $i < $loops; $i++) {
|
||||
// We catch the exception thrown by the step definition to execute it again.
|
||||
try {
|
||||
@@ -320,10 +325,12 @@ class behat_base extends Behat\MinkExtension\Context\RawMinkContext {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($microsleep) {
|
||||
usleep(100000);
|
||||
} else {
|
||||
sleep(1);
|
||||
if ($this->running_javascript()) {
|
||||
if ($microsleep) {
|
||||
usleep(100000);
|
||||
} else {
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -39,41 +39,47 @@ class behat_selectors {
|
||||
* @var Allowed types when using text selectors arguments.
|
||||
*/
|
||||
protected static $allowedtextselectors = array(
|
||||
'dialogue' => 'dialogue',
|
||||
'activity' => 'activity',
|
||||
'block' => 'block',
|
||||
'region' => 'region',
|
||||
'table_row' => 'table_row',
|
||||
'list_item' => 'list_item',
|
||||
'table' => 'table',
|
||||
'fieldset' => 'fieldset',
|
||||
'css_element' => 'css_element',
|
||||
'xpath_element' => 'xpath_element'
|
||||
'dialogue' => 'dialogue',
|
||||
'fieldset' => 'fieldset',
|
||||
'list_item' => 'list_item',
|
||||
'question' => 'question',
|
||||
'region' => 'region',
|
||||
'section' => 'section',
|
||||
'table' => 'table',
|
||||
'table_row' => 'table_row',
|
||||
'xpath_element' => 'xpath_element',
|
||||
);
|
||||
|
||||
/**
|
||||
* @var Allowed types when using selector arguments.
|
||||
*/
|
||||
protected static $allowedselectors = array(
|
||||
'dialogue' => 'dialogue',
|
||||
'activity' => 'activity',
|
||||
'block' => 'block',
|
||||
'region' => 'region',
|
||||
'table_row' => 'table_row',
|
||||
'list_item' => 'list_item',
|
||||
'link' => 'link',
|
||||
'button' => 'button',
|
||||
'link_or_button' => 'link_or_button',
|
||||
'select' => 'select',
|
||||
'checkbox' => 'checkbox',
|
||||
'radio' => 'radio',
|
||||
'file' => 'file',
|
||||
'filemanager' => 'filemanager',
|
||||
'optgroup' => 'optgroup',
|
||||
'option' => 'option',
|
||||
'table' => 'table',
|
||||
'css_element' => 'css_element',
|
||||
'dialogue' => 'dialogue',
|
||||
'field' => 'field',
|
||||
'fieldset' => 'fieldset',
|
||||
'file' => 'file',
|
||||
'filemanager' => 'filemanager',
|
||||
'link' => 'link',
|
||||
'link_or_button' => 'link_or_button',
|
||||
'list_item' => 'list_item',
|
||||
'optgroup' => 'optgroup',
|
||||
'option' => 'option',
|
||||
'question' => 'question',
|
||||
'radio' => 'radio',
|
||||
'region' => 'region',
|
||||
'section' => 'section',
|
||||
'select' => 'select',
|
||||
'table' => 'table',
|
||||
'table_row' => 'table_row',
|
||||
'text' => 'text',
|
||||
'css_element' => 'css_element',
|
||||
'xpath_element' => 'xpath_element'
|
||||
);
|
||||
|
||||
@@ -86,8 +92,14 @@ class behat_selectors {
|
||||
* @var XPaths for moodle elements.
|
||||
*/
|
||||
protected static $moodleselectors = array(
|
||||
'text' => <<<XPATH
|
||||
//*[contains(., %locator%)][count(./descendant::*[contains(., %locator%)]) = 0]
|
||||
'activity' => <<<XPATH
|
||||
//li[contains(concat(' ', normalize-space(@class), ' '), ' activity ')][normalize-space(.) = %locator% ]
|
||||
XPATH
|
||||
, 'block' => <<<XPATH
|
||||
//div[contains(concat(' ', normalize-space(@class), ' '), ' block ') and
|
||||
(contains(concat(' ', normalize-space(@class), ' '), concat(' ', %locator%, ' ')) or
|
||||
descendant::h2[normalize-space(.) = %locator%] or
|
||||
@aria-label = %locator%)]
|
||||
XPATH
|
||||
, 'dialogue' => <<<XPATH
|
||||
//div[contains(concat(' ', normalize-space(@class), ' '), ' moodle-dialogue ') and
|
||||
@@ -96,28 +108,36 @@ XPATH
|
||||
]) = %locator%] |
|
||||
//div[contains(concat(' ', normalize-space(@class), ' '), ' yui-dialog ') and
|
||||
normalize-space(descendant::div[@class='hd']) = %locator%]
|
||||
XPATH
|
||||
, 'block' => <<<XPATH
|
||||
//div[contains(concat(' ', normalize-space(@class), ' '), ' block ') and
|
||||
(contains(concat(' ', normalize-space(@class), ' '), concat(' ', %locator%, ' ')) or
|
||||
descendant::h2[normalize-space(.) = %locator%] or
|
||||
@aria-label = %locator%)]
|
||||
XPATH
|
||||
, 'region' => <<<XPATH
|
||||
//*[self::div | self::section | self::aside | self::header | self::footer][./@id = %locator%]
|
||||
XPATH
|
||||
, 'table_row' => <<<XPATH
|
||||
.//tr[contains(normalize-space(.), %locator%)]
|
||||
XPATH
|
||||
, 'list_item' => <<<XPATH
|
||||
.//li[contains(normalize-space(.), %locator%)]
|
||||
XPATH
|
||||
, 'filemanager' => <<<XPATH
|
||||
//div[contains(concat(' ', normalize-space(@class), ' '), ' ffilemanager ')]
|
||||
/descendant::input[@id = //label[contains(normalize-space(string(.)), %locator%)]/@for]
|
||||
XPATH
|
||||
, 'list_item' => <<<XPATH
|
||||
.//li[contains(normalize-space(.), %locator%)]
|
||||
XPATH
|
||||
, 'question' => <<<XPATH
|
||||
//div[contains(concat(' ', normalize-space(@class), ' '), ' que ')]
|
||||
[contains(div[@class='content']/div[@class='formulation'], %locator%)]
|
||||
XPATH
|
||||
, 'region' => <<<XPATH
|
||||
//*[self::div | self::section | self::aside | self::header | self::footer][./@id = %locator%]
|
||||
XPATH
|
||||
, 'section' => <<<XPATH
|
||||
//li[contains(concat(' ', normalize-space(@class), ' '), ' section ')][./descendant::*[self::h3]
|
||||
[normalize-space(.) = %locator%][contains(concat(' ', normalize-space(@class), ' '), ' sectionname ') or
|
||||
contains(concat(' ', normalize-space(@class), ' '), ' section-title ')]] |
|
||||
//div[contains(concat(' ', normalize-space(@class), ' '), ' sitetopic ')]
|
||||
[./descendant::*[self::h2][normalize-space(.) = %locator%] or %locator% = 'frontpage']
|
||||
XPATH
|
||||
, 'table' => <<<XPATH
|
||||
.//table[(./@id = %locator% or contains(.//caption, %locator%) or contains(concat(' ', normalize-space(@class), ' '), %locator% ))]
|
||||
XPATH
|
||||
, 'table_row' => <<<XPATH
|
||||
.//tr[contains(normalize-space(.), %locator%)]
|
||||
XPATH
|
||||
, 'text' => <<<XPATH
|
||||
//*[contains(., %locator%)][count(./descendant::*[contains(., %locator%)]) = 0]
|
||||
XPATH
|
||||
);
|
||||
|
||||
|
||||
+23
-14
@@ -486,6 +486,11 @@ class block_manager {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Block regions should not be docked during editing when all the blocks are hidden.
|
||||
if ($this->page->user_is_editing() && $this->page->user_can_edit_blocks()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->check_is_loaded();
|
||||
$this->ensure_content_created($region, $output);
|
||||
if (!$this->region_has_content($region, $output)) {
|
||||
@@ -493,7 +498,7 @@ class block_manager {
|
||||
return false;
|
||||
}
|
||||
foreach ($this->visibleblockcontent[$region] as $instance) {
|
||||
if (!empty($instance->content) && !get_user_preferences('docked_block_instance_'.$instance->blockinstanceid, 0)) {
|
||||
if (!get_user_preferences('docked_block_instance_'.$instance->blockinstanceid, 0)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -745,19 +750,23 @@ class block_manager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method, calls add_block repeatedly for all the blocks in $blocks.
|
||||
* Convenience method, calls add_block repeatedly for all the blocks in $blocks. Optionally, a starting weight
|
||||
* can be used to decide the starting point that blocks are added in the region, the weight is passed to {@link add_block}
|
||||
* and incremented by the position of the block in the $blocks array
|
||||
*
|
||||
* @param array $blocks array with array keys the region names, and values an array of block names.
|
||||
* @param string $pagetypepattern optional. Passed to @see add_block()
|
||||
* @param string $subpagepattern optional. Passed to @see add_block()
|
||||
* @param string $pagetypepattern optional. Passed to {@link add_block()}
|
||||
* @param string $subpagepattern optional. Passed to {@link add_block()}
|
||||
* @param boolean $showinsubcontexts optional. Passed to {@link add_block()}
|
||||
* @param integer $weight optional. Determines the starting point that the blocks are added in the region.
|
||||
*/
|
||||
public function add_blocks($blocks, $pagetypepattern = NULL, $subpagepattern = NULL, $showinsubcontexts=false, $weight=0) {
|
||||
$initialweight = $weight;
|
||||
$this->add_regions(array_keys($blocks), false);
|
||||
foreach ($blocks as $region => $regionblocks) {
|
||||
$weight = 0;
|
||||
foreach ($regionblocks as $blockname) {
|
||||
foreach ($regionblocks as $offset => $blockname) {
|
||||
$weight = $initialweight + $offset;
|
||||
$this->add_block($blockname, $region, $weight, $showinsubcontexts, $pagetypepattern, $subpagepattern);
|
||||
$weight += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2118,12 +2127,12 @@ function blocks_find_block($blockid, $blocksarray) {
|
||||
|
||||
// Functions for programatically adding default blocks to pages ================
|
||||
|
||||
/**
|
||||
* Parse a list of default blocks. See config-dist for a description of the format.
|
||||
*
|
||||
* @param string $blocksstr
|
||||
* @return array
|
||||
*/
|
||||
/**
|
||||
* Parse a list of default blocks. See config-dist for a description of the format.
|
||||
*
|
||||
* @param string $blocksstr Determines the starting point that the blocks are added in the region.
|
||||
* @return array the parsed list of default blocks
|
||||
*/
|
||||
function blocks_parse_default_blocks_list($blocksstr) {
|
||||
$blocks = array();
|
||||
$bits = explode(':', $blocksstr);
|
||||
@@ -2134,7 +2143,7 @@ function blocks_parse_default_blocks_list($blocksstr) {
|
||||
}
|
||||
}
|
||||
if (!empty($bits)) {
|
||||
$rightbits =trim(array_shift($bits));
|
||||
$rightbits = trim(array_shift($bits));
|
||||
if ($rightbits != '') {
|
||||
$blocks[BLOCK_POS_RIGHT] = explode(',', $rightbits);
|
||||
}
|
||||
|
||||
@@ -54,4 +54,41 @@ class portfolio extends base {
|
||||
public static function get_manage_url() {
|
||||
return new moodle_url('/admin/portfolio.php');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines if there should be a way to uninstall the plugin via the administration UI.
|
||||
* @return boolean
|
||||
*/
|
||||
public function is_uninstall_allowed() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pre-uninstall hook.
|
||||
* This is intended for disabling of plugin, some DB table purging, etc.
|
||||
*/
|
||||
public function uninstall_cleanup() {
|
||||
global $DB;
|
||||
|
||||
// Get all instances of this portfolio.
|
||||
$count = $DB->count_records('portfolio_instance', array('plugin' => $this->name));
|
||||
if ($count > 0) {
|
||||
// This portfolio is in use, get the it's ID.
|
||||
$rec = $DB->get_record('portfolio_instance', array('plugin' => $this->name));
|
||||
|
||||
// Remove all records from portfolio_instance_config.
|
||||
$DB->delete_records('portfolio_instance_config', array('instance' => $rec->id));
|
||||
// Remove all records from portfolio_instance_user.
|
||||
$DB->delete_records('portfolio_instance_user', array('instance' => $rec->id));
|
||||
// Remove all records from portfolio_log.
|
||||
$DB->delete_records('portfolio_log', array('portfolio' => $rec->id));
|
||||
// Remove all records from portfolio_tempdata.
|
||||
$DB->delete_records('portfolio_tempdata', array('instance' => $rec->id));
|
||||
|
||||
// Remove the record from the portfolio_instance table.
|
||||
$DB->delete_records('portfolio_instance', array('id' => $rec->id));
|
||||
}
|
||||
|
||||
parent::uninstall_cleanup();
|
||||
}
|
||||
}
|
||||
@@ -44,7 +44,7 @@ class memcached extends handler {
|
||||
protected $acquiretimeout = 120;
|
||||
/**
|
||||
* @var int $lockexpire how long to wait before expiring the lock so that other requests
|
||||
* may continue execution, ignored if memcached <= 2.1.0.
|
||||
* may continue execution, ignored if PECL memcached is below version 2.2.0.
|
||||
*/
|
||||
protected $lockexpire = 7200;
|
||||
|
||||
@@ -86,7 +86,7 @@ class memcached extends handler {
|
||||
* @return bool success
|
||||
*/
|
||||
public function start() {
|
||||
// NOTE: memcached <= 2.1.0 expires session locks automatically after max_execution_time,
|
||||
// NOTE: memcached before 2.2.0 expires session locks automatically after max_execution_time,
|
||||
// this leads to major difference compared to other session drivers that timeout
|
||||
// and stop the second request execution instead.
|
||||
|
||||
@@ -119,7 +119,7 @@ class memcached extends handler {
|
||||
ini_set('memcached.sess_prefix', $this->prefix);
|
||||
ini_set('memcached.sess_locking', '1'); // Locking is required!
|
||||
|
||||
// Try to configure lock and expire timeouts - ignored if memcached <=2.1.0.
|
||||
// Try to configure lock and expire timeouts - ignored if memcached is before version 2.2.0.
|
||||
ini_set('memcached.sess_lock_max_wait', $this->acquiretimeout);
|
||||
ini_set('memcached.sess_lock_expire', $this->lockexpire);
|
||||
}
|
||||
|
||||
@@ -85,53 +85,31 @@ class manager {
|
||||
*/
|
||||
public static function reset_scheduled_tasks_for_component($componentname) {
|
||||
global $DB;
|
||||
$cronlockfactory = \core\lock\lock_config::get_lock_factory('cron');
|
||||
|
||||
if (!$cronlock = $cronlockfactory->get_lock('core_cron', 10, 60)) {
|
||||
throw new \moodle_exception('locktimeout');
|
||||
}
|
||||
$tasks = self::load_default_scheduled_tasks_for_component($componentname);
|
||||
|
||||
$tasklocks = array();
|
||||
foreach ($tasks as $taskid => $task) {
|
||||
$classname = get_class($task);
|
||||
if (strpos($classname, '\\') !== 0) {
|
||||
$classname = '\\' . $classname;
|
||||
}
|
||||
|
||||
// For tasks, the first run should also follow the schedule.
|
||||
$task->set_next_run_time($task->get_next_scheduled_time());
|
||||
|
||||
// If there is an existing task with a custom schedule, do not override it.
|
||||
$currenttask = self::get_scheduled_task($classname);
|
||||
if ($currenttask && $currenttask->is_customised()) {
|
||||
$tasks[$taskid] = $currenttask;
|
||||
}
|
||||
|
||||
if (!$lock = $cronlockfactory->get_lock($classname, 10, 60)) {
|
||||
// Could not get all the locks required - release all locks and fail.
|
||||
foreach ($tasklocks as $tasklock) {
|
||||
$tasklock->release();
|
||||
if ($currenttask = self::get_scheduled_task($classname)) {
|
||||
if ($currenttask->is_customised()) {
|
||||
// If there is an existing task with a custom schedule, do not override it.
|
||||
continue;
|
||||
}
|
||||
$cronlock->release();
|
||||
throw new \moodle_exception('locktimeout');
|
||||
|
||||
// Update the record from the default task data.
|
||||
self::configure_scheduled_task($task);
|
||||
} else {
|
||||
// Ensure that the first run follows the schedule.
|
||||
$task->set_next_run_time($task->get_next_scheduled_time());
|
||||
|
||||
// Insert the new task in the database.
|
||||
$record = self::record_from_scheduled_task($task);
|
||||
$DB->insert_record('task_scheduled', $record);
|
||||
}
|
||||
$tasklocks[] = $lock;
|
||||
}
|
||||
|
||||
// Got a lock on cron and all the tasks for this component, time to reset the config.
|
||||
$DB->delete_records('task_scheduled', array('component' => $componentname));
|
||||
foreach ($tasks as $task) {
|
||||
$record = self::record_from_scheduled_task($task);
|
||||
$DB->insert_record('task_scheduled', $record);
|
||||
}
|
||||
|
||||
// Release the locks.
|
||||
foreach ($tasklocks as $tasklock) {
|
||||
$tasklock->release();
|
||||
}
|
||||
|
||||
$cronlock->release();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -160,20 +138,11 @@ class manager {
|
||||
*/
|
||||
public static function configure_scheduled_task(scheduled_task $task) {
|
||||
global $DB;
|
||||
$cronlockfactory = \core\lock\lock_config::get_lock_factory('cron');
|
||||
|
||||
if (!$cronlock = $cronlockfactory->get_lock('core_cron', 10, 60)) {
|
||||
throw new \moodle_exception('locktimeout');
|
||||
}
|
||||
|
||||
$classname = get_class($task);
|
||||
if (strpos($classname, '\\') !== 0) {
|
||||
$classname = '\\' . $classname;
|
||||
}
|
||||
if (!$lock = $cronlockfactory->get_lock($classname, 10, 60)) {
|
||||
$cronlock->release();
|
||||
throw new \moodle_exception('locktimeout');
|
||||
}
|
||||
|
||||
$original = $DB->get_record('task_scheduled', array('classname'=>$classname), 'id', MUST_EXIST);
|
||||
|
||||
@@ -182,8 +151,6 @@ class manager {
|
||||
$record->nextruntime = $task->get_next_scheduled_time();
|
||||
$result = $DB->update_record('task_scheduled', $record);
|
||||
|
||||
$lock->release();
|
||||
$cronlock->release();
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
@@ -323,8 +323,11 @@ class component_installer {
|
||||
/// Move current revision to a safe place
|
||||
$destinationdir = $CFG->dataroot.'/'.$this->destpath;
|
||||
$destinationcomponent = $destinationdir.'/'.$this->componentname;
|
||||
@remove_dir($destinationcomponent.'_old'); //Deleting possible old components before
|
||||
@rename ($destinationcomponent, $destinationcomponent.'_old'); //Moving to a safe place
|
||||
@remove_dir($destinationcomponent.'_old'); // Deleting a possible old version.
|
||||
|
||||
// Moving to a safe place.
|
||||
@rename($destinationcomponent, $destinationcomponent.'_old');
|
||||
|
||||
/// Unzip new version
|
||||
if (!unzip_file($zipfile, $destinationdir, false)) {
|
||||
/// Error so, go back to the older
|
||||
|
||||
+13
-3
@@ -168,9 +168,11 @@ function min_enable_zlib_compression() {
|
||||
* Note: ".php" is NOT allowed in slasharguments,
|
||||
* it is intended for ASCII characters only.
|
||||
*
|
||||
* @param boolean $clean - Should we do cleaning on this path argument. If you set this
|
||||
* to false you MUST be very careful and do the cleaning manually.
|
||||
* @return string
|
||||
*/
|
||||
function min_get_slash_argument() {
|
||||
function min_get_slash_argument($clean = true) {
|
||||
// Note: This code has to work in the same cases as normal get_file_argument(),
|
||||
// but at the same time it may be simpler because we do not have to deal
|
||||
// with encodings and other tricky stuff.
|
||||
@@ -180,7 +182,12 @@ function min_get_slash_argument() {
|
||||
if (!empty($_GET['file']) and strpos($_GET['file'], '/') === 0) {
|
||||
// Server is using url rewriting, most probably IIS.
|
||||
// Always clean the result of this function as it may be used in unsafe calls to send_file.
|
||||
return min_clean_param($_GET['file'], 'SAFEPATH');
|
||||
$relativepath = $_GET['file'];
|
||||
if ($clean) {
|
||||
$relativepath = min_clean_param($relativepath, 'SAFEPATH');
|
||||
}
|
||||
|
||||
return $relativepath;
|
||||
|
||||
} else if (stripos($_SERVER['SERVER_SOFTWARE'], 'iis') !== false) {
|
||||
if (isset($_SERVER['PATH_INFO']) and $_SERVER['PATH_INFO'] !== '') {
|
||||
@@ -199,5 +206,8 @@ function min_get_slash_argument() {
|
||||
}
|
||||
|
||||
// Always clean the result of this function as it may be used in unsafe calls to send_file.
|
||||
return min_clean_param($relativepath, 'SAFEPATH');
|
||||
if ($clean) {
|
||||
$relativepath = min_clean_param($relativepath, 'SAFEPATH');
|
||||
}
|
||||
return $relativepath;
|
||||
}
|
||||
|
||||
+2
-2
@@ -125,8 +125,8 @@ $tasks = array(
|
||||
array(
|
||||
'classname' => 'core\task\create_contexts_task',
|
||||
'blocking' => 1,
|
||||
'minute' => '*',
|
||||
'hour' => '*',
|
||||
'minute' => '0',
|
||||
'hour' => '0',
|
||||
'day' => '*',
|
||||
'dayofweek' => '*',
|
||||
'month' => '*'
|
||||
|
||||
@@ -978,7 +978,8 @@ class oci_native_moodle_database extends moodle_database {
|
||||
|
||||
default: // Bind as CHAR (applying dirty hack)
|
||||
// TODO: Optimise
|
||||
oci_bind_by_name($stmt, $key, $this->oracle_dirty_hack($tablename, $columnname, $params[$key]));
|
||||
$params[$key] = $this->oracle_dirty_hack($tablename, $columnname, $params[$key]);
|
||||
oci_bind_by_name($stmt, $key, $params[$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+15
@@ -299,6 +299,21 @@ Y.extend(Editor, Y.Base, {
|
||||
setupAutomaticPolling: function() {
|
||||
this._registerEventHandle(this.editor.on(['keyup', 'paste', 'cut'], this.updateOriginal, this));
|
||||
|
||||
// Call this.updateOriginal after dropped content has been processed.
|
||||
this._registerEventHandle(this.editor.on('drop', this.updateOriginalDelayed, this));
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Calls updateOriginal on a short timer to allow native event handlers to run first.
|
||||
*
|
||||
* @method updateOriginalDelayed
|
||||
* @chainable
|
||||
*/
|
||||
updateOriginalDelayed: function() {
|
||||
Y.soon(Y.bind(this.updateOriginal, this));
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
|
||||
+3
-3
File diff suppressed because one or more lines are too long
+15
@@ -297,6 +297,21 @@ Y.extend(Editor, Y.Base, {
|
||||
setupAutomaticPolling: function() {
|
||||
this._registerEventHandle(this.editor.on(['keyup', 'paste', 'cut'], this.updateOriginal, this));
|
||||
|
||||
// Call this.updateOriginal after dropped content has been processed.
|
||||
this._registerEventHandle(this.editor.on('drop', this.updateOriginalDelayed, this));
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Calls updateOriginal on a short timer to allow native event handlers to run first.
|
||||
*
|
||||
* @method updateOriginalDelayed
|
||||
* @chainable
|
||||
*/
|
||||
updateOriginalDelayed: function() {
|
||||
Y.soon(Y.bind(this.updateOriginal, this));
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
|
||||
+15
@@ -297,6 +297,21 @@ Y.extend(Editor, Y.Base, {
|
||||
setupAutomaticPolling: function() {
|
||||
this._registerEventHandle(this.editor.on(['keyup', 'paste', 'cut'], this.updateOriginal, this));
|
||||
|
||||
// Call this.updateOriginal after dropped content has been processed.
|
||||
this._registerEventHandle(this.editor.on('drop', this.updateOriginalDelayed, this));
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Calls updateOriginal on a short timer to allow native event handlers to run first.
|
||||
*
|
||||
* @method updateOriginalDelayed
|
||||
* @chainable
|
||||
*/
|
||||
updateOriginalDelayed: function() {
|
||||
Y.soon(Y.bind(this.updateOriginal, this));
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
|
||||
Vendored
+7
-5
@@ -108,11 +108,12 @@ class core_external extends external_api {
|
||||
* @return string
|
||||
* @since Moodle 2.4
|
||||
*/
|
||||
public static function get_string($stringid, $component = 'moodle', $stringparams = array()) {
|
||||
public static function get_string($stringid, $component = 'moodle', $lang = null, $stringparams = array()) {
|
||||
$params = self::validate_parameters(self::get_string_parameters(),
|
||||
array('stringid'=>$stringid, 'component' => $component, 'stringparams' => $stringparams));
|
||||
array('stringid'=>$stringid, 'component' => $component, 'lang' => $lang, 'stringparams' => $stringparams));
|
||||
|
||||
return get_string($params['stringid'], $params['component'],
|
||||
$stringmanager = get_string_manager();
|
||||
return $stringmanager->get_string($params['stringid'], $params['component'],
|
||||
core_external::format_string_parameters($params['stringparams']), $params['lang']);
|
||||
}
|
||||
|
||||
@@ -163,11 +164,12 @@ class core_external extends external_api {
|
||||
public static function get_strings($strings) {
|
||||
$params = self::validate_parameters(self::get_strings_parameters(),
|
||||
array('strings'=>$strings));
|
||||
$stringmanager = get_string_manager();
|
||||
|
||||
$translatedstrings = array();
|
||||
foreach($params['strings'] as $string) {
|
||||
|
||||
if (empty($string['lang'])) {
|
||||
if (!empty($string['lang'])) {
|
||||
$lang = $string['lang'];
|
||||
} else {
|
||||
$lang = current_language();
|
||||
@@ -177,7 +179,7 @@ class core_external extends external_api {
|
||||
'stringid' => $string['stringid'],
|
||||
'component' => $string['component'],
|
||||
'lang' => $lang,
|
||||
'string' => get_string($string['stringid'], $string['component'],
|
||||
'string' => $stringmanager->get_string($string['stringid'], $string['component'],
|
||||
core_external::format_string_parameters($string['stringparams']), $lang));
|
||||
}
|
||||
|
||||
|
||||
Vendored
+12
-6
@@ -41,7 +41,7 @@ class core_external_testcase extends externallib_advanced_testcase {
|
||||
$service->id = 12;
|
||||
|
||||
// String with two parameters.
|
||||
$returnedstring = core_external::get_string('addservice', 'webservice',
|
||||
$returnedstring = core_external::get_string('addservice', 'webservice', null,
|
||||
array(array('name' => 'name', 'value' => $service->name),
|
||||
array('name' => 'id', 'value' => $service->id)));
|
||||
|
||||
@@ -53,7 +53,7 @@ class core_external_testcase extends externallib_advanced_testcase {
|
||||
|
||||
// String with one parameter.
|
||||
$acapname = 'A capability name';
|
||||
$returnedstring = core_external::get_string('missingrequiredcapability', 'webservice',
|
||||
$returnedstring = core_external::get_string('missingrequiredcapability', 'webservice', null,
|
||||
array(array('value' => $acapname)));
|
||||
|
||||
// We need to execute the return values cleaning process to simulate the web service server.
|
||||
@@ -73,7 +73,7 @@ class core_external_testcase extends externallib_advanced_testcase {
|
||||
|
||||
// String with two parameter but one is invalid (not named).
|
||||
$this->setExpectedException('moodle_exception');
|
||||
$returnedstring = core_external::get_string('addservice', 'webservice',
|
||||
$returnedstring = core_external::get_string('addservice', 'webservice', null,
|
||||
array(array('value' => $service->name),
|
||||
array('name' => 'id', 'value' => $service->id)));
|
||||
}
|
||||
@@ -84,6 +84,8 @@ class core_external_testcase extends externallib_advanced_testcase {
|
||||
public function test_get_strings() {
|
||||
$this->resetAfterTest(true);
|
||||
|
||||
$stringmanager = get_string_manager();
|
||||
|
||||
$service = new stdClass();
|
||||
$service->name = 'Dummy Service';
|
||||
$service->id = 12;
|
||||
@@ -94,16 +96,20 @@ class core_external_testcase extends externallib_advanced_testcase {
|
||||
'stringid' => 'addservice', 'component' => 'webservice',
|
||||
'stringparams' => array(array('name' => 'name', 'value' => $service->name),
|
||||
array('name' => 'id', 'value' => $service->id)
|
||||
)
|
||||
),
|
||||
'lang' => 'en'
|
||||
),
|
||||
array('stringid' => 'addaservice', 'component' => 'webservice')
|
||||
array('stringid' => 'addaservice', 'component' => 'webservice', 'lang' => 'en')
|
||||
));
|
||||
|
||||
// We need to execute the return values cleaning process to simulate the web service server.
|
||||
$returnedstrings = external_api::clean_returnvalue(core_external::get_strings_returns(), $returnedstrings);
|
||||
|
||||
foreach($returnedstrings as $returnedstring) {
|
||||
$corestring = get_string($returnedstring['stringid'], $returnedstring['component'], $service);
|
||||
$corestring = $stringmanager->get_string($returnedstring['stringid'],
|
||||
$returnedstring['component'],
|
||||
$service,
|
||||
'en');
|
||||
$this->assertSame($corestring, $returnedstring['string']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -656,6 +656,7 @@ class zip_archive extends file_archive {
|
||||
case 'ISO-8859-6': $encoding = 'CP720'; break;
|
||||
case 'ISO-8859-7': $encoding = 'CP737'; break;
|
||||
case 'ISO-8859-8': $encoding = 'CP862'; break;
|
||||
case 'EUC-JP':
|
||||
case 'UTF-8':
|
||||
if ($winchar = get_string('localewincharset', 'langconfig')) {
|
||||
// Most probably works only for zh_cn,
|
||||
|
||||
+1
-1
@@ -2905,7 +2905,7 @@ class MoodleQuickForm_Rule_Required extends HTML_QuickForm_Rule {
|
||||
global $CFG;
|
||||
if (!empty($CFG->strictformsrequired)) {
|
||||
if (!empty($format) && $format == FORMAT_HTML) {
|
||||
return array('', "{jsVar}.replace(/(<[^img|hr|canvas]+>)| |\s+/ig, '') == ''");
|
||||
return array('', "{jsVar}.replace(/(<(?!img|hr|canvas)[^>]*>)| |\s+/ig, '') == ''");
|
||||
} else {
|
||||
return array('', "{jsVar}.replace(/^\s+$/g, '') == ''");
|
||||
}
|
||||
|
||||
@@ -767,6 +767,8 @@ class grade_category extends grade_object {
|
||||
* Set the flags on the grade_grade items to indicate how individual grades are used
|
||||
* in the aggregation.
|
||||
*
|
||||
* WARNING: This function is called a lot during gradebook recalculation, be very performance considerate.
|
||||
*
|
||||
* @param int $userid The user we have aggregated the grades for.
|
||||
* @param array $usedweights An array with keys for each of the grade_item columns included in the aggregation. The value are the relative weight.
|
||||
* @param array $novalue An array with keys for each of the grade_item columns skipped because
|
||||
@@ -779,44 +781,32 @@ class grade_category extends grade_object {
|
||||
private function set_usedinaggregation($userid, $usedweights, $novalue, $dropped, $extracredit) {
|
||||
global $DB;
|
||||
|
||||
// First set them all to weight null and status = 'unknown'.
|
||||
if ($allitems = grade_item::fetch_all(array('categoryid'=>$this->id))) {
|
||||
list($itemsql, $itemlist) = $DB->get_in_or_equal(array_keys($allitems), SQL_PARAMS_NAMED, 'g');
|
||||
// Reset aggregation to unknown and 0 for all grade items for this user and category.
|
||||
$params = array('categoryid' => $this->id, 'userid' => $userid);
|
||||
$itemssql = "SELECT id
|
||||
FROM {grade_items}
|
||||
WHERE categoryid = :categoryid";
|
||||
|
||||
$itemlist['userid'] = $userid;
|
||||
$sql = "UPDATE {grade_grades}
|
||||
SET aggregationstatus = 'unknown',
|
||||
aggregationweight = 0
|
||||
WHERE userid = :userid
|
||||
AND itemid IN ($itemssql)";
|
||||
|
||||
$DB->set_field_select('grade_grades',
|
||||
'aggregationstatus',
|
||||
'unknown',
|
||||
"itemid $itemsql AND userid = :userid",
|
||||
$itemlist);
|
||||
$DB->set_field_select('grade_grades',
|
||||
'aggregationweight',
|
||||
0,
|
||||
"itemid $itemsql AND userid = :userid",
|
||||
$itemlist);
|
||||
}
|
||||
$DB->execute($sql, $params);
|
||||
|
||||
// Included.
|
||||
// Included with weights.
|
||||
if (!empty($usedweights)) {
|
||||
// The usedweights items are updated individually to record the weights.
|
||||
foreach ($usedweights as $gradeitemid => $contribution) {
|
||||
$DB->set_field_select('grade_grades',
|
||||
'aggregationweight',
|
||||
$contribution,
|
||||
"itemid = :itemid AND userid = :userid",
|
||||
array('itemid'=>$gradeitemid, 'userid'=>$userid));
|
||||
$sql = "UPDATE {grade_grades}
|
||||
SET aggregationstatus = 'used',
|
||||
aggregationweight = :contribution
|
||||
WHERE itemid = :itemid AND userid = :userid";
|
||||
|
||||
$params = array('contribution' => $contribution, 'itemid' => $gradeitemid, 'userid' => $userid);
|
||||
$DB->execute($sql, $params);
|
||||
}
|
||||
|
||||
// Now set the status flag for all these weights.
|
||||
list($itemsql, $itemlist) = $DB->get_in_or_equal(array_keys($usedweights), SQL_PARAMS_NAMED, 'g');
|
||||
$itemlist['userid'] = $userid;
|
||||
|
||||
$DB->set_field_select('grade_grades',
|
||||
'aggregationstatus',
|
||||
'used',
|
||||
"itemid $itemsql AND userid = :userid",
|
||||
$itemlist);
|
||||
}
|
||||
|
||||
// No value.
|
||||
@@ -844,6 +834,7 @@ class grade_category extends grade_object {
|
||||
"itemid $itemsql AND userid = :userid",
|
||||
$itemlist);
|
||||
}
|
||||
|
||||
// Extra credit.
|
||||
if (!empty($extracredit)) {
|
||||
list($itemsql, $itemlist) = $DB->get_in_or_equal(array_keys($extracredit), SQL_PARAMS_NAMED, 'g');
|
||||
|
||||
@@ -597,14 +597,32 @@ M.util.init_block_hider = function(Y, config) {
|
||||
this.set('block', '#'+this.get('id'));
|
||||
var b = this.get('block'),
|
||||
t = b.one('.title'),
|
||||
a = null;
|
||||
a = null,
|
||||
hide,
|
||||
show;
|
||||
if (t && (a = t.one('.block_action'))) {
|
||||
var hide = Y.Node.create('<img class="block-hider-hide" tabindex="0" alt="'+config.tooltipVisible+'" title="'+config.tooltipVisible+'" />');
|
||||
hide.setAttribute('src', this.get('iconVisible')).on('click', this.updateState, this, true);
|
||||
hide = Y.Node.create('<img />')
|
||||
.addClass('block-hider-hide')
|
||||
.setAttrs({
|
||||
alt: config.tooltipVisible,
|
||||
src: this.get('iconVisible'),
|
||||
tabindex: 0,
|
||||
'title': config.tooltipVisible
|
||||
});
|
||||
hide.on('keypress', this.updateStateKey, this, true);
|
||||
var show = Y.Node.create('<img class="block-hider-show" tabindex="0" alt="'+config.tooltipHidden+'" title="'+config.tooltipHidden+'" />');
|
||||
show.setAttribute('src', this.get('iconHidden')).on('click', this.updateState, this, false);
|
||||
hide.on('click', this.updateState, this, true);
|
||||
|
||||
show = Y.Node.create('<img />')
|
||||
.addClass('block-hider-show')
|
||||
.setAttrs({
|
||||
alt: config.tooltipHidden,
|
||||
src: this.get('iconHidden'),
|
||||
tabindex: 0,
|
||||
'title': config.tooltipHidden
|
||||
});
|
||||
show.on('keypress', this.updateStateKey, this, false);
|
||||
show.on('click', this.updateState, this, false);
|
||||
|
||||
a.insert(show, 0).insert(hide, 0);
|
||||
}
|
||||
},
|
||||
|
||||
+55
-1
@@ -536,15 +536,69 @@ class core_media_player_youtube extends core_media_player_external {
|
||||
|
||||
self::pick_video_size($width, $height);
|
||||
|
||||
$params = '';
|
||||
$start = self::get_start_time($url);
|
||||
if ($start > 0) {
|
||||
$params .= "start=$start&";
|
||||
}
|
||||
|
||||
$listid = $url->param('list');
|
||||
// Check for non-empty but valid playlist ID.
|
||||
if (!empty($listid) && !preg_match('/[^a-zA-Z0-9\-_]/', $listid)) {
|
||||
// This video is part of a playlist, and we want to embed it as such.
|
||||
$params .= "list=$listid&";
|
||||
}
|
||||
|
||||
return <<<OET
|
||||
<span class="mediaplugin mediaplugin_youtube">
|
||||
<iframe title="$info" width="$width" height="$height"
|
||||
src="https://www.youtube.com/embed/$videoid?rel=0&wmode=transparent" frameborder="0" allowfullscreen="1"></iframe>
|
||||
src="https://www.youtube.com/embed/$videoid?{$params}rel=0&wmode=transparent" frameborder="0" allowfullscreen="1"></iframe>
|
||||
</span>
|
||||
OET;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for start time parameter. Note that it's in hours/mins/secs in the URL,
|
||||
* but the embedded player takes only a number of seconds as the "start" parameter.
|
||||
* @param moodle_url $url URL of video to be embedded.
|
||||
* @return int Number of seconds video should start at.
|
||||
*/
|
||||
protected static function get_start_time($url) {
|
||||
$matches = array();
|
||||
$seconds = 0;
|
||||
|
||||
$rawtime = $url->param('t');
|
||||
if (empty($rawtime)) {
|
||||
$rawtime = $url->param('start');
|
||||
}
|
||||
|
||||
if (is_numeric($rawtime)) {
|
||||
// Start time already specified as a number of seconds; ensure it's an integer.
|
||||
$seconds = $rawtime;
|
||||
} else if (preg_match('/(\d+?h)?(\d+?m)?(\d+?s)?/i', $rawtime, $matches)) {
|
||||
// Convert into a raw number of seconds, as that's all embedded players accept.
|
||||
for ($i = 1; $i < count($matches); $i++) {
|
||||
if (empty($matches[$i])) {
|
||||
continue;
|
||||
}
|
||||
$part = str_split($matches[$i], strlen($matches[$i]) - 1);
|
||||
switch ($part[1]) {
|
||||
case 'h':
|
||||
$seconds += 3600 * $part[0];
|
||||
break;
|
||||
case 'm':
|
||||
$seconds += 60 * $part[0];
|
||||
break;
|
||||
default:
|
||||
$seconds += $part[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return intval($seconds);
|
||||
}
|
||||
|
||||
protected function get_regex() {
|
||||
// Regex for standard youtube link
|
||||
$link = '(youtube(-nocookie)?\.com/(?:watch\?v=|v/))';
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user